
" Все интерфейсы и протоколы только и нужны, чтобы сделать memcpy() "
В программировании микроконтроллеров помимо написания прошивок ещё периодически приходится писать клиентские программы для загрузки *.hex файлов в микроконтроллер через загрузчик.
Как водится, самое сложное в этом процессе - это сесть и написать ТЗ. Только после ТЗ появляется ответ на извечный вопрос: "что делать?".
В самом классическом случае loader - это консольное windows приложение. Такие утилиты зачастую поставляют сами производители микроконтроллеров: STm, TI, Nordic Semiconductor и пр. Так как boot пины позволяют производить загрузку прошивки из UART. Еще такие загрузчики пишут сами продуктовые компании для DevOps процессов внутри компании и для пользователей того или иного прибора.
В этом тексте я попробовал порассуждать на тему того, какой же должна быть эта самая утилита FW_Loader.
Определения
Алгоритм — последовательность действий.
Программа — алгоритм написанный на языке программирования.
Процесс — исполняемый экземпляр программы в памяти.
Модульный тест — функция, которая вызывает другую функцию с известными аргументами и проверяет наличие ожидаемого результата. В случае противоречия сигнализирует об ошибке.
Прошивка (firmware) — содержимое энергонезависимой памяти электронного устройства с микроконтроллером. В прошивке всегда есть код, а иногда ещё образ файловой системы NVRAM, конфиги процессора. Монолитная прошивка может содержать ещё и загрузчик.
Загрузчик — это отдельная прошивка, которая загружает другую прошивку. Обычно загрузчик стартует сразу после подачи питания перед запуском приложения. Это чисто системная часть кода.
CLI — Интерфейс командной строки. Это способ взаимодействовать с программой обменом текстами по принципу запрос‑ответ.
connectivity — всё что связано с интерфейсами и протоколами.
Обязательные технические требования
Общий план таков, что надо загрузить прошивку в память при помощи тандема on-chip загрузчика и утилиты FW_Loader по UART. То есть обновить прошивку без программатора. Условно FW Loader - это консольное Windows PC приложение для нарезания .hex (или bin) файла и отправки фрагментов прошивки по последовательному COM порту.
0--В утилите FW_Loader должен быть progress bar. Индикатор прогресса. Чтобы оператор мог непрерывно оценивать сколько ему еще ждать окончания обновления прошивки. Нет ничего мучительнее, чем неизвестность.
1--Утилита FW_Loader должна быть консольным приложением. Консольное приложение проше протестировать и быстрее написать. Также консольным приложением можно управлять из других программ.
2--Программа FW_Loader должна быть собрана для OS Windows. Это самая распространенная ОС.
3--Программа FW_Loader должна обладать своей собственной системой команд. Система команд это ключи, аргументы командной строки.
4--Все команды должны вызываться, как в интерактивном режиме, так и в пакетном режиме.
5--Аргументы командной строки должны быть позиционными. Самый главные аргументы в начале. Вспомогательные аргументы в конце. Это наиболее простой и быстрый способ для реализации в коде.
6--Утилита FW_Loader должна уметь проверять нынешнее содержимое прошивки в ROM памяти с указанным *.hex файлом. Так называемый режим верификации содержимого памяти.
29--Программа FW_Loader должна автоматически определять COM порт на котором находится наш target процессор. Программа FW_Loader должна уметь сканировать все доступные в операционной системе COM порты и находить тот COM port на котором подключена электронная плата.
7--В утилите FW_Loader должна быть команда ping для проверки физического соединения между PC и электронной платой.
7--У утилиты FW Loader должен быть интерактивный режим. То есть режим командной строки в stdio. Подобно тому, как это происходит в программе BusyBox.
9--У утилиты FW Loader должен быть пакетный режим. То есть утилита должна отрабатывать свои аргументы командной строки и сразу после этого завершать свое исполнение.
10--Программа FW_Loader должна работать с *.hex файлом.
11--Программа FW_Loader должна работать с *.bin файлом. В этом случае надо отдельно указывать по какому смещению следует прописывать данный bin файл.
12--Утилита должна записывать прошивку по частям. Микроконтроллер всё равно не сможет разместить всю прошивку в RAM памяти.
13--Программа FW_Loader должна позволять конфигурировать паузу между отправкой байтов в COM порт аргументами командной строки. Это нужно, чтобы загрузчик не захлебнулся от интенсивного потока входных байт. Также полезно при отладке.
14--Пауза между отправкой байтов должна передаваться через командную строку, как аргумент команды.
15--Программа FW_Loader должна входить в интерактивный режим только в случае пуска без аргументов командной строки. В случае пуска с аргументами командной строки утилита только отрабатывает свои ключи и автоматически выходит, возвращая код ошибки.
То есть приложение FW_Loader должно быть пригодно для запуска из другого приложения и
сообщать ему простым в использовании способом о возникновении проблемы.
16--Программа FW_Loader должна возвращать код ошибки в случае неудачного подключения и прошивки.
17--Программа FW_Loader должна собираться из скрипта сборки . Это позволит подключить её к серверу сборки Jenkins.
18--Программа FW_Loader должна быть одно-поточным процессом в операционной системе.
19--Программа FW_Loader должна собираться из скриптов сборки GNU Make.
20--Программа FW_Loader должна содержать модульные тесты.
21--Битовая скорость UART должна передаваться через ключи утилиты.
22--После обновления утилита должна давать команду прыжка в приложение.
23--У каждой CLI команды утилиты FW_Loader должна быть справка. Справку можно изучить в интеррактивном режиме работы утилиты буквально набрав название команды.
24--Должна быть предусмотрена возможность вычитывать содержимое физической памяти из MCU.
25--По окончании обновления утилита FW_Loader должна печатать отчёт об обновлении прошивки: продолжительность обновления прошивки в секундах, размер бинаря, битовая скорость обновления. Эти метрики и будут являться критериями эффективности процесса обновления прошивки.
26--Программа FW_Loader должна поддерживать по меньшей мере два протокола передачи данных. Бинарный протокол для крохотных загрузчиков размером 8kByte....32kByte ROM. И текстовый CLI-образный протокол для больших полноценных загрузчиков.
27--В случае с ARM Cortex-M процессорами Loader должен проверять массив векторов прерываний и указатель на верхушку стека. Если там валидные значения, то позволять записывать. Если не валидные то блокировать запить. Всё равно такая прошивка зависнет.
К сожалению в RISC-V всё по-другому и там, глядя на бинарь, не к чему прицепиться.
28--Программа FW_Loader должна быть собрана на языке программирования Си. Это позволит пере использовать исходный код (парсинг hex файла, бинарный протокол, CLI) между прошивкой и PC программой для FW_Loader. Дело в том, что утилиту Loader, как привило пишет тот же программист, что и программирует сам микроконтроллер. А так, как сам загрузчик написан на Си, поэтому есть резон и приложение писать тоже на Си.
Желательные технические требования
1--Желательно, чтобы программа FW_Loader была так же собрана для OS Linux. В современных реалиях Linuх более приоритетная ОС для утилит.
2--Желательно сделать аргументы командной строки именованными (то есть с ключом префиксом), а не позиционными. Это позволит передавать аргументы в любой последовательности.
3--Желательно, чтобы фрагменты прошивки передавались в зашифрованном виде. Шифрование особенно нужно только если обновление по сети происходит, и есть вероятность перехвата трафика.
4--В CLI режиме желательно, чтобы фрагменты прошивки передавались в сжатом виде. Хотя бы в кодировке BASE64. Это позволит сократить продолжительность процесса обновления прошивки на 15%..25%. Посмотрите сами. Записи на BASE64 занимают меньше или равно символов. Я имею в виду, что hex - текстовый. То есть BASE16. Один байт кодируется двумя символами. 4 бита кодируются одним символом. В BASE64 же 6 битов кодируются одним символом. Вот и получается сжатие на 33%.
BASE64 len | BASE64 | hex=BASE16 | hex len |
8 | AAAAAAA= | 0000000000 | 10 |
8 | /////w== | FFFFFFFF | 8 |
12 | DJ4MdKaHIe4= | 0c9e0c74a68721ee | 16 |
5--Желательно, чтобы FW_Loader могла проверять нынешнюю версию загруженной прошивки. Дело в том, что в автоматических DevOps процессах нет смысла обновлять новую версию прошивки на старую версию. Утилита должна хотя бы выдавать предупреждение, что возникла такая ситуация.
Механизм обновления
В самом классическом виде обновление прошивки происходит через последовательный виртуальный COM порт благодаря микросхемам-переходникам с USB на UART (CP2102) на максимально возможной битовой скорости 921600 бит/c. Параметры кадра: два стоповых бита, нет проверки четности, один кадр - 8 бит.
Перед обновлением необходимо проверить link, проверить нынешнюю версию прошивки, отправить пакет стирания содержимого микросхемы. Далее записывать области памяти и проверять, что фактически данные тоже прописались.
В конце отправить микроконтроллеру команду прыгнуть по начальному адресу и исполнять прописанное приложение.
Кода вообще не нужен Loader?
Вы удивитесь, но на самом деле утилита даже Loader не нужна, если
1--к микроконтроллеру подключена SD карта. В этом случае Вы можете монтировать SD карту к LapTop, скопировать *.hex. Затем запустить в прошивке SPI, FatFs, читать прошивку и записать ее в on-chip Flash прямо загрузчиком. Именно так и происходит обновление прошивки на портативных диктофонах.
2--В UART-bootloader имеет смысл делать реализацию стандартных протоколов типа xModem, тогда и клиентской утилиты не потребуется. Некоторые терминалы поддерживают протокол xModem.
Итог
Вот такие базовые атрибуты для утилиты Loader мне удалось выделить. Разумеется тема обновления прошивки намного шире. Загрузчик это не только ещё одна прошивка в репозитории. Для загрузчика нужна полноценная инфраструктура и экосистема. В самом простом виде это консольное Win приложение (FW Loader) под PC для отправки прошивки по serial COM порту. А для искушенного пользователя надо ещё сделать FW Loader c GUI-интерфейсом, потом загрузку из браузера Chrome/Opera/FireFox. Причем надо всё сделать под три-четыре операционки: Windows, Linux, Mac. Также нужно мобильное приложение для отправки прошивки из-под Android и iOS. И ещё нужен Web-сервер с авторизацией для поиска на земном шарике всех не обновлённых электронных зубных щеток и раскатывания новых обновлений FW на смартфоны их владельцев. Поэтому загрузчики и Loader-ы это на самом деле очень-очень много работы.
Если есть, что добавить, то пишите в комментариях.
Словарь
Акроним | Расшифровка |
FW | FirmWare |
OS | Operation System |
ТЗ | Техническое задание |
DFU | device firmware update |
UART | universal asynchronous receiver-transmitter |
CRC | Cyclic redundancy check |
Ссылки
# | Ссылка | URL |
1 | Intel HEX: описание формата файла | https://microsin.net/programming/pc/intel-hex-file-format.html |
2 | Как собрать Си программу в OS Windows | |
3 | Атрибуты Хорошего Канального Протокола Передачи Данных | |
4 | Атрибуты Хорошего Загрузчика | |
5 | Работа с последовательным портом в windows и linux | |
6 | COM-порт в Windows (программирование) | https://ru.wikibooks.org/wiki/COM-порт_в_Windows_(программирование) |
7 | OpenBLT | |
8 | hex-to-base64 |