STM32开发学习——使用 Cortex-M3/M4/M7 故障异常原因与定位
文章目录
- STM32开发学习——使用 Cortex-M3/M4/M7 故障异常原因与定位
- 文档说明:
- 官方参考文档线上链接(可在线阅读与下载):
- 故障异常处理程序
- HardFault
- 优先级升级说明
- 故障状态寄存器
- 硬故障状态寄存器 (HFSR)
- UsageFault 状态寄存器 (UFSR)
- 总线故障状态寄存器 (BFSR) 和总线故障地址寄存器 (BFAR)
- MemManage 故障状态寄存器 (MMFSR) 和 MemManage 故障地址寄存器 (MMFAR)
- 堆栈恢复
- CPU 寄存器恢复
 
 
文档说明:
分享一下在Stm32学习过程收集到的一些值得记录的好资料,以便自己保留印象和尽可能的应用到工作中,达到事半功倍的效果。
这是一篇关于Cortex-M内核故障异常原因的说明与定位的分享。
官方参考文档线上链接(可在线阅读与下载):
MDK:AN209
SEGGER:AN00016_AnalyzingHardFaultsOnCortexM
Cortex-M故障 - SEGGER Wiki
故障异常处理程序
-  HardFault:是默认异常,检测指令获取、数据读/写、中断向量获取和中断(进入/退出)的寄存器堆叠(保存/恢复)时的内存访问错误。 HardFault 的固定优先级为 -1,即它比除 NMI 之外的所有其他中断和异常具有更高的优先级。 因此,当应用程序代码中发生错误、中断或其他异常时,始终可以输入 HardFault 异常处理程序。 HardFault 是 IRQ 编号为 -13 的向量表中的异常编号 3。 
-  MemManage:检测内存管理单元 (MPU) 中定义的区域的内存访问冲突;例如,从仅具有读/写访问权限的内存区域执行代码。 MemManage 是向量表中的异常编号 4,IRQ 编号 -12,具有可配置的优先级。 
-  BusFault:检测指令获取、数据读/写、中断向量获取和中断(进入/退出)寄存器堆叠(保存/恢复)时的内存访问错误。 BusFault 是向量表中的异常编号 5,IRQ 编号为 -11,具有可配置的优先级。 可以在系统控制块 (SCB) 中显式启用总线故障。当未启用 BusFault 时,将引发 HardFault。 
-  UsageFault:检测未定义指令的执行,加载/存储多个的未对齐内存访问。启用后,将检测到除以零和其他未对齐的内存访问。 UsageFault 是向量表中的异常编号 6,IRQ 编号为 -10,并且具有可配置的优先级。 如果未启用 UsageFault,则会引发 HardFault。 
 
HardFault
HardFault 异常始终处于启用状态,并具有固定的优先级(高于其他中断和异常,但低于不可屏蔽中断 NMI)。因此,在禁用故障异常或在执行故障异常处理程序期间发生故障时,将执行 HardFault 异常。所有其他故障异常(MemManage 故障、BusFault 和 UsageFault)都具有可编程的优先级。复位后,这些异常将被禁用,并且可以使用系统控制块 (SCB) 中的寄存器在系统或应用软件中启用。
优先级升级说明
通常,异常优先级与异常掩码寄存器的值一起确定处理器是否进入错误处理程序,以及错误处理程序是否可以抢占另一个错误处理程序。在某些情况下,具有可配置优先级的故障被视为 HardFault。这称为优先级升级,故障被描述为升级为 HardFault。在以下情况下,将升级到 HardFault:
- 故障处理程序导致的故障类型与它所处理的故障类型相同。之所以发生这种向 HardFault 升级的原因是处理程序无法抢占自身(它必须具有与当前优先级相同的优先级)。
- 故障处理程序导致的故障优先级与其所处理的故障相同或更低。这是因为新错误的处理程序无法抢占当前正在执行的错误处理程序。
- 异常处理程序会导致优先级等于或低于当前正在执行的异常的错误。
- 发生故障,但未启用该故障的处理程序。
故障状态寄存器
硬故障状态寄存器 (HFSR)
HFSR 位于 SCB 的地址 0xE000ED2C。 它是一个 32 位寄存器。
[31] DEBUGEVT - Reserved for use by debugger/debug probe. Always write 0.
[30] FORCED   - If 1, HardFault has been caused by escalation of another exception, because it is disabled or because of priority.
[1]  VECTTBL  - If 1, a BusFault occurred by reading the vector table for exception processing.
UsageFault 状态寄存器 (UFSR)
UFSR 是一个 16 位伪寄存器,是地址 0xE000ED28 处可配置故障状态寄存器 (CFSR) 的一部分。 它也可以直接访问,半字访问0xE000ED2A。
[9] DIVBYZERO  - If 1, SDIV or UDIV instruction executed with divisor 0.
[8] UNALIGNED  - If 1, LDM, STM, LDRD, STRD on unaligned address executed, or single load or store executed when enabled to trap.
[3] NOCP       - If 1, access to unsupported (e.g. not available or not enabled) coprocessor.
[2] INVPC      - If 1, illegal or invalid EXC_RETURN value load to PC.
[1] INVSTATE   - If 1, execution in invalid state. E.g. Thumb bit not set in EPSR, or invalid IT state in EPSR.
[0] UNDEFINSTR - If 1, execution of undefined instruction.
总线故障状态寄存器 (BFSR) 和总线故障地址寄存器 (BFAR)
BFSR 是 CFSR 中的 8 位伪寄存器。它可以通过字节访问地址0xE000ED29直接访问。 BFAR 是一个 32 位寄存器,0xE000ED38。
[7] BFARVALID   - If 1, the BFAR contains the address which caused the BusFault.
[5] LSPERR      - 1f 1, fault during floating-point lazy stack preservation.
[4] STKERR      - If 1, fault on stacking for exception entry.
[3] UNSTKERR    - If 1, fault on unstacking on exception return.
[2] IMPRECISERR - If 1, return address is not related to fault, e.g. fault caused before.
[1] PRECISERR   - If 1, return address instruction caused the fault.
[0] IBUSERR     - If 1, fault on instruction fetch.
MemManage 故障状态寄存器 (MMFSR) 和 MemManage 故障地址寄存器 (MMFAR)
MMFSR 是 CFSR 中的 8 位伪寄存器。它可以通过字节访问地址xE000ED28直接访问。 MMFAR 是一个 32 位寄存器,xE000ED34。
[7] MMARVALID - If 1, the MMFAR contains the address which caused the MemManageFault.
[5] MLSPERR   - 1f 1, fault during floating-point lazy stack preservation.
[4] MSTKERR   - If 1, fault on stacking for exception entry.
[3] MUNSTKERR - If 1, fault on unstacking on exception return.
[1] DACCVIOL  - If 1, data access violation.
[0] IACCVIOL  - If 1, instruction access violation.
堆栈恢复
在异常输入时,异常处理程序可以检查故障发生时使用了哪个堆栈。 当设置位 EXC_RETURN[2] 时,已使用 MSP,否则已使用 PSP。
堆栈可用于恢复 CPU 寄存器值。
CPU 寄存器恢复
在异常输入时,一些 CPU 寄存器存储在堆栈中,可以从那里读取以进行错误分析。 以下寄存器是可恢复的:
 r0       = pStack[0];  // Register R0r1       = pStack[1];  // Register R1r2       = pStack[2];  // Register R2r3       = pStack[3];  // Register R3r12      = pStack[4];  // Register R12lr       = pStack[5];  // Link register LRpc       = pStack[6];  // Program counter PCpsr.byte = pStack[7];  // Program status word PSR