Поговорим о загрузчиках для микроконтроллерных проектов. Допустим у вас есть фитнес браслет, электро-самокат, робот пылесос, или электронная зубная щетка и Вы хотите обновить прошивку загрузчиком. Какое же поведение должно быть у хорошего загрузчика?
Сначала определимся с терминологией:
--загрузчик - это отдельная прошивка, которая загружает другую прошивку. Обычно загрузчик стартует сразу после подачи питания перед запуском приложения. Это чисто системная часть кода.
--боевая flash - диапазон flash памяти в котором исполняется приложение микроконтроллера.
--временная flash - диапазон Flash памяти (on-chip или off-chip) в которую складируется новая прошивка
--прошивка (firmware) - содержимое энергонезависимой памяти электронного устройства с микроконтроллером. В прошивке всегда есть код, а иногда ещё образ файловой системы NVRAM, конфиги процессора. Монолитная прошивка может содержать еще и загрузчик.
--NVRAM - энергонезависимая память с произвольным доступом. По сути Key-Val-Map(ка). В ней могут храниться любые бинарные данные, ассоциированные со своим ID(шником).
--тыква / кирпич - электронное устройство с бракованной прошивкой, которое либо зависло либо постоянно без конца перезагружается. Такое устройство можно восстановить только программатором.
--таблица векторов прерываний - это таблица адресов функций обработчиков прерываний. Первая колонка это номер прерывания, вторая колонка абсолютный адрес обработчика прерываний в on-chip NOR-Flash памяти. Обычно в этой таблице сотни записей. У каждого микроконтроллера она своя. В бинарном файле перечислена вторая колонка как массив uint32_t: индекс массива-номер прерывания, значение - адрес ISR.
Достоинства загрузчика
1--Можно обновлять прошивку без программатора (обновление "в полях").
Среди программистов-микроконтроллеров есть даже мем что
Самая лучшая функция прошивки это возможность обновления прошивки.
2--Можно обновлять прошивку по любому интерфейсу: UART, BlueTooth, WiFi, LTE, CAN и прочее.
3--Когда есть загрузчик, то можно делать DevOps. Автоматически обновлять прошивки после сборки из репозитория.
Недостатки загрузчика
2--Надо выделить под загрузчик часть Flash памяти. Это порядка нескольких десятков килобайт ROM.
Главная задача хорошего загрузчика - это дать возможность обновлять прошивку и ни при каких обстоятельствах не позволить устройству превратиться в тыкву.
Какие программные компоненты обычно должны быть в загрузчике?
№ |
Программный компонент |
Необходимость |
1 |
Драйвер Flash памяти |
обязательно |
2 |
Драйвер UART |
обязательно |
3 |
NVRAM |
обязательно |
4 |
CRC |
обязательно |
5 |
CLI |
желательно |
6 |
Драйвер внешней Flash памяти |
зависит от платформы |
7 |
Драйвер SD карты |
зависит от платформы |
8 |
драйвер SPI-flash |
зависит от платформы |
9 |
поддержка Fat-FS |
зависит от платформы |
Далее представлены атрибуты хорошего загрузчика
1) Саму физическую загрузку прошивки должен осуществлять не загрузчик, а как не парадоксально само приложение. Дело в том, что в приложении больше памяти и больше драйверов для разнообразных интерфейсов. Поэтому ничего не мешает 10% прошивки получить по WiFi, 20% по BlueTooth, 30% по RS485 еще 30% по CAN. Затем принять конфиги из модулированного звука через аудиокодек а настройки NVRAM получить от сканера QR кодов в драйвере видеокамеры. Если бы мы пытались засунуть поддержку всех возможных интерфейсов и протоколов в загрузчик, то загрузчик был бы больше самого приложения! Одновременно с этим в приложении уже есть поддержка разнородного connectivity (всех этих интерфейсов и протоколов). Поэтому закачкой данных должно заниматься именно приложение.
2) Загрузчик должен быть компактным в плане требуемого ROM. Если загрузчик маленький, то будет больше места для приложения и его бизнес логики, которая и создает основную ценность продукта.
3) Загрузчик должен быть однопоточной NoRTOS прошивкой.
4) Загрузчик перед записью должен проверять контрольную сумму приложения. Если CRC32 не cовпадает то такую прошивку лучше не прописывать. Правильная CRC это всего лишь гарантия, что прошивка как файл передалась корректно. Это не защита от чужеродного firmware.
5) Загрузчик должен уметь прошивать как минимум по UART. Когда всё сломается пере прошивка по UART окажется единственным спасением. Нет проводного интерфейса проще UART. В UART нечему ломаться. UART требует меньше всего NOR-Flash(а). Плюс для UART куча дешевых переходников USB-UART и бесплатного софта для serial портов типа Putty и TeraTerm.
6) Загрузчик должен проверять, что первое слово прошивки по нулевому адресу это реальный для данного микроконтроллера адрес RAM памяти. Дело в том, что в Cortex-M это указатель Stack Pointer прошивки. Если это не так, то эту прошивку загружать нельзя. Она всё равно зависнет тот час же.
7) Загрузчик должен проверять, что в бинарном файле прошивки действительные (валидные) адреса таблицы векторов прерывания. В Cortex-M это адрес +0x00000004 от начала прошивки в начале бинарного файла. Надо проверить, что там валидный ResetHandler. Что его адрес принадлежит Flash памяти.
8) В загрузчике должна быть NVRAM. Это позволит передавать команды от приложения к загрузчику. Или сервер может прописать в NVRAM правильную контрольную сумму для того чтобы загрузчик мог рассчитать CRC и сверить с тем что прописал сервер в NVRAM. В случае несовпадения отказаться загружать подозрительную прошивку. Вот минимальный список переменных для управления загрузчиком
№ |
Переменная NVRAM |
размер, [байт] |
1 |
Начальный адрес по которому следует прописывать прошивку |
4 |
2 |
Ожидаемая контрольная сумма прошивки |
4 |
3 |
Команда загрузчику. Запустить прошивку, остаться в загрузчике, запустить без проверки CRC |
1 |
4 |
Длина прошивки в байтах |
4 |
5 |
Счётчик числа запусков загрузчика (BootCnt) |
1 |
6 |
Ключ шифрования |
256 |
9) Перед прыжком в приложение загрузчик должен отключить все прерывания.
10) отключить системный таймер, так как в приложении может быть RTOS. Если сработает прерывания по системному таймеру до инициализации планировщика, то приложение с RTOS зависнет.
11) Если это Cortex-M ядро, то перед прыжком в приложение надо указать ядру, где теперь будет новая таблица адресов обработчиков прерывания
SCB->VTOR = app_start_address;
12) Загрузчик может переназначить верхушку стека. Хотя это и так cделает StartUp код приложения до запуска main().
__set_MSP(stack_top);
13) У загрузчика должна быть UART-CLI. Это позволит подключиться к консоли загрузчика и проверить диагностику, прописывать NVRAM. Протокол CLI - текстовый. Его понимает и человек и утилита.
14) Если загрузчику не удалось записать прошивку из Flash хранилища (SD-карта, off-chip SPI-flash или on-chip flash), то загрузчик должен написать про это в UART-CLI и перейти в режим ожидания прошивки по UART.
15) Загрузчик должен как-то проверить, что прошивка, которая поступила принадлежит именно нужному вендору, а не злоумышленнику. Поэтому в прошивку надо добавить специальную константу по константному заданному адресу, чтобы загрузчик мог найти эту константу и в случае её совпадения с нужным значением прописать эту прошивку в боевую flash. Или можно оформить эту магическую константу по произвольному адресу просто добавив перед ней преамбулу. Тогда загрузчик может просканировать всю память и найти константу по преамбуле.
16)Прошивка должна приходить в зашифрованном виде. В этом же зашифрованном виде она должна храниться в off-chip flash (SPI или SD). Прошивка должна расшифровываться по кусочкам прямо в загрузчике и после расшифровки записываться в боевую flash.
17) Для дополнительной безопасности на электронной плате можно поставить внешний аппаратный сторожевой таймер (например этот TPS3828-33QDBVRQ1). Этот таймер сбрасывается через GPIO пин. Надо периодически подавать отрицательные перепады чтобы плата не сбрасывалась. Оригинальная прошивка знает про этот пин. Если кто-то попытается записать неоригинальную прошивку, которая не догадывается о существовании внешнего аппаратного сторожевого таймера, то эта неоригинальная прошивка будет постоянно сбрасываться.
*18) instant firmware update (мгновенное обновление прошивки)
Загрузчик должен уметь записывать и запускать принятую прошивку по любому смещению адреса Flash памяти. Это позволит сэкономить время на отчистку и запись прошивки в боевую flash память. Вместо удаления старой прошивки и записи на её место новой можно просто переключить боевую память на другой диапазон и тут же запустить на исполнение от туда код.
https://habr.com/ru/articles/575014/
19) Когда стартует загрузчик или приложение прошивка должена увеличивать счётчик запусков BootCnt. Если счетчик запусков превысит число N (например N=5), то загрузчик/приложение прикажет сам себе остаться в загрузчике. Приложение же должно обнулять счетчик запусков BootCnt после успешной инициализации или, например, на 30й секунде своей работы. Это своего рода защита от тыквы. Если залили приложение, которое из-за исключения постоянно reset(тится ) где-то в инициализации, то такое приложение после N reset(тов) автоматически свалится в загрузчик и можно будет споконо записать по UART нормальную прошивку.
20) Загрузчику не обязательно находится в начале Flash памяти. Загрузчик можно прописывать в самый последний сектор flash памяти, а приложение в начало Flash. Это позволит запускать приложение быстрее. Как загрузчик прыгает в приложение так и приложение может прыгать в загрузчик.
21) Загрузчик это не только еще одна прошивка в репозитории. Для загрузчика нужна инфраструктура и экосистема. В самом простом виде это консольное Win приложение (FW Loader) под PC для отправки прошивки по serial порту. А для смузи-поколения надо сделать FW Loader c GUI-интерфейсом, загрузку из браузера Chrome/Opera/FireFox. Причем всё надо сделать под три операционки: Windows, Linux, Mac. Также нужно мобильное приложение для отправки прошивки из-под Android и iOS. И ещё нужен Web-сервер с авторизацией для поиска необновлённых электронных зубных щеток и раскатывания новых обновлений FW на них. Поэтому загрузчики это на самом деле очень-очень много работы.
22) Сам загрузчик обычно записывают программатором по SWD/JTAG однако в приложении должна быть возможность записать другой загрузчик.
Вывод
Как видите, разработка надежного универсального быстрого загрузчика это достаточно комплексная задача.
Если есть, что добавить, то пишите в комментариях.
Словарь
Акроним |
Расшифровка |
SPI |
Serial Peripheral Interface |
DFU |
device firmware update |
FOTA |
Firmware Over The Air |
OTA |
Over The Air |
NVRAM |
Non-volatile random-access memory |
CRC |
cyclic redundancy check |
FW |
FirmWare |
UART |
universal asynchronous receiver-transmitter |
SD |
Secure Digital (Memory Card) |
FS |
File System |
ISR |
Interrupt Service Routine |
Links
https://habr.com/ru/companies/rainbow/articles/275381/
http://microsin.net/programming/arm/appnote-6282-safe-and-secure-bootloader-implementation.html
https://microtechnics.ru/mikrokontroller-i-bootloader-opisanie-i-princip-raboty/
https://chipenable.ru/index.php/item/140
https://www.feaser.com/openblt/doku.php
https://habr.com/ru/articles/432966/
https://habr.com/ru/companies/ruvds/articles/536132/
https://habr.com/ru/companies/ruvds/articles/536156/
Контрольные вопросы про загрузчики
1--Зачем нужен загрузчик во встраиваемых системах? Назовите минимум 3 его функции.
2--Как загрузчик может обмениваться данными с приложением?
3--В чем опасность вызова функций загрузчика из приложения?
4--Как защитить микроконтроллер от загрузки чужеродного кода через загрузчик?
5--Как загрузчику понять, что загрузчик принял в самом деле прошивку, а не набор случайных циферок с правильной CRC?
6--Как сделать обновление прошивки по TCP/IP, если в загрузчике хватает NorFlash памяти только для драйвера UART?
7--Можно ли сделать так, чтобы загрузчик стартовал не с адреса начала Main Flash 0x0800_0000, а например с адреса 0x0806_0000?
8--Почему в микроконтроллерах STM32 секторы NOR Flash(а) разных размеров?
*9--Вам прислали прошивки в *.bin файле. Как загрузить и запустить эту прошивку по произвольному отступу в on-chip Nor Flash памяти?
Комментарии (53)
zatim
12.08.2023 17:04+5П. 17 - весьма сомнителен. Внешний вотчдог виден невооруженным глазом, тип легко определяется по коду маркировки, функционал - по разводке платы. При реверсе платы для написании левой прошивки этот финт будет легко обнаружен и учтен в ПО.
aabzel Автор
12.08.2023 17:04функционал - по разводке платы. При реверсе платы для написании левой прошивки этот финт будет легко обнаружен и учтен в ПО.
Провод сброса внешнего аппаратного сторожевого таймера может быть проложен в серединном слое #5 и заходить BGA в BGA. А слои #4 #6 металлизация. Такое даже X-Rays не увидят.
Внешний вотчдог виден невооруженным глазом, тип легко определяется по коду маркировки
А маркировка всех чипов на PCB стёрта наждачной бумагой или гравировальным аппаратом.zatim
12.08.2023 17:04+4Нет, реверс инжиниринг очень сильно облегчает тот факт, что компоненты могут стоять только или сверху или снизу платы. А снаружи всегда видно, отходит ли провод от вывода или нет. Хоть бга, хоть не бга, компоненты легко паяются, их можно отпаять и все увидеть. Если вывод задействован, это сразу повод насторожиться и выявить его функцию.
Даже если проводники идут внутри платы, то концы соединения всегда выходят наружу, ибо соединяют компоненты, которые всегда стоят снаружи. Соединения выявляются прозвонкой.
Для выявления функции даже стертая маркировка не помеха. Если у микросхемы 4 вывода, и 3 из них это общий, питание и ресет, то догадаться о функции 4 ноги проще простого. Я таким образом, например, вычислил функции ножек неизвестной 16-ногой микросхемы ШИМ - контроллера в заряднике от ноута и подобрал более доступный аналог. Единственное, этот аналог потреблял ток в несколько раз больше, пришлось пересчитать гасящие резисторы, но в итоге все заработало.
fronda
12.08.2023 17:04+3писал на CAN, никаких UART, т.е. на чипе был сериальник, но не разведен.
aabzel Автор
12.08.2023 17:04писал на CAN
История из жизни.
В новом релизе прошивки драйвер CAN не работает. Устройство не отвечает по CAN.
И что Вы тут предпримете чтобы починить гаджет?makkarpov
12.08.2023 17:04+1К вам такой же вопрос. Залили вы приложение с дефектным сетевым интерфейсом, а по вашей же логике за подготовку образа отвечает именно приложение. Дальнейшие действия?
aabzel Автор
12.08.2023 17:04Дальнейшие действия?
Подключусь к UART-CLI, дам команду прыгнуть в загрузчик и остаться в нем, обновлю приложение по UART.
makkarpov
12.08.2023 17:04+6Я так тоже могу, только загрузчик не нужен - беру программатор, подключаюсь, прошиваю. Разве что с защитой флеша вопросы, но например в новых STM можно закрыть отладочный интерфейс не полностью, а с требованием аутентификации.
Вопрос в том, что устройство висит/стоит/лежит у юзеров, им тоже брать UART кабель и прошивать, если вдруг через OTA прилетела неудачная прошивка?
aabzel Автор
12.08.2023 17:04+2Вопрос в том, что устройство висит/стоит/лежит у юзеров, им тоже брать UART кабель и прошивать, если вдруг через OTA прилетела неудачная прошивка?
Да.
cujos
12.08.2023 17:04+1в релизе не работает, в загрузчике должен работать, не работает в последней версии загрузчика - нужно иметь возможность восстановиться на первую:
после обновления загрузчика делать проверку и подтверждение работоспособности от мастера, если нет определенное время - восстанавливать предыдущую, например, как с настройками видео в винде
ну и jtag никто не отменял
uart нужен для отладки, но не обязателен в конечном изделии (как и jtag)
Zuy
12.08.2023 17:04+5Автоиндустрия так и работает, все загрузчики только по CAN. А больше никак, когда в автомобиле под сотню блоков, к каждому UART не подключишь.
aabzel Автор
12.08.2023 17:04+1Автоиндустрия так и работает, все загрузчики только по CAN.
Ну правильно.
В приложении старая прошивка принимает куски новой прошивки по CAN и сохраняет их во временную память (например в SPI-Flash).
Как только полная прошивка принята прошивка прыгает в загрузчик, где драйвера CAN может и не быть вообще и загрузчик просто переписывает из временной flash в боевую flash.
Со стороны всё выглядит как обновление прошивки по CAN, хотя в загрузчике нет ни одной строчки кода тяжеловесного драйвера CAN.Zuy
12.08.2023 17:04+1Не знаю, где так сделано, но там где я работал именно загрузчики принимали прошивку по CAN. Приложения в устройстве вообще может не быть.
aabzel Автор
12.08.2023 17:04Не знаю, где так сделано
судя по
https://habr.com/ru/news/712888/
в яндексе
aabzel Автор
12.08.2023 17:04загрузчики принимали прошивку по CAN.
А на стороне PC какая утилита была FW Loader(ом), которая посылала прошивку?
aabzel Автор
12.08.2023 17:04Автоиндустрия так и работает, все загрузчики только по CAN.
Вот польский автомобильный ECU контроллер газовых пропановых форсунок от KME
https://kme.eu/kme/en/produkt/nevo-sky-sun-ecu-2/
У него вообще CAN нет.
Обновление и конфигурация по UART.Zuy
12.08.2023 17:04+2Так я и не против, у кого-то CAN, у кого-то UART. Я видел и варианты только с USB. Тут же дело такое, если есть автомобиль и там уже CAN, то никто дополнительно UART впихивать не будет, смысла же нет
Sun-ami
12.08.2023 17:04+2Загрузчики бывают как минимум двух типов — те, что берут прошивку из памяти, куда её загружает предыдущая прошивка, и те, что получают прошивку непосредственно извне. Гибриды возможны, но смысла в них немного — если есть физический доступ — прошить можно и программатором, к тому же есть чипы с заводским загрузчиком, поддерживающим множество интерфейсов. А получать прошивку непосредственно извне часто смысл есть — в устройстве может не хватать памяти для хранения загруженной прошивки.
makkarpov
12.08.2023 17:04+3Хорошо видно, что задачу даже не пытались разделять на слои абстракции.
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).
aabzel Автор
12.08.2023 17:04почему именно UART?
Нет интерфейса проще UART. В UART нечему ломаться.
makkarpov
12.08.2023 17:04+2Критерий применимости - не простота интерфейса с точки зрения количества проводков и сигнала на этих проводках, а возможность использования такого интерфейса конечным пользователем.
Толку от UART, выведенного на потаенный разъем, не больше, чем от SWD, выведенного туда же - конечный пользователь ни тем, ни другим воспользоваться не сможет. Вроде как не в 1997 году живем, когда RS-232 разъем был на каждом компьютере. Толку от USB DFU сильно больше, например - пользователь втыкает устройство в обычный компьютер, скачивает утилиту и возвращает устройство к жизни.
aabzel Автор
12.08.2023 17:04+1Толку от USB DFU сильно больше, например - пользователь втыкает устройство в обычный компьютер, скачивает утилиту и возвращает устройство к жизни.
Хорошо. Тогда пусть это будет USB Type-C, чтобы пользователь не перепутал ориентацию.
makkarpov
12.08.2023 17:04+1Можно и Type B, это не принципиально. Ориентацию он тоже не перепутает, потому что разъем физически нельзя вставить наоборот.
А вот покупать USB-UART кабель специально для вашего устройства гарантированно никто не будет, если мы говорим об устройстве для широких слоев населения. Его просто принесут вам в сервисный центр, вернут обратно в магазин или может быть даже отправят назад почтой - после чего с кирпичом вы будете разбираться сами. Можете посчитать, сколько денег стоит добавление USB, а сколько - оплата всего этого процесса. USB, конечно, не гарантирует отсутствие возврата кирпичей, но хотя бы может уменьшить их количество.
aabzel Автор
12.08.2023 17:04+1А вот покупать USB-UART кабель специально для вашего устройства гарантированно никто не будет, если мы говорим об устройстве для широких слоев населения. Его просто принесут вам в сервисный центр, вернут обратно в магазин или может быть даже отправят назад почтой - после чего с кирпичом вы будете разбираться сами. Можете посчитать, сколько денег стоит добавление USB, а сколько - оплата всего этого процесса. USB, конечно, не гарантирует отсутствие возврата кирпичей, но хотя бы может уменьшить их количество.
Тогда уж лучше заложить чип CP2102 переходник USB-UART в само устройство на PCB. Это всего 25 мм^2 площади.
Пользователь получит USB, разработчик - крохотный загрузчик по UART.
CrashLogger
12.08.2023 17:04+1Пользователи бывают разные. Те, кто вообще не знают, что такое прошивка, просто скажут "ой, сломалось" и пойдут в сервисный центр или купят новое. А те, кто знают, скорее всего уже имеют такой кабель, потому что UART используется повсеместно для самых разных целей.
aabzel Автор
12.08.2023 17:04+1Почему именно CLI?
Потому что CLI текстовый. Его понимает и человек и утилита.
aabzel Автор
12.08.2023 17:04+2Почему не USB DFU, например?
Драйвер USB весьма тяжеловесный в сравнении с UART, а загрузчик должен быть компактным.
По USB можно загружать прошивку уже в приложении, а загрузчику оставить только UART.
makkarpov
12.08.2023 17:04+3Лично умещал драйвер USB (ACM класс) в 3 килобайта флеша и 200 байт RAM (причем я не то, чтобы сильно старался - никаких оптимизаций под размер там не было).
USB в целом весьма простой протокол (когда у вас есть аппаратный интерфейс, он берет на себя огромную часть сложности), DFU - в особенности.
aabzel Автор
12.08.2023 17:04+2Почему не бинарный протокол?
Бинарный протокол очень тяжело читать человеку глазами. Особенно пакеты с little endian.
VelocidadAbsurda
12.08.2023 17:04+2А зачем его читать глазами? По мне так лучше время программиста и ресурсы контроллера, которые ушли бы на CLI, пустить на вылизывание наиболее простого бинарного протокола, за приемлемое время получить загрузчик, на который можно полагаться, и нужда смотреть глазами в этот протокол отпадёт.
aabzel Автор
12.08.2023 17:04По мне так лучше время программиста и ресурсы контроллера, которые ушли бы на CLI
в CLI нет ничего сложного. По факту это синтаксический разбор строчек. Если напишите в личку я могу вообще вам сорцы CLI прислать.
makkarpov
12.08.2023 17:04+1Довольно странно видеть рассуждения о том, что полезный USB мы выкинем, а парсер текстового формата оставим. Хотя текстовый CLI загрузчику нужен так же, как собаке бензобак.
Это не только синтаксический разбор строчек (тоже не очень компактная вещь, если делать по уму), а еще как минимум readline-подобный обработчик ввода. Валидация и подробные сообщения об ошибках. Автодополнение не помешало бы. Всякие help команды и справка по аргументам. Для того, чтобы человеку не приходилось разбирать байты, просто пишется консольная утилита для хоста, которая сама становится этим CLI и может иметь произвольную сложность.
Еще я слабо представляю набор команд у встроенного CLI, кроме "напечатать статус", "залить прошивку" и "перезагрузиться". Но это уже малосущественные детали.
P.S. А если у меня контроллер подключен к системе по SPI, например? Делать CLI over SPI?
aabzel Автор
12.08.2023 17:04Для того, чтобы человеку не приходилось разбирать байты, просто пишется консольная утилита для хоста, которая сама становится этим CLI и может иметь произвольную сложность.
Если в прошивке есть CLI то не нужна вспомогательная утилита. Можно общаться с прошивкой напрямую прямо в Putty (которая есть для всех операционных систем).
В этом тексте
https://habr.com/ru/articles/694408/
всё обосновано
aabzel Автор
12.08.2023 17:04Для того, чтобы человеку не приходилось разбирать байты, просто пишется консольная утилита для хоста, которая сама становится этим CLI и может иметь произвольную сложность.
Да. А потом еще такую же утилиту для Win, Linux, Mac, Android, iOS, MS-DOS, OS/2, IBM POWER8 и БЭСМ-6.
Не проще ли просто реализовать текстовый UART-CLI протокол на уровне Firmware? С раскраской логов, ASCI таблицами.
Тогда и не будет нужды писать этот калейдоскоп no-name утилит-переходников под все известные платформы.
aabzel Автор
12.08.2023 17:04P.S. А если у меня контроллер подключен к системе по SPI, например? Делать CLI over SPI?
Надо уволить схемотехника, который спроектировал электронную плату без выведенного на вилку 2,54мм UART.
aabzel Автор
12.08.2023 17:04Еще я слабо представляю набор команд у встроенного 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,
Indemsys
Лучше когда приложение стартует по сбросу, а не из загрузчика. Это легко делается если есть батарейная RAM. Снимает кучу хлопот с реинициализацией периферии.
Самое удобное когда загрузчик сам забирает прошивку из интернета. Поэтому лучше когда загрузчик включает в себя полный фреймворк IoT с RTOS, MQTT и клиентом FTPS. Тоже снимает кучу проблем по поддержке, а займёт всего пару сотен килобайт.
aabzel Автор
А что мешает самому приложению достать прошивку из интернета по MQTT и FTPS?
Indemsys
Если приложение скачивает прошивку, то это все тот же загрузчик.
aabzel Автор
200kByte+ на загрузчик! Обычно на загрузчик остается 32кByte, ну максимум 128кByte.
Indemsys
В 128 кбайт поместится весьма малофункциональный загрузчик.
aabzel Автор
Стартует приложение и до запуска супер цикла где-то в инициализации происходит исключение.
Прошивка сваливаетcя в Hard Fault Handler. затем по сторожевому таймеру перезагружается и история повторяется.
Результат устройство тыква.
Indemsys
Нет, сценарий описали неправильно.
Современные микроконтроллеры стартуют со своего внутреннего заводского загрузчика в ROM-е.
aabzel Автор
Это это история из prod(a).
Polarisru
А если в контроллере всего 32 кб? Что делать, как жить?
aabzel Автор
Когда так мало Flash памяти, то прошивку надо писать на Assembler
LLDevLab
Основы ассемблера
https://www.youtube.com/watch?v=-sWD-5s4Sc4&list=PLeQDJtBkrIiQvx92-9gOHzp6R6utJR-h5
Sun-ami
В 32 кб отлично влазит программа на C++ на много тысяч строк, и компактный загрузчик. Тут главное не пытаться впихнуть туда всё, что вы считаете атрибутами хорошей программы, особенно CLI, но также и RTOS и файловую систему. А также всячески избегать использования арифметики с плавающей точкой.
Polarisru
Во-во, а то развелось тут гуру, которые даже слышали про ассемблер!