HardFault 不是根因,而是 Cortex-M 无法继续执行时交给你的最后一份现场。异常入口会自动保存一部分寄存器;故障处理程序只要把这份栈帧、SCB 状态寄存器和固件版本保存下来,通常就能把“设备偶尔死机”缩小到具体的指令地址和访问类型。
先判断异常使用了哪一个栈
线程模式可能使用 PSP,异常和启动代码常用 MSP。HardFault 包装函数需要根据 EXC_RETURN 判断自动压栈的寄存器帧来自哪个栈,再把其中的 pc、lr、xpsr 复制到可靠的存储区域。只打印处理函数自己的调用栈,往往看不到真正出错的任务。
保存后可以用与固件完全匹配的 ELF 解析地址:
1 | arm-none-eabi-addr2line -e firmware.elf -f -C 0x08001234 |
地址、优化级别和符号文件必须对应同一次构建。若使用了 bootloader 或链接脚本重定位,也要先确认记录的 PC 是逻辑地址还是实际映射地址。
异常处理路径越短越好
故障处理程序不应申请堆内存、等待锁、访问可能已经坏掉的外设驱动,也不要依赖串口日志一定能发出去。更稳妥的是把寄存器、状态和少量栈内容写进保留 RAM 或预先准备好的 Flash 槽,随后复位;下一次启动再把转储上传并符号化。这样一次二次故障不会把唯一的线索冲掉。
参考:CmBacktrace