ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

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

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.0HEX 合并只是这个工具集的一角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 用 -intelMotorola 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 表示文件自身每条记录的内嵌校验和是合法的说明这个文件没有在传输或转换过程中被破坏。参数说明格式参数同样是必填的如果不写 -intelsrec_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 到 0x0800FFFFapp 编译链接在 0x08020000 到 0x0803FFFF但最终量产固件需要把 app 放到 0x08010000 开始的位置给后面的 OTA 缓存区让出空间。这时用 -offset 参数处理 app.hexsrec_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 而不是 -intelsrecord 没有 -ihex 这个参数写了会直接被拒绝。为了减少这类错误我在脚本里把格式参数全部固定写成 -intel不在这里用简写。4. 避坑指南srecord 合并 HEX 的四个常见翻车点4.1 地址重叠被静默覆盖合并成功但烧录后程序跑飞现象srec_cat 命令正常退出生成 merged.hex 没有报错烧录到目标芯片后 bootloader 无法跳转app 直接跑飞用调试器读 Flash 才发现 0x08004000-0x08007FFF 的数据根本不是期望的内容。原因两个输入文件的地址区间重叠srec_cat 对同地址数据采用“后读覆盖先读”的规则并且不给出任何警告。例如 boot.hex 数据覆盖到 0x08007FFFapp.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 BOOTboot.hex set APPapp.hex set OFF0x20000 set FILL0xff set START0x08000000 set END0x08040000 set OUTmerged_%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 验证”固化成了每天必经的三步流程。现在每次出量产固件无论多急我都会强制走这套流程因为命令行不会骗你但参数会。希望帮到你。本文还有配套的精品资源点击获取
返回列表