2、系统架构设计:双分区备份架构(A/B分区)原理与设计

好,咱们进入正题。星载计算机的固件升级,最怕什么?

怕升级到一半,卫星飞丢了。怕新固件有bug,老固件又回不去了。说白了,就是怕「变砖」。在地面上,手机变砖还能刷机,卫星在天上,谁去给它刷?

所以,双分区备份架构——也就是A/B分区,就成了星载固件设计的标配。我个人习惯叫它「AB双胞胎」方案。今天我就把这个架构的底裤给你扒干净。

2.1 什么是A/B分区?

简单说,就是在存储芯片里划出两个完全独立的区域。一个叫A分区,一个叫B分区。每个分区里都放着一套完整的固件镜像。

你想想看,这就像飞机有两个引擎。一个坏了,另一个顶上。A/B分区的核心思想就是:永远保证有一个可用的固件在运行

核心原则:任何时候,至少有一个分区是「已知良好」的状态。

我在项目中遇到过一件事。有一次,某颗卫星的固件升级因为宇宙射线干扰,写到一半数据就错了。幸好当时用的是A/B分区方案,系统自动回滚到老版本,卫星正常工作。嗯,那次之后,我对这个架构的敬畏心又多了几分。

2.2 分区布局与存储映射

咱们来看一个典型的存储布局。假设我们有一颗256MB的NOR Flash,我会这样划分:

区域 起始地址 大小 内容
Bootloader 0x0000_0000 2MB 一级启动代码,不可升级
分区A 0x0020_0000 120MB 固件镜像A + 配置数据A
分区B 0x07A0_0000 120MB 固件镜像B + 配置数据B
状态区 0x0F20_0000 4MB 启动计数、升级标志、校验值

注意看,Bootloader是单独划出来的。为什么?因为它不能参与升级。Bootloader是「守门员」,它负责决定这次该从A启动还是从B启动。如果Bootloader自己坏了,那才是真正的灾难。

警告:Bootloader区域必须写保护。我在早期的一个项目中,因为Bootloader区域没有硬件写保护,结果一次误操作把Bootloader覆盖了,整颗卫星的固件都废了。血的教训。

2.3 启动流程:谁来决定启动哪个分区?

好,现在分区划好了。那系统上电后,到底跑A还是跑B?

流程是这样的:

  1. Bootloader读取状态区:看看上次升级是否成功,看看当前哪个分区被标记为「有效」。
  2. 检查启动计数:如果某个分区连续启动失败超过3次,就自动切换到另一个分区。
  3. 校验分区完整性:对选中的分区做CRC或SHA256校验。校验通过,跳转执行。
  4. 启动后上报状态:应用固件启动后,会向状态区写入「启动成功」标志。

这里有个关键点:「启动成功」标志是在应用固件完全初始化之后才写入的。如果固件在初始化到一半就挂了,这个标志就不会写进去。下次重启,Bootloader一看,嗯?上次没写成功标志?那说明这个分区有问题,换另一个!

我曾经见过一个设计,把「启动成功」标志放在Bootloader里写。结果呢?Bootloader刚跳转过去,还没等应用跑起来,就把标志写了。后来应用固件崩溃了,Bootloader还以为它跑得好好的。这叫什么?这叫自欺欺人。

我的建议:「启动成功」标志一定要由应用固件自己写。Bootloader只负责读。这是职责分离,也是安全底线。

2.4 升级流程:如何安全地更新固件?

假设当前系统从A分区启动,我们要升级到新版本。流程是这样的:

1. 地面发送升级指令,指定目标分区为B
2. 系统将新固件写入B分区(A分区仍在运行)
3. 写入完成后,对B分区做完整性校验
4. 校验通过后,在状态区标记B分区为「待验证」
5. 系统重启
6. Bootloader发现B分区标记为「待验证」,尝试从B启动
7. B分区启动成功,写入「启动成功」标志
8. 地面确认后,发送「提交」指令
9. 系统将B分区标记为「永久有效」,A分区变为「备用」

你发现没有?整个升级过程中,A分区一直在运行。就算B分区写坏了,系统重启后还是从A启动。这就是A/B架构的精髓——在线升级,离线备份

如果升级后发现问题怎么办?很简单。地面发送「回滚」指令,系统重启,Bootloader看到A分区还是好的,直接切回去。整个过程对卫星业务的影响,也就是一次重启的时间。

2.5 状态区的设计细节

状态区虽然只有4MB,但它的设计直接决定了整个系统的可靠性。我一般会在状态区里放这些东西:

  • 当前活动分区:0表示A,1表示B
  • 待验证分区:刚升级完,还没确认的分区
  • 启动计数器:每个分区连续启动失败的次数
  • 升级状态机:IDLE、WRITING、VERIFYING、COMMITTED等状态
  • 全局校验值:对整个状态区做CRC,防止状态区本身被破坏

这里有个小技巧。状态区的写入次数很频繁,尤其是启动计数器。如果直接用Flash的普通区域,没几次就把Flash写穿了。我建议用磨损均衡技术,或者干脆把状态区放在EEPROM或FRAM里。FRAM的写入寿命是10^12次,基本不用担心。

避坑指南:我曾经在一个项目里,把状态区放在Flash的同一个页面上。结果每次升级都擦写这个页面,半年后这个页面就坏了。后来改成FRAM,再也没出过问题。

2.6 双分区架构的变体

不是所有星载计算机都需要完整的A/B分区。根据任务需求,还有几种变体:

  • 完整A/B镜像:两个分区各放一套完整固件。可靠性最高,但存储开销大。
  • A/B增量分区:A分区放完整固件,B分区只放差异部分。节省空间,但回滚逻辑复杂。
  • 三分区架构:A、B、C三个分区。用于长寿命卫星,可以承受多次升级失败。
  • 黄金分区 + 工作分区:一个只读的黄金分区(出厂固件),一个可读写的工作分区。升级只改工作分区,出问题就回黄金分区。

我个人比较推荐完整A/B镜像。虽然占空间,但逻辑简单。在太空中,简单就是可靠。你想想看,一个复杂的回滚逻辑,万一在某个边界条件下出bug,那可就麻烦了。

2.7 小结

双分区备份架构,说白了就是「留一手」。永远给自己留一条退路。它的核心设计要点,我总结成三句话:

  • 分区独立:A和B互不干扰,各自有完整的固件和配置。
  • 状态可靠:状态区要防写穿、防篡改、防误读。
  • 回滚可控:任何时候都能回到上一个已知良好的版本。

下一章,我会讲Bootloader的具体实现。那是整个升级方案的「守门员」,也是最容易出坑的地方。咱们到时候细聊。