STM32H5 开启 STiROT(ST immutable Root of Trust)安全不可变根信任启动功能后,会出现一类隐蔽故障:同样一套应用代码,不开启 STiROT 时 IWDG 独立看门狗运行完全正常;完成 STiROT Provisioning 配置之后,上电持续发生看门狗复位。
从日志现象看,明明代码已经调用HAL_IWDG_Refresh()喂狗,但喂狗操作实际没有生效,MCU 反复重启。该问题不是业务逻辑 BUG,是 STiROT 启动流程带来 IWDG 寄存器写保护状态异常导致。本文基于 LAT1682 官方案例还原复现代码、现象、根因、临时修复方案以及工程注意事项。
资料获取:实战经验 | LAT1682 使用STiROT后看门狗意外复位问题分析
1. 故障现象复现
1.1 测试条件
- 硬件:STM32H573‑DK 开发板;
- 工程:STM32CubeMX 生成 STiROT 示例工程,应用内部启用 IWDG 独立看门狗;
- 两组对比测试:
- 不开启 STiROT:程序正常运行,看门狗不会触发复位;
- 开启 STiROT 并且完成 Provisioning 配置:上电反复 IWDG 看门狗复位。
1.2 关键测试代码片段
HAL_Init();
__HAL_FLASH_PREFETCH_BUFFER_ENABLE();
SCB->VTOR = 0xC000400;
HAL_MPU_Disable();
HAL_MPU_Disable_NS();
HAL_ICACHE_Disable();
SystemClock_Config();
MX_GTZC_S_Init();
MX_GPIO_Init();
MX_USART1_UART_Init();
printf("IWDG1‑PR:0x%x,RLR:0x%x,WINR:0x%x,SR:0x%x\r\n",
hiwdg.Instance->PR,hiwdg.Instance->RLR,hiwdg.Instance->WINR,hiwdg.Instance->SR);
MX_IWDG_Init();
HAL_IWDG_Refresh(&hiwdg); //执行喂狗
printf("IWDG2‑PR:0x%x,RLR:0x%x,WINR:0x%x,SR:0x%x\r\n",
hiwdg.Instance->PR,hiwdg.Instance->RLR,hiwdg.Instance->WINR,hiwdg.Instance->SR);
HAL_IWDG_Refresh(&hiwdg);
if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST) != 0x00u)
{
printf("IWDG reset.\r\n");
}
__HAL_RCC_CLEAR_RESET_FLAGS();
while (1)
{
HAL_IWDG_Refresh(&hiwdg);
HAL_Delay(500);
HAL_GPIO_TogglePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin);
HAL_IWDG_Refresh(&hiwdg);
//……其余LED翻转、喂狗逻辑
}
1.3 串口日志现象
打印输出只能看到前半段寄存器打印,随后直接触发看门狗复位。
现象解读:MX_IWDG_Init()执行完毕,紧接着调用HAL_IWDG_Refresh()喂狗,但是喂狗动作并未真正生效,IWDG 计数器递减到 0,触发系统复位。修改看门狗超时时间参数,故障依旧,说明和超时时间配置本身无关。
2. 根因定位:STiROT 执行后 IWDG 处于写保护锁定状态
STiROT 是芯片 ROM 内置的第一级引导代码,芯片上电复位后优先运行 STiROT。STiROT 运行阶段会操作 IWDG 外设,结束之后IWDG 寄存器维持在写保护开启状态。
虽然 HAL 库内部MX_IWDG_Init()初始化函数内部包含打开 IWDG 写保护的逻辑,但在 STiROT 场景下,该内部解锁流程无法正常生效,后续的重装载、喂狗操作无法真正写入硬件寄存器。上层应用调用HAL_IWDG_Refresh()只是执行库函数,硬件 IWDG 计数器得不到重装载,最终计数器下溢触发看门狗复位。
关键点:没有开启 STiROT 时,复位后 IWDG 写保护状态符合 HAL 库预期,初始化流程可以正常工作;一旦经过 STiROT 执行流程,IWDG 写保护处于异常锁定,直接调用 MX_IWDG_Init 无法完成解锁。
3. 临时修复代码方案
在调用MX_IWDG_Init()看门狗初始化之前,手动执行 IWDG 写保护开启访问,增加少量延时,再执行初始化。
hiwdg.Instance = IWDG;
__HAL_IWDG_START(&hiwdg);
IWDG_ENABLE_WRITE_ACCESS(&hiwdg); //手动打开IWDG写访问权限
HAL_Delay(1);
HAL_Delay(1); //增加短延时,等待硬件状态生效
MX_IWDG_Init(); //再执行看门狗初始化
增加以上前置代码之后,STiROT 模式下看门狗可以正常初始化,HAL_IWDG_Refresh()喂狗操作硬件生效,不再发生意外看门狗复位。
文档提示:该问题属于当前 HAL 库版本下的临时规避手段,后续 HAL 库版本更新有可能修复该行为,实际项目需要关注固件包版本更新说明。
4. 工程落地排查清单
4.1 现象:开启 STiROT 就反复 IWDG 复位,关闭 STiROT 运行正常
- 在
MX_IWDG_Init()之前增加手动IWDG_ENABLE_WRITE_ACCESS()解锁以及短延时; - 确认 STiROT 配置项,确认 IWDG 是软件启动模式,区分选项字节硬件启动 IWDG 场景;
- 抓取复位标志位
RCC_FLAG_IWDGRST确认确实是 IWDG 产生的复位,排除其它复位源干扰。
4.2 开发注意事项
- 故障只出现在经过 STiROT 引导启动的路径;普通不启用 STiROT 的启动流程不受该问题影响;
- 不能单纯依靠修改看门狗超时时间来规避,该故障与超时参数无关;
- 该规避方案为当前 HAL 库版本下临时 workaround,升级 STM32CubeH5 固件包之后,需要重新验证该问题是否已经被修复,不要永久固化 workaround;
- IWDG 属于独立看门狗,依靠 LSI 低速 RC 时钟,不受主系统时钟影响,调试时注意 DebugMCU 对 IWDG 计数器冻结配置。
5. 小结
- STM32H5 开启 STiROT 安全启动后,STiROT ROM 代码运行完毕会让 IWDG 外设维持写保护锁定状态;原生自动生成的
MX_IWDG_Init()内部解锁逻辑在此场景下失效,上层调用HAL_IWDG_Refresh()喂狗无法写入硬件,计数器下溢,产生反复看门狗复位。 - 故障特征:关闭 STiROT 一切正常;开启 STiROT 后即使代码频繁调用喂狗,依旧复位;修改看门狗超时时间不能消除故障。
- 临时解决方法:在
MX_IWDG_Init()初始化函数调用之前,手动调用IWDG_ENABLE_WRITE_ACCESS()打开写访问,配合短延时,再执行看门狗初始化。 - 该方案属于当前 HAL 库版本的临时规避措施,后续升级 STM32CubeH5 固件包需要复测,确认库是否已经修复该特殊场景的初始化逻辑。
6. FAQ
Q:为什么关闭 STiROT 的时候,不需要手动 IWDG_ENABLE_WRITE_ACCESS?
A:不经过 STiROT 执行流程,系统复位后 IWDG 写保护状态符合 HAL 库预期,MX_IWDG_Init()内部解锁逻辑可以正常工作;STiROT 运行改变了 IWDG 写保护硬件状态,带来该特殊场景问题。
Q:选项字节开启硬件 IWDG 自动启动,会不会遇到同样问题?
A:硬件模式 IWDG 上电自动启动,该场景需要参考 AN6007 STiROT 官方文档说明,和本案例软件初始化 IWDG 场景不完全等同,需要单独验证。
Q:升级新版本 STM32CubeH5 固件包,还需要保留这一段 workaround 代码吗?
A:不一定,文档提示该问题未来库版本可能修复,升级之后要做 STiROT 完整上电复现测试,如果现象消失,可以移除手动解锁代码。
免责声明:本文全部基于 ST 官方 LAT1682 文档,该代码为临时规避手段,产品项目请结合 STM32CubeH5 固件版本、AN6007 STiROT 官方文档进行验证。
132