Several reasons may lead to a hard fault, for example, calling a function pointer with an invalid address, stack overflow, trying to read or write to an on-chip peripheral that is powered down or not being clocked, accessing non-mapped memory etc. It is often difficult to find out what caused the hard fault, fortunately the cortex-M stores some information in ARM fault status register, the hardware automatically pushes several CPU register on the stack before entering the Hard Fault Handler. This document below shows a way to debug a Hard Fault in MQX.
For Hard Fault, we can hook our exception handler into the vector table. we will find vector table in the vector.c source file in the BSP library. By default, isr is configured to DEFAULT_VECTOR, which is the _int_kernel_isr() function of the MQX dispatcher. We cam put our own function, like void my_kernel_isr (void), to vector table offset 0x0c.
Inside my_kernel_isr(), we can get the interrupt stack frame, CPU register content at the time of exception and use directly the my_kernel_isr - just remove the static keyword, as we need the my_kernel_isr to be global, as it is referenced from vectors.c and it will be implemented in the application, main.c, for example.
Now, put breakpoint to this my_kernel_isr and see the registers read by prvGetRegistersFromStack(). Typically at most interest would by "lr" and "pc". For example, "lr" would have an address of an instruction that a return from a function call would return to.
By looking into the .map file or using the debugger, we will know, which function has been executed by the CPU when exception occurred.
Hook our own kernel isr into the vector table
In file vectors.c, the default ISR for Hard_Fault is DEFAULT_VECTOR
Now we modified it to my_kernel_isr, so when hard fault happens, my_kernel_isr will be executed.
Read the register value
The following code is for CodeWarrior/Kinetis Design Studio to a C module, for IAR/KEIL, we need to write the same function as an assembler source file.