STM32H5(如 H503RB)擦写 FLASH 时触发 HardFault,核心原因是开启 ICACHE(指令缓存)后读取了 FLASH 的 RO(只读)区域(如 FLASHSIZE_BASE)——RO 区域默认不可缓存,缓存访问会引发总线错误。解决方案有两种:擦写前后关闭 / 重启 ICACHE,或通过 MPU 将 RO 区域设为 Non-cacheable,两种方案均可彻底规避异常。
资料获取:开发经验 | LAT1579 STM32H5擦写FLASH时意外触发hardfault
1. 问题背景:HardFault 的诡异触发场景
客户基于 STM32H503RB 开发,遇到关键异常:
- 异常现象:使能 ICACHE 以提升代码效率,在 FLASH 擦写前调用
GetSector函数(通过地址查找扇区)时,意外触发 HardFault; - 正常情况:关闭 ICACHE 后,FLASH 擦写、扇区查找均正常;
- 核心环境:STM32H503RB(双 bank FLASH,支持 read-while-write)、STM32CubeH5 例程 “FLASH_EraseProgram”、ICACHE 使能。
2. 问题复现:3 步必现异常
2.1 基础配置
- 基于官方 “FLASH_EraseProgram” 例程,保留 FLASH 擦写核心逻辑;
- 在
main函数开头使能 ICACHE:
2.2 关键修改(触发异常)
- 注释例程中 “擦写前关闭 ICACHE、擦写后重启” 的代码;
- 调用
GetSector函数查找目标地址对应的扇区:
2.3 定位关键触发点
- 单步调试发现:HardFault 触发在读取
FLASHSIZE_BASE(0x08FFF80CUL)时; - 该地址属于 FLASH 的 RO 区域,ICACHE 开启时缓存访问导致总线错误。
3. 根源拆解:RO 区域的缓存访问禁忌
3.1 RO 区域的定义与特性
根据 STM32H5 参考手册,FLASH 的 RO 区域范围为0x08FFF800~0x08FFFFFF,包含多个关键寄存器地址:
| 地址 | 定义 | 用途 |
|---|---|---|
| 0x08FFF800UL | UID_BASE | 唯一设备 ID 寄存器 |
| 0x08FFF80CUL | FLASHSIZE_BASE | FLASH 容量数据寄存器 |
| 0x08FFF80EUL | PACKAGE_BASE | 封装信息寄存器 |
- RO 区域通过 AHB 主接口访问,默认不可缓存;
- 手册明确要求:RO/OTP 区域需禁用缓存,否则需通过 MPU 配置 Non-cacheable 属性。
3.2 异常触发逻辑
- ICACHE 开启后,CPU 会缓存访问过的指令 / 数据,当读取 RO 区域时,缓存访问与 RO 区域的 “不可缓存” 属性冲突;
- 冲突引发总线错误,触发 Cortex-M33 内核的 HardFault 中断,且异常并非直接发生在 FLASH 擦写函数,而是前置的扇区查找(读取 FLASHSIZE_BASE)。
4. 解决方案:两种落地方法,按需选择
方法 1:擦写 FLASH 前后关闭 / 重启 ICACHE(简单直接)
核心逻辑:暂时关闭 ICACHE 规避 RO 区域访问冲突,擦写完成后重新开启以恢复性能,适配大多数场景。
核心代码示例
方法 2:MPU 配置 RO 区域为 Non-cacheable(无需关 ICACHE)
核心逻辑:通过 MPU 将 RO 区域(0x08FFF800~0x08FFFFFF)标记为 Non-cacheable,ICACHE 可持续开启,兼顾性能与兼容性,适合需要全程启用缓存的场景。
核心代码示例(MPU 配置)
使用说明
- 在
main函数开头先配置 MPU,再启用 ICACHE: - 后续 FLASH 擦写、扇区查找无需关闭 ICACHE,直接执行即可。
5. 关键注意:RO 区域全量地址表
除 FLASHSIZE_BASE 外,以下地址均属于 RO 区域,访问时需禁用缓存:
| 地址 | 宏定义 | 功能描述 |
|---|---|---|
| 0x08FFF800UL | UID_BASE | 唯一设备标识符(96 位) |
| 0x08FFF80CUL | FLASHSIZE_BASE | FLASH 容量寄存器(16 位) |
| 0x08FFF80EUL | PACKAGE_BASE | 封装类型寄存器(16 位) |
| 0x08FFF810UL | RESERVED | 保留 RO 区域 |
| 0x08FFF800~0x08FFFFFF | - | 完整 RO 区域范围 |
6. 开发经验小结
- RO/OTP 区域禁忌:STM32H5 的 RO、OTP 区域默认不可缓存,开启 ICACHE 后直接访问必触发 HardFault;
- 排查技巧:带 Cache 的 STM32 型号(H5/H7/G4 等)遇到不明 HardFault,可先关闭 ICACHE 排查 —— 缓存访问冲突是高频诱因;
- 方案选择:简单场景用 “关闭 / 重启 ICACHE”,性能敏感场景用 “MPU 配置”,后者无需中断缓存功能,更适合持续高性能需求;
- 双 bank 特性:STM32H5 的双 bank FLASH 支持 read-while-write,但不改变 RO 区域的缓存访问限制,不可混淆。
阅读全文
125