Course contentsShow
← Embedded Systems & Computer Architecture
Lesson 206 of 9363. Microcontroller Fundamentals and Bare-Metal CFree lesson

Handling Fault Exceptions for System Reliability

Implement HardFault and MemManage handlers to capture diagnostic information when the processor encounters illegal instructions or memory violations.

In this lesson, you will learn how to implement custom exception handlers to capture vital diagnostic information when your microcontroller encounters critical hardware faults.

When a processor hits an illegal instruction (e.g., trying to execute data) or violates memory protection rules (e.g., accessing a restricted peripheral register), it triggers a HardFault or MemManage exception. By default, many systems loop infinitely on a fault, leaving you blind to the cause. To improve reliability, we define custom handlers that extract the "state of the crime" from the processor registers.

Capturing the Fault Context

When an exception occurs, the hardware automatically pushes the processor state (registers like R0-R3, R12, LR, PC, and xPSR) onto the stack. We can write a handler that extracts these values to see exactly where the program was executing when it failed.

For a HardFault handler, we use a simple naked function to pull the stack pointer into a C structure, allowing us to inspect the saved PC (Program Counter) and LR (Link Register) to identify the failing instruction.

void HardFault_Handler(void) {
    __asm volatile (
        "tst lr, #4                \n" // Check if using MSP or PSP
        "ite eq                    \n"
        "mrseq r0, msp             \n"
        "mrsne r0, psp             \n"
        "b print_fault_info        \n" // Branch to C function to log data
    );
}

void print_fault_info(uint32_t *stack_frame) {
    // stack_frame[6] contains the PC of the instruction that caused the fault
    uint32_t fault_pc = stack_frame[6];
    // Log the PC to a serial port or persistent memory for post-mortem analysis
}

MemManage Faults

A MemManage fault occurs specifically when a memory access violates your defined access permissions. By reading the MemManage Fault Status Register (MMFSR), you can determine if the fault was caused by a data access violation, an instruction fetch error, or an unstacking error.

By implementing these handlers, you transform a "silent crash" into a diagnostic report. Instead of the system simply hanging, you can log the fault to non-volatile memory, allowing you to debug the specific instruction that caused the failure after the device reboots.

Key Takeaway: Implementing dedicated fault handlers allows you to capture the processor's saved context, turning fatal system crashes into actionable diagnostic logs for improved reliability.