STM32 HAL project dependent on definition location of `SysTick_Handler()` in an unexpected way

As is known, the STM32 HAL forces the user to define the SysTick_Handler() function in order to increment the systick needed by functions like HAL_Delay(), otherwise any systick-dependent processes are stuck in a forever loop. The function looks like this:

void SysTick_Handler(void)
{
  HAL_IncTick();
}

While I was working on a porting script which ports code from a STM32CubeIDE project to PlatformIO, I noticed that the systick is not incremented if the SysTick_Handler() is defined in a file in the following structure:

- include
- lib
	|- port
		|...
		|- stm32yyxx_it.h <-- SysTick_Handler() declared here
		|- stm32yyxx_it.c <-- SysTick_Handler() defined here
		|- port.c
		|...
- src
	|- main.c
- test
- platformio.ini

If SysTick_Handler() is defined in main.c or port.c, everything works and the systick gets incremented. port.c contains the code generated labeled as “main.c” within the STM32CubeIDE which then calls a function in the while(1) loop defined in main.c, similar to how the Arduino FW calls loop(). In short: port.c is the program entry, not main.c. This is useful because it allows for the code to be modified by the GUI of the STM32CubeIDE, which can then be copied over to the PlatformIO project without much hassle, as can be seen by the naming scheme of stm32yyxx_it.c, which is directly taken from STM32CubeIDE.

The STM32CubeIDE puts the definition of Systick_Handler() into stm32yyxx_it.c, but that is never enacted in the PlatformIO project. Strangely, if I omit any definition of Systick_Handler(), the compiler doesn’t warn be about a missing definition, but at the same time I was unable to find a __weak definition. Putting the definition of the Systick_Handler() into any other arbitrary file located in the port folder also doesn’t work. I would like a solution that makes the definition in stm32yyxx_it.c sufficient, because that file contains all other important interrupt handlers, which I assume don’t work either (not tested).

This can be reproduced with any standard config for an STM32 project which uses HAL_Delay() by putting the SysTick_Handler() definition anywhere else than the main.c file or the file that contains the main() function. How would I go about debugging such an issue?

Can you try the suggestion in STM32FreeRTOS vTaskDelay() not returning - #2 by maxgerhardt (equivalent this)?

Oh wow. That fixes it.

I don’t understand what’s going on in this case, as the link you provided deals with FreeRTOS, which isn’t present in my case. Since the related issue is closed and 4 years old, I wonder why it happened in my case. Anyway, thank you for the workaround.

Copy+paste workaround quickview:
platformio.ini:

lib_archive = no

This problem is not really FreeRTOS specific, it’s a general issue with _weak function linking, which is also used for most interrupt functions. Somehow, in the regular archiving and linking order that PlatformIO does, code in lib/ will fail to properly overwrite _weak functions defined in the core. If direct object file linking is used instead, it works.

1 Like