3. 通信协议基础
Bootloader 的通信协议并不是“把数据从 A 发到 B”这么简单。它要在有限的硬件资源、不可靠的物理链路和严格的升级时序之间建立一套可预测的规则。理解协议分层、串行通信原理、帧结构、同步/异步方式以及差错控制,是设计可靠 Bootloader 通信协议的五块基石。
一、协议分层模型:把复杂问题切成可管理的层
Bootloader 通信协议通常借鉴 OSI 的分层思想,但会大幅简化。典型的分层如下:
- 物理层:定义电气特性,如 UART 的 TTL/RS-232/RS-485 电平、CAN 的差分信号、SPI 的时钟极性。
- 数据链路层:负责帧定界、字节填充、校验和重传,保证相邻节点之间无差错地传输帧。
- 传输/会话层:管理命令-响应配对、超时重试、序号与确认,保证升级数据按序到达。
- 应用层:定义具体命令,如擦除 Flash、写入数据、校验固件、跳转执行。
分层的价值在于:更换物理介质(UART 换 CAN)时,只需替换物理层和部分链路层,上层命令语义保持不变。Bootloader 协议设计中最常见的错误是把所有逻辑塞进一个“大函数”,导致换一个波特率或加一个校验就要重写全部代码。
二、串行通信原理:一位一位地传
串行通信把并行数据按时间顺序逐位发送。以 UART 为例,发送端把 8 位数据加上起始位、校验位、停止位组成一个字符帧,接收端通过检测起始位下降沿来同步采样。关键参数包括波特率、数据位、停止位和校验位,双方必须完全一致。
波特率误差是常见故障源。若发送端与接收端时钟偏差超过约 2%~3%,采样点会逐渐偏移,导致误码。Bootloader 中常用 115200、460800 甚至 921600 bps,高波特率对时钟精度要求更高。CAN 则采用位填充和差分信号,抗干扰能力更强,适合车载 Bootloader。
三、帧结构:协议的“集装箱”
帧是链路层传输的基本单位。一个典型的 Bootloader 帧包含:帧头、长度、命令/地址、数据、校验和帧尾。帧头用于接收端快速定位帧起点,长度字段决定后续读取多少字节,校验字段用于检错。
帧格式示例(UART Bootloader):
+--------+--------+--------+--------+----------+--------+
| 帧头 | 长度 | 命令 | 序号 | 数据 | CRC16 |
| 0xAA55 | 1 Byte | 1 Byte | 1 Byte | N Bytes | 2 Byte |
+--------+--------+--------+--------+----------+--------+
帧设计要避免“帧头出现在数据中”造成误同步。常用方法有:字节填充(转义)、固定长度、或使用带长度字段的 TLV 结构。Bootloader 升级数据量大,帧长通常取 128~1024 字节,兼顾效率和 RAM 占用。
四、同步与异步通信:时钟从哪来
同步通信中,收发双方共享时钟信号(如 SPI、I2C),数据位与时钟边沿对齐,传输效率高,适合板内 Bootloader 与外部 Flash 通信。异步通信没有共享时钟,依靠起始位和约定的波特率采样(如 UART),硬件简单但效率略低。
Bootloader 场景中,UART 异步通信最常用,因为 PC 端工具链成熟;SPI 同步通信多用于 MCU 与外部存储之间的固件搬运;CAN 则介于两者之间,通过位同步机制实现多节点通信。
五、差错控制基础:让错误可发现、可恢复
差错控制包括检错和纠错。Bootloader 中最常用的是检错加重传:
- 奇偶校验:每字节加 1 位,只能发现奇数个位错误,能力弱。
- 校验和:累加求和,实现简单,但无法发现字节顺序错误。
- CRC16/CRC32:检错能力强,是 Bootloader 帧校验和整包校验的首选。
- 序号与 ACK:接收端确认正确帧,发送端超时重传,解决丢帧问题。
整包校验通常在固件全部传输完成后进行,例如对整段 Flash 计算 CRC32,与协议中携带的期望值比对,一致才跳转执行。这能防止“帧都正确但整体被篡改或写入错误”的情况。
六、案例:一次 UART Bootloader 升级的完整数据流
下面用一张信号链/数据流图展示从 PC 到 MCU 的升级过程,涵盖握手、擦除、传输、校验和跳转五个阶段。
该数据流中,PC 端负责封装帧并维护重传队列,MCU 端负责解析、校验和写入 Flash。ACK/NAK 构成闭环,确保每一帧都被确认。整包 CRC 比对通过后,Bootloader 修改启动标志并复位跳转到 App。
七、常见误区与复盘
| 误区 | 后果 | 改进措施 |
|---|---|---|
| 只用校验和,不用 CRC | 突发错误漏检率高 | 帧校验用 CRC16,整包用 CRC32 |
| 没有序号和重传 | 丢帧后固件不完整 | 加入帧序号、ACK 和超时重传 |
| 帧头与数据冲突 | 接收端误同步 | 使用长度字段或字节填充 |
| 波特率误差过大 | 高波特率下误码率上升 | 校准时钟,误差控制在 2% 以内 |
| 擦除与写入无超时 | Flash 忙时阻塞通信 | 加入超时和忙等待状态机 |