3. 双Bank机制核心概念

在STM32的双Bank固件升级方案中,真正决定“升级是否安全、回滚是否可靠”的,并不是Flash容量大小,而是四个核心概念:Bank交换、Bank激活、启动映射,以及双Bank与双分区的本质区别。理解这四个概念,才能正确设计升级流程、Bootloader跳转逻辑和回滚策略。

一、Bank交换:让“备用区”变成“运行区”

双Bank机制最直观的理解是:芯片内部有两块物理上独立的Flash存储区,分别称为Bank1和Bank2。当前正在运行的固件位于其中一个Bank,新固件被写入另一个Bank。升级完成后,系统通过一次“交换”动作,让新固件所在的Bank成为启动目标。

这里的“交换”并不是把两块Flash的数据互相搬运,而是通过配置选项字节中的Bank交换标志(SWAP_BANK),改变Bank1和Bank2在地址空间中的映射关系。交换后,原本位于Bank2的固件会映射到Bank1的启动地址,CPU从复位向量开始执行时,实际取到的是新固件。

关键点:Bank交换改变的是“地址映射关系”,不是“数据内容”。因此交换动作极快,且不会产生擦写损耗。

二、Bank激活:决定哪块Bank真正参与启动

Bank激活与Bank交换经常被混为一谈,但二者关注点不同。Bank交换解决“地址怎么映射”,Bank激活解决“哪块Bank被允许启动”。在STM32中,激活状态通常由选项字节中的nSWAP_BANK、nBOOT0、nBOOT1等位共同决定,部分系列还涉及SECURITY和BOOT_LOCK。

一个典型的激活流程如下:

  1. Bootloader检查升级标志,确认新固件已完整写入备用Bank;
  2. 校验新固件头部、CRC或签名,确保镜像有效;
  3. 写入选项字节,设置SWAP_BANK,使备用Bank成为启动Bank;
  4. 触发系统复位,CPU从新的启动映射地址取指;
  5. 若新固件启动失败,Bootloader再次交换回原Bank,完成回滚。

因此,Bank激活不是单一寄存器操作,而是一组“校验—配置—复位—确认”的状态迁移过程。

三、启动映射:复位向量从哪里取

STM32上电或复位后,CPU从0x0000_0000地址取出MSP初值,从0x0000_0004取出复位向量。双Bank机制下,这个地址空间会根据SWAP_BANK位被重映射到Bank1或Bank2的起始地址。

理解启动映射时,需要区分三个地址概念:

  • 物理地址:Bank1和Bank2各自真实的Flash地址,如0x0800_0000和0x0804_0000;
  • 映射地址:CPU看到的0x0000_0000区域,由SWAP_BANK决定指向哪个物理Bank;
  • 向量表偏移:固件内部通过SCB->VTOR设置中断向量表位置,通常与APP起始地址一致。

如果Bootloader和APP都使用双Bank,必须保证向量表偏移与当前激活Bank一致,否则会出现“能启动但中断跑飞”的典型故障。

双Bank启动映射与激活关系 CPU 复位取指 0x0000_0000 MSP + Reset Vector 启动映射选择 SWAP_BANK 位 nSWAP_BANK / BOOT 配置 Bank1 物理区 0x0800_0000 当前运行固件 A 状态:激活 / 运行中 Bank2 物理区 0x0804_0000 新固件 B(已写入) 状态:待激活 / 备用 交换前 交换后 Bank 激活状态迁移 运行 Bank1 固件 A 写入 Bank2 固件 B 交换激活 复位 回滚路径:若固件 B 启动失败,Bootloader 再次交换 SWAP_BANK 使 Bank1 重新映射到启动地址,恢复固件 A 运行 失败回滚

四、双Bank与双分区的本质区别

很多工程师会把“双Bank”和“双分区”当成同一件事,实际上二者在硬件支持、切换方式和可靠性上差异明显。

对比维度 双Bank 双分区
硬件基础 芯片内部两块独立Flash Bank,有专用选项字节 同一块Flash内人为划分两个区域
切换方式 配置SWAP_BANK,硬件级地址重映射 由Bootloader跳转地址决定,软件级
切换速度 极快,仅改选项字节后复位 取决于跳转逻辑,通常也较快
回滚能力 硬件映射可逆,回滚可靠 依赖Bootloader实现,需自行保证
擦写并行 支持RWW,读写可并行 同一Bank内无法真正并行
适用场景 高可靠OTA、安全升级 资源受限、无Bank硬件支持的芯片

五、典型误区与复盘

误区一:认为交换Bank就是把数据复制过去。实际上交换只改映射,数据仍在原物理位置。
误区二:只改SWAP_BANK却不更新VTOR,导致中断向量仍指向旧Bank,出现HardFault。
误区三:把双分区方案直接套用到双Bank芯片上,浪费了硬件RWW和硬件回滚能力。

一个可靠的工程实践是:在Bootloader中维护一个升级状态结构体,记录当前激活Bank、待激活Bank、固件版本和校验结果。每次复位后先读取该结构体,再决定是否执行交换。这样即使升级过程中断电,也能通过状态机恢复到已知安全状态。

typedef struct {
    uint32_t magic;          // 0x5A5A1234
    uint8_t  active_bank;    // 0: Bank1, 1: Bank2
    uint8_t  pending_bank;   // 待激活Bank
    uint8_t  upgrade_state;  // IDLE / WRITING / READY / SWAPPED
    uint32_t fw_version;
    uint32_t fw_crc;
} upgrade_ctrl_t;

总结来说,Bank交换解决“地址映射”,Bank激活解决“启动选择”,启动映射解决“复位向量从哪里取”,而双Bank与双分区的区别则决定了方案是否具备硬件级可靠回滚能力。四者配合,才能构成STM32双Bank固件升级的完整基础。