STM32L476 HardFault immediately after entering Reset_Handler (before .data initialization)
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 = 0x20000034Vector table
Vector table begins at 0x08000000.
First entries:
0x20020000 // MSP
0x08000197 // Reset_Handler
0x08000201 // NMI
0x0800018D // HardFaultReading both
0x00000000and
0x08000000shows identical contents, so the Flash alias appears correct.
VTOR:
0xE000ED08 = 0x00000000Reset_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 = 0x000000000x1400 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_Handleris 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
}
