• 正文
  • 相关推荐
申请入驻 产业图谱

STM32C5的双Bank:让升级不在停机

09/18 08:23
292
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

嵌入式开发里有个长期存在的限制:CPU 从 Flash 取指,而 Flash 的擦除和编程会占用存储阵列。所以一旦你开始写 Flash,程序就没法继续跑——不是变慢,是停下来。

前段时间 ST 推出了 STM32C5 系列。144 MHz 的 Cortex-M33,最大 1024 KB Flash、256 KB SRAM,定位是入门到中端这一档仔,细翻手册,注意到里面有一个双 Bank 功能。

(Bank在自动翻译被翻译成了银行)它列出双 Bank 结构支持三件事:

一是同时操作——读-写并行是支持的,擦除和编程都算在内。

二是两个 Bank 共享同一个接口。这句话看着像补充说明,其实是个限定:读和写能并行,写和写不能。两个 Bank 的编程和擦除走同一套控制接口,没法真正同时做。

三是 Bank 交换——两个 Bank 的用户 Flash 地址映射可以对调,相应的寄存器也一起交换。后面还跟了一句安全说明:安全标志对物理 Bank 保持有效,所以数据不会因为交换到安全配置更低的 Bank 而泄露。

本期我们介绍一下STM32的双 Bank 功能作用以及如何使用。

1、双BANK并不是直接分两半

以 STM32C562RET6 为例。它的用户 Flash 是 512 KB,在 stm32c562xx.h 里定义得很清楚:

#define FLASH_SIZE_MAX      (0x00080000UL)  /* 512 Kbytes user flash */#define FLASH_BANK_SIZE     (FLASH_SIZE >> 1U)  /* 256 Kbytes per bank */#define FLASH_PAGE_SIZE     0x2000U         /* 8 Kbytes pages */#define FLASH_BANK_NB       (2U)#define FLASH_PAGE_NB       (FLASH_BANK_SIZE/FLASH_PAGE_SIZE)

512 KB 平分,每个 Bank 256 KB,页大小 8 KB,每 Bank 32 页。Bank 1 从 0x08000000 开始,Bank 2 从 0x08040000 开始。

关键在于这两个 Bank 有独立的存储阵列。Bank 2 在擦除时占用的是它自己的阵列,Bank 1 的读通路不受影响,CPU 继续从 Bank 1 取指,中断照常进。这就是手册里说的 read-while-write。

这里有个容易误解的地方,手册讲得很明确:两个 Bank 共享同一个接口。所以读和写可以并行,写和写不行——两个 Bank 的编程和擦除走的是同一套控制接口,没法真正同时做。不能指望两个 Bank 能同时进入编程状态做并行写入。

除了 RWW,双 Bank 还提供 Bank 交换:两个 Bank 的地址映射可以对调,让原本从 0x08000000 取指的代码实际执行物理 Bank 2 的内容。这是硬件级的地址重定向,重启后切换固件分区靠的就是它。地址映射对调时,相关的配置寄存器也跟着一起交换。

从HAL的接口能看出这一层。stm32c5xx_hal_flash_itf.c里同时提供了一组功能:

HAL_FLASH_ITF_OB_SetBankTopology()   /* 设置单/双 Bank */HAL_FLASH_ITF_OB_GetBankTopology()   /* 读取当前配置 */HAL_FLASH_ITF_OB_SetBankSwap()       /* 设置 Bank 交换 */HAL_FLASH_ITF_OB_IsBankSwapped()     /* 查询是否已交换 */

SetBankTopology 的说明里有一句限定:"for products with less user memory"。也就是说,对于容量较小的型号,Flash 可以在单 Bank 和双 Bank 之间通过选项字节切换。一旦配成单 Bank,整个 Flash 视作一个连续阵列,RWW 就不存在了,你写 Flash 的时候 CPU 一样要停。

SetBankSwap 则是另一个方向的用法。它可以让 Bank 的物理地址映射对调,配合双 Bank 就能做"在 A 区跑、把新固件写进 B 区,重启后切换"的升级流程。双 Bank 的价值不止 RWW 一项,它同时是可靠 OTA 的基础。

2、RRW测试

接着博主在 NUCLEO-C562RE 上跑了一个简单的RRW测试:用 HAL_FLASH_EraseByAddr() 擦掉整个 Bank 2,然后切到 Quad-Word 模式写入几个测试字,再回读校验。

代码和中断向量全部链接在 Bank 1:

ROM (rx) : org = 0x8000000, len = 0x40000

擦除范围从 0x08040000 开始,长度 256 KB。这条边界和代码所在的区间完全不重叠,所以擦除期间取指不发生冲突。SysTick 持续的计数。SysTick 每 1 ms 进一次回调,主程序在擦除前记下计数值,擦除返回后比对:

rww_irq_count = 0;irq_count_before = rww_irq_count;rww_phase = RWW_PHASE_ERASING;if (HAL_FLASH_EraseByAddr(hflash, FLASH_BANK2_BASE_ADDR,                          FLASH_BANK2_SIZE, FLASH_TIMEOUT_MS) != HAL_OK){  rww_phase = RWW_PHASE_FAIL;}elseif (rww_irq_count == irq_count_before){  rww_phase = RWW_PHASE_FAIL;}

一次 256 KB 的擦除是阻塞式调用,前台会一直卡在里面。如果这段期间中断计数纹丝不动,说明 CPU 根本没在执行别的代码,RWW 就没实现;计数增长,才证明中断确实从 Bank 1 正常响应了。

这个判据的好处是它会失败。把它放到单 Bank 配置下,或者把擦除地址改成 Bank 1 自己所在的区间,rww_irq_count 就不会变,程序会直接判 FAIL。

同时,使用一个定期来改变,LED 的闪烁频率。擦除和编程期间 PA5 每 25 ms 翻转一次,心跳很快;成功之后放慢到 500 ms;失败则用 100 ms 的快闪区分。人眼看到擦除过程中灯还在快速闪,用来判断 RWW 是否在工作。

3、注意事项

中断向量和中断服务程序的位置是硬约束。 RWW 生效的前提是执行代码不在被操作的 Bank 里。链接脚本里把 .isr_vector、.text 放在 0x08000000 起的 256 KB 内,是这套方案成立的一部分,不是可选的优化。如果你后续改动了内存布局,把一部分代码放到了 Bank 2,那部分代码在擦 Bank 2 期间就不可用。

擦除耗时决定了你的实时性预算。 RWW 解决的是"能不能继续运行",不是"擦除变快了"。前台仍然被阻塞在擦除调用里,只是中断能进来。如果应用里有硬实时的中断任务,还得算清楚最坏情况下的中断延迟是否可接受——可以进一步考虑用 HAL_FLASH_EraseByAddr_IT() 这样的中断版本,把阻塞也去掉。

结语

有的方案靠 RAM 执行加一次短停摆凑合,有的干脆上双机热备,双 Bank 的意义可以概括成一句话:它把"更新 Flash"从一件必须停机的事,变成了一件可以和主程序并行的事。对需要在现场升级固件、又不能让设备停机的产品,这一条就够决定选型了。

相关推荐

嵌入式开发兴趣爱好者,热衷于电子信息技术,嵌入式开发,物联网技术等领域开发。