news 2026/9/29 16:55:04

srecord合并HEX文件:量产烧录的地址偏移与避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
srecord合并HEX文件:量产烧录的地址偏移与避坑指南

简介:这是面向嵌入式与微控制器开发者的 srecord-1.65.0 Windows 64 位版本,核心用途是把 KEIL MDK 等环境生成的多个 HEX 文件合并为单一烧录文件。合并过程中会自动核对各文件记录的地址、纠正地址顺序,并对冲突或重复数据做处理,确保输出逻辑连贯,适合固件升级、批量部署和大型工程维护场景。资源包共 2000 个文件,以 HTML 帮助文档、JavaScript 脚本、MD5 校验、MAP 映射、PNG 示意图、C 头文件为主,另附 PDF 说明和可运行的 DLL/EXE 程序,整体约 17.91MB,目录结构清晰,便于按文档、脚本、映射与库文件分类查阅。目前已有 122 人学习下载。通过这份资源,工程师可获得完整可用的 Windows 64 位工具链,既能用命令行或界面高效完成 HEX 合并,也能根据示例和文档掌握地址拼接、格式控制、输出大小限制等高级用法;工具同时支持 Linux/macOS 且开源免费,适合在不同开发环境中复用。

1. 量产烧录前的最后一公里:srecord 把多个 HEX 拼成一个

在嵌入式固件开发中,bootloader 和 app 分开编译、分开生成 HEX 是常态;到了量产烧录阶段,就要把它们合并成一个文件一次性写入。以前我靠 Keil 自带工具加手工文本拼接,地址对不对全凭肉眼,一次遗漏导致整批板子无法启动,返工成本高得让人崩溃。后来换成 srecord-1.65.0-win64 这个 HEX 文件合并工具,一条命令完成合并和填充,还带格式检查,彻底摆脱手工对地址的焦虑。这套方法适合搞单片机开发、需要把多个 HEX 合成一个烧录文件的工程师,也适合第一次听说 srecord 的新手。下面内容包含可复制的批量合并流程,以及我实际摔过的四个坑的解决方法。

2. 认识 srecord 1.65.0:HEX 合并只是这个工具集的一角

2.1 工具定位:srec_cat、srec_info、srec_cmp 怎么分工

很多人把 srecord 当成一个“HEX 文件合并工具”,这没错,但这只是它能力的冰山一角。srecord 是一整套专门处理烧录文件的开源工具集,长期维护且稳定,在嵌入式工具链里存在了很多年。工具集里真正常用的有三个命令:srec_cat、srec_info、srec_cmp。srec_cat 负责读入多个文件、按规则处理、再输出一个新文件;srec_info 负责解析文件并打印地址范围、数据长度和格式信息;srec_cmp 负责对比两个文件的内容差异。

它们的分工对应了固件合并的标准工作流:先用 srec_info 摸清每个输入文件的地址范围,再用 srec_cat 做合并或偏移,最后再用 srec_info 验证输出文件。这三个命令配合起来,能覆盖从“查看信息”到“合并处理”再到“验证结果”的完整闭环。srec_cmp 我在回归测试中用的比较多,给 bootloader 加功能后重新编译,用它对比新旧 HEX 就能知道除了预期变化外还有没有别的内容被改动。

这种命令分工设计的价值在于:每一步都可以单独验证,出错时你能快速定位是输入问题还是处理参数问题。如果我当初用一个全功能图形界面工具,很多时候只能看到最终结果,出了问题根本不知道错在哪个环节。命令行看着简陋,但每一步都透明,这恰恰是量产固件最需要的可追溯性。

2.2 win64 包解压与 PATH 配置

srecord-1.65.0-win64 这个包是面向 Windows 64 位系统的预编译版本,解压即用,不依赖额外的运行时。我通常把包解压到 C:\tools\srecord-1.65.0-win64,目录结构大致如下:

目录内容
binsrec_cat.exe、srec_info.exe、srec_cmp.exe 等可执行文件
doc官方手册,含每个命令的参数表与示例
examples格式转换与脚本参考

为了让命令在任何目录下都能直接执行,我建议把 bin 目录追加到系统 PATH。做法是在命令提示符里运行 sysdm.cpl 打开系统属性,切到“高级”页点击“环境变量”,在系统变量的 Path 列表里追加一行 C:\tools\srecord-1.65.0-win64\bin。注意路径不要带引号,也不要带末尾反斜杠,否则个别命令解析的时候会出怪问题。

配置完成后必须重开命令提示符窗口,已打开的窗口不会自动刷新环境变量。然后执行 srec_info --version 验证。看到版本号输出就说明 PATH 生效了。这一步如果跳过,后面所有 srec_ 开头的命令都会提示“不是内部或外部命令”,那是新手最常见的第一个报错,和工具本身没关系。

2.3 命令格式:为什么每个输入文件都要带格式参数

srecord 的命令风格和常见的 Unix 工具不太一样。它要求每个输入文件后面紧跟一个格式参数:Intel HEX 用 -intel,Motorola S-record 用 -motorola,纯二进制用 -binary。这个参数不是可选项,漏掉就会报无法识别格式。以 Keil4 为例,工程里勾选 Output 页的 Create HEX File 后,生成的 .hex 就是标准 Intel HEX 格式,srecord 可以直接用 -intel 读取。

这种“每个输入文件后跟独立格式参数”的设计,直接好处是命令里可以混用不同格式的文件。实际项目里我就遇到过:一段从 Flash 导出的 raw bin 表头,一份用 GCC 生成的 .srec bootloader,一份 Keil 生成的 .hex 应用,三个文件需要同一命令合并。如果工具是单一格式识别模式,这种场景根本没法处理。

srec_cat table.bin -binary boot.srec -motorola app.hex -intel -o all.hex -intel

逻辑说明:命令按参数顺序读取三个文件,table.bin 按裸二进制解析(地址从 0 开始,没有内置地址信息),boot.srec 按 Motorola S-record 解析,app.hex 按 Intel HEX 解析;合并后的数据统一以 Intel HEX 格式写入 all.hex。输出格式用 -o 后面的 -intel 指定,与输入格式完全独立。参数说明:-binary 适合没有地址信息的纯数据文件,-motorola 是飞思卡尔/NXP 工具链常见的 SREC 格式,-intel 是 Keil、IAR、ST-Link 等工具默认支持的格式。

还有一个常见误解是把格式参数放在命令最后,以为它会全局生效。这是错的。srecord 的参数与它前面的文件绑定,并不会作用于后面所有文件,-intel 写的位置不同,效果完全不同。如果你把 -intel 写在命令最后,srecord 会把它当成输出相关参数,或者直接报错。所以每条命令我都习惯从左到右逐段读:文件 A 后跟格式 A,文件 B 后跟格式 B,最后是输出参数。这种顺序结构用熟了以后,排查命令错误会非常快。

另有一种思路是在 Python 里解析 Intel HEX 再重写,我早期也这么干过。但自己写解析器意味着要处理地址跨段拆分、行校验和校验、空洞填充这些细节,写出来的脚本只对自己手上的文件有效。srecord 把这些边界情况都收敛掉了,同类工作用它更省心。选型上的建议是,如果你的合并规律简单到只有“拼接”,写脚本问题不大;一旦涉及偏移、填充、校验、格式转换四件事同时出现,直接用 srecord 反而效率最高。

3. 用 srec_cat 合并 HEX:从确认地址到偏移与验证的一条龙操作

3.1 合并前先做信息检查:srec_info 的使用

合并 HEX 的第一件事不是打开命令行,而是先查看每个输入文件的地址范围。srec_info 的任务就是这个。命令格式和 srec_cat 类似,输入文件后必须跟格式参数:

srec_info boot.hex -intel srec_info app.hex -intel

输出大致如下:

Format: Intel Hexadecimal Addresses: 0x08000000 - 0x08003FFF Data: 16K bytes Checksum: ok

逻辑说明:srec_info 会解析文件中的所有数据记录,把分散的记录统一求并集,输出一个总体的地址范围。Data 后面的字节数代表文件中实际承载的数据总量,而不是按地址计算得到的区间大小,因为区间内可能有空洞。Checksum: ok 表示文件自身每条记录的内嵌校验和是合法的,说明这个文件没有在传输或转换过程中被破坏。

参数说明:格式参数同样是必填的,如果不写 -intel,srec_info 会报无法识别格式。注意一点:srec_info 输出里的地址范围只表示文件内数据的地址,并不代表它在目标 Flash 上的最终烧录地址。我见过有人拿编译地址直接当烧录地址用,结果合并后实际存放位置和链接脚本设定的位置不一致,导致程序完全跑不起来。这个动作看似多余,但能省下后面排查问题的几个小时。

3.2 无重叠场景:一行命令直接拼

如果 boot.hex 的数据结束地址小于等于 app.hex 的数据起始地址,且两个文件都不需要移动位置,直接合并就行。命令是最简单的一个:

srec_cat boot.hex -intel app.hex -intel -o merged.hex -intel

逻辑说明:srec_cat 从左到右处理参数,把 boot.hex 解析成一串地址-数据记录,把 app.hex 解析成另一串记录,按地址排序后合成一个数据集。如果两段地址有重叠,后读入的文件会覆盖先读入的同地址数据,这个行为要在心里有数。输出参数 -o 指定文件名,最后的 -intel 指定输出格式,输出格式可以和输入格式不一样。

参数说明:输入文件顺序会影响重叠区域的覆盖结果。如果 boot 和 app 的地址重叠,交换两个输入文件的位置会得到不同的合并文件。所以如果你发现合并结果和预期不符,第一反应应该是检查两个输入文件的地址区间是否有重叠,而不是怀疑命令本身语法有问题。

如果需要把裸二进制文件也拼进去,比如一段校准参数表,可以直接加一个输入:

srec_cat params.bin -binary boot.hex -intel app.hex -intel -o merged.hex -intel

二进制文件没有内嵌地址,srecord 默认从地址 0x00000000 开始排布。如果你的目标 MCU 地址空间起始点不是 0,就需要给它单独加偏移,这个在第 3.3 节会讲到。

3.3 带偏移合并:把 app 移动到目标 Flash 区间

真正量产时更常见的行为是:app 源码编译时的链接地址是固定的,但为了配合 bootloader 的占用空间,需要把 app 整体搬移到另一段地址。以常用的 STM32 系列为例,bootloader 占了 0x08000000 到 0x0800FFFF,app 编译链接在 0x08020000 到 0x0803FFFF,但最终量产固件需要把 app 放到 0x08010000 开始的位置,给后面的 OTA 缓存区让出空间。

这时用 -offset 参数处理 app.hex:

srec_cat boot.hex -intel app.hex -intel -offset -0x10000 -o merged.hex -intel

逻辑说明:-offset -0x10000 表示把紧贴在它前面的 app.hex 的所有数据地址整体减 0x10000,也就是把 0x08020000-0x0803FFFF 的数据挪到 0x08010000-0x0802FFFF。boot.hex 在它前一个位置先被读取,不受这个偏移影响。这里要强调,-offset 参数只作用于紧挨在它前面的那个输入文件,这是 srecord 最容易用错的地方,没有之一。

如果是正向偏移,比如把编译在 0x08010000 的 app 挪到 0x08030000,那就写成 -offset 0x20000。这里的 0x20000 是十六进制表示,对应十进制 131072 字节。如果你习惯先做 hex 转十进制换算,一定要在命令行之外完成,不要在命令里直接写十进制数。偏移量写错是合并时后果最隐蔽的错误,因为命令不会报错,烧录进去才发现启动不了。

参数补充:偏移量可以是任意整数,包括负数,这给地址搬移提供了很大灵活性。但要注意,偏移之后文件里记录的逻辑地址必须落在目标 MCU 的有效地址空间内,否则烧录器写入时会直接报地址越界。这个约束靠你自己的 Flash 布局决定,srecord 本身不做任何边界检查。

3.4 合并后的验证:两句命令确认结果没跑偏

合并命令执行完,输出文件是不是正确,必须靠验证而不是靠信心。我的固定流程是用 srec_info 再读一遍输出文件:

srec_info merged.hex -intel

验证点有三个。第一,地址范围是否符合预期:把偏移量代入原始起始地址算一遍,和输出的起始地址对比,偏差大于 0 就不对。第二,数据字节数是否等于输入文件字节数之和,在没有加 -fill 的前提下:如果少了,说明可能有文件没有被完整读入;如果多了,说明有地址重叠导致内容被覆盖。第三,Checksum 状态是否为 ok,如果显示 checksum error,说明输出文件在写入过程中出了问题。

如果我有两个“应该完全相同”的文件,还会用 srec_cmp 做对比:

srec_cmp left.hex -intel right.hex -intel

这条命令会逐条记录比对地址和数据,全部一致时不输出任何内容,只在出现差异时打印不同的地址位置。它适合验证“改版后的固件是否只有预期的变化”,属于回归测试的范畴。另外,命令里还有一个高频错误是把格式参数写成 -ihex 而不是 -intel,srecord 没有 -ihex 这个参数,写了会直接被拒绝。为了减少这类错误,我在脚本里把格式参数全部固定写成 -intel,不在这里用简写。

4. 避坑指南:srecord 合并 HEX 的四个常见翻车点

4.1 地址重叠被静默覆盖,合并成功但烧录后程序跑飞

现象:srec_cat 命令正常退出,生成 merged.hex 没有报错,烧录到目标芯片后 bootloader 无法跳转,app 直接跑飞,用调试器读 Flash 才发现 0x08004000-0x08007FFF 的数据根本不是期望的内容。

原因:两个输入文件的地址区间重叠,srec_cat 对同地址数据采用“后读覆盖先读”的规则,并且不给出任何警告。例如 boot.hex 数据覆盖到 0x08007FFF,app.hex 数据从 0x08004000 开始,合并后这段区间实际是 app 的内容,boot 的部分内容被无声替换。

解决:合并之前用 srec_info 把每个输入文件的结束地址算清楚,结束地址 = 起始地址 + 数据字节数 - 1。一旦发现有重叠,就给后读的文件加偏移,或者重新编译调整链接地址。另外一个实用自查技巧:把两个输入文件的顺序调换后再合并一次,如果输出文件变了,说明有重叠存在;如果输出文件没变,说明两个文件的地址区间是分离的。这个技巧判断重叠非常快,我在现场排查时经常用。

4.2 报错 unrecognized format:本质是漏了格式参数

现象:执行命令时提示 unrecognized format,命令中止,输出文件没有生成。

原因:srecord 不会自动探测文件格式,每个输入文件必须在其后紧跟格式参数。最容易漏掉的是最后一个文件后面的格式参数,因为人眼看到前面都写了,很容易漏掉最后那个。还有一个变体是把参数写成 --intel 双横线形式,srecord 的命令行只接受单横线短选项,双横线会直接被当成未知参数处理。

解决:直接检查命令中每个输入文件后面是否都有格式标识。习惯好的话,从第一条命令开始就把格式参数当成文件名的一部分,无论读多少个文件都不会漏。如果确定文件是 Intel HEX 但 srec_info 读出来数据范围很怪,那很可能是用 -binary 解析了一个文本格式文件,换成 -intel 就好了。这个排查思路适用于所有格式,不只是 HEX。

4.3 偏移量十六进制写成了十进制,地址凭空少一大截

现象:合并后 app 能在调试器里加载,但跳转后立刻进入 HardFault,查看反汇编发现入口地址比预期低了很多。

原因:-offset 参数是字节数,0x20000 是十六进制,等于十进制的 131072。如果直接写 20000,实际偏移量只有 20000 字节,所有数据地址都比预期少了约 110KB,程序入口自然不对。

解决:写偏移参数前,用计算器或心算完成十六进制到十进制的换算,确认无误后再写入命令。我在批处理脚本里习惯给每个偏移量加一行注释,标注它对应的十进制数和 KB 值,比如 rem 0x20000 = 131072 bytes / 128KB,这样以后回看脚本不用重新推算。srecord 不校验这个参数是否合理,它只是把数值带入地址计算,所以这类错误不会产生任何报错信息,只能靠验证输出地址范围来发现,这也是我坚持合并后用 srec_info 复检的原因。

4.4 量产烧录器报地址空洞错误,用 -fill 填充整个区间

现象:合并文件在仿真器加载完全正常,但用某些量产烧录器烧录时报错,提示地址不连续,或者烧录完成后校验失败。

原因:Intel HEX 允许地址空洞存在,绝大多数调试链路如 ST-Link、J-Link 都能正常处理,但部分量产烧录器要求文件内地址必须连续,遇到空洞会根据自身策略填充 0x00、0xFF 或者直接中断烧录,于是校验和就对不上。

解决:给 srec_cat 增加 -fill 参数,在指定地址区间内把空洞填满。一条带填充的完整命令如下:

srec_cat boot.hex -intel app.hex -intel -offset 0x20000 -fill 0xff 0x08000000 0x08040000 -o merged.hex -intel

逻辑说明:-fill 0xff 后面的两个地址定义了填充区间,srec_cat 先把该区间内所有空洞填成 0xFF,再叠加输入文件的数据,输入文件有实际数据的地址不会被覆盖。参数说明:填充值一般用 0xFF,因为多数 Flash 芯片擦除后的默认状态就是 0xFF,烧录器写 0xFF 不会产生实际的 Flash 写操作,在烧录时间和 Flash 寿命上都更友好。两个边界地址按实际 Flash 布局填写,一定要覆盖到 app 偏移后的末尾地址,否则尾部空洞还是会漏出去。

5. 把合并流程固化成脚本:一个参数改完就出活

5.1 带日期命名的批处理脚本

手动敲命令适合临时处理,如果每周都要出一次量产固件,我建议你把合并流程写进批处理脚本。以下是我沿用很久的模板:

@echo off set BOOT=boot.hex set APP=app.hex set OFF=0x20000 set FILL=0xff set START=0x08000000 set END=0x08040000 set OUT=merged_%date:~0,4%%date:~5,2%%date:~8,2%.hex srec_cat %BOOT% -intel %APP% -intel -offset %OFF% -fill %FILL% %START% %END% -o %OUT% -intel srec_info %OUT% -intel

逻辑说明:脚本用批处理变量把所有可变参数集中到文件头部,日常出固件只需要改 BOOT、APP、OFF 三个值。set 语句里的 %date% 是 Windows 的系统日期变量,按区域设置不同,%date:~0,4%%date:~5,2%%date:~8,2% 拼接出来形如 20260618,这个日期串直接变成输出文件名的一部分,方便多版本追溯。最后一行 srec_info 会在合并完成后自动打印输出文件的地址范围,让你在拿到文件的同时完成一次完整性检查。

5.2 在合并阶段就写入校验和

量产固件建议把 CRC32 直接写进合并结果里,这样 bootloader 在跳转前可以做完整性校验。srecord 的 CRC32 写入参数是 -crc32-b-e,写法如下:

srec_cat merged.hex -intel -crc32-b-e 0x0803FFFC -o merged_crc.hex -intel

这里的 -b 表示 big-endian 字节序,-e 表示把校验值写在文件末尾地址 0x0803FFFC 开始的四个字节。Bootloader 计算完整个 app 区域的 CRC32 后,与这个地址的值比对,一致说明固件完整。这个参数需要确保 0x0803FFFC 落在实际数据范围内,否则校验值会写到空洞里,失去意义。

在那次因为偏移量写错导致整批板子返工之后,我把“合并前用 srec_info 查地址、合并中用脚本带参数执行、合并后自动 srec_info 验证”固化成了每天必经的三步流程。现在每次出量产固件,无论多急我都会强制走这套流程,因为命令行不会骗你,但参数会。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 16:54:51

Windows平台RTMP低延迟推流实战:SmartMediaKit与编码调优

做流媒体开发这几年,我在 Windows 平台上做 RTMP 推流验证的次数多得数不清。SmartMediaKit 是我后来用得越来越顺手的一套开源流媒体工具包,它本身是一套完整的媒体服务框架,内置了 RTMP、RTSP、HLS、GB28181 等协议支持,在 Wind…

作者头像 李华
网站建设 2026/9/29 16:54:50

地图API收费困局如何破?从按量付费到降本增效的实战指南

前阵子有个做校园外卖小程序的朋友半夜找我,说收到高德开放平台的欠费提醒,一晚上被扣了三百多块。他当时很困惑:“路径规划接口的文档里明明写着免费,怎么突然就开始计费了?”我帮他查了调用日志才发现,当…

作者头像 李华
网站建设 2026/9/29 16:51:20

Abaqus 2020 FlexNet错误-7,96排查与修复全攻略

1. 问题现象与错误码拆解先说结论:FlexNet Licensing error:-7,96这个报错,八成不是 Abaqus 本体坏了,而是许可证(License)没有“对上暗号”。我见过太多人卡在这一步,以为是软件破解不完整、系统不兼容&am…

作者头像 李华
网站建设 2026/9/29 16:50:32

C++贪心算法实战:从排序、优先队列到经典题全解析

作为常年在算法题和工程代码之间反复横跳的人,我越来越觉得贪心算法是最接近“现实决策”的一类算法。它在C里的落地,不只是背几个模板题,而是训练一种观察问题的角度:局部最优能不能推出全局最优,怎么证明&#xff0c…

作者头像 李华
网站建设 2026/9/29 16:50:18

尾缀为377 的DSP和MCU的型号对比

【型号末尾377 DSP和MCU】后缀为 377 的 DSP 和 MCU 有那些?型号末尾377(xx377)的DSP/MCU(控制类,带DSP能力)说明:TI C2000是MCUDSP融合,行业一般叫DSP MCU;英飞凌AURIX …

作者头像 李华
网站建设 2026/9/29 16:49:56

光子操控与测量技术开源实战:从DREAMVFIA到光量子计算入门

做光量子计算这些年,我最大的感受是:硬件苦,调试更苦。光子看不见摸不着,一套光路调下来,实验室里最常听见的不是讨论物理,而是“怎么又飘了”。所以当朋友们聊到DREAMVFIA 开源项目的时候,我第…

作者头像 李华