4、烧录文件格式:Hex、S19、Bin、ELF 格式详解

做量产烧录这么多年,我见过太多工程师在文件格式上栽跟头了。有人拿着 ELF 文件直接往烧录器里塞,结果烧进去跑不起来;有人把 Hex 和 Bin 混为一谈,校验和怎么都对不上。说白了,选错格式,后面所有流程都是白搭。

今天咱们就把这四种格式彻底聊透。你搞清楚它们的区别,量产时就能少踩一半的坑。

4.1 四种格式的核心差异

先看一张总览表,心里有个底:

格式 全称 包含信息 是否可执行 量产常用度
Hex Intel HEX 地址 + 数据 + 校验和 否 ★★★★★
S19 Motorola S-record 地址 + 数据 + 校验和 否 ★★★★☆
Bin Binary 纯二进制数据 否 ★★★★★
ELF Executable and Linkable Format 代码 + 数据 + 符号表 + 调试信息 + 重定位表 是 ★☆☆☆☆

关键认知:量产烧录只看 地址 + 数据 + 校验。ELF 里那些符号表、调试信息,烧录器根本用不上,反而容易出问题。

4.2 Intel HEX 格式详解

Hex 是我个人最推荐的量产格式。它用 ASCII 文本表示二进制数据,每行都带地址和校验和,传输过程中出错了能及时发现。

一行典型的 Hex 记录长这样:

:10000000 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF F0
| |       |_______________________________________________|  |
| |       数据区(16字节)                                    |
| 记录类型(00=数据)                                          |
起始码                                                        校验和

Hex 有几种记录类型,量产时最常用的是:

  • 00 — 数据记录,烧录的主体
  • 01 — 文件结束记录,告诉烧录器「到此为止」
  • 04 — 扩展线性地址记录,处理 32 位地址时必用
  • 05 — 启动地址记录,有些 MCU 需要它指定入口

我的经验:有一次客户给的 Hex 文件缺少 04 记录,烧录器默认从 0x0000 开始写,结果程序跑飞了。后来我养成了习惯——量产前先用工具检查 Hex 文件头,确保扩展地址记录完整。

4.3 Motorola S-record (S19) 格式

S19 和 Hex 本质上是同一类东西,都是文本格式、带地址、带校验。区别在于行首标识和校验算法。

S19 的行结构:

S1 13 0000 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF F0 7E
| |  |   |_______________________________________________|  |
| |  地址长度(19字节)                                        |
| 记录类型(S1=16位地址数据)                                   |
记录类型标识                                                  校验和

S19 的常见记录类型:

  • S0 — 文件头,通常包含文件名或注释
  • S1 — 16 位地址数据记录
  • S2 — 24 位地址数据记录
  • S3 — 32 位地址数据记录
  • S5 — 记录计数
  • S7/S8/S9 — 结束记录

我个人的习惯是:用 NXP/Freescale 的芯片时优先选 S19,因为他们的工具链对 S19 支持最好。用 ST/Infineon 的芯片,Hex 更通用。

4.4 Binary (Bin) 格式

Bin 格式最简单,也最「暴力」。它没有地址信息,没有校验和,就是纯粹的二进制数据流。

举个例子:如果你要烧录 64KB 的 Flash,Bin 文件就是 65536 个字节,从 0x0000 到 0xFFFF 依次排列。烧录器必须知道起始地址,否则数据全错位。

注意:Bin 文件不包含地址信息,所以量产时一定要在烧录工具里手动指定起始地址。我见过有人把 Bin 烧到 0x08000000 的 STM32 上,结果忘记改地址,程序直接写到了 0x00000000 的系统区——板子直接变砖。

Bin 格式的优势在于:

  • 文件体积最小,传输快
  • 解析简单,烧录器处理速度最快
  • 适合大容量 Flash 的批量烧录

缺点是:一旦数据中间有空洞(比如地址不连续),Bin 文件会变得很大,因为空洞也要用 0xFF 填充。

4.5 ELF 格式——为什么量产不用它?

ELF 是编译器直接输出的格式,包含的信息非常丰富:

  • 代码段(.text)
  • 数据段(.data、.bss)
  • 符号表(函数名、变量名)
  • 调试信息(DWARF)
  • 重定位表

听起来很强大对吧?但量产烧录时,这些信息反而是累赘。

原因有三:

  1. 烧录器只认地址和数据,ELF 里的符号表、调试信息它看不懂
  2. ELF 文件可能包含多个段,烧录器需要解析段表,容易出错
  3. 安全风险——ELF 暴露了函数名和变量名,别人拿到文件就能逆向你的代码结构

我的建议:开发阶段用 ELF 调试没问题。但到了量产环节,一定要把 ELF 转换成 Hex 或 Bin。这是量产安全的第一道防线。

4.6 如何选择正确的格式?

这个问题没有标准答案,但我可以给你一套决策逻辑:

量产烧录格式选择决策流程 量产烧录格式选择决策流程 开始选择格式 烧录器/芯片支持 Hex 吗? 是 否 推荐使用 Hex 格式 带地址+校验,通用性强 支持 S19 格式吗? 是 否 推荐使用 S19 格式 NXP/Freescale 芯片首选 只能用 Bin 格式 必须手动指定起始地址 最终建议:优先 Hex → S19 → Bin 量产前务必做格式验证和校验 提示:ELF 格式仅用于开发调试,量产前必须转换为 Hex/S19/Bin

简单总结一下我的选择原则:

  • Hex — 通用性最强,90% 的烧录器和芯片都支持
  • S19 — NXP/Freescale 生态首选,地址范围更灵活
  • Bin — 追求速度或芯片只支持裸数据时用,但要小心地址
  • ELF — 量产时别碰,除非你清楚自己在做什么

4.7 格式转换工具

实际项目中,我们经常需要在不同格式之间来回转换。下面是我常用的工具:

工具 支持转换 平台 我的评价
objcopy (GNU) ELF ↔ Hex/S19/Bin Linux/Windows 最强大,量产脚本首选
srec_cat Hex ↔ S19 ↔ Bin 跨平台 格式转换瑞士军刀
J-Flash ELF/Hex/S19/Bin 互转 Windows 图形界面,适合调试
STM32CubeProgrammer ELF → Hex/Bin Windows/Linux ST 芯片专用,稳定

我最常用的是 objcopy,因为它可以集成到自动化脚本里。举个例子:

# ELF 转 Hex(保留地址信息)
arm-none-eabi-objcopy -O ihex firmware.elf firmware.hex

# ELF 转 Bin(纯二进制,需指定起始地址)
arm-none-eabi-objcopy -O binary firmware.elf firmware.bin

# Hex 转 Bin
arm-none-eabi-objcopy -I ihex -O binary firmware.hex firmware.bin

小技巧:用 objcopy 转 Bin 时,默认从 0x0000 开始。如果你的芯片 Flash 起始地址不是 0x0000(比如 STM32 是 0x08000000),记得加 --change-addresses 参数调整偏移。

4.8 量产前的格式验证清单

每次量产前,我都会过一遍这个清单,确保格式没问题:

  1. 校验和验证 — Hex/S19 每行都有校验和,用工具重新算一遍,确认没被篡改
  2. 地址范围检查 — 确认文件里的地址没有超出芯片 Flash 范围
  3. 空洞检查 — 检查数据是否有不连续的空洞,避免烧录器解析出错
  4. 文件完整性 — 确认文件有正确的结束记录(Hex 的 :00000001FF,S19 的 S7/S8/S9)
  5. 烧录后回读比对 — 烧完读出来和原始文件做 CRC 比对,这是最终防线

我曾经踩过的坑:有一次量产 5000 片,Hex 文件在传输过程中被截断了最后一行(结束记录)。烧录器没报错,但烧出来的芯片上电后随机死机。从那以后,我强制要求所有 Hex 文件在烧录前必须通过校验和验证,少一行都不行。

嗯,格式这块就聊到这儿。你只要记住:量产用 Hex,调试用 ELF,Bin 要小心,S19 看平台。下次咱们聊烧录协议和通信接口,那又是另一片天地了。