Cortex-M HardFault Decoder (CFSR / HFSR / BFAR / MMFAR + Stack Frame)
Paste registers or type them manually. Get a verdict, reliability hints (BFAR/MMFAR), decoded flags, and a short checklist.
Inputs
Works with values like 0x40000000 or 40000000.
Tip: only a subset is needed for a solid first diagnosis: HFSR + CFSR + (BFAR/MMFAR) + PC/LR/xPSR.
Verdict
Waiting for registers...
Reliability badges indicate whether BFAR/MMFAR can be trusted (and when they can be misleading).
Decoded flags
MMSR / BFSR / UFSRStack frame
Waiting for stack data
Checklist
- Paste fault registers to analyze
Share & export
Share a link to this analysis or copy a Markdown report for a bug ticket or team chat.
Works offline. No data is sent unless you choose email export.
How to use this decoder
1. Capture key registers
Log HFSR, CFSR, BFAR, MMFAR and the stacked PC/LR/xPSR from your HardFault handler.
2. Paste or type
Use Manual for exact values, or Quick paste to parse a console dump like HFSR=0x40000000.
3. Trust the badges
BFAR/MMFAR are only reliable when BFARVALID/MMARVALID are set. Imprecise faults can point to a later PC.
HardFault handler snippet
Drop this into your firmware to capture registers and the stacked PC/LR/xPSR. Adjust the includes for your MCU family.
C/CMSIS capture
#include <stdint.h>
#include "core_cmX.h"
typedef struct {
uint32_t r0;
uint32_t r1;
uint32_t r2;
uint32_t r3;
uint32_t r12;
uint32_t lr;
uint32_t pc;
uint32_t xpsr;
} stacked_regs_t;
void HardFault_HandlerC(uint32_t *stack_ptr) {
const stacked_regs_t *r = (const stacked_regs_t *)stack_ptr;
uint32_t hfsr = SCB->HFSR;
uint32_t cfsr = SCB->CFSR;
uint32_t bfar = SCB->BFAR;
uint32_t mmfar = SCB->MMFAR;
// Print with your logger (printf, RTT, etc.)
// Example: printf("HFSR=0x%08lX CFSR=0x%08lX\n", hfsr, cfsr);
} GCC/Clang wrapper
__attribute__((naked)) void HardFault_Handler(void) {
__asm volatile (
"tst lr, #4\n"
"ite eq\n"
"mrseq r0, msp\n"
"mrsne r0, psp\n"
"b HardFault_HandlerC\n"
);
} ArmCC/Keil wrapper
__asm void HardFault_Handler(void) {
TST LR, #4
ITE EQ
MRSEQ R0, MSP
MRSNE R0, PSP
B HardFault_HandlerC
} Common fixes checklist
- MPU permissions: verify execute and read/write access for the faulting region.
- Stack overflow: validate stack size, alignment, and guards.
- Null or bad pointers: check PC=0 and function pointer LSB (Thumb state).
- Alignment issues: packed structs, DMA buffers, and unaligned loads.
- FPU not enabled: NOCP means CP10/CP11 are not configured.
- Imprecise stores: add DSB/ISB or reduce write buffering when debugging.
FAQ
What is the CFSR register?
The Configurable Fault Status Register (SCB->CFSR) encodes Usage, Bus, and MemManage faults. It combines UFSR (bits 16-31), BFSR (8-15), and MMFSR (0-7).
What does BFARVALID mean?
When set in BFSR, BFAR holds a valid faulting address. If cleared, the BFAR value is not reliable.
How do I debug an IMPRECISERR?
Imprecise faults are delayed by write buffering. The stacked PC often points after the real offending store. Use barriers (__DSB()), disable write buffer (if possible), or add instrumentation to localize the crash.
Why is DIVBYZERO not showing up?
DIVBYZERO only faults if CCR.DIV_0_TRP is enabled. Otherwise the core may not trigger a UsageFault on divide-by-zero.
What is EXC_RETURN?
EXC_RETURN is a special value loaded in LR on exception entry. It encodes return mode (Thread/Handler), stack selection (PSP/MSP), and whether an extended FP context was stacked.