Double Definition of port interrupt handlers using CubeIDE with GCC on STM32F4

Hello kind people out there,
I just recently startet using FreeRTOS, therefore I don’t have much experience yet. I also didn’t find any post online of someone having the same problem, so I hope I can get some help here. About the problem:
I’m using a STM32F411 Nucleo Board together with ST’s CubeIDE. I’m using their Firmware Package version 1.26.2 (most recent version at this time). I use CubeMX for configuration and generation of initialization code. However, I don’t use the FreeRTOS implementation provided by CubeMX (I would like to work with the FreeRTOS API directly, not using the CMSIS RTOS API).
Because I would like to continue using CubeMX, I couldn’t start with a demo as its recommended. So i followed the guide on how to add FreeRTOS to an existing project. Im fairly confident that the integration of source- and headerfiles was successfull and error-free. I used the port from GCC/ARM_CM4F and the RTOS_Config.h from the CORTEX_M4F_STM32F407ZG-SK demo.

Upon compiling I now get error messages, stating that the interrupt handlers are defined twice.

c:\st\stm32cubeide_1.7.0\stm32cubeide\plugins\\tools\arm-none-eabi\bin\ld.exe: ./FreeRTOS/Source/portable/GCC/ARM_CM4F/port.o: in function `SVC_Handler':
F:/STM32Cube/Test_FreeRTOS/Debug/../FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c:249: multiple definition of `SVC_Handler'; ./Core/Src/stm32f4xx_it.o:F:/STM32Cube/Test_FreeRTOS/Debug/../Core/Src/stm32f4xx_it.c:148: first defined here
c:\st\stm32cubeide_1.7.0\stm32cubeide\plugins\\tools\arm-none-eabi\bin\ld.exe: ./FreeRTOS/Source/portable/GCC/ARM_CM4F/port.o: in function `PendSV_Handler':
F:/STM32Cube/Test_FreeRTOS/Debug/../FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c:443: multiple definition of `PendSV_Handler'; ./Core/Src/stm32f4xx_it.o:F:/STM32Cube/Test_FreeRTOS/Debug/../Core/Src/stm32f4xx_it.c:174: first defined here
c:\st\stm32cubeide_1.7.0\stm32cubeide\plugins\\tools\arm-none-eabi\bin\ld.exe: ./FreeRTOS/Source/portable/GCC/ARM_CM4F/port.o: in function `SysTick_Handler':
F:/STM32Cube/Test_FreeRTOS/Debug/../FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c:497: multiple definition of `SysTick_Handler'; ./Core/Src/stm32f4xx_it.o:F:/STM32Cube/Test_FreeRTOS/Debug/../Core/Src/stm32f4xx_it.c:187: first defined here
c:\st\stm32cubeide_1.7.0\stm32cubeide\plugins\\tools\arm-none-eabi\bin\ld.exe: ./FreeRTOS/Source/tasks.o: in function `xTaskIncrementTick':
F:/STM32Cube/Test_FreeRTOS/Debug/../FreeRTOS/Source/tasks.c:2861: undefined reference to `vApplicationTickHook'
c:\st\stm32cubeide_1.7.0\stm32cubeide\plugins\\tools\arm-none-eabi\bin\ld.exe: F:/STM32Cube/Test_FreeRTOS/Debug/../FreeRTOS/Source/tasks.c:2891: undefined reference to `vApplicationTickHook'
c:\st\stm32cubeide_1.7.0\stm32cubeide\plugins\\tools\arm-none-eabi\bin\ld.exe: ./FreeRTOS/Source/portable/MemMang/heap_4.o: in function `pvPortMalloc':
F:/STM32Cube/Test_FreeRTOS/Debug/../FreeRTOS/Source/portable/MemMang/heap_4.c:263: undefined reference to `vApplicationMallocFailedHook'

(Please ignore the errors relating to missing hook functions, I didn’t disable those in config yet)

I already found the FAQ entry describing this exact problem (“FreeRTOS FAQ - My application does not run, what could be wrong?” then the “Special note to ARM Cortex-M users” written in red): The three handlers are indeed defined in CMSIS. The problem: Because I’m using CubeMX, adding the __weak attribute to the CMSIS function is overwritten every time I regenerate my code.

What would be the best way to solve this problem?

I tried calling the RTOS-handlers from the respective CMSIS-handlers, but the compiler threw a “implicit declaration” error at me. This makes sense of course, but I couldn’t find the header where SVC_Handler, PendSV_Handler and SysTick_Handler are declared. Is this a valid/good approach after all?

Thanks to everybody reading this and providing help!

PS: Unfortionately I cannot upload my project because I’m a new user, but if someone would like to take a look, I’m sure we can work this out.

Have a look at this post

Hope it helps :slight_smile:

1 Like

Thank you very much! Why is it always that someone finds the exact post treating the problem when I couldn’t find anything in the last hours…

Deleting the functions works - until the next code generation. I was hoping there is a way to sneak around the re-generation of this part of code. Using the method stated in the post seems like a very, very complicated approach. Using the FreeRTOS distribution provided by ST, then replacing FreeRTOS and also deleting the CMSIS Wrapper…

I might have to use this method, but If there is any other (preferably simpler) approach I would be super greatful!

1 Like

Probably best if you integrate FreeRTOS via CubeMX in your case. Yes it will write code for you that uses CMSIS-RTOS, but that’s OK. You can still use the native FreeRTOS API. For queues, semaphores, and other FreeRTOS resources, don’t create any of that in CubeMX.

Thank you both. I tried out using including FreeRTOS via the CubeMX Middleware option. I changed the files to the newest release of FreeRTOS and deleted/didn’t use the CMSIS wrapper. That worked fine in the first place. However, I run into the same problem as before: Once I make any change in CubeMX and regenerate code, it overrides all changes I made to any files. That means it replaces the newest FreeRTOS release with an older one, re-includes the CMSIS-Wrapper and changes up the initalization in my main.c file. There must be a way to use native FreeRTOS together with CubeMX, or am I wrong? It would be a pity if using CubeMX means I must use the provided implementation and cannot use native FreeRTOS…

Using a tool like CubeMx is often an All or Nothing situation. I will sometimes use it to generate an initial state for a program, and then start a brand new version of my program and copy in the pieces of the code I want, and then start from there. If I need to go back to make changes at the CubeMx level, I can regenerate that first code base, and then copy in the changes I want from the CubeMx version into my own database.

My personal opinion is that many vender libraries are ‘you get what you paid from them, free’, so it makes sense to not tie yourself to them. The CubeMx project configuration tool is. a useful tool, but I find then breaking away from the run time libraries provided is very useful. When I first start on a processor, I might initially use the vendor libraries, but I normally find that it makes sense to adapt and fix them as I go along, so I first wrap them with a generic vendor-agnostic wrapper and then can fix the provided implementation as needed. This also means that I can change the project to a different vendor’s chip if I want, which is one of the reasons they want you to be using their libraries, to lock you into their family of processors.

1 Like

In my normal projects, I use CubeMX just like richard-damon does. However, I have one project where I maintain the CubeMX connection, meaning it can re-generate code without messing anything up.

  1. Write code only inside files you create or within designated areas in files created by CubeMX.
  2. Accept the FreeRTOS version included in CubeMX. (I do have an exception to this rule in one branch, where I use the latest version of FreeRTOS, and I use git to quickly discard any CubeMX changes to the FreeRTOS files.)
  3. Leave all CMSIS-RTOS wrappers and usage alone. Don’t delete or change it. But in the code you write yourself, use the native FreeRTOS API. This means you don’t use CubeMX to create any OS resources like queues, semaphores, and timers.

It does work, but again everything richard-damon said above is spot on.

Thank you everybody for your answers. I understand all your points, relying on CubeMX is not the best idea in a productive enviroment. However, due to limited time, I’m kind of stuck with the comfort of CubeMX and I will continue using it.

With some help of a coworker I found the easiest and best solution to my problem:
CubeMX offers a function to disable the auto-generation of certain interrupt handlers (IRQ handlers). This can be found in CubeMX under System Core → NVIC → Code generation. By unchecking the

“Generate IRQ handler” box for the “System service call via SWI instruction” (maps to ‘SVC_Handler’),

“Pendable request for system service” (maps to ‘PendSV_Handler’) and

“System tick timer” (maps to ‘SysTick_Handler’),

CubeMX will no longer auto-generate these functions. This way the functions can be redefined in FreeRTOSConfig.h and no double definition is occuring!