STM32 HAL Tutorial: Detecting and Responding to System Faults
Abstract
Learn how to handle STM32 faults including HardFault, BusFault, UsageFault, and Memory Management Fault using HAL. Step-by-step guide for robust embedded applications.
1. Introduction
Even with watchdogs and CRC/ECC, embedded systems can encounter unexpected conditions:
- Illegal memory access
- Division by zero
- Invalid instructions
- Bus or peripheral errors
STM32 provides fault exceptions to detect and respond to these errors. This is core dependent, but this is common among all cores:
- HardFault – triggered on unrecoverable errors
These are dependent on the core and not available on M0+:
- BusFault – occurs on memory access violations
- UsageFault – triggered by undefined instructions, divide by zero
- Memory Management Fault (MemManage) – invalid memory access
By the end of this episode, you’ll be able to:
- Detect and log faults
- Implement recovery strategies
- Debug system errors efficiently
2. Prerequisites
- STM32 board
- STM32CubeIDE installed
Knowledge of watchdogs, HAL, and memory mapping
3. Fault Handler Overview
STM32 automatically generates default handlers in stm32g0xx_it.c:
- By default, the MCU halts in the infinite loop.
- You can customize handlers to log errors, reset MCU, or blink LEDs.
4. Jumping to an Aligned Address - Hardfault
The Cortex-M0+ core only supports the Thumb instruction set, where instructions must be aligned on a 2-byte boundary (half-word). The least significant bit (LSB) of a branch address is used to set the T-bit in the PSR, and it must be ‘1’. If you try to branch to an even address (with LSB=0), you’ll generate a fault.
void cause_alignment_fault() {
void (*function_ptr)(void);
// Point to an address in Flash, but make sure the LSB is 0 (an even address)
// We take a valid function address and clear the LSB
function_ptr = (void (*)(void))((uint32_t)&cause_alignment_fault & ~1U);
// Attempting this call will cause a HardFault
function_ptr();
}
/* USER CODE END 0 */
5. Accessing an Invalid or Unmapped Address - Hardfault
Attempting to access a memory address outside of the defined memory map (Flash, RAM, Peripherals) will result in a fault. For an STM32G0, an address like 0x30000000 is typically unmapped.
void cause_invalid_address_fault() {
volatile uint32_t* p_address = (uint32_t*)0x30000000;
*p_address = 0x12345678; // Accessing a non-existent memory region causes a HardFault
}
6. Stack Overflow - Hardfault and might disconnect from Debug Session
If your program uses too much stack space (e.g., deep recursion or large local variables), the stack pointer can go beyond the allocated RAM for the stack. The first time it tries to PUSH a register to an invalid memory location outside of RAM, a HardFault will occur.
void cause_stack_overflow(int depth) {
volatile uint8_t local_array[128]; // Allocate a chunk of stack
local_array[0] = depth;
// Infinite recursion
cause_stack_overflow(depth + 1);
}
Full Source Code: hackerembedded/STM32_EP17
7. Debugging HardFaults
- Step 1: Enable stack frame capture in CubeMX or IDE.
- Step 2: Use UART to log fault registers.
- Step 3: Analyze faulting instruction using PC (program counter).
8. Example: Combine Watchdog + Fault Handler
- Watchdogs reset MCU on hang-ups
- Fault handlers catch invalid instructions or memory violations
- Together, they provide robust error detection and recovery
void HardFault_Handler(void)
{
/* USER CODE BEGIN HardFault_IRQn 0 */
/* USER CODE END HardFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
NVIC_SystemReset();//Reset the MCU
/* USER CODE END W1_HardFault_IRQn 0 */
}
}
9. Hands-On Lab Example
1. Trigger HardFault desired:
void cause_alignment_fault() {
void (*function_ptr)(void);
// Point to an address in Flash, but make sure the LSB is 0 (an even address)
// We take a valid function address and clear the LSB
function_ptr = (void (*)(void))((uint32_t)&cause_alignment_fault & ~1U);
// Attempting this call will cause a HardFault
function_ptr();
}
void cause_invalid_address_fault() {
volatile uint32_t* p_address = (uint32_t*)0x30000000;
*p_address = 0x12345678; // Accessing a non-existent memory region causes a HardFault
}
void cause_stack_overflow(int depth) {
volatile uint8_t local_array[128]; // Allocate a chunk of stack
local_array[0] = depth;
// Infinite recursion
cause_stack_overflow(depth + 1);
}
/* USER CODE END 0 */
/* USER CODE BEGIN 2 */
cause_stack_overflow(0);
cause_invalid_address_fault();
cause_alignment_fault();
/* USER CODE END 2 */
2. Observe MCU enters HardFault_Handle
3. Reset MCU to recover
Tip: Use watchdog + fault handler for maximum reliability in industrial systems.
10. Advantages of Fault Handlers
- Detects software and hardware errors before system fails silently
- Works with watchdogs and CRC/ECC to build fully reliable systems
- Logs error data for post-mortem analysis
- Enables safe recovery in critical applications


