HardFault_Handler
This commit is contained in:
@@ -145,3 +145,102 @@ void SVC_Handler_C(os_uintptr_t* svc_args){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
/* */
|
||||||
|
|
||||||
|
// https://interrupt.memfault.com/blog/cortex-m-hardfault-debug
|
||||||
|
// Logic for dealing with the exception. Typically:
|
||||||
|
// - log the fault which occurred for postmortem analysis
|
||||||
|
// - If the fault is recoverable,
|
||||||
|
// - clear errors and return back to Thread Mode
|
||||||
|
// - else
|
||||||
|
// - reboot system
|
||||||
|
|
||||||
|
|
||||||
|
#define AUTO_REBOOT_ENABLE /* 允许自动重启 */
|
||||||
|
#define OUTPUT_FAULT_TO_CONSOLE_ENABLE /* 在调试终端输出运行时信息 */
|
||||||
|
#define RECOVER_FROM_FAULT_ENABLE /* 尝试从错误中继续运行 */
|
||||||
|
|
||||||
|
#if defined(RECOVER_FROM_FAULT_ENABLE)
|
||||||
|
static void recover_from_task_fault(void){
|
||||||
|
while(1){
|
||||||
|
os_task_yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef OS_PACKED_STRUCT(ContextStateFrame) {
|
||||||
|
uint32_t r0;
|
||||||
|
uint32_t r1;
|
||||||
|
uint32_t r2;
|
||||||
|
uint32_t r3;
|
||||||
|
uint32_t r12;
|
||||||
|
uint32_t lr;
|
||||||
|
uint32_t return_address;
|
||||||
|
uint32_t xpsr;
|
||||||
|
} ContextStateFrame_t;
|
||||||
|
|
||||||
|
void HardFault_Handler_C(ContextStateFrame_t* frame, uint32_t lr_value){
|
||||||
|
uint32_t bus_fault_address = SCB->BFAR;
|
||||||
|
uint32_t mem_manage_fault_address = SCB->MMFAR;
|
||||||
|
uint32_t cfsr = SCB->CFSR;
|
||||||
|
|
||||||
|
#if defined(AUTO_REBOOT_ENABLE)
|
||||||
|
const uint32_t usage_fault_mask = 0xffff0000;
|
||||||
|
const bool non_usage_fault_occurred =
|
||||||
|
(cfsr & ~usage_fault_mask) != 0;
|
||||||
|
// the bottom 8 bits of the xpsr hold the exception number of the
|
||||||
|
// executing exception or 0 if the processor is in Thread mode
|
||||||
|
const bool faulted_from_exception = ((frame->xpsr & 0xFF) != 0);
|
||||||
|
|
||||||
|
if (faulted_from_exception || non_usage_fault_occurred) {
|
||||||
|
// For any fault within an ISR or non-usage faults
|
||||||
|
// let's reboot the system
|
||||||
|
volatile uint32_t *aircr = (volatile uint32_t *)0xE000ED0C;
|
||||||
|
*aircr = (0x05FA << 16) | 0x1 << 2;
|
||||||
|
while (1) { } // should be unreachable
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(OUTPUT_FAULT_TO_CONSOLE_ENABLE)
|
||||||
|
printf("[HardFault]\n");
|
||||||
|
printf("- Stack frame:\n");
|
||||||
|
printf(" R0 = %08"OS_PRIx"\n", frame->r0);
|
||||||
|
printf(" R1 = %08"OS_PRIx"\n", frame->r1);
|
||||||
|
printf(" R2 = %08"OS_PRIx"\n", frame->r2);
|
||||||
|
printf(" R3 = %08"OS_PRIx"\n", frame->r3);
|
||||||
|
printf(" R12 = %08"OS_PRIx"\n", frame->r12);
|
||||||
|
printf(" LR = %08"OS_PRIx"\n", frame->lr);
|
||||||
|
printf(" PC = %08"OS_PRIx"\n", frame->return_address);
|
||||||
|
printf(" PSR = %08"OS_PRIx"\n", frame->xpsr);
|
||||||
|
printf("- FSR/FAR:\n");
|
||||||
|
printf(" CFSR = %08"OS_PRIx"\n", cfsr);
|
||||||
|
printf(" HFSR = %08"OS_PRIx"\n", SCB->HFSR);
|
||||||
|
printf(" DFSR = %08"OS_PRIx"\n", SCB->DFSR);
|
||||||
|
printf(" AFSR = %08"OS_PRIx"\n", SCB->AFSR);
|
||||||
|
if(cfsr & 0x0080){
|
||||||
|
printf(" MMFAR = %08"OS_PRIx"\n", mem_manage_fault_address);
|
||||||
|
}
|
||||||
|
if(cfsr & 0x8000){
|
||||||
|
printf(" BFAR = %08"OS_PRIx"\n", bus_fault_address);
|
||||||
|
}
|
||||||
|
printf("- Misc:\n");
|
||||||
|
printf(" LR/EXC_RETURN = %08"OS_PRIx"\n", lr_value);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(RECOVER_FROM_FAULT_ENABLE)
|
||||||
|
// Clear any logged faults from the CFSR
|
||||||
|
SCB->CFSR |= SCB->CFSR;
|
||||||
|
// the instruction we will return to when we exit from the exception
|
||||||
|
frame->return_address = (uint32_t)recover_from_task_fault;
|
||||||
|
// the function we are returning to should never branch
|
||||||
|
// so set lr to a pattern that would fault if it did
|
||||||
|
frame->lr = 0xdeadbeef;
|
||||||
|
// reset the psr state and only leave the
|
||||||
|
// "thumb instruction interworking" bit set
|
||||||
|
frame->xpsr = (1 << 24);
|
||||||
|
#else
|
||||||
|
while(1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,5 +67,15 @@ __PendSV_SwitchTo
|
|||||||
|
|
||||||
ENDP
|
ENDP
|
||||||
|
|
||||||
|
HardFault_Handler PROC
|
||||||
|
EXPORT HardFault_Handler
|
||||||
|
tst lr, #4 // 检查 EXC_RETURN (LR) 的位 2
|
||||||
|
ite eq
|
||||||
|
mrseq r0, msp // 如果位 2 是 0,栈帧在 MSP
|
||||||
|
mrsne r0, psp // 如果位 2 是 1,栈帧在 PSP
|
||||||
|
mov r1, lr
|
||||||
|
b HardFault_Handler_C // 跳转到 C 实现,r0 作为第一个参数传入
|
||||||
|
ENDP
|
||||||
|
|
||||||
END
|
END
|
||||||
|
|
||||||
|
|||||||
@@ -76,5 +76,18 @@ cpu_clz:
|
|||||||
CLZ R0, R0
|
CLZ R0, R0
|
||||||
BX LR
|
BX LR
|
||||||
|
|
||||||
|
.section .text.HardFault_Handler,"ax",%progbits
|
||||||
|
.global HardFault_Handler
|
||||||
|
.thumb_func
|
||||||
|
HardFault_Handler:
|
||||||
|
tst lr, #4
|
||||||
|
ite eq
|
||||||
|
mrseq r0, msp
|
||||||
|
mrsne r0, psp
|
||||||
|
mov r1, lr
|
||||||
|
b HardFault_Handler_C
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.align 4
|
.align 4
|
||||||
.end
|
.end
|
||||||
Reference in New Issue
Block a user