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