4. 双分区机制核心概念

双分区机制是 ECU 在 OTA 升级与故障恢复场景下最常用的可靠性设计。它的核心思想并不复杂:在 Flash 中预留两块可独立运行、可独立擦写的应用镜像区域,让“正在运行的程序”和“正在写入的程序”物理隔离。这样即使升级过程中断电、通信中断或新镜像校验失败,ECU 仍能回到一个已知可用的版本继续工作。理解双分区,关键要抓住 A/B 分区、主备分区、镜像槽、分区状态标志、启动标志、回滚策略与冗余设计思想这几个概念之间的关系。

一、A/B 分区与主备分区:两种常见组织方式

A/B 分区通常指两块容量相同、地位对等的应用分区,例如 Slot A 与 Slot B。当前运行在 A,则把新固件写入 B;升级成功后通过启动标志切换到 B,A 则成为下一次升级的备用区。主备分区则更强调角色差异:主分区是默认启动区,备分区是恢复区或候选区。两者在物理布局上可能相似,但语义不同——A/B 更强调“轮换”,主备更强调“优先级与兜底”。

镜像槽(Image Slot)是对可存放完整应用镜像的物理区域的抽象描述。一个镜像槽通常包含头部信息、版本号、长度、校验值、签名以及实际代码段。Bootloader 不直接关心“A 还是 B”,而是关心“哪个槽的镜像有效、哪个槽被标记为待启动”。因此,镜像槽是双分区机制中最基础的存储单元。

二、分区状态标志与启动标志

仅有分区还不够,Bootloader 必须知道每个分区的状态。常见做法是在 Flash 中维护一块元数据区,记录每个槽的状态标志。典型状态包括:

  • VALID:镜像完整且校验通过,可被启动。
  • INVALID:镜像损坏或校验失败,不可启动。
  • TESTING:新镜像已写入,等待首次试运行确认。
  • CONFIRMED:新镜像已成功运行并被正式确认。
  • ROLLBACK:需要回退到旧版本。

启动标志(Boot Flag)则决定下一次复位后 Bootloader 跳转到哪个槽。它通常是一个独立的小字段,例如 active_slot 与 pending_slot。升级时先写 pending_slot,重启后 Bootloader 根据 pending_slot 跳转,并在试运行成功后把 active_slot 更新为新槽。这样即使写入过程中断电,也不会破坏当前可运行镜像。

核心原则:先写备用槽,再改启动标志;先验证新镜像,再确认切换。任何时刻都至少保留一个 VALID 镜像。

三、回滚策略与冗余设计思想

回滚策略是双分区机制的安全阀。常见回滚触发条件包括:新镜像启动后看门狗复位次数超限、应用层自检失败、CAN 通信超时、关键外设初始化失败等。一旦满足回滚条件,Bootloader 将启动标志指回旧槽,并把新槽标记为 INVALID 或 ROLLBACK,等待下一次重新升级。

冗余设计思想不仅体现在“有两个分区”,还体现在元数据的冗余。若状态标志只存一份,擦写时断电可能导致标志丢失。工程上常采用双份元数据加 CRC 校验,或使用“主元数据 + 备份元数据”的方式,确保启动决策本身也是可靠的。

四、典型升级与回滚流程

下面给出一个简化的双分区升级流程,便于理解各标志的时序关系:

1. 当前 active_slot = A,A 状态 VALID,B 状态 INVALID
2. 收到新固件,写入 Slot B,写入完成后校验
3. 校验通过:B 状态 = TESTING,pending_slot = B
4. 复位,Bootloader 读取 pending_slot = B,跳转 B
5. B 试运行成功,应用调用 confirm 接口
6. Bootloader 更新:active_slot = B,B 状态 = CONFIRMED
7. A 状态保留为 VALID,作为下次升级的备用槽
8. 若第 5 步失败或超时,则 pending_slot = A,B 状态 = ROLLBACK

这个流程中,第 3 步和第 6 步是仅有的两次“写启动标志”操作,且都发生在镜像写入完成或试运行成功之后,因此断电风险窗口很小。

五、案例与常见误区

某车身控制器在 OTA 升级中曾出现“升级后无法启动”的问题。排查发现,Bootloader 在写入新镜像前就先把启动标志改成了新槽,结果写入中途断电,新槽不完整,旧槽又不再被启动,导致 ECU 变砖。修正方案是严格遵循“先写镜像、后改标志”的顺序,并在启动时增加镜像完整性校验。

常见误区:把“双分区”简单理解为“两份代码”。若没有状态标志、启动标志和回滚逻辑,双分区只是多占了一块 Flash,并不能带来可靠性提升。

另一个误区是忽略元数据寿命。状态标志频繁擦写会导致 Flash 扇区磨损,工程上应把元数据放在独立扇区,并采用追加写或磨损均衡策略。

六、关键概念对照清单

概念 作用 典型取值/形式
A/B 分区 两块对等应用区,轮换升级 Slot A / Slot B
主备分区 主区默认启动,备区兜底 Primary / Backup
镜像槽 存放完整镜像的物理单元 头部 + 代码 + 校验
分区状态标志 描述镜像是否可用 VALID / INVALID / TESTING / CONFIRMED
启动标志 决定下次启动跳转槽 active_slot / pending_slot
回滚策略 失败时恢复旧版本 看门狗计数、自检失败触发
冗余设计 保证元数据与镜像可靠 双份元数据 + CRC
双分区机制核心概念关系图 Bootloader 读取启动标志 → 校验 → 跳转 元数据区 active_slot / pending_slot 状态标志 + CRC 冗余 Slot A(当前运行) 镜像头 + 版本 + 长度 + 签名 应用程序代码段 状态:VALID / CONFIRMED Slot B(升级候选) 镜像头 + 版本 + 长度 + 签名 新固件代码段 状态:TESTING / INVALID 写入新镜像 回滚:pending_slot = A 运行槽 候选槽 元数据 升级写入 回滚路径

总结来看,双分区机制的核心不是“多一块 Flash”,而是围绕镜像槽建立一套可验证、可切换、可回滚的状态机。A/B 分区提供物理冗余,状态标志提供判断依据,启动标志提供切换入口,回滚策略提供失败兜底,元数据冗余则保证这套机制自身不会成为单点故障。只有这些概念协同工作,ECU 才能在 OTA 升级中真正做到“升级失败不丢功能”。