4. 量产烧录文件准备
在开发阶段,工程师通常直接在 IDE 中点击“Download”完成烧录,工具链会自动处理 ELF 文件中的段信息、加载地址和符号表。但进入量产环节后,烧录器(如 SEGGER Flasher、J-Link 配合生产脚本)面对的不再是调试会话,而是一个需要被反复、稳定、可校验地写入目标芯片的镜像文件。开发产物与量产镜像之间,存在一次关键的格式转换与地址整理工作。这一节要解决的核心问题是:IDE 输出的 hex、bin、elf、srec 各自是什么、量产该选哪一种、多个地址段如何合并成一份可用的烧录文件。
四种文件格式的本质区别
ELF(Executable and Linkable Format)是编译器与链接器的完整输出,它不只包含机器码,还包含节区(section)名称、符号表、调试信息、重定位记录。它的“可执行内容”分散在若干具有明确加载地址的段中,因此 ELF 本身携带地址信息,但体积大、结构复杂,量产烧录器一般不会直接把它当作最终镜像,而是把它作为转换的源头。
HEX(Intel HEX)与 SREC(Motorola S-record)都属于带地址的文本格式。它们把二进制数据按记录行组织,每行包含地址、数据长度、数据和校验和。区别在于:Intel HEX 用冒号“:”开头,记录类型字段区分数据记录、扩展线性地址记录、起始地址记录等;SREC 用“S”开头,S1/S2/S3 表示不同地址宽度的数据记录,S7/S8/S9 表示起始地址。两者都能表达不连续的多个地址段,适合烧录器解析。
BIN 是纯二进制镜像,只有数据字节,不携带任何地址信息。它的写入位置完全由烧录器配置的起始地址决定。因此 BIN 体积最小、解析最快,但一旦地址配置错误,数据就会整体偏移,且无法表达多个不连续段。
从 ELF 到量产镜像的转换链路
以 SEGGER 工具链为例,最常用的转换工具是 objcopy(GNU 工具链自带)以及 SEGGER 提供的 JLinkExe 配合脚本、JFlash 的工程导出功能。典型转换命令如下:
# ELF 转 Intel HEX
arm-none-eabi-objcopy -O ihex firmware.elf firmware.hex
# ELF 转 Motorola SREC
arm-none-eabi-objcopy -O srec firmware.elf firmware.srec
# ELF 转 纯二进制(需指定只导出 .text/.data 等可加载段)
arm-none-eabi-objcopy -O binary --only-section=.text \
--only-section=.data firmware.elf firmware.bin
这里有一个容易被忽略的细节:直接对整个 ELF 执行 -O binary,objcopy 会从最低加载地址一直填充到最高加载地址,中间的空洞(例如 Flash 与 RAM 之间的大段未使用空间)会被填成 0x00 或 0xFF,导致 BIN 文件异常巨大。正确做法是用 --only-section 明确指定需要导出的可加载段,或者先用 readelf -S 查看各段的地址与大小,确认哪些段真正需要烧录。
多地址段合并:量产镜像的关键一步
实际项目中,需要烧录的内容往往不止一段。例如:Bootloader 位于 0x08000000,应用程序位于 0x08008000,而校准参数或设备序列号区位于 0x0803F800。这三段在 ELF 中可能是分开的,甚至来自不同的构建产物。量产时希望把它们合并成一份 HEX 或 SREC,让烧录器一次写入。
合并工具推荐使用 SEGGER 的 JFlash 或 srec_cat(SRecord 工具集)。以 srec_cat 为例:
# 将 bootloader.hex、app.hex、calib.hex 合并为一份量产镜像
srec_cat bootloader.hex -intel app.hex -intel calib.hex -intel \
-o production.hex -intel
# 若某段是 BIN,需要显式给出其加载地址
srec_cat bootloader.hex -intel app.bin -binary -offset 0x08008000 \
-o production.hex -intel
合并时必须检查三件事:地址是否重叠、地址是否连续或存在空洞、各段是否落在芯片真实可写区域内。地址重叠会导致后写入的数据覆盖先写入的数据,srec_cat 默认会报错,但某些工具会静默覆盖,必须人工确认。空洞本身不是错误,HEX/SREC 允许不连续地址,烧录器会跳过空洞;但如果空洞跨越了 Flash 扇区边界,某些烧录算法会因擦除粒度问题失败,需要提前规划。
量产镜像的验证与交付
合并完成后,不能直接把文件丢给产线。至少要做两步验证。第一步是回读比对:用 J-Link 或 Flasher 把 production.hex 烧入一片样片,再通过 JLinkExe 的 savebin 命令把 Flash 内容读回,与原始各段数据做逐字节比较。第二步是地址抽查:用 JFlash 打开 production.hex,查看其地址范围视图,确认 Bootloader 起始、App 起始、Calib 起始三个关键地址与链接脚本一致。
交付给产线的文件建议包含:production.hex(或 production.srec)、一份记录各段地址与长度的说明文件、以及烧录器工程文件(.jflash)。如果产线使用 SEGGER Flasher,通常还会把 production.hex 与 Flasher 的配置文件一起打包,Flasher 上电后按配置自动烧录并校验,操作员只需插拔治具,不需要接触文件本身。
常见问题与判断依据
转换过程中最常遇到三类问题。第一类是 BIN 文件过大,原因通常是未用 --only-section 过滤,把调试段或 RAM 段也导出了,判断方法是查看 BIN 文件大小是否远大于实际代码量。第二类是烧录后程序不运行,常见原因是 HEX 中缺少起始地址记录,或者向量表地址与链接脚本不一致,判断方法是检查 HEX 文件末尾是否有 :04000005 类型的起始线性地址记录。第三类是多段合并后某段丢失,原因是 srec_cat 的输入格式参数写错(例如把 -intel 写成了 -motorola),判断方法是合并后用文本编辑器搜索该段起始地址对应的记录行是否存在。
把这些问题在文件准备阶段解决,产线上的烧录良率才有保障。量产镜像的本质,是把开发阶段“工具自动处理”的隐含信息,显式地整理成一份地址明确、格式确定、可校验、可复现的交付物。