3、刷写文件格式:S19/HEX/BIN 文件解析

做 ECU 刷写,第一关就是看懂刷写文件。你拿到的 .s19、.hex 或者 .bin,里面到底存了什么?说白了,就是地址 + 数据 + 校验。我刚开始接触这行时,也对着这些文件发懵,后来被一个校验错误坑过一次,才老老实实把格式吃透。

今天咱们就把这三种格式掰开揉碎,看看它们怎么描述地址、怎么组织数据、校验和又是怎么算的。

3.1 三种格式的定位差异

先给个总览,你心里有个谱:

格式 存储方式 是否含地址 可读性 典型用途
S19 (SREC) ASCII 文本 是 高 NXP/Infineon 等 MCU 刷写
HEX (Intel HEX) ASCII 文本 是 高 Intel/ARM 架构,通用烧录
BIN 二进制 否 低 Bootloader 直接烧录,固件镜像

BIN 文件最简单——它就是内存的原始镜像,从起始地址开始,一个字节挨着一个字节。没有地址信息,没有校验,纯粹的数据流。所以刷 BIN 时,你必须知道它该烧到哪个地址,否则就乱套了。

S19 和 HEX 则自带地址和校验,刷写工具能自动解析。我个人习惯在开发阶段用 S19 或 HEX,量产时才转成 BIN 给产线用。

3.2 S19 格式深度解析

S19 也叫 Motorola S-record,在汽车电子圈用得特别多。每行都以大写字母 S 开头,后面跟一个数字表示记录类型。

先看一个真实例子:

S214A0000102030405060708090A0B0C0D0E0F1A

我来拆解一下:

  • S2 — 记录类型。S2 表示 24 位地址(3 字节),这是最常用的类型。
  • 14 — 本行数据长度(十六进制),这里是 20 字节。注意:这个长度包括地址 + 数据 + 校验和,但不包括类型和长度本身。
  • A00010 — 地址,3 字节,即 0x00A00010。
  • 010203...0F — 数据,16 字节。
  • 1A — 校验和。
校验和怎么算? 把长度、地址、数据所有字节加起来,取低 8 位,然后取反(0xFF - 结果)。比如上面这行:0x14 + 0xA0 + 0x00 + 0x10 + 0x01 + ... + 0x0F = 0xE5,0xFF - 0xE5 = 0x1A。嗯,对上了。

S19 常见的记录类型:

  • S0 — 文件头,通常包含文件名或注释。
  • S1 — 16 位地址的数据记录。
  • S2 — 24 位地址的数据记录(最常用)。
  • S3 — 32 位地址的数据记录。
  • S5 — 数据记录计数。
  • S7/S8/S9 — 结束记录,对应 32/24/16 位起始地址。

我在项目中遇到过一个问题:某个供应商给的 S19 文件用了 S3 记录(32 位地址),但我们的刷写工具只支持 S2。结果刷到一半就报地址越界。后来我加了个格式检测,提前拦截不兼容的文件。

3.3 Intel HEX 格式解析

Intel HEX 以冒号 : 开头,每行结构也很清晰:

:10A000000102030405060708090A0B0C0D0E0F1A

拆解一下:

  • 10 — 数据长度,16 字节。
  • A000 — 地址,2 字节,即 0xA000。
  • 00 — 记录类型。00 表示数据记录。
  • 010203...0F — 数据,16 字节。
  • 1A — 校验和。
注意地址处理: Intel HEX 的地址是 16 位的,但实际 ECU 地址往往超过 64KB。这时会用扩展地址记录(类型 04)来指定高 16 位地址。刷写工具必须把扩展地址和后续数据记录的地址拼接起来,否则会烧错位置。

Intel HEX 的记录类型:

类型码 含义 说明
00 数据记录 普通数据,地址为 16 位
01 文件结束 最后一行,无数据
02 扩展段地址 指定段地址(很少用)
04 扩展线性地址 指定高 16 位地址,常用
05 起始地址 指定程序入口地址

校验和算法:所有字节(包括长度、地址、类型、数据)加起来,取低 8 位,然后取补码(0x100 - 结果)。比如上面那行:0x10 + 0xA0 + 0x00 + 0x00 + 0x01 + ... + 0x0F = 0xE6,0x100 - 0xE6 = 0x1A。

3.4 BIN 格式与地址映射

BIN 文件没有地址信息,所以刷写时必须配合一个起始地址。比如你有一个 256KB 的 BIN 文件,起始地址是 0x08000000,那么文件中的第 0 字节就对应 0x08000000,第 1 字节对应 0x08000001,以此类推。

我曾经犯过一个低级错误:把 BIN 文件烧到了错误的偏移地址,结果 ECU 启动后完全没反应。后来花了半天才定位到是地址偏移搞错了。所以我现在每次刷 BIN 前,都会用 hexdump 工具看一眼文件头,确认内容是否合理。

三种格式的地址与数据关系总结:
  • S19:每行自带地址,支持 16/24/32 位地址,适合分段刷写。
  • HEX:每行自带地址 + 扩展地址机制,适合大地址空间。
  • BIN:纯数据,地址由外部指定,适合连续地址空间。

3.5 知识结构图:刷写文件解析流程

下面这张图展示了从拿到刷写文件到最终烧录的核心流程:

刷写文件解析流程 刷写文件解析与烧录流程 刷写文件 格式判断:S19 / HEX / BIN S19 解析 提取 S2/S3 记录 HEX 解析 处理扩展地址 BIN 解析 指定起始地址 校验和验证 烧录到 ECU S19/HEX 自带校验,BIN 需外部校验 校验失败则终止刷写

3.6 校验和计算实战

校验和是刷写文件的最后一道防线。我见过太多因为校验和错误导致刷写失败、ECU 变砖的案例。下面给出三种格式的校验和计算代码片段,你可以在刷写工具中直接使用。

S19 校验和计算(C 语言):

uint8_t s19_checksum(const uint8_t *line, int len) {
    uint8_t sum = 0;
    // 从长度字节开始,到数据结束
    for (int i = 2; i < len - 2; i += 2) {
        uint8_t byte = hex_to_byte(line[i], line[i+1]);
        sum += byte;
    }
    return 0xFF - sum;  // 取反
}

Intel HEX 校验和计算(C 语言):

uint8_t hex_checksum(const uint8_t *line, int len) {
    uint8_t sum = 0;
    // 从长度字节开始,到数据结束
    for (int i = 1; i < len - 2; i += 2) {
        uint8_t byte = hex_to_byte(line[i], line[i+1]);
        sum += byte;
    }
    return 0x100 - sum;  // 补码
}
小技巧: 解析 S19 或 HEX 时,不要只依赖文件自带的校验和。我习惯在刷写前再算一遍,跟文件里的校验和比对。如果对不上,直接报错,绝不往下走。这能避免很多莫名其妙的问题。

3.7 避坑指南

最后分享几个我踩过的坑:

  • 地址对齐问题: 有些 MCU 要求刷写地址按 4 字节或 8 字节对齐。如果 S19 文件里有非对齐地址,刷写工具要自动填充或报错。
  • 空区域处理: S19 和 HEX 文件可能只包含非空区域。刷写时要注意,未覆盖的区域是保持原值还是擦除。我曾经因为没处理空区域,导致旧数据残留,ECU 行为异常。
  • 文件编码: S19 和 HEX 是 ASCII 文本,但有些工具会输出带 BOM 的 UTF-8 文件。解析时最好跳过 BOM,否则第一行会解析失败。
  • 校验和溢出: 有些工具算校验和时用 8 位加法,有些用 16 位。确保你的算法跟刷写工具一致,否则校验永远过不了。

嗯,格式解析这块就这些。你只要把地址、数据、校验和这三个要素搞清楚,S19、HEX、BIN 在你眼里就是透明的。下次拿到刷写文件,先看一眼格式,再算一遍校验和,心里就有底了。