NodeLoop
CFSR / HFSR / BFAR / MMFAR + Stack frame

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.

Verdict

Waiting for registers...

Reliability badges indicate whether BFAR/MMFAR can be trusted (and when they can be misleading).

Decoded flags

MMSR / BFSR / UFSR
No fault flags active

Stack frame

Waiting for stack data

Checklist

  • Paste fault registers to analyze
Frictionless handoff

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.