Skip to main content
Visitor
July 21, 2026
Question

STM32L476 HardFault immediately after entering Reset_Handler (before .data initialization)

  • July 21, 2026
  • 1 reply
  • 4 views

I'm working on a completely bare-metal STM32L476RG project using GCC + CMake + OpenOCD + GDB (no HAL, no CubeMX).

The MCU consistently HardFaults immediately after entering Reset_Handler, before any .data copy or .bss initialization occurs.

Toolchain

  • MCU: STM32L476RG
  • GCC: arm-none-eabi-gcc 15.2.1
  • OpenOCD + GDB
  • CMake project
  • -mcpu=cortex-m4
  • -mthumb
  • -nostartfiles
 

Linker

Memory layout:

FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
RAM (rwx): ORIGIN = 0x20000000, LENGTH = 128K

_estack = ORIGIN(RAM) + LENGTH(RAM);

Relevant symbols:

_sdata  = 0x20000000
_edata = 0x20000030
_sidata = 0x08000A7C

_sbss = 0x20000030
_ebss = 0x20000034
 

Vector table

Vector table begins at 0x08000000.

First entries:

0x20020000   // MSP
0x08000197 // Reset_Handler
0x08000201 // NMI
0x0800018D // HardFault

Reading both

0x00000000

and

0x08000000

shows identical contents, so the Flash alias appears correct.

VTOR:

0xE000ED08 = 0x00000000
 

Reset_Handler

void Reset_Handler(void)
{
extern uint32_t _sdata, _edata, _sidata;
extern uint32_t _sbss, _ebss;

uint32_t *_sdatap = &_sdata;
uint32_t *_edatap = &_edata;
uint32_t *_sidatap = &_sidata;

uint32_t *_sbssp = &_sbss;
uint32_t *_ebssp = &_ebss;

while (_sdatap < _edatap)
*_sdatap++ = *_sidatap++;

while (_sbssp < _ebssp)
*_sbssp++ = 0;

main();

while (1);
}
 

What GDB shows

Breakpoint at Reset_Handler is hit correctly.

Disassembly:

push {r7, lr}
sub sp, #24
add r7, sp, #0
...

Flash contents at that location match the disassembly exactly.

 

The strange part

Using stepi:

  • push {r7,lr} executes.
  • Immediately afterwards execution enters HardFault_Handler.

We never reach the first ldr instruction.

So the fault appears to occur before any .data or .bss initialization.

 

Fault status registers

HFSR = 0x40000000
CFSR = 0x1400
SHCSR = 0x00000000

0x1400 decodes to:

  • INVSTATE
  • UNDEFINSTR

No BusFault bits are set.

This is confusing because the instruction stream consists only of valid Thumb instructions (push, sub sp,#24, add).

 

HardFault handler

I also tried a naked HardFault handler:

__attribute__((naked))
void HardFault_Handler(void)
{
__asm volatile(
"tst lr,#4\n"
"ite eq\n"
"mrseq r0,msp\n"
"mrsne r0,psp\n"
"bkpt #0\n");
}

The exception frame pointed to by r0 contains only zeros, which I did not expect.

 

Things I've already verified

  • Reset vector is correct.
  • Vector table contents are correct.
  • Flash programming is correct.
  • Linker symbols match the literal pool in Reset_Handler.
  • MSP starts at 0x20020000.
  • Reset_Handler is definitely entered.
  • CPU is identified correctly (CPUID = 0x410FC241).
  • Project is compiled for Cortex-M4 Thumb (-mcpu=cortex-m4 -mthumb).
 

My question

Has anyone seen a Cortex-M4 HardFault immediately after entering Reset_Handler, before any memory initialization, with CFSR = 0x1400 (INVSTATE + UNDEFINSTR)?

Is there something obvious I'm overlooking, or does this point toward a toolchain/debug configuration issue rather than a startup-code problem?

Below are my startup.c and linker.ld files. I couldnt upload since the site is telling me that they are unsupported file type.
Ive used the same startup.c and linker script before for a previous project and it worked fine. The only changes i’ve made is use the entire memory for the linker script this time and allocate 4 KB for stack and heap each.

#include "common.h"

extern uint32_t _estack; //Tells the compiler _estack has been declared somewhere outside file
void Reset_Handler(void);
void Default_Handler(void);

void NMI_Handler(void) __attribute__((weak, alias("Default_Handler")));
//void HardFault_Handler(void) __attribute__((weak, alias("Default_Handler")));
__attribute__((naked))
void HardFault_Handler(void)
{
__asm volatile(
"tst lr, #4 \n"
"ite eq \n"
"mrseq r0, msp \n"
"mrsne r0, psp \n"
"bkpt #0 \n"
);
}
void MemManage_Handler(void) __attribute__((weak, alias("Default_Handler")));
void BusFault_Handler(void) __attribute__((weak, alias("Default_Handler")));
void UsageFault_Handler(void) __attribute__((weak, alias("Default_Handler")));
void SVCall_Handler(void) __attribute__((weak, alias("Default_Handler")));
void Debug_Handler(void) __attribute__((weak, alias("Default_Handler")));
void PendSV_Handler(void) __attribute__((weak, alias("Default_Handler")));
void SysTick_Handler(void) __attribute__((weak, alias("Default_Handler")));
void WWDG_Handler(void) __attribute__((weak, alias("Default_Handler")));
void PVD_PVM_Handler(void) __attribute__((weak, alias("Default_Handler")));
void RTC_TAMP_STAMP_CSS_LSE_Handler(void) __attribute__((weak, alias("Default_Handler")));
void RTC_WKUP_Handler(void) __attribute__((weak, alias("Default_Handler")));
void FLASH_Handler(void) __attribute__((weak, alias("Default_Handler")));
void RCC_Handler(void) __attribute__((weak, alias("Default_Handler")));
void EXTI0_Handler(void) __attribute__((weak, alias("Default_Handler")));
void EXTI1_Handler(void) __attribute__((weak, alias("Default_Handler")));
void EXTI2_Handler(void) __attribute__((weak, alias("Default_Handler")));
void EXTI3_Handler(void) __attribute__((weak, alias("Default_Handler")));
void EXTI4_Handler(void) __attribute__((weak, alias("Default_Handler")));
void DMA1_CH1_Handler(void) __attribute__((weak, alias("Default_Handler")));
void DMA1_CH2_Handler(void) __attribute__((weak, alias("Default_Handler")));
void DMA1_CH3_Handler(void) __attribute__((weak, alias("Default_Handler")));
void DMA1_CH4_Handler(void) __attribute__((weak, alias("Default_Handler")));
void DMA1_CH5_Handler(void) __attribute__((weak, alias("Default_Handler")));
void DMA1_CH6_Handler(void) __attribute__((weak, alias("Default_Handler")));
void DMA1_CH7_Handler(void) __attribute__((weak, alias("Default_Handler")));
void ADC1_2_Handler(void) __attribute__((weak, alias("Default_Handler")));
void CAN1_TX_Handler(void) __attribute__((weak, alias("Default_Handler")));
void CAN1_RX0_Handler(void) __attribute__((weak, alias("Default_Handler")));
void CAN1_RX1_Handler(void) __attribute__((weak, alias("Default_Handler")));
void CAN1_SCE_Handler(void) __attribute__((weak, alias("Default_Handler")));
void EXTI9_5_Handler(void) __attribute__((weak, alias("Default_Handler")));
void TIM1_BRK_TIM15_Handler(void) __attribute__((weak, alias("Default_Handler")));
void TIM1_UP_TIM16_Handler(void) __attribute__((weak, alias("Default_Handler")));
void TIM1_TRG_COM_TIM17_Handler(void) __attribute__((weak, alias("Default_Handler")));
void TIM1_CC_Handler(void) __attribute__((weak, alias("Default_Handler")));
void TIM2_Handler(void) __attribute__((weak, alias("Default_Handler")));
void TIM3_Handler(void) __attribute__((weak, alias("Default_Handler")));
void TIM4_Handler(void) __attribute__((weak, alias("Default_Handler")));
void I2C1_EV_Handler(void) __attribute__((weak, alias("Default_Handler")));
void I2C1_ER_Handler(void) __attribute__((weak, alias("Default_Handler")));
void I2C2_EV_Handler(void) __attribute__((weak, alias("Default_Handler")));
void I2C2_ER_Handler(void) __attribute__((weak, alias("Default_Handler")));
void SPI1_Handler(void) __attribute__((weak, alias("Default_Handler")));
void SPI2_Handler(void) __attribute__((weak, alias("Default_Handler")));
void USART1_Handler(void) __attribute__((weak, alias("Default_Handler")));
void USART2_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
void USART3_Handler(void) __attribute__((weak, alias("Default_Handler")));
void EXTI15_10_Handler(void) __attribute__((weak, alias("Default_Handler")));
void RTC_ALARM_Handler(void) __attribute__((weak, alias("Default_Handler")));
void DFSDM1_FLT3_Handler(void) __attribute__((weak, alias("Default_Handler")));
void TIM8_BRK_Handler(void) __attribute__((weak, alias("Default_Handler")));
void TIM8_UP_Handler(void) __attribute__((weak, alias("Default_Handler")));
void TIM8_TRG_COM_Handler(void) __attribute__((weak, alias("Default_Handler")));
void TIM8_CC_Handler(void) __attribute__((weak, alias("Default_Handler")));
void ADC3_Handler(void) __attribute__((weak, alias("Default_Handler")));
void FMC_Handler(void) __attribute__((weak, alias("Default_Handler")));
void SDMMC1_Handler(void) __attribute__((weak, alias("Default_Handler")));
void TIM5_Handler(void) __attribute__((weak, alias("Default_Handler")));
void SPI3_Handler(void) __attribute__((weak, alias("Default_Handler")));
void UART4_Handler(void) __attribute__((weak, alias("Default_Handler")));
void UART5_Handler(void) __attribute__((weak, alias("Default_Handler")));
void TIM6_DACUNDER_Handler(void) __attribute__((weak, alias("Default_Handler")));
void TIM7_Handler(void) __attribute__((weak, alias("Default_Handler")));
void DMA2_CH1_Handler(void) __attribute__((weak, alias("Default_Handler")));
void DMA2_CH2_Handler(void) __attribute__((weak, alias("Default_Handler")));
void DMA2_CH3_Handler(void) __attribute__((weak, alias("Default_Handler")));
void DMA2_CH4_Handler(void) __attribute__((weak, alias("Default_Handler")));
void DMA2_CH5_Handler(void) __attribute__((weak, alias("Default_Handler")));
void DFSDM1_FLT0_Handler(void) __attribute__((weak, alias("Default_Handler")));
void DFSDM1_FLT1_Handler(void) __attribute__((weak, alias("Default_Handler")));
void DFSDM1_FLT2_Handler(void) __attribute__((weak, alias("Default_Handler")));
void COMP_Handler(void) __attribute__((weak, alias("Default_Handler")));
void LPTIM1_Handler(void) __attribute__((weak, alias("Default_Handler")));
void LPTIM2_Handler(void) __attribute__((weak, alias("Default_Handler")));
void OTG_FS_Handler(void) __attribute__((weak, alias("Default_Handler")));
void DMA2_CH6_Handler(void) __attribute__((weak, alias("Default_Handler")));
void DMA2_CH7_Handler(void) __attribute__((weak, alias("Default_Handler")));
void LPUART1_Handler(void) __attribute__((weak, alias("Default_Handler")));
void QUADSPI_Handler(void) __attribute__((weak, alias("Default_Handler")));
void I2C3_EV_Handler(void) __attribute__((weak, alias("Default_Handler")));
void I2C3_ER_Handler(void) __attribute__((weak, alias("Default_Handler")));
void SAI1_Handler(void) __attribute__((weak, alias("Default_Handler")));
void SAI2_Handler(void) __attribute__((weak, alias("Default_Handler")));
void SWPMI1_Handler(void) __attribute__((weak, alias("Default_Handler")));
void TSC_Handler(void) __attribute__((weak, alias("Default_Handler")));
void LCD_Handler(void) __attribute__((weak, alias("Default_Handler")));
void AES_Handler(void) __attribute__((weak, alias("Default_Handler")));
void RNG_HASH_Handler(void) __attribute__((weak, alias("Default_Handler")));
void FPU_Handler(void) __attribute__((weak, alias("Default_Handler")));
void HASH_CRS_Handler(void) __attribute__((weak, alias("Default_Handler")));

int main(void);

const uint32_t vector[] __attribute__((section(".isr_vector"))) = { //__attribute__ is used to create separate section for vector table so that it doesnt end up in data section
(uint32_t)&_estack,
(uint32_t)&Reset_Handler,
(uint32_t)&NMI_Handler,
(uint32_t)&HardFault_Handler,
(uint32_t)&MemManage_Handler,
(uint32_t)&BusFault_Handler,
(uint32_t)&UsageFault_Handler,
0,
0,
0,
0,
(uint32_t)&SVCall_Handler,
(uint32_t)&Debug_Handler,
0,
(uint32_t)&PendSV_Handler,
(uint32_t)&SysTick_Handler,

(uint32_t)&WWDG_Handler,
(uint32_t)&PVD_PVM_Handler,
(uint32_t)&RTC_TAMP_STAMP_CSS_LSE_Handler,
(uint32_t)&RTC_WKUP_Handler,
(uint32_t)&FLASH_Handler,
(uint32_t)&RCC_Handler,
(uint32_t)&EXTI0_Handler,
(uint32_t)&EXTI1_Handler,
(uint32_t)&EXTI2_Handler,
(uint32_t)&EXTI3_Handler,
(uint32_t)&EXTI4_Handler,
(uint32_t)&DMA1_CH1_Handler,
(uint32_t)&DMA1_CH2_Handler,
(uint32_t)&DMA1_CH3_Handler,
(uint32_t)&DMA1_CH4_Handler,
(uint32_t)&DMA1_CH5_Handler,
(uint32_t)&DMA1_CH6_Handler,
(uint32_t)&DMA1_CH7_Handler,
(uint32_t)&ADC1_2_Handler,
(uint32_t)&CAN1_TX_Handler,
(uint32_t)&CAN1_RX0_Handler,
(uint32_t)&CAN1_RX1_Handler,
(uint32_t)&CAN1_SCE_Handler,
(uint32_t)&EXTI9_5_Handler,
(uint32_t)&TIM1_BRK_TIM15_Handler,
(uint32_t)&TIM1_UP_TIM16_Handler,
(uint32_t)&TIM1_TRG_COM_TIM17_Handler,
(uint32_t)&TIM1_CC_Handler,
(uint32_t)&TIM2_Handler,
(uint32_t)&TIM3_Handler,
(uint32_t)&TIM4_Handler,
(uint32_t)&I2C1_EV_Handler,
(uint32_t)&I2C1_ER_Handler,
(uint32_t)&I2C2_EV_Handler,
(uint32_t)&I2C2_ER_Handler,
(uint32_t)&SPI1_Handler,
(uint32_t)&SPI2_Handler,
(uint32_t)&USART1_Handler,
(uint32_t)&USART2_IRQHandler,
(uint32_t)&USART3_Handler,
(uint32_t)&EXTI15_10_Handler,
(uint32_t)&RTC_ALARM_Handler,
(uint32_t)&DFSDM1_FLT3_Handler,
(uint32_t)&TIM8_BRK_Handler,
(uint32_t)&TIM8_UP_Handler,
(uint32_t)&TIM8_TRG_COM_Handler,
(uint32_t)&TIM8_CC_Handler,
(uint32_t)&ADC3_Handler,
(uint32_t)&FMC_Handler,
(uint32_t)&SDMMC1_Handler,
(uint32_t)&TIM5_Handler,
(uint32_t)&SPI3_Handler,
(uint32_t)&UART4_Handler,
(uint32_t)&UART5_Handler,
(uint32_t)&TIM6_DACUNDER_Handler,
(uint32_t)&TIM7_Handler,
(uint32_t)&DMA2_CH1_Handler,
(uint32_t)&DMA2_CH2_Handler,
(uint32_t)&DMA2_CH3_Handler,
(uint32_t)&DMA2_CH4_Handler,
(uint32_t)&DMA2_CH5_Handler,
(uint32_t)&DFSDM1_FLT0_Handler,
(uint32_t)&DFSDM1_FLT1_Handler,
(uint32_t)&DFSDM1_FLT2_Handler,
(uint32_t)&COMP_Handler,
(uint32_t)&LPTIM1_Handler,
(uint32_t)&LPTIM2_Handler,
(uint32_t)&OTG_FS_Handler,
(uint32_t)&DMA2_CH6_Handler,
(uint32_t)&DMA2_CH7_Handler,
(uint32_t)&LPUART1_Handler,
(uint32_t)&QUADSPI_Handler,
(uint32_t)&I2C3_EV_Handler,
(uint32_t)&I2C3_ER_Handler,
(uint32_t)&SAI1_Handler,
(uint32_t)&SAI2_Handler,
(uint32_t)&SWPMI1_Handler,
(uint32_t)&TSC_Handler,
(uint32_t)&LCD_Handler,
(uint32_t)&AES_Handler,
(uint32_t)&RNG_HASH_Handler,
(uint32_t)&FPU_Handler,
(uint32_t)&HASH_CRS_Handler
};

void Reset_Handler(void){ //extern declaration of start,end and ram copy of data as well as of start and end of bss
extern uint32_t _sdata;
extern uint32_t _edata;
extern uint32_t _sidata;

extern uint32_t _sbss;
extern uint32_t _ebss;

uint32_t *_sdatap = &_sdata;
uint32_t *_edatap = &_edata;
uint32_t *_sidatap = &_sidata;

uint32_t *_sbssp = &_sbss;
uint32_t *_ebssp = &_ebss;

while(_sdatap<_edatap){ //Initializing data variables and zeroing bss variables
(*_sdatap) = (*_sidatap);
_sdatap++;
_sidatap++;
}

while(_sbssp<_ebssp){
(*_sbssp) = 0;
_sbssp++;
}

main(); //Calling main

while(1){ //Infinite loop in the event of main somehow returning
}
}

void Default_Handler(void){
while(1){};
}

void HardFault_C(uint32_t *stack)
{
volatile uint32_t r0 = stack[0];
volatile uint32_t r1 = stack[1];
volatile uint32_t r2 = stack[2];
volatile uint32_t r3 = stack[3];
volatile uint32_t r12 = stack[4];
volatile uint32_t lr = stack[5];
volatile uint32_t pc = stack[6];
volatile uint32_t psr = stack[7];

while (1);
}
ENTRY(Reset_Handler)


_Min_Heap_Size = 0x1000;
_Min_Stack_Size = 0x1000;

MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
}

_estack = ORIGIN(RAM) + LENGTH(RAM);


SECTIONS
{
.isr_vector :
{
. = ALIGN(128);
KEEP(*(.isr_vector))
} > FLASH

.text :
{
*(.text*)
*(.rodata*)
. = ALIGN(4);
_etext = .;
} > FLASH

.data :
{
_sdata = .;
*(.data*)
_edata = .;
} > RAM AT > FLASH

_sidata = LOADADDR(.data);

.bss :
{
_sbss = .;
*(.bss*)
*(COMMON)
_ebss = .;
} > RAM
}

 

1 reply

TDK
July 21, 2026

Generate a bare CubeMX project and compare. It’ll take 5 minutes. Especially compare the disassembly at Reset_Handler.

"If you feel a post has answered your question, please click ""Accept as Solution""."