
" Все интерфейсы и протоколы только и нужны, чтобы сделать 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 |
Комментарии (24)
VO_Obsidian
13.05.2025 20:24Не совсем понятно для кого эти требования подходят. В большинстве случаев удобнее всего сделать обёртку над фирменными утилитами, например STM32CubeProgrammerCLI или esptool. Ну и тут уже половина требований можно считать выполненными, т.к. они реализованы в них.
grand1987
13.05.2025 20:246--Программа FW_Loader должна быть собрана на языке программирования Си.
Питон + pyinstaller / bincopy / serial и argparse решают задачу. Если надо добавь шифрование, также решается добавлением библиотеки. Также питон однопоточный.
aabzel Автор
13.05.2025 20:24Я же написал почему на Си. Потому что прошивка пишется на Си. Протокол одинаковый. Значит 70 % исходников общие.
Ну сами подумайте, кто программирует микроконтроллеры на python?
Я понимаю, что Вам хочется за счёт embedded компании выучить python , а потом пойти на python сайты программировать. Успехов!
aabzel Автор
13.05.2025 20:24Я понимаю . У Вас IDE IAR не может exe скомпилировать. Вот и приходится менять язык для desktop разработки.
VelocidadAbsurda
13.05.2025 20:24Поддержу, не вижу особого смысла писать такого рода утилиты на С. Python проще, а главное, оброс массой простых в использовании библиотек на все случаи жизни. Просто приведу примеры: у нас в ходу загрузчики, общающиеся через целый зоопарк интерфейсов: UART, USB, BLE, CAN, UDS-DoIP-Ethernet. Для всех этих интерфейсов нашлись достаточно удобные кросс-платформенные Python библиотеки, благодаря которым написание загрузчиков ощущалось как отдых от основной деятельности, какой-нибудь CAN на приём поднялся вообще тремя строчками итд. Сколько времени/сил отняло бы завести сами эти интерфейсы под две ОС на С даже думать не хочется, невозможность переиспользовать Сшную реализацию своих протоколов - мелочи в сравнении с этим. А уж со всякой «косметикой» вроде именованных параметров командной строки, которые автор статьи аж в отдельный пункт TODO вынес, или разноцветным выводом в консоль, на Python вопросов вообще не возникает.
В embedded вообще хватает хардкора, так пусть он будет только там, где оправдан. Поверхностные знания Python, которых хватит для написания подобного рода утилит, достаются довольно «дёшево».
Indemsys
13.05.2025 20:24Я даже больше скажу.
Вот прямо сейчас я сделал на Python загрузчик. Буквально за пять минут и через две итерации:Он реально работает!
Только что проверил на своем дивайсе. Конвертирует HEX в бинарник и загружает через FTP сервер реализованый в моем модуле.
А вот весь текст скрипта:Скрытый текст
import os import ftplib import tempfile import sys from intelhex import IntelHex import wx def convert_hex_to_bin(hex_path, bin_path): """ Convert Intel HEX file to a binary file using IntelHex library. """ ih = IntelHex() ih.loadhex(hex_path) # Write binary file; fill gaps with 0xFF # The tobinfile signature is (filename, start=None, end=None, pad=0xFF) ih.tobinfile(bin_path, pad=0xFF) class FTPUploaderFrame(wx.Frame): def __init__(self, parent=None, title="FTP HEX->BIN Uploader"): super().__init__(parent, title=title, size=(500, 400)) panel = wx.Panel(self) vbox = wx.BoxSizer(wx.VERTICAL) # FTP Connection gb_conn = wx.StaticBox(panel, label="FTP Connection") sbs_conn = wx.StaticBoxSizer(gb_conn, wx.VERTICAL) fgs = wx.FlexGridSizer(4, 2, 10, 10) fgs.AddGrowableCol(1, 1) fgs.Add(wx.StaticText(panel, label="Host:"), 0, wx.ALIGN_CENTER_VERTICAL) self.host_txt = wx.TextCtrl(panel, value="192.168.16.137") fgs.Add(self.host_txt, 1, wx.EXPAND) fgs.Add(wx.StaticText(panel, label="Port:"), 0, wx.ALIGN_CENTER_VERTICAL) self.port_txt = wx.TextCtrl(panel, value="21") fgs.Add(self.port_txt, 1, wx.EXPAND) fgs.Add(wx.StaticText(panel, label="Username:"), 0, wx.ALIGN_CENTER_VERTICAL) self.user_txt = wx.TextCtrl(panel, value="ftp_login") fgs.Add(self.user_txt, 1, wx.EXPAND) fgs.Add(wx.StaticText(panel, label="Password:"), 0, wx.ALIGN_CENTER_VERTICAL) self.pass_txt = wx.TextCtrl(panel, value="pass", style=wx.TE_PASSWORD) fgs.Add(self.pass_txt, 1, wx.EXPAND) sbs_conn.Add(fgs, 1, wx.ALL|wx.EXPAND, 10) vbox.Add(sbs_conn, 0, wx.ALL|wx.EXPAND, 10) # HEX File Selection gb_file = wx.StaticBox(panel, label="HEX File") sbs_file = wx.StaticBoxSizer(gb_file, wx.HORIZONTAL) self.file_txt = wx.TextCtrl(panel, value="Test.hex", style=wx.TE_READONLY) file_btn = wx.Button(panel, label="Browse...") file_btn.Bind(wx.EVT_BUTTON, self.on_browse) sbs_file.Add(self.file_txt, 1, wx.ALL|wx.EXPAND, 5) sbs_file.Add(file_btn, 0, wx.ALL, 5) vbox.Add(sbs_file, 0, wx.LEFT|wx.RIGHT|wx.EXPAND, 10) # Progress Gauge self.gauge = wx.Gauge(panel, range=100, size=(450, 25)) vbox.Add(self.gauge, 0, wx.ALL|wx.CENTER, 10) # Upload Button upload_btn = wx.Button(panel, label="Convert & Upload") upload_btn.Bind(wx.EVT_BUTTON, self.on_upload) vbox.Add(upload_btn, 0, wx.ALL|wx.CENTER, 10) panel.SetSizer(vbox) self.Centre() def on_browse(self, event): with wx.FileDialog( self, "Select HEX file", wildcard="HEX files (*.hex)|*.hex|All files (*.*)|*.*", style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST ) as dlg: if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() self.file_txt.SetValue(path) def on_upload(self, event): host = self.host_txt.GetValue().strip() port_str = self.port_txt.GetValue().strip() username = self.user_txt.GetValue().strip() password = self.pass_txt.GetValue().strip() hex_path = self.file_txt.GetValue() if not host or not hex_path: wx.MessageBox( "Please specify both FTP host and HEX file.", "Error", wx.OK | wx.ICON_ERROR ) return try: port = int(port_str) except ValueError: wx.MessageBox( "Port must be a number.", "Error", wx.OK | wx.ICON_ERROR ) return bin_path = os.path.splitext(hex_path)[0] + ".bin" try: convert_hex_to_bin(hex_path, bin_path) except Exception as e: wx.MessageBox( f"Failed to convert HEX to binary:\n{e}", "Conversion Failed", wx.OK | wx.ICON_ERROR ) return try: filesize = os.path.getsize(bin_path) uploaded = 0 import time start_time = time.time() def callback(data): nonlocal uploaded uploaded += len(data) percent = int(uploaded / filesize * 100) wx.CallAfter(self.gauge.SetValue, percent) with ftplib.FTP() as ftp: ftp.connect(host, port) ftp.login(username, password) with open(bin_path, 'rb') as f: ftp.storbinary( f'STOR {os.path.basename(bin_path)}', f, blocksize=8192, callback=callback ) elapsed = time.time() - start_time speed = filesize / elapsed if elapsed > 0 else 0 # Show dialog with bytes and speed dlg = wx.MessageDialog( self, f"Uploaded {filesize} bytes in {elapsed:.2f} s\nSpeed: {speed:.1f} bytes/sec", "Upload Complete", wx.OK ) dlg.SetOKLabel("Close") dlg.ShowModal() dlg.Destroy() self.gauge.SetValue(0) except Exception as e: wx.MessageBox( f"FTP upload error:\n{e}", "Upload Failed", wx.OK | wx.ICON_ERROR ) return # Optionally cleanup # os.remove(bin_path) def main(): app = wx.App(False) frame = FTPUploaderFrame() frame.Show() app.MainLoop() # Unit tests for conversion import unittest class TestHexConversion(unittest.TestCase): def test_simple_conversion(self): # Create a minimal Intel HEX file with 2 lines of data (16 bytes each) content = ( ":020000040000FA\n" ":100000000C9423000C944E000C944E000C944E00A6\n" ":00000001FF\n" ) with tempfile.NamedTemporaryFile('w+', suffix='.hex', delete=False) as tmp_hex: tmp_hex.write(content) tmp_hex.flush() bin_path = tmp_hex.name.replace('.hex', '.bin') convert_hex_to_bin(tmp_hex.name, bin_path) self.assertTrue(os.path.exists(bin_path)) size = os.path.getsize(bin_path) # Expect 16 bytes of data self.assertEqual(size, 16) os.remove(bin_path) os.remove(tmp_hex.name) def test_conversion_with_empty_file(self): # Create an empty HEX file should result in 0-byte binary with tempfile.NamedTemporaryFile('w+', suffix='.hex', delete=False) as tmp_hex: tmp_hex.write("") tmp_hex.flush() bin_path = tmp_hex.name.replace('.hex', '.bin') convert_hex_to_bin(tmp_hex.name, bin_path) self.assertTrue(os.path.exists(bin_path)) size = os.path.getsize(bin_path) self.assertEqual(size, 0) os.remove(bin_path) os.remove(tmp_hex.name) if __name__ == "__main__": if len(sys.argv) > 1 and sys.argv[1] == '--test': unittest.main(module=__name__, argv=sys.argv[:1]) else: main()
Даже юнит-тест прикручен!
Тему с загрузчиками можно закрывать полностью
Indemsys
13.05.2025 20:24Десктоп утилиты для пршивки - плохая идея. Даже писать приложение для смартфона плохая идея. Придется заниматься их поддержкой и постоянным переносом на новые апгрейды OS и тестированием. Но не для того делают загрузчики чтобы получить головную боль.
Что важнее для инфраструктуры загрузчика - это кастомная упаковка, надежная шифрация и гибкость способов доставки.
Даже WEB интерфейс не лучший вариант. Лучше иметь просто открытый WEB API для загрузчика. А уж "морду" вам нарисует ChatGPT какую хотите и итегрирует в систему заказчика. Никаких артефактов производителя чипов не будет.
Вот в этом загрузчике доставка прошивки сделана даже по MQTT протоколу через любого MQTT брокера, даже самого примитивного. Это в добавок к FTP, HTTP, и просто USB Mass Storage Class, и в крайнем случае можно передать через SD карту с аппаратным паролем.
Решение с аргументами в командной строке утилиты тоже уже архаичное.
ИМХО, но лучшее решение - конфигурационный файл. Как в утилите упаковщика из проекта этого загрузчика.
Это гораздо мощнее и гибче.
А вот сам конфигурационный файл вы можете создавать хоть на Python хоть на Bash.
На это есть GitHub Copilot, который вам наваяет любых сборщиков конфигов за секунды.
Python и Bash знать при этом не нужно. Copilot пишет код на на них с первого раза и без ошибок. Потому что он умеет их сам компилировать, запускать и перепроверять.
old_merman
13.05.2025 20:24Десктоп утилиты для пршивки - плохая идея. Даже писать приложение для смартфона плохая идея.
+100
"Идеальный механизм – это механизм, которого нет, а функции его выполняются" (ТРИЗ)
slog2
13.05.2025 20:24В программируемом девайсе должен быть USB-COM который в windows не требует специальных драйверов, а лоадер должен сам находить номер порта куда подключен программируемый девайс. В этом основной затык у не очень продвинутых юзеров.
Как вариант в windows девайс обнаруживается как внешний диск, на который надо просто скопировать файл прошивки, без всяких специальных лоадеров. Но это для жирных процессоров.
Indemsys
13.05.2025 20:24Почти все популярные фреймворки для микроконтроллеров на сегодня имеют RNDIS.
Windows 11 подхватывает RNDIS также без всяких бубнов с драйверами.
Но при этом имеет и загрузку через FTP более чем удобную и стандартную, и тот же терминал что и через COM порт, и сам порт искать не надо, и еще с десяток сервисов.
А с USB-COM вы определенно лишаете себя кучи удовольствий.
aabzel Автор
13.05.2025 20:24Не часто прочитаешь слово "фреймворк" и "микроконтроллер "в одном предложении.
Что такое RNDIS?
ailcat
13.05.2025 20:24Оченно грубо: проприетарный фетиш мелкомягких, когда USB-устройство подключается как Ethernet-девайс (например, как FTP-сервер).
Оченно недобро: на слабом МК - отличнейший способ превратить скучный процесс обновления в интереснейшее приключение с заранее неизвестным результатом.
pvvv
13.05.2025 20:24Но зачем?
Если используется usb, со стороны МК в бутлоадере прикинуться mass storage'м и со стороны ПК тупо скопировать туда файл прошивки без каких-либо дополнительных утилит.
aabzel Автор
13.05.2025 20:24Да. Либо на sd карту, подключенную к spi прописывать hex.
pvvv
13.05.2025 20:24Какая
блохаSD? КакойзаяцSPI? Почему HEX?Насколько знаю никто текстовый формат непосредственно в железку передавать не будет. Не исключаю что всегда возможно найдутся альтернативно одарённые, но если посмотреть на встроенные бутромы различных МК все обычно городят свой примитивный протокол (бинарный!) с указанием адреса/размера и контрольной суммы куда что писать во внутреннюю (и не очень) память.
Есть даже некие попытки как-то стандартизовать это, например, мелкомягкий .UF2 (в rp2040)
А весь описанный функционал можно спокойно перенести внутрь МК, а со стороны ПК "идеальным loaderом" становится консольная команда copy.
yappari
13.05.2025 20:24Желательно, чтобы фрагменты прошивки передавались в сжатом виде. Хотя бы в кодировке BASE64
Интересно, с каких это пор бейз64 вдруг стал "сжатым" видом.
aabzel Автор
13.05.2025 20:24Хороший вопрос. Посмотрите сами
https://cryptii.com/pipes/hex-to-base64В пределе, по мере увеличения длинны массива записи на BASE64 занимают меньше символов
0000000000 (10)
AAAAAAA= (8)FFFFFFFF
/////w==0c9e0c74a68721ee (16)
DJ4MdKaHIe4= (12)Вот и получается, что BASE64 - это такое паллиативное сжатие.
ailcat
13.05.2025 20:24Простите, что?
BASE64 как раз таки УВЕЛИЧИВАЕТ объем передаваемых данных - вместо 3 байт бинарника получается 4 байта транспортного протокола.
Ибо передавать в слабенький МК с ограниченной RAM что-то, отличное от бинарника - это как вёдрами носить бетон на стройке небоскреба (уж пардон за ассоциацию). Все иные форматы должны конвертироваться в *.bin самим FW_Loader, и только потом загружаться в МК.P.S.
Но само использование BASE64 я поддерживаю на 146%.
Ибо этот протокол заведомо пролазит через любые настройки и аппаратные реализации COM-портов, включая удаленные соединения через Modbus/ASCII, конвертеры Ethernet/COM с кривой поддержкой Xon/Xoff и 7-битные радиомодемы. То есть, благодаря ему можно создавать загрузчик(и) через любую среду передачи от "большого" компа, имея один коротенький бутлоадер в МК.aabzel Автор
13.05.2025 20:24Я имею в виду, что hex - текстовый. То есть BASE16. Один байт кодируется двумя символами. 4 бита кодируются одним символом.
В BASE64 же 6 битов кодируются одним символом.Вот и получается сжатие на 33%.
yappari
13.05.2025 20:24О, да. А если в текстовый файл писать бинарное, а не шестнадцатеричное представление, то сжатие окажется ещё в 4 раза выше! Крутота!
Вообще, если скармливается именно контроллеру и именно гекс, и при этом надо его ужимать для скорости, это почти наверняка говорит о том, что формат выбран неверно (нужно разве что для чего-то из экзотики/антиквариата, как упомянуто выше). А для утилиты, отсылающей прошивку в девайс, пофиг, сжат гекс или нет. Скорости ощутимо не добавится.
aabzel Автор
13.05.2025 20:24Удивительно, что никто не написал, что в утилите FW_Loader должен быть progress bar. Индикатор прогресса.
Чтобы оператор мог непрерывно оценивать сколько ему еще ждать окончания обновления прошивки. Нет ничего мучительнее, чем неизвестность.
Только сейчас про него вспомнил.
4chemist
Тут идут слова благодарности конторе Espressif с ее серией микроконтроллеров с Wi-Fi. Никогда еще не было так легко обновить прошивку по воздуху. Никаких проводов, разъемов, гальванических развязок, USB-to-serial переходников, настроек скорости последовательного порта, командировок. Даже софта FW_loader не надо! В вебморде выбрал прошивку с рабочего стола ноутбука, из теплого офиса с удобным креслом за тысячу километров от железки, и, с чувством достоинства, нажал кнопку "Загрузить". Поработал и получил денег кучу.