Pull to refresh

Comments 72

Лучше когда приложение стартует по сбросу, а не из загрузчика. Это легко делается если есть батарейная RAM. Снимает кучу хлопот с реинициализацией периферии.

Самое удобное когда загрузчик сам забирает прошивку из интернета. Поэтому лучше когда загрузчик включает в себя полный фреймворк IoT с RTOS, MQTT и клиентом FTPS. Тоже снимает кучу проблем по поддержке, а займёт всего пару сотен килобайт.

Самое удобное когда загрузчик сам забирает прошивку из интернета. Поэтому лучше когда загрузчик включает в себя полный фреймворк IoT с RTOS, MQTT и клиентом FTPS. Тоже снимает кучу проблем по поддержке, а займёт всего пару сотен килобайт.

А что мешает самому приложению достать прошивку из интернета по MQTT и FTPS?

Если приложение скачивает прошивку, то это все тот же загрузчик.

, а займёт всего пару сотен килобайт.

200kByte+ на загрузчик! Обычно на загрузчик остается 32кByte, ну максимум 128кByte.

В 128 кбайт поместится весьма малофункциональный загрузчик.

Лучше когда приложение стартует по сбросу, а не из загрузчика.

Стартует приложение и до запуска супер цикла где-то в инициализации происходит исключение.
Прошивка сваливаетcя в Hard Fault Handler. затем по сторожевому таймеру перезагружается и история повторяется.

Результат устройство тыква.

Нет, сценарий описали неправильно.

Современные микроконтроллеры стартуют со своего внутреннего заводского загрузчика в ROM-е.

Современные микроконтроллеры могут стартовать много как - с заводского загрузчика, с фиксированного адреса RAM, с фиксированного адреса FLASH - все зависит от конфигурации, заданной во фьюзах или определенным подключением специальных выводов. Как правило его конфигурируют на старт из FLASH, где и находится пользовательская прошивка.

 все зависит от конфигурации, заданной во фьюзах или определенным подключением специальных выводов

В STM32 это пины BOOT0 и BOOT1.

У некоторых - только BOOT0. Я в курсе :)

А если в контроллере всего 32 кб? Что делать, как жить?

В 32 кб отлично влазит программа на C++ на много тысяч строк, и компактный загрузчик. Тут главное не пытаться впихнуть туда всё, что вы считаете атрибутами хорошей программы, особенно CLI, но также и RTOS и файловую систему. А также всячески избегать использования арифметики с плавающей точкой.

Во-во, а то развелось тут гуру, которые даже слышали про ассемблер!

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

П. 17 - весьма сомнителен. Внешний вотчдог виден невооруженным глазом, тип легко определяется по коду маркировки, функционал - по разводке платы. При реверсе платы для написании левой прошивки этот финт будет легко обнаружен и учтен в ПО.

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

Провод сброса внешнего аппаратного сторожевого таймера может быть проложен в серединном слое #5 и заходить BGA в BGA. А слои #4 #6 металлизация. Такое даже X-Rays не увидят.

Внешний вотчдог виден невооруженным глазом, тип легко определяется по коду маркировки


А маркировка всех чипов на PCB стёрта наждачной бумагой или гравировальным аппаратом.

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

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

Для выявления функции даже стертая маркировка не помеха. Если у микросхемы 4 вывода, и 3 из них это общий, питание и ресет, то догадаться о функции 4 ноги проще простого. Я таким образом, например, вычислил функции ножек неизвестной 16-ногой микросхемы ШИМ - контроллера в заряднике от ноута и подобрал более доступный аналог. Единственное, этот аналог потреблял ток в несколько раз больше, пришлось пересчитать гасящие резисторы, но в итоге все заработало.

писал на CAN, никаких UART, т.е. на чипе был сериальник, но не разведен.

писал на CAN

История из жизни.
В новом релизе прошивки драйвер CAN не работает. Устройство не отвечает по CAN.
И что Вы тут предпримете чтобы починить гаджет?

К вам такой же вопрос. Залили вы приложение с дефектным сетевым интерфейсом, а по вашей же логике за подготовку образа отвечает именно приложение. Дальнейшие действия?

Дальнейшие действия?

Подключусь к UART-CLI, дам команду прыгнуть в загрузчик и остаться в нем, обновлю приложение по UART.

Я так тоже могу, только загрузчик не нужен - беру программатор, подключаюсь, прошиваю. Разве что с защитой флеша вопросы, но например в новых STM можно закрыть отладочный интерфейс не полностью, а с требованием аутентификации.

Вопрос в том, что устройство висит/стоит/лежит у юзеров, им тоже брать UART кабель и прошивать, если вдруг через OTA прилетела неудачная прошивка?

Вопрос в том, что устройство висит/стоит/лежит у юзеров, им тоже брать UART кабель и прошивать, если вдруг через OTA прилетела неудачная прошивка?

Да.

в релизе не работает, в загрузчике должен работать, не работает в последней версии загрузчика - нужно иметь возможность восстановиться на первую:
после обновления загрузчика делать проверку и подтверждение работоспособности от мастера, если нет определенное время - восстанавливать предыдущую, например, как с настройками видео в винде
ну и jtag никто не отменял
uart нужен для отладки, но не обязателен в конечном изделии (как и jtag)

Автоиндустрия так и работает, все загрузчики только по CAN. А больше никак, когда в автомобиле под сотню блоков, к каждому UART не подключишь.

Автоиндустрия так и работает, все загрузчики только по CAN. 

Ну правильно.
В приложении старая прошивка принимает куски новой прошивки по CAN и сохраняет их во временную память (например в SPI-Flash).
Как только полная прошивка принята прошивка прыгает в загрузчик, где драйвера CAN может и не быть вообще и загрузчик просто переписывает из временной flash в боевую flash.

Со стороны всё выглядит как обновление прошивки по CAN, хотя в загрузчике нет ни одной строчки кода тяжеловесного драйвера CAN.

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

Яндекс пока ещё далек от автоиндустрии. Как дорастут может придет просветление :)

Яндекс пока ещё далек от автоиндустрии.

яндекс по сути - таксопарк

Так в том-то и дело, им вообще все равно что там в машинах внутри

Они в основном занимаются взломом иномарок.
Пытаются делать реверс инжиниринг трафика в CAN шине.

 загрузчики принимали прошивку по CAN.

А на стороне PC какая утилита была FW Loader(ом), которая посылала прошивку?

Автоиндустрия так и работает, все загрузчики только по CAN.

Вот польский автомобильный ECU контроллер газовых пропановых форсунок от KME

https://kme.eu/kme/en/produkt/nevo-sky-sun-ecu-2/

У него вообще CAN нет.
Обновление и конфигурация по UART.

Так я и не против, у кого-то CAN, у кого-то UART. Я видел и варианты только с USB. Тут же дело такое, если есть автомобиль и там уже CAN, то никто дополнительно UART впихивать не будет, смысла же нет

Автоиндустрия так и работает, все загрузчики только по CAN.

CAN это всего лишь физический и канальный уровень модели OSI-7.

А поверх CAN какой протокол?

Загрузчики бывают как минимум двух типов — те, что берут прошивку из памяти, куда её загружает предыдущая прошивка, и те, что получают прошивку непосредственно извне. Гибриды возможны, но смысла в них немного — если есть физический доступ — прошить можно и программатором, к тому же есть чипы с заводским загрузчиком, поддерживающим множество интерфейсов. А получать прошивку непосредственно извне часто смысл есть — в устройстве может не хватать памяти для хранения загруженной прошивки.

И по какому протоколу по хорошему следует получать прошивку извне?

Это зависит от того, какие интерфейсы и протоколы используются в работе - протокол обновления должен быть совместим с ними, и быть максимально простым, и в то же время гарантировать надёжную загрузку. В случае Ethernet логично использовать собственный протокол поверх UDP.

Хорошо видно, что задачу даже не пытались разделять на слои абстракции.

1 - Зависит от конкретного приложения, но если речь идет об устройстве с физическим интерфейсом (например, USB) - то загрузчик. Если это что-то сложное с WiFi и интернетом - тогда отдельно надо озаботиться тем, чтобы не отстрелить себе ногу при OTA. Например, путем сохранения минимально работающей (достаточной, чтобы обновиться) прошивки в отдельный recovery-раздел внешней флешки.

4, 6, 7 - при запуске уже записанной во флеш прошивки достаточно банальной проверки контрольной суммы и флага, что эта прошивка вообще присутствует.

4, 15, 17 - я правильно понимаю, что BGA дорожки, аппаратный вотчдог и стирание маркировки предлагаются из-за того, что загрузчик не осилил банальную аутентификацию загружаемой прошивки?

13, 14 - почему именно UART? Почему именно CLI? Почему не USB DFU, например? Почему не бинарный протокол? Универсальные советы редко бывают хорошими.

9 - по Reference Manual ядро стартует со включенными прерываниями, и такой совет потребует доработки приложения. Отключать надо источники прерываний, а не сами прерывания. Аналогично 12 - по спецификации ядро ставит стек из первого слова векторной таблицы, загрузчик должен сделать так же. Даже если конкретный startup файл его и переставляет сразу же, поведение должно совпадать.

18 - перемещаемый и позиционно-независимый код - это две абсолютно разные вещи. Для перемещаемого кода вам придется хранить метаинформацию о перемещениях и применять эти перемещения. Позиционно-независимый код тоже имеет свои накладные расходы, но может запускаться из любого адреса. Сама необходимость такой фичи выглядит сомнительной, если только речь не идет про какие-то A/B boot схемы.

20 - сначала стартует загрузчик, потом приложение (по тем же причинам отстрела ноги). Если конкретный чип не позволяет конфигурировать VTOR или отображение памяти (например, новые STM позволяют) - то загрузчику особо больше негде быть, кроме как в начале флеша.

22 - наоборот, неплохо бы предпринять меры для того, чтобы даже при баге в приложении оно физически не могло испортить загрузчик. Если МК не позволяет что-то более гибкое - то просто пометить соответствующие страницы как R/O, если позволяет - то использовать эти механизмы (напр., Securable Flash на контроллерах STM32G4).

почему именно UART?

Нет интерфейса проще UART. В UART нечему ломаться.

Критерий применимости - не простота интерфейса с точки зрения количества проводков и сигнала на этих проводках, а возможность использования такого интерфейса конечным пользователем.

Толку от UART, выведенного на потаенный разъем, не больше, чем от SWD, выведенного туда же - конечный пользователь ни тем, ни другим воспользоваться не сможет. Вроде как не в 1997 году живем, когда RS-232 разъем был на каждом компьютере. Толку от USB DFU сильно больше, например - пользователь втыкает устройство в обычный компьютер, скачивает утилиту и возвращает устройство к жизни.

Толку от USB DFU сильно больше, например - пользователь втыкает устройство в обычный компьютер, скачивает утилиту и возвращает устройство к жизни.

Хорошо. Тогда пусть это будет USB Type-C, чтобы пользователь не перепутал ориентацию.

Можно и Type B, это не принципиально. Ориентацию он тоже не перепутает, потому что разъем физически нельзя вставить наоборот.

А вот покупать USB-UART кабель специально для вашего устройства гарантированно никто не будет, если мы говорим об устройстве для широких слоев населения. Его просто принесут вам в сервисный центр, вернут обратно в магазин или может быть даже отправят назад почтой - после чего с кирпичом вы будете разбираться сами. Можете посчитать, сколько денег стоит добавление USB, а сколько - оплата всего этого процесса. USB, конечно, не гарантирует отсутствие возврата кирпичей, но хотя бы может уменьшить их количество.

А вот покупать USB-UART кабель специально для вашего устройства гарантированно никто не будет, если мы говорим об устройстве для широких слоев населения. Его просто принесут вам в сервисный центр, вернут обратно в магазин или может быть даже отправят назад почтой - после чего с кирпичом вы будете разбираться сами. Можете посчитать, сколько денег стоит добавление USB, а сколько - оплата всего этого процесса. USB, конечно, не гарантирует отсутствие возврата кирпичей, но хотя бы может уменьшить их количество.

Тогда уж лучше заложить чип CP2102 переходник USB-UART в само устройство на PCB. Это всего 25 мм^2 площади.

Пользователь получит USB, разработчик - крохотный загрузчик по UART.

Пользователи бывают разные. Те, кто вообще не знают, что такое прошивка, просто скажут "ой, сломалось" и пойдут в сервисный центр или купят новое. А те, кто знают, скорее всего уже имеют такой кабель, потому что UART используется повсеместно для самых разных целей.

Почему именно CLI?

Потому что CLI текстовый. Его понимает и человек и утилита.

Почему не USB DFU, например?

Драйвер USB весьма тяжеловесный в сравнении с UART, а загрузчик должен быть компактным.

По USB можно загружать прошивку уже в приложении, а загрузчику оставить только UART.

Лично умещал драйвер USB (ACM класс) в 3 килобайта флеша и 200 байт RAM (причем я не то, чтобы сильно старался - никаких оптимизаций под размер там не было).

USB в целом весьма простой протокол (когда у вас есть аппаратный интерфейс, он берет на себя огромную часть сложности), DFU - в особенности.

Почему не бинарный протокол?

Бинарный протокол очень тяжело читать человеку глазами. Особенно пакеты с little endian.

А зачем его читать глазами? По мне так лучше время программиста и ресурсы контроллера, которые ушли бы на CLI, пустить на вылизывание наиболее простого бинарного протокола, за приемлемое время получить загрузчик, на который можно полагаться, и нужда смотреть глазами в этот протокол отпадёт.

По мне так лучше время программиста и ресурсы контроллера, которые ушли бы на CLI

в CLI нет ничего сложного. По факту это синтаксический разбор строчек. Если напишите в личку я могу вообще вам сорцы CLI прислать.

Довольно странно видеть рассуждения о том, что полезный USB мы выкинем, а парсер текстового формата оставим. Хотя текстовый CLI загрузчику нужен так же, как собаке бензобак.

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

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

P.S. А если у меня контроллер подключен к системе по SPI, например? Делать CLI over SPI?

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

Если в прошивке есть CLI то не нужна вспомогательная утилита. Можно общаться с прошивкой напрямую прямо в Putty (которая есть для всех операционных систем).

В этом тексте
https://habr.com/ru/articles/694408/
всё обосновано

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

Да. А потом еще такую же утилиту для Win, Linux, Mac, Android, iOS, MS-DOS, OS/2, IBM POWER8 и БЭСМ-6.

Не проще ли просто реализовать текстовый UART-CLI протокол на уровне Firmware? С раскраской логов, ASCI таблицами.

Тогда и не будет нужды писать этот калейдоскоп no-name утилит-переходников под все известные платформы.

Забыли упомянуть MS-DOS, OS/2, IBM POWER8 и БЭСМ-6.

P.S. А если у меня контроллер подключен к системе по SPI, например? Делать CLI over SPI?

Надо уволить схемотехника, который спроектировал электронную плату без выведенного на вилку 2,54мм UART.

Еще я слабо представляю набор команд у встроенного CLI, кроме "напечатать статус", "залить прошивку" и "перезагрузиться".


Вот список наиболее часто употребительных команд CLI безотносительно к конкретному проекту:

1 Показать список доступных команд Help/TAB, 2 перезагрузиться, 3 запустить модульные тесты, 4 установить/считать напряжение на GPIO, 5 установить подтяжку напряжения на GPIO, 6 показать напряжение на входах ADC, 7 запуск аппаратных таймеров, 8 включить/отключить конкретное прерывание, 9 перенастроить частоту процессорного ядра, 10 прыгнуть в загрузчик,11 показать версию софта и железа, 12 показать историю команд, 13 установить уровень логирования для конкретного компонента, 14 показать таблицу состояния потоков и их свойства (стек, приоритет), 15 показать счетчик принятых/отправленных пакетов по всем протоколам,16 показать список файлов в файловой системе FatFs, 17 отобразить в UART содержимое конкретного файла,18 Просканировать шину I2C, 19 пульнуть произвольные данные в SPI/I2C/I2S/MDIO, 20 Вычитать кусок памяти из REG RAM FLASH, 21 Найти адрес по значению, 22 повторить конкретную команду N раз с периодом P,

22 Атрибута Хорошего Загрузчика

не хватает: «по моему мнению»

3) Загрузчик должен быть однопоточной NoRTOS прошивкой.

Это почему это должен? Есть у меня отлаженные драйвера всего и вся под РТОС. Собираю из тех же исходников загрузчик. Дешево, надежно и практично.

Чтобы уменьшить бинарь и упростить код загрузчика.

По факту загрузчику на UART многозадачность нужна как собаке бензобак.

Техподдержка NoRTOS прошивки проще.
Если код простой, то и ломаться там будет не чему.

Где-то я уже читал сегодня про собаку и бензобак. По моим многолетним наблюдениям есть с десяток типовых ошибок, которые регулярно допускают программисты различного уровня при реализации драйвера UART и протоколов поверх него. Опять же по опыту проще отлаживать и сопровождать тот код, который используется в большем количестве проектов и применений без значительных изменений. Размер бинаря несомненно важен. Например есть у нас проект загрузчика под STM8S003F3P6TR. Под загрузчик выделено чуть больше 1кб. Там нет ртосей. Но есть и проекты в 1МБ флеши. Там загрузчик 64 кб с использованием POSIX ртос, фс, внешней памятью, шифрованием и т.д. и он собирается из тех же исходников, что и основной проект. В этом есть свой кайф.

загрузчик собирается из тех же исходников, что и основной проект. 


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

Вы такой самоуверенный, как будто ничего хитрее хала никогда не видели. Расскажите как собрать NoRTOS версию драйверов вот от этой вещи

как будто ничего хитрее хала никогда не видели

А Вам я рекомендую открыть для себя Zephyr Project.

В Заголовке Слово "Хорошего" Надо Изменить На "Моего".

Спасибо за статью, у меня вроде как подошёл момент когда надо об этом озаботиться в коде и были разные мысли по этому поводу, некие казались абсурдными. Но теперь почти уверен, что к моему контроллеру (в единственном экземпляре) на stm32 с 32к проще поставить рядом малинку для прошивки :)

Или не воспринимать слишком серьезно подобные личные оценочные суждения, написанные как непререкаемая истина :) Загрузчик должен стартовать до основной прошивки и передать управление основной программе, либо по какому-либо условию/сигналу принять извне удобным способом новую основную прошивку и записать ее во флэш контроллера. И всё :) Остальные фичи могут быть востребованы, а могут и не быть, зависит от задач и пожеланий :) И методы реализации этих фич так же могут быть разными.

Простейший загрузчик вполне можно уложить и в пару килобайт, а может быть даже и меньше :)

Sign up to leave a comment.

Articles