Файлы прошивки чаще всего приходят в одном из двух текстовых форматов. Intel HEX придумала Intel для программаторов ПЗУ. Его выдаёт утилита objcopy из GNU Binutils — avr-objcopy в Arduino IDE, arm-none-eabi-objcopy в STM32CubeIDE, — а также Keil и IAR; читают его avrdude, STM32CubeProgrammer и почти любой программатор. Motorola S-record (файлы .s19, .s28, .s37, .srec, .mot) — формат Motorola, привычный для микроконтроллеров NXP и Renesas. Оба описывают одно и то же: какие байты по каким адресам записать. Третий вариант — двоичный образ .bin без адресов и проверок.
Как пользоваться
- Вставьте текст файла в поле, откройте файл кнопкой или перетащите его на панель. Кнопки примеров подставят прошивку AVR, начало образа STM32, тот же код в S-record и файл с ошибками.
- Под панелью появятся ошибки и замечания, таблица записей с раскрашенными полями, карта памяти и hex-дамп.
- Для файла .bin задайте адрес, с которого он пишется в память: у STM32 это 08000000.
- Чтобы сравнить прошивку с объёмом памяти, выберите плату или микроконтроллер.
- В блоке «Преобразовать и скачать» выберите формат и скачайте файл. Если в файле неверные контрольные суммы, в блоке ошибок появится кнопка их исправления.
Как устроена запись Intel HEX
Каждая строка — одна запись. Она начинается с двоеточия, дальше идут байты, записанные парами шестнадцатеричных цифр, старшая цифра первой:
| Поле | Символов | Что содержит |
|---|---|---|
| Начало | 1 | двоеточие «:» |
| Длина | 2 | число байтов в поле данных, от 00 до FF |
| Адрес | 4 | 16-битное смещение первого байта данных, старший байт первым |
| Тип | 2 | что это за запись, от 00 до 05 |
| Данные | 2 на байт | данные или параметры записи |
| Контрольная сумма | 2 | дополнение суммы предыдущих байтов до нуля |
Типов записей шесть:
| Тип | Название | Данные | Что делает |
|---|---|---|---|
| 00 | данные | байты прошивки | кладёт байты с адреса базы + смещение |
| 01 | конец файла | нет | завершает файл, всегда :00000001FF |
| 02 | расширенный адрес сегмента | 2 байта | база = значение × 16, адреса до 0x10FFEF — чуть больше 1 МБ |
| 03 | стартовый адрес CS:IP | 4 байта | точка входа для 8086 |
| 04 | расширенный линейный адрес | 2 байта | старшие 16 бит адреса, до 4 ГБ |
| 05 | стартовый линейный адрес | 4 байта | точка входа, 32 бита |
Поле адреса в записях 01–05 не используется и заполняется нулями. Записи 03 и 05 программатору не нужны — он пишет только данные, — но objcopy переносит в них точку входа из ELF-файла: в HEX загрузчика Arduino есть запись 03 с адресом 0000:7E00, а в прошивке STM32 запись 05 указывает на обработчик сброса.
Контрольная сумма: пример вручную
Возьмём вторую строку примера AVR: :08001000D9F72A95C1F7F5CFDD.
| Поле | Байты | Сумма нарастающим итогом |
|---|---|---|
| Длина | 08 | 08 |
| Адрес | 00 10 | 18 |
| Тип | 00 | 18 |
| Данные | D9 F7 2A 95 C1 F7 F5 CF | 623 |
Младший байт суммы — 23. Контрольная сумма — его дополнение до 100: 100 − 23 = DD, как и записано в конце строки. Проверяют наоборот: сумма всех байтов записи вместе с контрольной должна оканчиваться на 00 — 623 + DD = 700. Восемь байтов данных начинаются с адреса 0010, значит, запись занимает 0010–0017.
Контрольная сумма ловит одиночную испорченную цифру, но не перестановку байтов и не потерю целой строки. Запись конца файла выдаёт только обрыв в конце, а пропавшую строку в середине покажет лишь CRC образа, если есть эталонное значение — например, опубликованное вместе с прошивкой.
Адрес: 16 бит, сегменты и линейная база
Поле адреса в записи данных — всего 16 бит. Файл без записей 02 и 04 описывает первые 64 КБ: этого хватает ATmega328P с его 32 КБ флеш-памяти. Для больших адресов перед записями данных ставят запись базы:
Здесь i — номер байта в записи. База действует, пока её не сменит следующая запись 02 или 04. Примеры:
| Запись базы | Смещение | Адрес байта | Где встречается |
|---|---|---|---|
:020000021200EA | 2462 | 0x00014462 | пример Keil |
:020000023000CC | E000 | 0x0003E000 | загрузчик Arduino Mega 2560 |
:02000004FFFFFC | 2462 | 0xFFFF2462 | пример Keil |
:020000040800F2 | 0000 | 0x08000000 | начало флеш-памяти STM32 |
Записи различаются переносом. После записи 02 смещение заворачивается внутри 64-килобайтного сегмента: байт за FFFF ложится в начало того же сегмента. После записи 04 адрес просто продолжается и заворачивается только за FFFFFFFF. GNU objcopy таких записей не создаёт — он обрывает запись на границе 64 КБ и ставит новую базу: ниже 1 МБ — записью 02, выше — записью 04. Если в одном файле встречаются и 02, и 04, objcopy при чтении складывает обе базы; так же считает пример в документе Intel о формате HEX-32. Инструмент делает так же и предупреждает: другие программы могут взять только последнюю базу.
Формат Motorola S-record
S-запись начинается с буквы S и цифры типа, за ними пары шестнадцатеричных цифр:
| Поле | Символов | Что содержит |
|---|---|---|
| Тип | 2 | S0…S9 |
| Длина | 2 | число байтов после этого поля: адрес, данные и контрольная сумма |
| Адрес | 4, 6 или 8 | 16, 24 или 32 бита, по типу записи |
| Данные | 2 на байт | данные или текст заголовка |
| Контрольная сумма | 2 | дополнение до единицы младшего байта суммы длины, адреса и данных |
| Тип | Адрес | Назначение |
|---|---|---|
| S0 | 16 бит, обычно 0000 | заголовок: имя модуля или любой текст, например «HDR» |
| S1, S2, S3 | 16, 24, 32 бита | данные |
| S5, S6 | 16, 24 бита | число записей S1–S3 перед ней, необязательная; S6 — позднее расширение |
| S7, S8, S9 | 32, 24, 16 бит | конец блока S3, S2, S1 и стартовый адрес |
Главное отличие от Intel HEX — адрес полной длины прямо в каждой записи данных и другое правило контрольной суммы: не дополнение до нуля, а инверсия младшего байта суммы. Для S9030000FC сумма 03 + 00 + 00 = 03, а FF − 03 = FC. Отличие в длине: поле длины в S-записи считает и адрес с контрольной суммой, а в Intel HEX — только данные. Завершающая запись S7 по описанию Motorola закрывает блок S3, S8 — блок S2, S9 — блок S1, но S7 и S8 нужны, только когда стартовому адресу не хватает двух байтов; иначе любой блок закрывают записью S9. Поэтому S9 после S3 законна, а S7 после S1 инструмент лишь отмечает как необычную. Запись S4 не определена.
Карта памяти, дамп и двоичный образ
Записи не обязаны идти по порядку и подряд. Инструмент собирает их в непрерывные диапазоны. Между диапазонами остаются промежутки: в hex-дампе и в файле .bin они заполняются байтом FF — так выглядит стёртая флеш-память. Байт заполнения можно сменить, например на 00 для образа ПЗУ.
Если две записи пишут в один адрес, в образ попадает более поздняя — так поступит программатор, записывая строки по очереди. Перекрытие с разными байтами — ошибка: обычно это два HEX-файла, склеенные вручную, или прошивка, наложенная на загрузчик по неверному адресу. Перекрытие с одинаковыми байтами безвредно, но тоже отмечается.
CRC-32 и суммы байтов считаются по тому же образу, что лёг бы в файл .bin: от первого адреса с данными до последнего, с заполнением промежутков. Это CRC-32 в варианте ZIP (CRC-32/ISO-HDLC) — та же, что у архиватора zip и функции zlib.crc32 в Python; команда POSIX cksum по умолчанию считает другой CRC. Другой алгоритм или диапазон — например, блок CRC микроконтроллера — подберите в калькуляторе CRC.
При переводе в Intel HEX инструмент пишет файл так же, как GNU objcopy: по 16 байт в записи (можно 32), строки CRLF, база ниже 1 МБ — записью 02, выше — записью 04, стартовый адрес сохраняется. Загрузчики Arduino optiboot и stk500v2 из ArduinoCore-avr после разбора и обратной записи совпадают с исходными файлами байт в байт. S-записи получают тип по наибольшему адресу данных и стартовому адресу: S1 до FFFF, S2 до FFFFFF, S3 выше. Заголовок S0 исходного S-record переносится байт в байт; при переводе из HEX или BIN в него пишется имя файла, если оно латиницей, иначе «HDR».
Размер прошивки и объём флеш-памяти
Размер прошивки — число байтов с данными, без промежутков и без повторов при перекрытии. Arduino IDE после компиляции сообщает ту же величину: сумму секций .text и .data, которые попадают в HEX; EEPROM уходит в отдельный файл .eep.
Сравнивать её надо не со всем объёмом флеш-памяти, а с доступным: загрузчик занимает её конец. По boards.txt ядра Arduino AVR скетчу на Arduino Uno доступно 32 256 байт из 32 768 (512 байт у optiboot), на Nano — 30 720 (под загрузчик отведено 2 КБ), на Mega 2560 — 253 952 из 262 144. Выберите плату в списке — инструмент покажет процент, как Arduino IDE, и предупредит, если данные залезают в область загрузчика или за пределы памяти. Объёмы памяти микроконтроллеров в том же списке взяты из данных атласа: описаний устройств Microchip для ATmega328P, ATmega8, ATtiny85 и ATtiny13A и базы STM32CubeMX для STM32F103C8, STM32F401CC и STM32F411CE. Файл «with_bootloader» из Arduino IDE и сам загрузчик лежат там законно. Подробнее о загрузчиках — в глоссарии, о прошивке без них — на странице avrdude.
Для STM32 важен ещё и адрес: флеш-память начинается с 0x08000000. Если в файле нет записи 04 и данные начинаются с нуля, программатор либо откажется писать, либо запишет их в другое место. Как устроены флеш-память, загрузчик и защита STM32 — на странице о флеш-памяти STM32.
Типичные ошибки
- Неверная контрольная сумма. Строку правили вручную или файл испортился при передаче. Инструмент покажет записанную и верную сумму и, если длина записи совпадает с числом байтов, исправит её. Если не совпадает и длина — байты потеряны, и новая сумма лишь скроет это.
- Нет записи конца файла. Файл оборвался при копировании или склеивании. Часть программаторов отказывается от такого файла, часть молча пишет неполную прошивку.
- Записи после конца файла. Обычно это два файла, склеенные без удаления строки
:00000001FFв конце первого. Программаторы обычно читают только первый. - Перекрывающиеся записи. Две части прошивки претендуют на один адрес. Чаще всего это прошивка, собранная для другого начального адреса, или повторно вставленный кусок.
- 16-битный адрес вместо 32-битного. Прошивка STM32 без записи 04 окажется по адресу 0x00000000 вместо 0x08000000. Запись 04 в файле для AVR сама по себе не ошибка: если не исключить секции .eeprom, .fuse и .signature ключами
-R, avr-objcopy кладёт их в HEX по адресам 0x810000 и выше, а прошивка ATmega2560 выходит за 64 КБ, и некоторые программы адресуют её записью 04 вместо 02. Насторожить должен диапазон, которого у выбранного микроконтроллера нет: его покажут карта памяти и сравнение с объёмом флеш-памяти. - Строчные буквы и пустые строки. Спецификация пишет цифры заглавными, но большинство программ понимает и строчные; пустые строки пропускаются. Инструмент отмечает это как замечание, не как ошибку.
Конфиденциальность
Файл читается и разбирается в браузере, на сервер ничего не передаётся, а в адресе страницы сохраняются только настройки — байт заполнения, адрес .bin, выбранная плата, формат вывода и число байтов в записи.
Частые вопросы
Как узнать размер прошивки по HEX-файлу?
Не по размеру файла. В Intel HEX каждый байт записан двумя символами, а у строки есть ещё двоеточие, длина, адрес, тип, контрольная сумма и перевод строки: строка с 16 байтами данных занимает 45 символов, и файл в 2,8 раза больше прошивки. Размер прошивки — сумма длин записей данных без перекрытий. Инструмент показывает её первой строкой результата; для скетча Arduino это то же число, что пишет Arduino IDE после компиляции, — сумма секций .text и .data.
Чем HEX отличается от BIN?
BIN — точная копия памяти без адресов: первый байт файла ложится по адресу, который указывают программатору, промежутки заполнены. HEX хранит адрес каждой записи и контрольные суммы, поэтому в одном файле могут быть несвязанные области — например, прошивка и загрузчик, — а повреждение строки заметно. Для STM32 BIN обычно пишут с адреса 0x08000000, для AVR — с нуля.
Как посчитать контрольную сумму строки Intel HEX?
Сложите все байты строки после двоеточия, кроме последнего: длину, два байта адреса, тип и данные. Возьмите младший байт суммы и вычтите его из 100 (в шестнадцатеричной записи). Для :0400000508000009 сумма 04 + 05 + 08 + 09 = 1A, а 100 − 1A = E6. Проверка обратная: сумма всех байтов вместе с контрольной должна оканчиваться на 00.
Что означает строка :020000040800F2?
Это запись типа 04 — расширенный линейный адрес. Её два байта данных 08 00 становятся старшими 16 битами адреса всех следующих записей данных: запись с адресом 0000 ляжет по 0x08000000, где у STM32 начинается флеш-память. Без такой записи файл адресует только первые 64 КБ.
Программатор пишет, что в HEX-файле ошибка контрольной суммы. Что делать?
Вставьте файл в инструмент — он покажет номер строки, сумму в файле и верную. Обычно строку испортили при ручной правке, копировании через буфер или пересылке. Если данные правили намеренно, кнопка «Исправить контрольные суммы» пересчитает их. Если вместе с суммой не сходится и поле длины — у записи потерялся или прибавился байт, — пересчитывать сумму нельзя: надо заново собрать или скачать прошивку.
Почему CRC-32 файла не совпадает с тем, что показывает программатор?
CRC зависит от того, какие байты в неё вошли. Здесь CRC-32 считается по образу от первого до последнего адреса с заполнением промежутков — как у файла .bin. Программатор может считать по всей флеш-памяти, с другим байтом заполнения или другим алгоритмом: блок CRC в STM32 по умолчанию даёт CRC-32/MPEG-2, а не «обычный» CRC-32 из ZIP. Совпадающий диапазон и алгоритм подберите в калькуляторе CRC.
Источники
- Intel. Hexadecimal Object File Format Specification, Revision A, 6 января 1988 — архивная копия официального файла Intel: поля записи, типы 00–05, правило контрольной суммы, адрес для записей 02 и 04 с переносом по модулю 64 КБ и 4 ГБ — эталоны тестов
- Intel. Data-File Conversion to INTEL HEX-32 Format (сервис Zapcode), 2000 — архивная копия документа с intel.com: пример сложения баз записей 04 и 02, адрес 0x010930F0; контрольные суммы в его примере напечатаны неверно — тест это проверяет
- Keil (Arm). Knowledgebase 1584: GENERAL: INTEL HEX FILE FORMAT — архивная копия: разобранная запись данных, адреса FFFF2462 и 00014462, запись 05, пример файла — эталоны тестов
- Motorola. M68000 Family Programmer's Reference Manual, 1992 (NXP M68000PRM), приложение C «S-Record Output Format» — поля S-записи, типы S0–S9, контрольная сумма как дополнение до единицы, пример модуля на с. C-3 — эталон тестов
- P. Miller. SRecord 1.65: srec_motorola(5) — записи-счётчики S5 и S6, пример файла с S5
- GNU Binutils 2.45: bfd/ihex.c и bfd/srec.c — как objcopy пишет Intel HEX: по 16 байт, CRLF, запись не пересекает границу 64 КБ, база ниже 1 МБ — записью 02, выше — 04; при чтении базы 02 и 04 складываются. S-записи: по 16 байт, тип S1/S2/S3 по адресам данных, в S0 — имя файла до 40 символов
- Arduino. ArduinoCore-avr, коммит 11b9130: загрузчики optiboot и stk500v2, boards.txt, platform.txt — HEX-файлы загрузчиков от avr-objcopy — эталоны тестов (обратная запись байт в байт); upload.maximum_size: Uno 32 256, Nano 30 720, Mega 2560 253 952 байт; размер скетча = .text + .data
- Microchip. ATmega Series Device Support (ATmega_DFP) 3.6.299 и ATtiny Series Device Support (ATtiny_DFP) 3.4.278, файлы описания устройств atdf — объём флеш-памяти ATmega328P, ATmega2560, ATmega8, ATtiny85 и ATtiny13A в списке для сравнения — из данных атласа GAW, собранных из этих паков
- STMicroelectronics. STM32_open_pin_data (база STM32CubeMX 6.18.0), коммит 7d1f151 — объём флеш-памяти STM32F103C8 (64 КБ), STM32F401CC (256 КБ) и STM32F411CE (512 КБ) — из данных атласа GAW
- STMicroelectronics. PM0075 Rev 2. STM32F10xxx Flash memory microcontrollers, programming manual — таблица 3: основная флеш-память STM32F1 начинается с адреса 0x0800 0000
Где пригодится
Встроить калькулятор на свой сайт
Скопируйте код и вставьте его в HTML страницы, статьи или вики. Виджет бесплатный, без рекламы, счётчиков и cookie. Условие одно — ссылка на GAW под рамкой остаётся на месте. Подробнее о виджетах
<iframe src="https://gaw.ru/embed/hex-dump/" title="Просмотр и проверка файлов прошивки Intel HEX, S-record и BIN" width="100%" height="640" style="border:1px solid #e3e5e9;border-radius:8px" loading="lazy" allow="clipboard-write"></iframe>
<p style="margin:6px 0 0;font-size:14px">Калькулятор: <a href="https://gaw.ru/tools/hex-dump/">Просмотр и проверка файлов прошивки Intel HEX, S-record и BIN</a> — GAW.ru</p>Автоподстройка высоты рамки
Если сайт разрешает скрипты, добавьте этот код один раз в любом месте страницы: рамка будет менять высоту вместе с результатом расчёта.
<script>window.addEventListener("message",function(e){if(e.origin!=="https://gaw.ru"||!e.data||e.data.type!=="gaw:embed-height")return;var f=document.querySelectorAll('iframe[src^="https://gaw.ru/embed/"]');for(var i=0;i<f.length;i++)if(f[i].contentWindow===e.source)f[i].style.height=e.data.height+"px"})</script>Обновлено .
Нашли ошибку в расчёте?