Debugging a hard fault in ARM Cortex M3
I have been working on the Stellaris LM3S6965 for quiet a while now. So I thought, may be I will put my learning’s in one place, so others can use them and not get stuck, where I did.
The Stellaris LM3S6965 is based on the ARM Cortex M3 architecture. What I am going to mention in my post, is how to track down the source of a hard fault. So let’s get straight to the point.
On getting a hard fault, check the value of MSP and PSP viz. the stack pointers. It’s likely the MSP, if you are not using an RTOS.
Go to the address contained in the MSP. The following registers would be on the stack in increasing order.
Registers ro - r3, r12, lr, pc, xpsr.
One thing I must mention is, if your fault handler does something other than spinning in a loop, a couple of other registers might be pushed on to the stack by the compiler. You need to take care of this. I am assuming here, that the default fault handler does nothing else besides spinning in a loop.
So take a look at the stack. The pushed PC should help you in debugging, as it usually points to the instruction that caused the fault.
The next place to look is in the NVIC viz. the Nested Vector Interrupt Controller. The Configurable Fault Status Register is at address 0xE000ED28 and contains bits that identify the cause of the fault and can also tell if the stacked PC actually points to the faulting instruction. There are a couple of other registers, the Memory Manage Fault Address register and the Bus Fault Address register which provide the address of the fault for those kinds of faults. But, you need to look at the status register first to identify the cause of the fault and that will tell you if the BFAR or MMFAR contains a useful address.
To learn more, refer to the ARM Cortex M3 technical reference manual. If you would like to learn about ARM architecture in general, the ARM System Developer’s Guide by Andrew Sloss, Dominic Symes and Chris Wright is a very good place to start.