usb-адаптер передатчика - альтернативная open-source прошивка

osnwt

Общему вниманию предлагается альтернативная open-source прошивка для USB-адаптера передатчика, собранного на ATmega8 по схеме с http://rcdesign.ru. Код написан на C и будет опубликован после подтверждения ее работоспособности с парой популярных передатчиков. У меня нет ни нормальной аппаратуры (кроме валкеры да еская), ни в точности той схемы, потому хотелось бы убедиться, что декодирование PPM работает так, как задумано.

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

Цели ее опубликования:

  • показать, что писать код под программный USB для AVR вовсе не так сложно, если использовать не ассемблерный вариант интерфейса (предположительно, использованный в оригинальной прошивке, судя по ее ограничениям), а открытый USB драйвер для AVR, написанный большей частью на C и отлично документированный;
  • помочь начинающим сделать свои варианты входных интерфейсов (например, чтение встроенного ADC контроллера - этот модуль также присутствует в составе исходного текста, или декодера различных вариантов PCM по аналогии с декодером PPM, дописав соответствующий модуль);
  • помочь начинающим сделать свои варианты выходных интерфейсов с кнопками, дополнительными каналами и др.;
  • показать вариант интеграции функциональности USB-адаптера в самодельный кодер передатчика, обсуждаемый вот в этой ветке. Дальнейшее развитие этого направления вижу в интеграции функций USB загрузчика в тот самый кодер (дает возможность смены прошивок без программатора - по тому же USB-). И в возможности настройки кодера и/или моделей через тот же USB интерфейс. Сам готов подключиться к этим задачам, как только соберу ту схему (делать плату руками или паять на макетке нет времени, так как я по работе не связан с изготовлением железа. Если кто может помочь с готовой платой на разумных условиях - с радостью бы воспользовался предложением);
  • выполнение требование лицензии на использованный open-source программный USB драйвер (публикация исходных текстов проектов, написанных с его использованием без приобретения коммерческой лицензии).

Прошивка для проверки (пока без исходников):

Краткое описание предложенной версии

Вход: PPM до 8 каналов, полярность не имеет значения.
Выход: HID джойстик на 8 аналоговых каналов.

В данной прошивке не выполняется маппинг каналов в соответствии с их назначением прямо или через NVRAM. Соответствие каналов жестко записано следующее (оно не соответствует маппингу по умолчанию в оригинальной прошивке):

1 - X
2 - Y
3 - Z
4 - Rx
5 - Ry
6 - Rz
7 - Slider
8 - Dial

Интересует принципиальная управляемость всех осей (смотреть в панели управления игровыми устройствами) с разной аппаратурой (с какой конкретно?). Если будет работать нормально, то, возможно, допишу маппинг каналов и второй вариант выходного интерфейса с дополнительными кнопками и, возможно, еще 9-м каналом (если он кому-то нужен - пока не видел, чтобы кто-то попросил).

После получения положительных (а как же иначе 😃) отзывов о принципиальной работоспособности опубликую исходный текст. Если это кому-то вообще интересно, конечно.

Краевед:

У меня эта прошивка вообще не запустилась 😦 пишет “устройство не опознано”

Какая версия Windows?
Попробую найти человека с собранной схемой поближе. Собственно, именно изготовление прошивки без возможности проверки и есть причина неоткрытия (пока) исходных текстов.

dmk:

Что значит “стандартно PPM поддерживает 8 каналов”?
А что, существует PPM поддерживающий более чем 8 каналов?

Откуда-то же они берутся…

Как уже писали, большое количество выходных каналов (джойстика) получают дублированием 8 входных каналов сигнала PPM, и только.

К сожалению, я не видел этой информации. Но и не вижу смысла в таком дублировании. Раскидать аналоговый канал на N дискретных - это понятно (хотя я не знаю алгоритмов, использованных в различной аппаратуре). А вот просто дублировать…

Краевед

Вынь ХР проф, со всеми обновлениями, не в ней дело - старая прошивка работает на ура, мега от 5 вольт запитана, USB придушен стабилитронами до 3.3в
Схема валяется на столе подключенная к программатору, я с ней эксперементирую, так что если есть еще прошивки для эксперементов - кинь, проверить можно за несколько секунд.

osnwt
Краевед:

Вынь ХР проф, со всеми обновлениями, не в ней дело

Да, дело явно не в ней. Скорее всего, что-то с пинами. Да вроде все правильно:

#define USB_CFG_IOPORTNAME	  D
/* This is the port where the USB bus is connected. When you configure it to
 * "B", the registers PORTB, PINB and DDRB will be used.
 */
#define USB_CFG_DMINUS_BIT	  0
/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected.
 * This may be any bit in the port.
 */
#define USB_CFG_DPLUS_BIT	   1
/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected.
 * This may be any bit in the port. Please note that D+ must also be connected
 * to interrupt pin INT0!
 */

старая прошивка работает на ура, мега от 5 вольт запитана, USB придушен стабилитронами до 3.3в

У меня все то же самое от версии винды до схемотехники, за одним исключением - пины другие и PPM проверялся на меге32, но в макетную плату на меге8 я свою прошивку шил (с другими пинами), и оно виделось как USB устройство.

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

Нет, так заочно не будет эффективным. Надо видеть, что на пинах. Другой причины не вижу.

Придется пробовать на живой схеме, только вот взять ее у знакомого надо как-то.

PS. Как-то я наблюдал ситуацию, что после ряда втыканий-вытыканий при экспериментах найденное устройство потом не вставало до удаления “неопознанного” при воткнутом девайсе. После чего после вынимания и нового подключения находилось устройство, которое начинало работать.

Предлагаю попробовать такой вариант.

Краевед

Пробовал, все равно устройство не опознано пишет

osnwt
Краевед:

Пробовал, все равно устройство не опознано пишет

Значит, завтра буду брать собранную схему и пробовать на ней.

PS. Неужели ни один человек больше не попробовал?
PPS. Куда-то делся линк на скачку. Ставлю еще раз в таком виде.
PPPS. Да, когда выше шла речь о “Если кто может помочь с готовой платой на разумных условиях” платы на меге128 для передатчика, то имелась в виду голая печатка, без деталей, ессно.

Vitaly

Я только одного не понял, зачем собственный USB-драйвер сочинять, когда есть готовый проект специально для таких целей ? Компилится и на сях, и на ассемблере, с кучей опций, хорошо документированный и т.д.

www.obdev.at/products/avrusb/projects.html

Если там грамотно опции покоцать, то даже в AVR 2313 влезет.

osnwt
Vitaly:

Я только одного не понял, зачем собственный USB-драйвер сочинять, когда есть готовый проект специально для таких целей ? Компилится и на сях, и на ассемблере, с кучей опций, хорошо документированный и т.д.

Виталий, спасибо за заботу 😃 Вероятно, кто-то чего-то действительно недопонял.

  1. Ни из каких моих высказываний не следует, что драйвер - самописанный. Более того, в списке выше последней из причин публикации исходников упоминается требование лицензии на драйвер. Ясно, что не на свой собственный. Хотя я бы без проблем мог решить вопрос об освобождении от этого требования (см. ниже), я пока не увидел в том необходимости.

  2. Если заглянуть на страницу проектов, то там видно, что одним из проектов является мой крипто-загрузчик. Из этого следует, что я, как минимум, знаю о существовании этого продукта и, скорее всего, не стал бы изобретать велосипед.

Crypto-Boot - an USB Boot Loader

  1. И я действительно знаю об этом драйвере, так как если заглянуть внутрь его readme, то там в ряде файлов видно упоминание автора о том, что он благодарен мне за порт драйвера под IAR компилятор. Кроме того, в процессе работы над тем портом была найдена пара серьезных багов в логике работы, которые были исправлены в тесном сотрудничестве с Кристианом, а также добавлено несколько расширений, полезных на тот момент мне, но включенных в официальный порт.

А теперь по существу: конечно же, мой исходник базируется на том драйвере. Почему я не хочу его открывать, пока он не заработал у других - потому, что я не хочу использовать людей, как подопытных кроликов 😃 Имея оригинальное железо, я за 5 минут бы выяснил причину неработоспособности его, так как она кроется не в системе, а что-то перепутано с пинами (напомню, что у меня железа такого нет). Пока же этого нет - зачем грузить других своими проблемами? Будет законченное решение - поделюсь со всеми.

Vitaly

О, какие люди, а я и не знал, что тут есть живые легенды, которые лапу приложили к тому чудо-проекту. Респект!

osnwt
osnwt:

Имея оригинальное железо, я за 5 минут бы выяснил причину неработоспособности его, так как она кроется не в системе, а что-то перепутано с пинами (напомню, что у меня железа такого нет).

Итак, всё оказалось почти так, как я и предполагал. От большого ума и желания красиво оформить исходные тексты. Я использовал условную компиляцию выбора пинов под свое железо и железо по схеме с сайта. Только в одном месте проверка варианта оказалась раньше, чем ее определение. Потому компилировалось совсем не то, что предполагалось.

Вот новая версия прошивки. Прошу проверить, а также проверить работу ее PPM с приведенными в исходном сообщении оговорками.

Краевед

ВО! Эта работает, причем очень хорошо, каналы отрабатываются ровно и без поддергиваний.

osnwt
Краевед:

ВО! Эта работает, причем очень хорошо, каналы отрабатываются ровно и без поддергиваний.

Спасибо, поскольку еще один человек мне писал, что с оригиналом есть проблемы со стабильностью. А с чем оно проверялось (версия Windows, передатчик)?

Итак, как и обещал, принимайте исходные тексты и файлы проекта под компилятор IAR (www.iar.com, доступна полнофункциональная ознакомительная 30-дневная версия):

Готов ответить на любые конкретные вопросы по тексту (кроме единственного, уже отвеченного непосредственно там). И ещё сразу говорю: портировать под gcc (WinAVR) или другие среды разработки у меня нет ни времени, ни желания. Но поскольку там не использовано никаких особенностей компилятора, это сделать достаточно просто самостоятельно.

Краевед

Попробовал на передатчиках санва и хайтек - одинакого хорошо, очень понравилось, спасибо!

lucky75

Прекрасно работает. Субъективно даже лучше оригинальной.

Psw

И я сейчас скомпилил исходнички для проверки, зашил в шнурок.
Всё не могу выложить фотку своей “печатки” с “ICSP” разъёмом.
Ну - заработал RC USB Device …
Однако - делалось правда без WIN калибровки новоявленного джоя (хлопотно/на спех) - в отличие от джоя Вад64, который скалибровать по первости не поленился - а винда не исключено что раздельно для разных джоев хранит калибровочные сведения.
С прошивкой от Вад64 дрыгается чаще ( могу заметить 5-6 раз в секунду ), но амплитуда меньше.
А после прошивки от osnwt дрыги реже, но при ентом амплитуда - процентов 20 от длинны калибровочного столбика в AFPD.
Ну и второй (эффект) обнаружился - при некоторых положениях рукояток (что-то в центре, а одна-две (руль высоты/элероны) - в край, думаю что в минимум) начинается жёсткая дрыготня всех каналов (мотор и хвост тоже) на 50% от хода - не исключено что тоже от отсутствия WIN калибровки - сигналы выходят за объявленные/обнаруженные минимумы/максимумы и принудительно центрятся самой виндой ?
Хотя почему при ентом дрыгаются все каналы, а не только тот, который в край ?
Используется PPM выход от RD8000, винда - XP SP2.
Надо второй шнурок забабахать и подцепить его к аналоговым выходам от пульта DF 5#4.
Снабдить его USB так сказать - будет отдельный симуляторный пультик.
Можно будет особо ретивым/настойчивым знакомцам его давать погонять - всяк дешевле, чем верт давать погонять - енто я уже пробовал, кроме смеха - ещё и ремонт…
Кроме того - сразу будет понятно - кто виноват в дрыготне - PPM кодер или USB конвертер - потому как тут всё в одном флаконе станет.
Жаль, что АЦП опрашивается, а не синхронен какому-либо таймерному прерыванию. Ну и усреднять - станет постабильнее. Хотя - вот для ентого и нужны исходники, что-бы пытаться их ковырять для само удовлетворения/образования.
В любом случае - спасибо за исходники/труд по релизу.

osnwt
Psw:

а винда не исключено что раздельно для разных джоев хранит калибровочные сведения.

Именно так - раздельно. Для нее это совершенно разные устройства.

Ну и второй (эффект) обнаружился - при некоторых положениях рукояток (что-то в центре, а одна-две (руль высоты/элероны) - в край, думаю что в минимум) начинается жёсткая дрыготня всех каналов (мотор и хвост тоже) на 50% от хода

Было бы, конечно, интересно найти причину такого поведения. Я наблюдал подобные эффекты с пультом от Валкеры 36. Там, как известно, не совсем честный PPM - после него идет несколько байтов дополнительной информации, сбивающей с толку декодер. Потому для этого пульта я делал специальную версию, ограничивая количество принимаемых каналов 6-ю. Тогда дрыганье исчезало. Выход кривой, но при отсутствии четкого представления, что там идет дальше, трудно сделать выводы о том, как с этим бороться. Я, во всяком случае, не стал.

не исключено что тоже от отсутствия WIN калибровки - сигналы выходят за объявленные/обнаруженные минимумы/максимумы и принудительно центрятся самой виндой ?

Маловероятно. По умолчанию (и здравому смыслу) при отсутствии калибровки винда должна воспринимать граничными те значения, которые прописаны в дескрипторе - а это 0…255, другого не дано. Что бы не принималось на входе - есть коррекция значений при формировании блока данных для отправки. Если только принимается совсем ерунда - тогда да, но это надо проверять.

Хотя почему при ентом дрыгаются все каналы, а не только тот, который в край ?

Возможно, идет потеря синхронизации по паузе - может, надо поиграться с ее определением, или увеличить ее ожидаемую длительность.

Надо второй шнурок забабахать и подцепить его к аналоговым выходам от пульта DF 5#4.
Снабдить его USB так сказать - будет отдельный симуляторный пультик.

Я так и делал, повесившись на потенциометры подобного пульта.

Кроме того - сразу будет понятно - кто виноват в дрыготне - PPM кодер или USB конвертер - потому как тут всё в одном флаконе станет.

Еще вариант - вывести вместо USB (или вместе с ним) полученные значения на UART. Тогда станет сразу ясно, где идет дерганье. USB тогда лучше не включать в такой ситуации - возможно влияние его на времянки, хотя при аппаратном захвате таймера не должен.

СТОП! Действительно, возможна ситуация, когда мы попадаем как раз на момент, когда таймер-то захватили, но в 0 его не прописали (обслуживая более приоритетное прерывание от USB-). Потом мы его все же обнулим, но позже, и длительность следующего импульса будет посчитана неправильно (он получится короче реального). И тогда будет то самое дерганье.

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

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

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

Идеи-то есть. Например, если точно известно количество импульсов в пачке, то при меньшем их количестве вообще пачку отбрасывать. Минус: теряется универсальность. Идея два: набирать статистику по конкретному передатчику. Скажем, ловим 10 пачек и смотрим, сколько импульсов там. Если, по большей части, их там будет 8, а когда-то - лишь 7 или меньше, значит все пачки, где меньше 8 импульсов, надо игнорировать. Но тоже минус: не будут работать пульты типа валкеры с дополнительными посылками в конце. Ну, что же - это плата за дешивизну программной реализации USB. Хотя надо думать - может, можно что-то и с этим поделать 😃

Жаль, что АЦП опрашивается, а не синхронен какому-либо таймерному прерыванию.

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

Ну и усреднять - станет постабильнее.

Не думаю, что это критично - АЦП 10-битный, а выход в данной реализации - 8-ми. Так что дрожание младших битов не может дать 20% столбика. Тут что-то другое.

Хотя - вот для ентого и нужны исходники, что-бы пытаться их ковырять для самоудовлетворения/образования.

Вот потому я и выложил - чтобы кто-то улучшил или дописал своё. А при обсуждении возникают новые мысли (как вот та ошибка с длительностью - в USB драйвере управление может находиться довольно долго - и тем самым ломать работу декодера).

К слову говоря: появилась новая авторская версия USB драйвера (пока у меня, но после тестирования появится на сайте автора), где поддержано динамическое управление всеми USB дескрипторами, которые могут быть статическими или генерироваться на лету во время выполнения. Как частный случай, это дает возможность штатно сделать устройство с переключаемыми интерфейсами (например, по кнопке), а не одним жестко скомпилированным. А код драйвера стал еще более оптимизированным по объему (а казалось бы - куда ещё)…

Vad64
osnwt:

Исправить код несложно: вместо обнуления надо писать в таймер разницу между текущим его значением и захваченным.

Олег, при измерении времени в таймер вообще лучше ничего не писАть. Если его обнулять или писАть в него, всегда будет потеря его фазы и временная ошибка. Когда есть прерывания, ошибка может быть значительной. Пусть таймер себе бежит свободно, а временной интервал всегда лучше вычислять как разницу между ICR и его прошлым значением. Также нет необходимости обрабатывать оба фронта входного сигнала - достаточно настроиться на любой. Полярность значения не имеет.
Что касается дрыганий - у меня причина в том, что наблюдается повторный вход в прерывание TIMER_CAPT. Т.е. обработка прерывания USB иногда длится более 0.9 мс. Наверное, это как-то можно победить, но я, честно говоря, не напрягался.

osnwt
Vad64:

при измерении времени в таймер вообще лучше ничего не писАть. Если его обнулять или писАть в него, всегда будет потеря его фазы и временная ошибка.

Это так, но есть одна проблема: я использую его переполнение выше TOP для поиска синхропаузы между пачками. Потому эта логика нарушится, если не трогать таймер. Хотя, безусловно, можно поменять логику: при измерении интервала просто сравнивать вычисленное значение с величиной TOP и в случае превышения считать, что имело место переполнение (пауза). Одной ISR станет меньше, а точность поднимется.

Когда есть прерывания

Посторонние (более приоритетные) прерывания (как USB в данном случае).

Также нет необходимости обрабатывать оба фронта входного сигнала - достаточно настроиться на любой. Полярность значения не имеет.

Посмотрел еще раз на PPM сигнал - да, действительно можно добавлять паузу 0.3 хоть до, хоть после импульса: результат будет одним и тем же, а код упростится.

Что касается дрыганий - у меня причина в том, что наблюдается повторный вход в прерывание TIMER_CAPT. Т.е. обработка прерывания USB иногда длится более 0.9 мс. Наверное, это как-то можно победить, но я, честно говоря, не напрягался.

Скорее, не повторный вход, а потеря одного из запросов. Да, именно оно видится реальной причиной дрыгания: потеря одного из импульсов приводит к “увеличению” длительности предыдущего на величину последующего, а все остальные сдвигаются на один. В итоге резко скачут все.

В документации на AVR-USB сказано, что драйвер может находиться в прерывании до 100 микросекунд, если хост соответствует стандартам. Реально далеко не все хосты им соответствуют. Далее, количество дрыганий, предположительно, может также зависеть от количества low-speed устройств на USB шине, так как драйвер обслуживает каждую транзакцию, даже если она не адресована нам. Потому можно просто попробовать выключить лишние устройства для подтверждения версии о причине дерготни, но это будет баловство. Думаю, что тут надо подходить иным путем. Я тоже пока напрягаться не планирую, но если возникнет идея, как перестать терять посылки - попробую реализовать. При этом самым простым (но не лучшим) решением видится отбрасывание пачки при неверном количестве импульсов (которое нужно получать автоматически). Для большинства аппаратов это должно работать удовлетворительно.

Vad64

> Посторонние (более приоритетные) прерывания (как USB в данном случае).

Да любые, не обязательно более приоритетные. При входе в любое прерывание все прерывания запрещаются. Если в это время возникает событие таймера, его сброс оттягивется на некоторое время. И даже если других прерываний нет, время реакции на прерывание таймера зависит от текущей выполняемой команды. Так что модификация таймера при измерении интервалов в общем случае - неудачная идея.

> Скорее, не повторный вход, а потеря одного из запросов.

Естественно, потеря. Просто я наблюдал повторный вход. А означал он, что прерывание таймера еще не окончило свою обработку, было прервано прерыванием USB и в USB просидело достаточно, чтобы выскочил новый запрос таймера (возможно даже не один).

> При этом самым простым (но не лучшим) решением видится отбрасывание пачки при неверном количестве импульсов

Это понизит вероятность дрыганий, но, возможно, не устранит их окончательно. Если есть вероятность пропуска произвольного количества событий РРМ, то будет ненулевая вероятность принятия ошибочного решения о “корректности” пачки. Так что в идеале нужна либо аппаратная поддержка USB, либо более продвинутая система регистрации событий РРМ, исключающая пропуски.

osnwt
Vad64:

При входе в любое прерывание все прерывания запрещаются. Если в это время возникает событие таймера, его сброс оттягивется на некоторое время.

Конечно, всё так. Просто в ряде случаев возможно глобальное разрешение прерываний сразу после входа в ISR, и тогда более приоритетное всё равно сможет случиться. Что касается таймера, то задержка на несколько циклов при отсчете длительности PPM не очень критична, она никак не даст скачков на единицы (десятки) процентов. Потому ей можно пренебречь (хотя в целом это, конечно же, неправильно). Но вот задержка внутри USB - это серьезная проблема.

Это понизит вероятность дрыганий, но, возможно, не устранит их окончательно. Если есть вероятность пропуска произвольного количества событий РРМ, то будет ненулевая вероятность принятия ошибочного решения о “корректности” пачки. Так что в идеале нужна либо аппаратная поддержка USB, либо более продвинутая система регистрации событий РРМ, исключающая пропуски.

Возможно, не устранит, но вероятность значительно снизить должно, как мне кажется (поскольку мы просто будем ждать паузы - не верится, что в USB мы можем проторчать 3 миллисекунды, например). Ну, а с выводом я согласен - остается только придумать, как это реализовать наиболее простыми средствами 😃