Necromant’s MultiDrop UART: Базовая плата.

По долгу службы работаю с кучей эмбеддед железяк. А что у них общего? Правильно УАРТ. То, по чему мы отлаживаемся и даем убуту инструкции грузить ядро. Когда борд много, понимаешь, что начинаешь обрастать интерфейсными микросхемами с usb на уарт, как дерево мхом, начинается чехарда(а /dev/ttyUSB0 у меня сейчас к этой плате подрублен, или я его переткнул?). Ну и особенно достает разница в логических уровнях.
В общем, это дело мне надоело и я смекнул:
1. работаю я обычно только с одной бордой из своего зоопарка.
2. на полке лежитмикросхемка ft232rl
3. а в ящике сдвиговые регистры и буферы…

Порывшись в хламе я так же откопал транзисторы в sot-23 корпусе (9012 и 8550), потенциометры и прочих хлам.
Собственно, мысль была такая. Делаем девайсину, которая будет мультиплексором изодного в N уартов. на ft232rl есть выводы CBUS, которые можно юзать в виде пинов общего назначения. Аж 4 штуки. Режим этот зовется bitbang и есть там даже библиотека для него – libftdi. Входы синхронного сдвигового регистра это clk и data. По фронту клока оно защелкивает данные и сдвигает их. Выход же параллельный. Таким образом, к ft232rl приросли 2 сдвиговых регистра.
Первый выбирает питание, второй адрес. Начнем с питания, так как именно оно и есть на базовой плате.
Мосфетов под рукой не было, но были транзисторы. Выбрал PNP, и заставил их работать в ключевом режиме. С коллектора питание идет на линейный стабилизатор ams1117. Выходное напряжение подстраивается потенциометром, а далее через диод Шоттки идет на VCCIO FT232RL и питание регистров. О как!
Итого 5 каналов настраиваемых подстроечниками, канал на 3.3 вольта и канал на 5 вольт. Настраиваться можно в диапазоне от 2х вольт до пяти, что я считаю очень неплохим диапазоном.
На базовой плате присутствовало только 2 разъема торчащие вверх, один с регистра выбора адреса, другой с выходов UART’a. Идея заключается в том, что количество каналов мы будем масштабировать лепя сверху “шилды”, на которых будет находиться, собственно, буфер и выходы уарта.
Далее пошло самое интересное. Оставалось нарисовать принципиалку этой хреновины, развести, протравить печатку и спаять. Хотя бы базовую плату. Эту задачу-то я и выполнил. Вышло примерно такое:

.
Не обошлось конечно без багов. транзисторы пришлось переворачивать и подгибать, ибо перепулось на футпринте база с эмиттером, а так же мне не в домек почему-то было, когда я рисовал схему, что когда все выходы сдвигового регистра отвечающего за питание единицы (то есть PNP транзистор закрыт), то и сам регистр отключен. И выйти из этого состояния никак. Потому пришлоь пожертвовать одним каналом, бросить провод на землю и обеспечить гарантированные 2 вольта дежурного напряжения.
Теперь дело остается за “шилдами”, которые будут крепиться сверху.

Сооружаем библиотеки для кикада полуавтоматически.

В общем, частенько надо сделать очередной символ для еесхемы. Благодаря утилитке от Rochbacher’a http://kicad.rohrbacher.net/quicklib.php это превращается в рутину. Скажи сколько выводов у микросхемы, забей имена пинов, скажи как ориентировать… Да в общем-то и все.
Вот только если ног за 200, заполнять это долго. Когда я делал символ для at91rm9200 терпение лопнуло на 30й ноге. А их там 208… Вот в тот момент мне и пришла в голову хорошая мысля. К сожалению, принимать файл с именами пинов утилита от Рохбахера не умеет, а его ящика почтового полазив по сайту я так и не нашел. Потому пришлось быстро сварганить костыль.

Нам потребуются:

bash (Куда же без него)
xdotool
okular (Или другой вювер PDF, который умеет выделять текст)

Шаг первый.
Открываем даташит и находим список ног. Например такое:

Шаг второй.
Копипастим имена ног в пустой файлик. Одна нога на одну строчку, строго по порядку.

Шаг третьий.
Далее немного черной магии. Берем вот этот готовый скрипт на баше:

#!/bin/bash
write_pin()
{
xdotool type "$1"
xdotool key Tab Tab Tab Tab Tab Tab
}
 
if [ $# -lt 1 ]; then
  echo "Usage: fill-pins filename"
  exit
fi
 
echo "Starting in 5 seconds..."
sleep 5
 
cat $1|while read line; do
  write_pin "$line"
done

Сохраняем, chmod +x, и скармливаем ему аргументом наш файлик с распиновкой. У нас есть 5 секунд переключиться на окно браузера и поставить курсор на строчку с надписью PIN1 (и выделить ее).
Далее скрипт читает каждую строчку из файла с распином, вбивает ее за нас в поле, жмет 6 раз Tab, чтобы перескочить на следующую… И так далее.
Можно пойти попить чаю. Выглядит забавно:

На время работы костыля лучше прихлопнуть все аськи, скайпы и прочее – так как одно всплывающее окошечко с “Приффет пайдем гулять” способно украсть фокус у браузера и, как следствие, загубить заполнение распина… а вхудшем случае ответить человеку в ICQ здоровенным списком пинов микросхемы…

USB Sniffo

Хех, еще одна неделька, и еще одна поделка. В общем, в этот раз сидя в своей дачной лаборатории я дебажил самодельный usb донгл. Унутрях аврка, vusb стек… в общем как обычно. Разве что багов огреб по полной программе. Результат глючил напрополую, проблема была явно не в коде.

Пришлось мастерить донгл для сниффинга усб транзакций. Нечто подобное пробегало уже недавно на HaD’e, но искать было лень. Часок убитый на разводку, потом традиционное шаманство с реагентами и вуоля. 2 порта, выведены пины для подключения осциллографа. Питание, D+, D- выведены на светодиоды, которые включаются джампером. Засверлил, приделал ножки.


Тонер по рекомендации товарища Inky не счищал, оставил для сущей “готишности”. После покрыл результат полиуретановым лаком, чтобы не боялось коррозии.

Принципиалка, разводка печатки в кикаде а так же готовый к печати постскрипт забираем тут:
sniffo.tar.gz

немного некромантии: воскрешаем HSDPA модем

Собственно, я его ухандакал. Настраивал роутер с OpenWrt, и подрубил к роутеру блок питания не на 5 а на 7.5 вольт.
Самому роутеру по барабану, у него степдаун мощный, а вот на усб заведено сырое питание со штекера… 7.5 вольт. В общем, модем после этого так и не ожил. Мигнул жалобно и сдох. Материл себя последними словами, ибо не столько жалко 30 баксов, сколько лениво опять месяц ждать, пока доедет. Потом я вздохнул и разобрал трупик.

Модем, к слову сказать, со странностями. Если долго не врубался, то вставка его в ноут отрубает ноутбук разом, как если бы было короткое замыкание по USB, в то время как повторное втыкание заставляет модем заработать.
Внутри нашлось прилично конденсаторов, как я и предполагал. Переходной процесс, пока они разряжены это закоротка, ток большой… В общем оно и ясно. Входные 5 вольт шунтировались двумя SMD кондерами 6V 470uF, после питание шло на неизвестную микросхему, а оттуда на 2х470uF 6V конденсатора + 2 танталовых неизвестного номинала им в параллель через катушку. LC фильтр в общем, причем C очень здоровое по номиналу. Если еще помню, gsm модули – это зараза прожорливая и любит потреблять burst’ами приличный ток.
На выходе микросхемы был ноль при включенном питании. Легко понять, что все, труп. Будем надеяться, что сам SoC не сдох. Ни даташитов, ничего на этот мелкий ноунейм преобразователь в интернете не нашлось, потому я засел искать доки на чип и думать какая напруга должна была выходить после. Астрал подсказывал мне что 3.3 вольта, но хотелось бы быть уверенным. Основная микросхема от Qualcomm, внутри ARM, кроме product brief на страничку ничего, а ядро арма может и 1.2 кушать. В общем собрал я lowdropper, и по очереди стал пробовать напруги, ожидая от какой напруги оно заведется. Завелось от 3.3 вольт.
Первым делом я вернул на место кондеры, и посадил на поксипол лоудроп.

Оный потом припаял проводками МГТФ-0.3 и забыл сфоткать.
Модем завелся, определился и проработал ровно 15 секунд – потом лоудроп перегрелся и вырубился.
Пришлось вздохнуть, сказать “прощай” эстетике, засверлить корпус, и посадить на поксипол мощный степдаун на 3.3 вольта на несколько ампер. Один черт лежать этому модему на чердаке с роутером в обнимку. Результат выглядит примерно так:

Один кондер с входных пяти вольт я всеже отпаял, чтобы ноутбук не вырубал. А то пока на ноутбуке буду отлаживать веб-интерфейс для модема он этими отключениями меня задолбает.

Результат завелся, заработал, поднял сеть и отпинговал яндекс. Особо гонять не было времени, но будем надеяться, больше багов не вылезет.

the_dropper

Потребовалось тут мне чтобы под рукой был девайс, выдающий разные напруги, которые меньше 3.3 вольт, да желательно покомпактнее. 38063 собирать было лень. Большей частью потому, что не хотелось мотать индуктивность: мой измеритель индуктивности стрельнули на недельку поюзать 2 месяца назад и так и не вернули.

Собственно, конструкция простая, как незнамо что. Кучка AMS1117, резюков, и светодиодик. Для рассчета номинала резюков подходит любой калькулятор для LM317. Резюк на светодиод я взял на 470 Ом.
Регуляторов я ставить не стал, так как нужны фиксированные обычно… Да и не было у меня под рукой подстроечников нужного диапазона.

Схемка примерно такая:

Вот так вот в 3d вышла печатка:

А вот так получилась сама плата:

Подручными средствами сделал девайсу ножки, шнур питания от usb и наклейку с номиналами выходных напряжений:

А вот тут можно взять проектик kicad: lowdropper.tar.gz

Роутер EDUP, RTL8196C и напильник: Эпизод первый, сборка тулчейна.

Не так давно стал обладателем карманного роутера с DX’a. Из плюсов стоит отметить наличие батарейки и чехла в комплекте. На этом хорошее заканчивается.
После краткого знакомства с функционалом девайса понял, что без серьезной доработки напильником юзать сию поделку никак не катит.

Начал с того, что разобрал. Внутри заметен неотмытый флюс, криво припаянные диоды. Антенна одна, smdшная, хотя разведено на плате две. опознать бы рассыпушные кондеры, и можно было бы второй комплект напаять и внешнюю вывести. Но учитывая что их там овер 10 штук и он меньше 0603, желание как-то отпало.

Уарт нашелся легко и непринужденно, куда вскоре была впаяна PBSка.
Унутрях кривой реалтековый загрузчик и ведро 2.4 серии. Частота 390Mhz, ОЗУ – 32, ПЗУ 4 метра в виде SPI флешины, USB 2.0 EHCI.

Гугль выдал мне на RTL8196C большой жирный кукиш. опенврт, дд-врт и прочие на этот чип вроде как забили.

Но кое что я все же нашел. Первое – что человек из проекта Wive-NG ( sfstudio.livejournal.com ) явно богат SDK под этот чип, и русским народным матом ругается в адрес криворуких *** *** ****** изувечивших ядро. Пришлось под openid регистрировать аккаунт для мессаджей и комментов в жжшке и поспрашать человека, и вот что я выяснил:

* SDK есть под 2.6.30, но он его не даст ибо NDA подписал, но оно есть в виде тарболлов которые выкладывают под свои роутеры длинки и иже с ними.
* Собирать надо только наркоманским тулчейном реалтековцев ибо их чип куда-то прокачался от MIPS’a… не в ту сторону.

Ура, сказал я, и попер в сеть за сырцами. Выбор пал на сырцы от TEW-652BRP. Там тот же вроде как чип, и сдк явно внутри подойдет.
Тарболл представлял из себя матрешку. Изрядно задолбавшись распаковвывать архив внутри архива, я нашел там исходники ядра линуха, тулчейна и еще кучки бородатых сопутствующих пакетов на радость археологам.

Далее изучив сырца ядра, я пришел в некое недоумение. Предупреждение относительно качеста сырцов явно было к месту. Ради своей поделки там соорудили новую архитектуру rlx (копия arch/mips) куда добавили поддержку своего камня.

Ладно, их тулчейном, так их тулчейном. Поматюгавшись на их скрипт сборки, который предполагал наличие сырцов с /toolchain (Гадим в корень, ай-ай-ай). Ладно, не гордые, сделал там симлинк на внешний веник со всей этой кухней, начинаем собирать тулчейн. И вот тут меня ждали приключения на всю мою голову. Слабонервным лучше не читать дальше.

Первая бага, от которой сборка вывалилась с ошибкой связана была с uclibc решилась вот этим патчем:
http://linux.derkeiler.com/Mailing-Lists/Kernel/2009-03/msg04460.html
Вторая бага при сборке gcc (кстати, 3.4.6, вот некроманты, а?). Жаловалось на отсутствующий файл c-parse.c
При помощи гугла и медитации допер, что этот файлик генерируется bison’ом, а оный генерировал в той версии файлик правильно, так как в нем была ошибка, и чтобы более новый bison, стоящий у меня в системе этот файлик сгенерил, надо прокрутить странички на 3 наверх, найти его выхлоп (который почему-то в мейкфайле игнорируется и за ошибку не считается), и запомнить строчки, на которые он материться. Далее открыть этот c-parse.y и заменить $$ на $<ttype>$, и все пойдет дальше.

Но если мы обрадовались, что теперь все пройдет как по маслу и завершиться успешно, то нас ждет великий облом. Следующая бага описана и решается здесь:

http://wiki.ok-labs.com/forum#nabble-td3526733

Пожалуй, это была последняя по существу. Правда? Нет! Почти в самом конце, когда паковался libgcc.a я узрел
*** buffer overflow detected ***: mips-linux-ar terminated

По счастью, имея дело с софтом разной степени бородатости и уродства, наученный горьким опытом, я держу при себе сразу все версии gcc которые есть в репозиториях бубунты, да и еще парочку самособранных, со времен когда я LFS собирал. Сборка при помощи gcc 4.1 решила проблему и я получил рабочий тулчейн. Если код, собранный им еще и заработает на роутере… вообще хорошо будет.

Продолжение следует.

Прошиваем AVR удаленно от ARM’a

Ладно, признаюсь, делаем робота, достаточно умного и большого. Настолько, что для мозгов потребовался ARM (SmartQ7) И микроконтроллер для грязной работы (чтобы рулить движками, собирать данные с датчиков и все это скармливать ARM’у на обработку) Но бегать за роботом с программатором или сидеть на конце пяти метрового усб шнура как-то “не комильфо”
Continue reading “Прошиваем AVR удаленно от ARM’a”

AVR: Учимся писать компактный код

AVR: Учимся писать компактный код.

В свое время, когда я только осваивал AVR, великое зло по имени ардуйно меня обошло стороной, за что я очень благодарен судьбе. Но время идет, и волею судьбы мне довелось познакомиться не столько с ардуйной, сколько с ее фанатами, которые после прочтения этой статьи меня, должно быть, возненавидят.
Не останусь в долгу и я, резонно заметив, что большинство проектов ардуинщиков где используются atmega1280 или 2560 (кто больше?) реализуемы если не на 555 таймере, то уж на аттайни2313.
Скажу более, это не единственная беда, частенько люди настолько загоняют себя в рамки той же ардуйны, что выходит весьма идиотский подход: не хватает ардуйны для решения задачи? Возьми две ардуйны. Не хватает шести? Возьми десять!
Если сказанное вызывает уже ненависть ко мне, я попал в точку, дальнейшее можно не читать.

Что не так с ардуйно?

Не так крайне многое. Своя нумерация пинов, кривое апи, и многое другое. Будучи средой для чайников ардуйна легко загоняет новичка в свои рамки и вызыввает священный ужас при одной мысли о выходе куда-то за пределы, где нет привычных скетчей и есть страшный СИ.
При том, что реально код они уже пишут на С/С++ многие ардуинщики и не знают и честно говорят, что пишут на ардуйно. Это вызывает иногда улыбку, примерно как когда человек говорит, что пишет на ассеблере masm. Они здорово напоминают мне приверженцев одного такого язычка с решеткой в названии. ( С#) Оный тоже до железок добрался, так что ждем новой волны зеленых “погромистов”.
Ну и, наконец, это С++. Его ниша никак не системное программирование. Здесь царство чистого СИ. Впрочем недостатки языка я не обсуждаю, скажу только, что при использовании С++ размер прошивки той же аврки пухнет как на дрожжах.

Но мы сейчас не ругаем ардуйно, а ищем конкретные выходы из положения, так ведь? Хочется и писать компактно, и чтобы удобно было.
Производители микроконтроллеров идут навстречу и в некоторых мк AT91RM9200, Stellaris Есть ROM с готовым набором костылей. В атмелевском варианте полезные штуки типа реализации xmodem’a, а у стеллариса вообще API, которое позволяет забыть что в регистры микроконтроллера надо что-то писать.
Что остается делать вымирающим фанатам красивого и компактного кода?
– Писать на ассемблере (круто, оптимально, позволяет познать дзен и научиться вселенскому терпению), но долго и не особо переносимо.
– Пользовать библиотеки типа avrlib, да таскать с собой по проектам вагон разных костылей, которые допиливать по мере необходимости.
– Или применять изыски для автогенерации кусков кода.

Про автогенерацию кода я скажу пару слов потом, когда закончу причесывать свою библиотеку для этих целей.
Сейчас же я рассмотрю парочку трюков, которые я использую для уменьшения размера кода. Начнем с простого.

Все ардуинщики знают штуку, по имени attachInterrupt(). Суть сего костыля проста. По вызову аттач интеррапт мы приклеиваем нашу собственную функцию-обработчик к тому или иному прерыванию. Причем, можем сделать это из кода. С одной стороны это хорошо, красиво и универсально, а с другой стороны…

Сколько раз в маленькой прошивке мк нам надо изменять функцию-обработчик того или иного прерывания? Можете не напрягаться, не часто. А теперь давайте оценим оверхед такой универсальности. Так как таблица векторов прерываний в AVR зашивается в Flash, то изменять ее из кода крайне нежелательно. (Можно, конечно, извратиться и перезаписывать флеш, но это скоро убьет его, так как количество циклов перезаписи ограничено).
А ардуине это реализовано так. Отдельный массив указателей в ОЗУ, куда attachInterrupt кидает указатель на функцию, которая будет вызываться. То есть как бы еще одна таблица векторов прерываний.

Иными словами, происходит нечто вроде этого:

поступило внешнее прерывание -> контроллер скакнул по адресу указанному в зашитой во флеше таблице векторов прерываний -> ардуиновская функция-обработчик загрузила в регистр адрес обработчика выставленного через attachInterrupt -> прыжок к обработчику -> мы обработали прерывание.

Давайте оценим потраченное на это место. Хотя бы для вызова функции по указателю. Для удобства сравнения перед вызовом функции ставим nop’ы.

Для теста набросаем вот такой файлик.

void (*fptr)(void)=0;
int main()
{
asm("nop");
fptr();
asm("nop");
}

Соберем его под архитектуру авр.

avr-gcc test.c -o out.elf

И отдизассемблируем полученную эльфятину.

avr-objdump -S out.elf

Это ассемблерный код, который нам сварганил gcc. Внимание на секцию мейн.

00000054

:
54: df 93 push r29
56: cf 93 push r28
58: cd b7 in r28, 0x3d ; 61
5a: de b7 in r29, 0x3e ; 62
5c: 00 00 nop
5e: 80 91 60 00 lds r24, 0x0060
62: 90 91 61 00 lds r25, 0x0061
66: e8 2f mov r30, r24
68: f9 2f mov r31, r25
6a: 09 95 icall
6c: 00 00 nop
6e: cf 91 pop r28
70: df 91 pop r29
72: 08 95 ret

Аккурат между двумя нопами инструкции, которые вызывают функцию по указателю. Запомним, и сварганим другой пример.

int callme()
{
}


int main()
{
asm("nop");
callme();
asm("nop");
}

Собираем elf, дизассемблируем, получаем:

00000072

:
72: df 93 push r29
74: cf 93 push r28
76: cd b7 in r28, 0x3d ; 61
78: de b7 in r29, 0x3e ; 62
7a: 00 00 nop
7c: eb df rcall .-42 ; 0x54
7e: 00 00 nop
80: cf 91 pop r28
82: df 91 pop r29
84: 08 95 ret

Как видно, разница одна инструкция против пяти. Четыре уходят на загрузку адреса. то есть 8 байт против двух.

Реально, конечно, оверхед не слишком большой, если функцию по указателю дергаем не так часто. Но не забываем, что каждая объявленная функция – это затраты на то, чтобы отправить в стек содержимое регистров и потом их оттуда достать. именно это и делает код в том же самом мейне, не относящийся к nop’ам.

Но не все же мы будем пихать в мейн, так? Тут опять есть выход.
Инлайны. Инлайн фунция, не заставляет компилятор загнать все регистры в стек, прыгнуть к коду, а потом вновь достать регистры из стека и вернуться при помощи ret. Она просто подставляет ее текст в место, где это надо.
В каких случаях это оптимально?
Смотрим дизасм функции callme состоящей из одного единственного nop и офигеваем.

00000054 :
54: df 93 push r29
56: cf 93 push r28
58: cd b7 in r28, 0x3d ; 61
5a: de b7 in r29, 0x3e ; 62
5c: 00 00 nop
5e: cf 91 pop r28
60: df 91 pop r29
62: 08 95 ret



На таком тесте видно, что это уже куча 14 байт оверхеда. Мелочь, если у нас сотни килобайт памяти, и в тоже время это ценное место, если у нас памяти кот наплакал – 1кб или 512 байт, на самых маленьких мк.

Но этого маловато, чтобы писать оптимально. Даже если выкинуть ардуйну, что лучше делать как можно раньше, код надо будет пытаться ужимать. Ниже привожу еще один жутко полезный трюк.

Инициализация переменных.
Допустим у нас есть массив чисел. Все числа надо инициализировать нулем, допустим в функции сброса, если они там что-то считают.
Любой программист, увидев, текст вроде:

char a[3];
a[0]=0;
a[1]=0;
a[2]=0;

Скажет китайский код, надо делать в цикле. А будет ли это реально меньше занимать памяти во флеше?
Давайте проверим.
Создаем массивчик:

char a[COUNT];

В мейн пихаем примерно такое:

int main()
{
reset();
}

А в виде reset’a делаем два разных варианта.

reset()
{
a[0]=0;
a[1]=0;
a[2]=0;
}

и

reset()
{
int i;
for (i=0; i<3; i++)
{
a[i]=0;
}
}

И что имеем на выходе?

Для начала дизассемблируем эльфятину с “китайским кодом” и видим вот такое:

00000054 :
54: df 93 push r29
56: cf 93 push r28
58: cd b7 in r28, 0x3d ; 61
5a: de b7 in r29, 0x3e ; 62
5c: 10 92 60 00 sts 0x0060, r1
60: 10 92 61 00 sts 0x0061, r1
64: 10 92 62 00 sts 0x0062, r1
68: cf 91 pop r28
6a: df 91 pop r29
6c: 08 95 ret

То есть 3 инициализации нулем превратились в 3 sts инструкции.

А теперь вариант с for

00000054 :
54: df 93 push r29
56: cf 93 push r28
58: 00 d0 rcall .+0 ; 0x5a
5a: cd b7 in r28, 0x3d ; 61
5c: de b7 in r29, 0x3e ; 62
5e: 1a 82 std Y+2, r1 ; 0x02
60: 19 82 std Y+1, r1 ; 0x01
62: 0c c0 rjmp .+24 ; 0x7c
64: 89 81 ldd r24, Y+1 ; 0x01
66: 9a 81 ldd r25, Y+2 ; 0x02
68: 80 5a subi r24, 0xA0 ; 160
6a: 9f 4f sbci r25, 0xFF ; 255
6c: e8 2f mov r30, r24
6e: f9 2f mov r31, r25
70: 10 82 st Z, r1
72: 89 81 ldd r24, Y+1 ; 0x01
74: 9a 81 ldd r25, Y+2 ; 0x02
76: 01 96 adiw r24, 0x01 ; 1
78: 9a 83 std Y+2, r25 ; 0x02
7a: 89 83 std Y+1, r24 ; 0x01
7c: 89 81 ldd r24, Y+1 ; 0x01
7e: 9a 81 ldd r25, Y+2 ; 0x02
80: 83 30 cpi r24, 0x03 ; 3
82: 91 05 cpc r25, r1
84: 7c f3 brlt .-34 ; 0x64
86: 0f 90 pop r0
88: 0f 90 pop r0
8a: cf 91 pop r28
8c: df 91 pop r29
8e: 08 95 ret

На этом месте тихонечко офигеваем: цикл нам обошелся в 40 байт или 20 инструкций. То есть до 20 элементов массива выгоднее инициализировать китайским кодом.
Смотрим сильно ли изменится если элементами будут 16ти битные числа:

00000054 :
54: df 93 push r29
56: cf 93 push r28
58: cd b7 in r28, 0x3d ; 61
5a: de b7 in r29, 0x3e ; 62
5c: 10 92 61 00 sts 0x0061, r1
60: 10 92 60 00 sts 0x0060, r1
64: 10 92 63 00 sts 0x0063, r1
68: 10 92 62 00 sts 0x0062, r1
6c: 10 92 65 00 sts 0x0065, r1
70: 10 92 64 00 sts 0x0064, r1
74: cf 91 pop r28
76: df 91 pop r29
78: 08 95 ret

В два раза больше sts при китайском коде. А теперь если воткнем цикл.

00000054 :
54: df 93 push r29
56: cf 93 push r28
58: 00 d0 rcall .+0 ; 0x5a
5a: cd b7 in r28, 0x3d ; 61
5c: de b7 in r29, 0x3e ; 62
5e: 1a 82 std Y+2, r1 ; 0x02
60: 19 82 std Y+1, r1 ; 0x01
62: 0f c0 rjmp .+30 ; 0x82
64: 89 81 ldd r24, Y+1 ; 0x01
66: 9a 81 ldd r25, Y+2 ; 0x02
68: 88 0f add r24, r24
6a: 99 1f adc r25, r25
6c: 80 5a subi r24, 0xA0 ; 160
6e: 9f 4f sbci r25, 0xFF ; 255
70: e8 2f mov r30, r24
72: f9 2f mov r31, r25
74: 11 82 std Z+1, r1 ; 0x01
76: 10 82 st Z, r1
78: 89 81 ldd r24, Y+1 ; 0x01
7a: 9a 81 ldd r25, Y+2 ; 0x02
7c: 01 96 adiw r24, 0x01 ; 1
7e: 9a 83 std Y+2, r25 ; 0x02
80: 89 83 std Y+1, r24 ; 0x01
82: 89 81 ldd r24, Y+1 ; 0x01
84: 9a 81 ldd r25, Y+2 ; 0x02
86: 83 30 cpi r24, 0x03 ; 3
88: 91 05 cpc r25, r1
8a: 64 f3 brlt .-40 ; 0x64
8c: 0f 90 pop r0
8e: 0f 90 pop r0
90: cf 91 pop r28
92: df 91 pop r29
94: 08 95 ret

Вариант с for тоже распух прилично. Таким образом можно сделать простой вывод: Если надо инициализировать что-то нулем, а памяти мало, то выгоднее набросать себе маленький костыль на ассемблере.

Пока это все примеры, которые я хотел раписать тут. Дальше мне заниматься этим было лениво.
Уменьшить размер прошивки и занимаемой оперативной памяти можно так же выгружая лишние данные в eeprom и progmem, но расписывать это мне, честно говоря, сейчас лениво.

Заключение.

Как видно из примеров, писать код занимающий мало места, требует знаний конкретной архитектуры, да и вообще штука это нетривиальная, но жутко интересная. Это вам не ПокажиСообщение(“Невосстановимая ошибка базы данных 1С”);

Немного некромантии: воскрешаем TRENDnet’овский роутер.

Собственно, перепал он мне в незапамятные времена. Судя по внутренностям работал когда-то в ведре с водой во влажной среде.
Особо роутера мне тогда не надо было, а тут вдруг понадобился, а в магазин бежать в лом.
В общем симптомы простые: работает, но тормозит жутко, сигнал в паре метров пропадает, а через некоторое время скорость передачи данных по вайфаю вообще падает до 10 кбайт/сек.
Пока греется паяльник вскрываем роутер, включаем. Ощутимо греется лоудроп на 1.8 вольт с маркировкой GS1117, металлический экран над радиочастотной частью покрыт коррозией и контакта нет. Один конденсатор на 47uF рядом “забеременел”, на ногах уже даже не держится, электролит потек.
Начал я с того, что закрыл радиочастотную часть куском текстолита. Вышло как-то так:

Далее был перепаян конденсатор, который уж явно не являлся более профпригодным, вышло как-то так:

Ну и, наконец, дошли до лоудропа.
На вход к нему идут честные 3.3 вольта, на выходе 1.8… должно быть. На практике же 1.56.
Либо что-то из того, что он питает вдруг стало кушать резко много, что не есть гут, либо это лоудропу трындец. GS1117, тем более на 1.8 вольт у меня под рукой не было. Но были AMS1117, что по сути тоже самое, только от другого китайца. Но на 5 вольт, 3.3 вольта и подстраиваемые. Настраиваются резюками, которые надо посадить между выходом ноги ADJ (Она у них вместо земли в подстраиваемых), и между ADJ и out.
Нехитрой математикой, полностью аналогичной применяемой для LM317 остановился на резюках номиналом 220 и 120 Ом, которые у меня были в SMD корпусах.
Далее немного медитируем паяльником. Одну ноги я отогнул немного, воткнул резюк, запаял, потом посадил второй. Вышло что-товроде вот такого.

Напаиваем резюки…

На выходе дало расчетные 1.9 вольт, что в теории не должно превышать макс. допустимое.

После вышеописанных шаманств роутер завелся. Вебморда отрисовалась мгновенно без тормазов. Сигнал правда не шибко хороший, и подсказывает мне астрал, надо бы остальные кондеры тоже перепаять по хорошему, но на 47uF под рукой была только одна штука.

Попутно я впаял штыри на разъем для JTAG’а и UART’a. Вдруг дойдут руки самопайку туда впаять, да софт закинуть. Благо на роутере uclinux, и где-то в интернете исходники пробегали.

Собственно, вот и все. Теперь можно наслаждаться еще одним отличным экземпляром отнекроманченной цифровой нежити. Сойдет для дачи.

HSDPA модемчик из китая и линукс.

Итак, я заставил его работать. Пришлось правда ставить винду параллельно, но не суть.
В общем эти модемы действуют так. Втыкаешь, и они определяются… как cdrom. С дровами. Под windows.
А уж дрова волшебной командой переключают модем в решим, где до него можно достучаться простым usbserial который есть в линухе с древних времен.
Для переключения придумали usb_modeswitch, но вот конфиг пришлось делать самому на основе снифа виндовых дров.
Вот оно:

########################################################
# HSDPA USB modem from dealextreme
# http://www.dealextreme.com/details.dx/sku.47013
# By Andrew 'Necromant' Andrianov

DefaultVendor= 0x05c6
DefaultProduct=0x2000

TargetVendor= 0x05c6
TargetProduct= 0x0015

# This modem doesn't react fast - it pauses for some 30-40 seconds
CheckSuccess=40

MessageEndpoint=0x08
MessageContent="5553424368032c882400000080000612000000240000000000000000000000"
# Nothing will work until you read the response from device
NeedResponse=1

А вот собственно дамп, который я выцарапал с винды:


[231 ms] UsbSnoop - FilterAddDevice(a6b42748) : DriverObject 898c1408, pdo 88b88b30
[232 ms] UsbSnoop - FilterDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_LEGACY_BUS_INFORMATION)
[232 ms] UsbSnoop - FdoHookDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_LEGACY_BUS_INFORMATION)
[232 ms] UsbSnoop - FilterDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_RESOURCE_REQUIREMENTS)
[233 ms] UsbSnoop - FdoHookDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_RESOURCE_REQUIREMENTS)
[233 ms] UsbSnoop - FilterDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_FILTER_RESOURCE_REQUIREMENTS)
[233 ms] UsbSnoop - FdoHookDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_FILTER_RESOURCE_REQUIREMENTS)
[233 ms] UsbSnoop - FilterDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_START_DEVICE)
[233 ms] UsbSnoop - FdoHookDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_START_DEVICE)
[233 ms] UsbSnoop - FilterDispatchAny(a6b3dfd2) : IRP_MJ_SYSTEM_CONTROL
[234 ms] UsbSnoop - FilterDispatchAny(a6b3dfd2) : IRP_MJ_INTERNAL_DEVICE_CONTROL
[234 ms] UsbSnoop - FdoHookDispatchInternalIoctl(a6b3e1ea) : fdo=8837b020, Irp=882c0368, IRQL=0
[234 ms] >>> URB 1 going down >>>
-- URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
TransferBufferLength = 00000012
TransferBuffer = 883c3e50
TransferBufferMDL = 00000000
Index = 00000000
DescriptorType = 00000001 (USB_DEVICE_DESCRIPTOR_TYPE)
LanguageId = 00000000
[237 ms] UsbSnoop - MyInternalIOCTLCompletion(a6b3e126) : fido=00000000, Irp=882c0368, Context=885ea8d0, IRQL=2
[237 ms] <<< URB 1 coming back <<< -- URB_FUNCTION_CONTROL_TRANSFER: PipeHandle = 8851a600 TransferFlags = 0000000b (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK) TransferBufferLength = 00000012 TransferBuffer = 883c3e50 TransferBufferMDL = 897ae7b8 00000000: 12 01 10 01 00 00 00 40 c6 05 00 20 00 00 01 02 00000010: 00 01 UrbLink = 00000000 SetupPacket = 00000000: 80 06 00 01 00 00 12 00 [237 ms] UsbSnoop - FilterDispatchAny(a6b3dfd2) : IRP_MJ_INTERNAL_DEVICE_CONTROL [237 ms] UsbSnoop - FdoHookDispatchInternalIoctl(a6b3e1ea) : fdo=8837b020, Irp=882c0368, IRQL=0 [238 ms] >>> URB 2 going down >>>
-- URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
TransferBufferLength = 00000009
TransferBuffer = 89887a68
TransferBufferMDL = 00000000
Index = 00000000
DescriptorType = 00000002 (USB_CONFIGURATION_DESCRIPTOR_TYPE)
LanguageId = 00000000
[241 ms] UsbSnoop - MyInternalIOCTLCompletion(a6b3e126) : fido=00000000, Irp=882c0368, Context=885ea8d0, IRQL=2
[241 ms] <<< URB 2 coming back <<< -- URB_FUNCTION_CONTROL_TRANSFER: PipeHandle = 8851a600 TransferFlags = 0000000b (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK) TransferBufferLength = 00000009 TransferBuffer = 89887a68 TransferBufferMDL = 897ae7b8 00000000: 09 02 20 00 01 01 00 a0 fa UrbLink = 00000000 SetupPacket = 00000000: 80 06 00 02 00 00 09 00 [241 ms] UsbSnoop - FilterDispatchAny(a6b3dfd2) : IRP_MJ_INTERNAL_DEVICE_CONTROL [241 ms] UsbSnoop - FdoHookDispatchInternalIoctl(a6b3e1ea) : fdo=8837b020, Irp=882c0368, IRQL=0 [242 ms] >>> URB 3 going down >>>
-- URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
TransferBufferLength = 00000020
TransferBuffer = 8986bcb8
TransferBufferMDL = 00000000
Index = 00000000
DescriptorType = 00000002 (USB_CONFIGURATION_DESCRIPTOR_TYPE)
LanguageId = 00000000
[245 ms] UsbSnoop - MyInternalIOCTLCompletion(a6b3e126) : fido=00000000, Irp=882c0368, Context=885ea8d0, IRQL=2
[245 ms] <<< URB 3 coming back <<< -- URB_FUNCTION_CONTROL_TRANSFER: PipeHandle = 8851a600 TransferFlags = 0000000b (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK) TransferBufferLength = 00000020 TransferBuffer = 8986bcb8 TransferBufferMDL = 897ae7b8 00000000: 09 02 20 00 01 01 00 a0 fa 09 04 00 00 02 08 06 00000010: 50 00 07 05 87 02 40 00 00 07 05 08 02 40 00 00 UrbLink = 00000000 SetupPacket = 00000000: 80 06 00 02 00 00 20 00 [245 ms] UsbSnoop - FilterDispatchAny(a6b3dfd2) : IRP_MJ_INTERNAL_DEVICE_CONTROL [245 ms] UsbSnoop - FdoHookDispatchInternalIoctl(a6b3e1ea) : fdo=8837b020, Irp=882c0368, IRQL=0 [246 ms] >>> URB 4 going down >>>
-- URB_FUNCTION_SELECT_CONFIGURATION:
ConfigurationDescriptor = 0x8986bcb8 (configure)
ConfigurationDescriptor : bLength = 9
ConfigurationDescriptor : bDescriptorType = 0x00000002
ConfigurationDescriptor : wTotalLength = 0x00000020
ConfigurationDescriptor : bNumInterfaces = 0x00000001
ConfigurationDescriptor : bConfigurationValue = 0x00000001
ConfigurationDescriptor : iConfiguration = 0x00000000
ConfigurationDescriptor : bmAttributes = 0x000000a0
ConfigurationDescriptor : MaxPower = 0x000000fa
ConfigurationHandle = 0x00000000
Interface[0]: Length = 56
Interface[0]: InterfaceNumber = 0
Interface[0]: AlternateSetting = 0
[306 ms] UsbSnoop - MyInternalIOCTLCompletion(a6b3e126) : fido=00000000, Irp=882c0368, Context=885ea8d0, IRQL=0
[306 ms] <<< URB 4 coming back <<< -- URB_FUNCTION_SELECT_CONFIGURATION: ConfigurationDescriptor = 0x8986bcb8 (configure) ConfigurationDescriptor : bLength = 9 ConfigurationDescriptor : bDescriptorType = 0x00000002 ConfigurationDescriptor : wTotalLength = 0x00000020 ConfigurationDescriptor : bNumInterfaces = 0x00000001 ConfigurationDescriptor : bConfigurationValue = 0x00000001 ConfigurationDescriptor : iConfiguration = 0x00000000 ConfigurationDescriptor : bmAttributes = 0x000000a0 ConfigurationDescriptor : MaxPower = 0x000000fa ConfigurationHandle = 0x88b188c0 Interface[0]: Length = 56 Interface[0]: InterfaceNumber = 0 Interface[0]: AlternateSetting = 0 Interface[0]: Class = 0x00000008 Interface[0]: SubClass = 0x00000006 Interface[0]: Protocol = 0x00000050 Interface[0]: InterfaceHandle = 0x899ddae0 Interface[0]: NumberOfPipes = 2 Interface[0]: Pipes[0] : MaximumPacketSize = 0x00000040 Interface[0]: Pipes[0] : EndpointAddress = 0x00000087 Interface[0]: Pipes[0] : Interval = 0x00000000 Interface[0]: Pipes[0] : PipeType = 0x00000002 (UsbdPipeTypeBulk) Interface[0]: Pipes[0] : PipeHandle = 0x899ddafc Interface[0]: Pipes[0] : MaxTransferSize = 0x00001000 Interface[0]: Pipes[0] : PipeFlags = 0x00000000 Interface[0]: Pipes[1] : MaximumPacketSize = 0x00000040 Interface[0]: Pipes[1] : EndpointAddress = 0x00000008 Interface[0]: Pipes[1] : Interval = 0x00000000 Interface[0]: Pipes[1] : PipeType = 0x00000002 (UsbdPipeTypeBulk) Interface[0]: Pipes[1] : PipeHandle = 0x899ddb1c Interface[0]: Pipes[1] : MaxTransferSize = 0x00001000 Interface[0]: Pipes[1] : PipeFlags = 0x00000000 [306 ms] UsbSnoop - FilterDispatchAny(a6b3dfd2) : IRP_MJ_INTERNAL_DEVICE_CONTROL [306 ms] UsbSnoop - FdoHookDispatchInternalIoctl(a6b3e1ea) : fdo=8837b020, Irp=882c0368, IRQL=0 [306 ms] >>> URB 5 going down >>>
-- URB_FUNCTION_SELECT_INTERFACE:
ConfigurationHandle = 0x88b188c0
Interface: Length = 56
Interface: InterfaceNumber = 0
Interface: AlternateSetting = 0
Interface: Class = 0x00000008
Interface: SubClass = 0x00000006
Interface: Protocol = 0x00000050
Interface: InterfaceHandle = 899ddae0
Interface: NumberOfPipes = 2
[369 ms] UsbSnoop - MyInternalIOCTLCompletion(a6b3e126) : fido=00000000, Irp=882c0368, Context=885ea8d0, IRQL=0
[369 ms] <<< URB 5 coming back <<< -- URB_FUNCTION_SELECT_INTERFACE: ConfigurationHandle = 0x88b188c0 Interface: Length = 56 Interface: InterfaceNumber = 0 Interface: AlternateSetting = 0 Interface: Class = 0x00000008 Interface: SubClass = 0x00000006 Interface: Protocol = 0x00000050 Interface: InterfaceHandle = 8852c5b8 Interface: NumberOfPipes = 2 Interface: Pipes[0] : MaximumPacketSize = 0x00000040 Interface: Pipes[0] : EndpointAddress = 0x00000087 Interface: Pipes[0] : Interval = 0x00000000 Interface: Pipes[0] : PipeType = 0x00000002 (UsbdPipeTypeBulk) Interface: Pipes[0] : PipeHandle = 0x8852c5d4 Interface: Pipes[0] : MaxTransferSize = 0x00010000 Interface: Pipes[0] : PipeFlags = 0x00000000 Interface: Pipes[1] : MaximumPacketSize = 0x00000040 Interface: Pipes[1] : EndpointAddress = 0x00000008 Interface: Pipes[1] : Interval = 0x00000000 Interface: Pipes[1] : PipeType = 0x00000002 (UsbdPipeTypeBulk) Interface: Pipes[1] : PipeHandle = 0x8852c5f4 Interface: Pipes[1] : MaxTransferSize = 0x00010000 Interface: Pipes[1] : PipeFlags = 0x00000000 [369 ms] UsbSnoop - FilterDispatchAny(a6b3dfd2) : IRP_MJ_INTERNAL_DEVICE_CONTROL [369 ms] UsbSnoop - FdoHookDispatchInternalIoctl(a6b3e1ea) : fdo=8837b020, Irp=882c0368, IRQL=0 [369 ms] >>> URB 6 going down >>>
-- URB_FUNCTION_CLASS_INTERFACE:
TransferFlags = 00000001 (USBD_TRANSFER_DIRECTION_IN, ~USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 00000001
TransferBuffer = 884f7e60
TransferBufferMDL = 00000000
UrbLink = 00000000
RequestTypeReservedBits = 00000000
Request = 000000fe
Value = 00000000
Index = 00000000
[372 ms] UsbSnoop - MyInternalIOCTLCompletion(a6b3e126) : fido=00000000, Irp=882c0368, Context=885ea8d0, IRQL=2
[372 ms] <<< URB 6 coming back <<< -- URB_FUNCTION_CONTROL_TRANSFER: PipeHandle = 8851a600 TransferFlags = 0000000b (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK) TransferBufferLength = 00000001 TransferBuffer = 884f7e60 TransferBufferMDL = 88369240 00000000: 00 UrbLink = 00000000 SetupPacket = 00000000: a1 fe 00 00 00 00 01 00 [373 ms] UsbSnoop - FilterDispatchAny(a6b3dfd2) : IRP_MJ_INTERNAL_DEVICE_CONTROL [373 ms] UsbSnoop - FdoHookDispatchInternalIoctl(a6b3e1ea) : fdo=8837b020, Irp=882c0368, IRQL=2 [373 ms] >>> URB 7 going down >>>
-- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
PipeHandle = 8852c5f4 [endpoint 0x00000008]
TransferFlags = 00000000 (USBD_TRANSFER_DIRECTION_OUT, ~USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 0000001f
TransferBuffer = 882567a0
TransferBufferMDL = 00000000
00000000: 55 53 42 43 68 03 2c 88 24 00 00 00 80 00 06 12
00000010: 00 00 00 24 00 00 00 00 00 00 00 00 00 00 00
UrbLink = 00000000
[374 ms] UsbSnoop - MyInternalIOCTLCompletion(a6b3e126) : fido=8836abf8, Irp=882c0368, Context=885ea8d0, IRQL=2
[374 ms] <<< URB 7 coming back <<< -- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: PipeHandle = 8852c5f4 [endpoint 0x00000008] TransferFlags = 00000000 (USBD_TRANSFER_DIRECTION_OUT, ~USBD_SHORT_TRANSFER_OK) TransferBufferLength = 0000001f TransferBuffer = 882567a0 TransferBufferMDL = 89854dd0 UrbLink = 00000000 [374 ms] UsbSnoop - FilterDispatchAny(a6b3dfd2) : IRP_MJ_INTERNAL_DEVICE_CONTROL [374 ms] UsbSnoop - FdoHookDispatchInternalIoctl(a6b3e1ea) : fdo=8837b020, Irp=882c0368, IRQL=2 [375 ms] >>> URB 8 going down >>>
-- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
PipeHandle = 8852c5d4 [endpoint 0x00000087]
TransferFlags = 00000002 (USBD_TRANSFER_DIRECTION_OUT, USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 00000024
TransferBuffer = 00000000
TransferBufferMDL = 88369240
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000020: 00 00 00 00
UrbLink = 00000000
[376 ms] UsbSnoop - MyInternalIOCTLCompletion(a6b3e126) : fido=8836abf8, Irp=882c0368, Context=885ea8d0, IRQL=2
[376 ms] <<< URB 8 coming back <<< -- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: PipeHandle = 8852c5d4 [endpoint 0x00000087] TransferFlags = 00000003 (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK) TransferBufferLength = 00000024 TransferBuffer = 00000000 TransferBufferMDL = 88369240 00000000: 05 80 02 00 33 00 00 00 42 4d 43 20 43 6f 72 70 00000010: 55 53 42 20 53 74 6f 72 61 67 65 20 20 20 20 20 00000020: 32 2e 33 31 UrbLink = 00000000 [376 ms] UsbSnoop - FilterDispatchAny(a6b3dfd2) : IRP_MJ_INTERNAL_DEVICE_CONTROL [376 ms] UsbSnoop - FdoHookDispatchInternalIoctl(a6b3e1ea) : fdo=8837b020, Irp=882c0368, IRQL=2 [377 ms] >>> URB 9 going down >>>
-- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
PipeHandle = 8852c5d4 [endpoint 0x00000087]
TransferFlags = 00000000 (USBD_TRANSFER_DIRECTION_OUT, ~USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 0000000d
TransferBuffer = 882567a0
TransferBufferMDL = 00000000
00000000: 55 53 42 43 68 03 2c 88 24 00 00 00 80
UrbLink = 00000000
[378 ms] UsbSnoop - MyInternalIOCTLCompletion(a6b3e126) : fido=8836abf8, Irp=882c0368, Context=885ea8d0, IRQL=2
[378 ms] <<< URB 9 coming back <<< -- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: PipeHandle = 8852c5d4 [endpoint 0x00000087] TransferFlags = 00000001 (USBD_TRANSFER_DIRECTION_IN, ~USBD_SHORT_TRANSFER_OK) TransferBufferLength = 0000000d TransferBuffer = 882567a0 TransferBufferMDL = 89854dd0 00000000: 55 53 42 53 68 03 2c 88 00 00 00 00 00 UrbLink = 00000000 [378 ms] UsbSnoop - FilterDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_INTERFACE) [379 ms] UsbSnoop - FilterDispatchPnp: Query for Bus interface for USB Function Drivers. [379 ms] InterfaceType: USB_BUS_INTERFACE_USBDI_GUID [379 ms] UsbSnoop - FdoHookDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_INTERFACE) [379 ms] UsbSnoop - FdoHookDispatchPnp: Query for Bus interface for USB Function Drivers. [379 ms] InterfaceType: USB_BUS_INTERFACE_USBDI_GUID [380 ms] UsbSnoop - FilterDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_CAPABILITIES) [380 ms] UsbSnoop - FdoHookDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_CAPABILITIES) [380 ms] UsbSnoop - FilterDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_PNP_DEVICE_STATE) [380 ms] UsbSnoop - FdoHookDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_PNP_DEVICE_STATE) [380 ms] UsbSnoop - FilterDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_DEVICE_RELATIONS) [380 ms] UsbSnoop - FdoHookDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_DEVICE_RELATIONS) [380 ms] UsbSnoop - FilterDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_CAPABILITIES) [380 ms] UsbSnoop - FdoHookDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_CAPABILITIES) [3820 ms] UsbSnoop - FilterDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_CAPABILITIES) [3820 ms] UsbSnoop - FdoHookDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_CAPABILITIES) [30999 ms] UsbSnoop - FilterDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_DEVICE_RELATIONS) [30999 ms] UsbSnoop - FdoHookDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_DEVICE_RELATIONS) [30999 ms] UsbSnoop - FilterDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_DEVICE_RELATIONS) [30999 ms] UsbSnoop - FdoHookDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_QUERY_DEVICE_RELATIONS) [30999 ms] UsbSnoop - FilterDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_SURPRISE_REMOVAL) [30999 ms] UsbSnoop - FdoHookDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_SURPRISE_REMOVAL) [31030 ms] UsbSnoop - FilterDispatchPnp(a6b4245c) : IRP_MJ_PNP (IRP_MN_REMOVE_DEVICE)

Теперь надо сказать usbserial'у, чтобы тот подцепил неизвестные ему до сего момента IDшники производителя и продукта.
modprobe usbserial vendor=0x05c6 product=0x0015
Оные опции лучше запихнуть куда-нибудь в конфиге, особенно если компьютер увешан этими usbserial конфертерами, как новогодняя елка.
Появится 3 усб девайса. Некоторые даже будут отвечать на AT команды.
Самое время настроить pppd/wvdial