STM32L4 SystemCoreClock access crashes the program during HAL initialization
-
I'm trying to blink an LED on a Nucleo-L476 with CubeMX and ST's HAL. It worked perfectly on Windows (System Workbench). Now, I'm trying to do the same on Linux with CubeMX and Qt Creator (my favorite IDE) and OpenOCD. I am now able to compile and debug the target.
However, the program crashes during HAL initialization. More precisely, when it tries to access the SystemCoreClock variable. The following code is called from HAL_Init(); in main():
__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) { uint32_t tickNum=123, *ptr1=NULL, *ptr2=NULL; // Added by me to debug ptr1 = &tickNum; // Added by me to debug ptr2 = &SystemCoreClock; // Added by me to debug tickNum = SystemCoreClock; // Added by me to debug *** crash here *** /* Configure the SysTick to have interrupt in 1 ms time basis */ HAL_SYSTICK_Config(SystemCoreClock/1000); // *** Crash here *** /* Configure the SysTick IRQ priority */ HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority ,0); /* Return function status */ return HAL_OK; }
I could replace SystemCoreClock by a constant, but the variable needs to be modified further down the line anyway. SystemCoreClock is declared in system_stm32l4xx.h and defined in system_stm32l4xx.c. Both files are part of the project.
** extern variable SystemCoreClock seems to have two different addresses.
Normal stuff (ptr1 == &ticknum and *ptr1 == ticknum):
(gdb) p &tickNum $3 = (uint32_t *) 0x20017fdc (gdb) p ptr1 $4 = (uint32_t *) 0x20017fdc (gdb) p *ptr1 $5 = 123
Strange stuff (ptr2 != &SystemCoreClock and *ptr2 != SystemCoreClock):
(gdb) p &SystemCoreClock $6 = (uint32_t *) 0x20000004 <SystemCoreClock> (gdb) p ptr2 $7 = (uint32_t *) 0x681b4b20 (gdb) p *ptr2 $8 = 0
When I say 'crash', I mean the program falls in an infinite loop in startup_stm32l476xx.s:
/** * @brief This is the code that gets called when the processor receives an * unexpected interrupt. This simply enters an infinite loop, preserving * the system state for examination by a debugger. * * @param None * @retval : None */ .section .text.Default_Handler,"ax",%progbits Default_Handler: Infinite_Loop: b Infinite_Loop
Trying to narrow down the search, I noticed that a variable declared outside a function is not properly accessed from within the function:
uint32_t dummyVar = 123; void dummyFunc() { uint32_t loc = 123; uint32_t *p = &loc; p = &dummyVar; // Debugger says &dummyVar = 0x20000004 and p = 0x011a3b01 __asm("nop"); __asm("nop"); __asm("nop"); loc = dummyVar; // *** Crash here }
The variable p here points outside the RAM, which starts at 0x20000000. The nop instructions make sure p = &dummyVar; is really executed and the debugger doesn't fool me.
Any idea?
-
I use Qt Creator for STM32 developments too.
You may have incorrect compiler flags applied so some instructions compiled are not valid for this STM32. When invalid instructions got executed, the ARM core generates a Hard Fault interrupt.
Here are the compiler flags I'm using for my stm32f4:
-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16
You may check the generated assembly and machine codes during debug session under Debug->Operate by Instruction