Notes / Machine Code & Assembly
HardFault analysis: which line did it die on?
When a HardFault occurs, the PC and LR saved on the stack and the fault status registers lead you to the cause and the location.
Common causes
- Access through a null pointer or to freed memory
- Access to the registers of a peripheral whose clock is off
- Stack overflow
- Unaligned access, division by zero (depending on configuration)
- Calling a bad function pointer (an address with the Thumb bit at 0)
How to find it
On entering the exception the CPU saves r0 to r3, r12, lr, pc and xPSR on the stack. The saved pc is the address of the instruction that caused the problem.
void HardFault_Handler(void) {
__asm volatile ("tst lr, #4\n ite eq\n mrseq r0, msp\n mrsne r0, psp\n b hf_c");
}
void hf_c(uint32_t *sp) {
volatile uint32_t pc = sp[6], lr = sp[5];
volatile uint32_t cfsr = SCB->CFSR, bfar = SCB->BFAR;
while (1); // inspect pc, lr and cfsr with the debugger
}
Fault registers
| Register | What it tells you |
|---|---|
| CFSR | The kind of fault (detail bits for bus / memory / usage faults) |
| BFAR | The data address that caused a bus fault |
| MMFAR | The address of a memory-management fault |
Convert the pc address to a source line with the map file or addr2line -e firmware.elf 0x080012AC and you have the location. In a fielded product, record these values in .noinit RAM or Flash and read them back after the reboot, and even faults that are hard to reproduce can be traced.