ToyLoader — простой бутлоадер для PIC18 по шине питания

PIC
 Недавно я решил сделать небольшую игрушку. Для неё я воспользовался контроллером pic18f2550, но не потому что он такой крутой, а потому что у меня завалялась их целая куча.
И приспичило мне менять в этой игрушке прошивку по мановению руки. Естественно, в таких случаях обычно используются бутлоадеры. Бутлоадер же в свою очередь должен как-то общаться с хостом, например через UART/USB/свой протокол. Но для всех них надо тащить к устройству дополнительные провода; чего мне не очень хотелось, а точнее очень не хотелось, поскольку девайс и так подключается к питанию довольно длинными проводами.

Естественный выход — грузить прошивку по шине питания. Покопавшись в интернетах, я нашёл подходящий мне бутлоадер — ZPL, но по сслыке меня ждал облом. «Сами с усами» — подумал я, и расчехлил компилятор…

Для начала я взял простую схему подключения через UART:

Слева — переходник USB→UART, справа — девайс на нашем контроллере.
Q1 можно взять любой, даже биполярный, он работает тупым инвертором. Для Q2 лучше взять что-нибудь пожирнее. Для маломощных устройств достаточно встроенных в контроллер защитных диодов. Для чего-нибудь помощнее лучше поставить внешний диод Шоттки. Значения резисторов и конденсаторов взяты наобум )
Я его слепила из того, что было...

В качестве Q1 и Q2 я взял FDS8958A (два транзистора в одном корпусе), в качестве D1 — BAT54C.
Всё это дело питается от USB, либо от внешнего блока питания, если потребляемый ток превышает 500мА, например при прошивке большого числа контроллеров параллельно. Собрано на куске платы от SMT-переходника.

Теперь про софт
Бутлоадер тихо мирно живёт в последнем килобайте памяти программ, там же и держит свои настройки (оригинальный ресет-вектор). В пользовательской программе не надо настраивать ничего, если она умещается в (32 — 1)кБ памяти. Также не требуется релокация стартового вектора (бутлоадер сделает это сам) и прерываний (он их просто не использует).

После старта контроллера бутлоадер пытается слушать UART-порт в течение примерно 36мс; время это взято от балды для внутреннего RC-генератора, и его можно легко менять в исходниках. Если на вход RX в это время будет подан меандр (много байт 0x55), то будет произведён автоматический расчёт baud rate и случится вход в режим бутлоадера. Если меандр обнаружен не будет — начнётся выполнение пользовательской программы.

На нижнем уровне протокол общения очень похож на то, что описано в AN1310; только CRC может отличаться, поскольку я особо не вникал какое там начальное значение и полином. Все команды передаются пакетами вида STX, STX, [DATA]*, CRC1, CRC2, ETX, где все значения констант и эскейп-последовательность такие же, как и в микрочиповских бутлоадерах. Сами же команды отличаются. Поскольку бутлоадер не диалоговый, то их всего-лишь 3 штуки:
Erase
0x11, [ ADDRH, ADDRL, PAGECOUNT ]*
ADDR — адрес, с которого надо начать стирание. PAGECOUNT — количество 64-байтных страниц, которые надо стереть. Таких диапазонов может быть несколько.

Write
0x12, ADDRH, ADDRL, [ DATA ]*
ADDR — адрес начала записываемых данных, должен быть выровнен по 32-байтным страницам. DATA — собственно, содержимое памяти.

Finish
0x13, [ CONFIG ]*
Эта команда заканчивает цикл прошивки, записывает правильный ресет-вектор в настройки бутлоадера. CONFIG — опциональный параметр, содержимое фьюзов. ВНИМАНИЕ: конфиг никик не проверяется, так что записав сюда невалидное значение можно запороть бутлоадер.

Хотя в нашем случае у бутлоадера и нет нормальной связи обратно с PC, но его можно научить «общаться» с внешним миром. Для этого достаточно отредактировать в файле boot.h дефайны, начинающиеся с NOTIFY_: у меня к порту B подвешено 8 светодиодов, и я на них вывожу состояние бутлоадера и разные его ошибки.

Со стороны PC софт достаточно простой. Написан он на C#, запускать его на linux или OSX я пока ещё не пробовал, но он должен нормально работать с помощью mono. Ничего особо интересного он не содержит, большая часть кода ушла на разбор HEX-файла и различные с ним операции.
Пользоваться им легко:
loader.exe firmware_hex -p=port [-b=baudrate]
сразу после запуска в указанный порт будет отправляться меандр. После того, как произойдёт вход в бутлоадер, надо нажать любую кнопку и начнётся прошивка.

Видео:


Baud-rate по-дефолту равен 115200. У меня получилось прошивать со скоростями от 9600 до 153600 на переходнике на базе cp2102. Я честно не знаю, что мешает добиться больших скоростей, мне и 115200 хватает.

 Исходники и бинарники можно скачать с гитхаба, лицензия BSD — что хотите с ними, то и делайте.
  • +5
  • 02 апреля 2012, 23:31
  • atd

Комментарии (20)

RSS свернуть / развернуть
Неплохой наброс. А как он определяет целостность прошивки и сообщает об этом программатору? Ведь обратной то ветви нет.
0
Если что-то побилось (проверяется crc16-ccitt), то он останавливается. Придётся шить, пока не получится.

Естественно, в серьёзных девайсах такого делать нельзя. Это так, игрушки )
0
А, т.е. пнули — брикнулось. Пинаем еще раз и так пока не заведется. Ну тоже неплохой вариант.
0
Я так понял, что хост получает то, что передает сам? Это для контроля правильности передачи данных?
0
Да, забыл написать: RX замкнут обратно не для того, чтобы проверить целостность, а из-за того, что почти все переходники USB→UART имеют буфер, и соответственно, неизвестную задержку перед отправкой данных. А у cp2102 не работают даже методы принудительного сброса этого буфера.

Софт на PC просто ждёт, пока не прочитает из порта то, что отослал, и только после этого считает, что отправка удалась.
0
А вот это интересная фишка.
0
а какой смысл во внешнем диоде?
0
При нагрузке на отсальные порты контроллера в примерно 100мА падение на внутреннем диоде составляет 0.9В (на pic18f2550-i/p), а если в помощь ему добавить внешний, то для BAT54C это будет всего-лишь 0.3В
0
и 100мА это, насколько я помню, предельный ток на пин для данного контроллера, а может даже и за пределами.
0
Это для пина, а для диода? В AVR вон диоды на 500мкА стоят, хотя пины — 20-40мА.
0
Да, насчёт диода я не в курсе. Но всё равно приятнее работать с 4.7V, чем с 4.1V, особенно если остальные части рассчитаны примерно на 5 вольт, да и контроллер греться не будет.
0
500 микроампер. Т.е. при практически любой попытке запитаться через этот диод — он сдыхает (причем часто в пробой).
0
Да, глянул в даташит, 20мА диод выдерживает. Так что мне ещё повезло, что контроллер не сдох, но грелся он знатно…
0
Огромное спасибо за статью )_ я как раз такой пик себе заказал ))) с программатором ) Вовремя! )))
0
утащил к себе ))))
0
Я б по земле передавал от устройства справа в конвертер данные по такому же принципу. Во время передачи отрывая землю справа и пуская по ней питание, слева соответственно отрывая в данный момент линию от минуса. И ловя логическую единицу слева. Вот какие мысли у меня по этой схеме. У кого какие мысли?
0
земля, не земля, какая разница. это уже больше на 1-wire будет похоже, и с таймингами будет пожостче.
0
Зато можно и писать и читать и проверять, что записал.
0
Все уже украдено до нас: pbus.
0
Там вообще-то передача данных по отдельной линии, тогда как здесь — только питание.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.