on 2026-03-20 3:53 AM
This knowledge article provides guidance on how to integrate middleware in VS Code with CMake-based project manually, using the FreeRTOS™ middleware from the STM32C5 package as an example. The knowledge article explains how to locate, enable, and configure middleware components using components.cmake. Additionally, how to integrate them into the application with the middleware’s CMakeLists.txt, and how to verify the integration.
STM32CubeMX2 offers an integrated workflow for a subset of middleware components. These components can be configured from the graphical user interface and generated directly into the user project, together with the initialization code and drivers. However, not all middleware delivered in STM32Cube packages is currently exposed in this way. In many cases, the middleware is provided as part of the device or board package and must be integrated into the MX2-generated project manually.
This document focuses on middleware that is available in the STM32Cube package but is not directly configured and generated by STM32CubeMX2.
Using FreeRTOS™ from the STM32C5 series package as an example, this document describes how to:
The objective is to provide a clear, repeatable method for integrating middleware that is not managed by the graphical user interface into MX2 projects. It's structured in a way that remains consistent with the MX2-generated organization and is scalable to other middleware beyond FreeRTOS™.
This document assumes a CMake-based STM32 project generated by STM32CubeMX2 and developed in Visual Studio Code. Before adding middleware such as FreeRTOS™, the base project, including a simple LED, must already be built and run on the board.
In STM32CubeMX2, prepare the project as follows:
At this stage, you should be able to:
The FreeRTOS™ middleware is added on top of this baseline manually as a reference for the process. The LED configured is used in the example task to demonstrate that the RTOS is running and scheduling correctly.
In an STM32CubeMX2 CMake project, the top-level CMakeLists.txt acts primarily as a hub: it creates the application target and then delegates most of the configuration to smaller .cmake modules.
After STM32CubeMX2 generation and initial CMake configuration, a typical project layout looks like:
Your top-level file is intentionally minimal:
cmake_minimum_required(VERSION 3.20)
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
set(CMAKE_C_COMPILER_FORCED TRUE)
set(CMAKE_CXX_COMPILER_FORCED TRUE)
include(cmake/target.cmake)
include(cmake/${TOOLCHAIN_FILE})
project(STM32C5_FreeRTOS_TaskPriority)
add_executable(STM32C5_FreeRTOS_TaskPriority)
include(cmake/files.cmake)
include(cmake/flags.cmake)
include(cmake/components.cmake)
# Stubs for project-specific customizations
target_sources(${CMAKE_PROJECT_NAME} PRIVATE)
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC)
target_compile_definitions(${CMAKE_PROJECT_NAME} PUBLIC)
target_compile_options(${CMAKE_PROJECT_NAME} PUBLIC)
target_link_options(${CMAKE_PROJECT_NAME} PUBLIC)
target_link_directories(${CMAKE_PROJECT_NAME} PUBLIC)
target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC)
The main roles of these files are:
cmake/target.cmake + toolchain file
cmake/components.cmake
This file is also the integration point for middleware. For FreeRTOS™, you do not manually list the *.c files; instead the developer has to:
The CMake logic in the STM32C5 FreeRTOS™ package then automatically adds the correct kernel sources, portable layer, heap implementation, and include paths.
cmake/files.cmake
cmake/flags.cmake
This section shows how to integrate FreeRTOS™ into the STM32CubeMX2‑generated STM32C5 project using the STM32C5 package’s own CMake support, instead of manually listing all the middleware source files.
The key steps are as follows:
From your STM32C5 firmware package, locate the FreeRTOS™ middleware folder:
<STM32C5_Package>/middleware/freertos/
Create a corresponding folder inside your project, for example:
Copy and paste all the files:
In cmake/components.cmake, you control which CMSIS components are active by populating CMSIS_COMPONENTS_LIST. To enable FreeRTOS™ core and a specific heap implementation (for this example Heap_4), extend the list for your configuration:
set(CMSIS_COMPONENTS_LIST ) # Start with empty component list. To be populated below by each config.
if(${CMAKE_BUILD_TYPE} STREQUAL "debug_GCC_NUCLEO-C562RE")
# Existing CMSIS / HAL / LL / MX2 components ...
list(APPEND CMSIS_COMPONENTS_LIST "Cvendor:STMicroelectronics#Cclass:CMSIS#Cgroup:CORE#Cversion:6.2.0")
# ...
list(APPEND CMSIS_COMPONENTS_LIST "Cvendor:STMicroelectronics#Cclass:Utility#Cgroup:sysmem#Cvariant:Standalone sysmem#Cversion:1.0.0")
# --- Add your FreeRTOS components (core+heap_4) ---
list(APPEND CMSIS_COMPONENTS_LIST "Cvendor:STMicroelectronics#Cclass:RTOS#Cgroup:FreeRTOS#Csub:Core#Cversion:11.2.0")
list(APPEND CMSIS_COMPONENTS_LIST "Cvendor:STMicroelectronics#Cclass:RTOS#Cgroup:FreeRTOS#Csub:MemMang#Cvariant:Heap_4#Cversion:11.2.0")
set(CMSIS_RTE_FOLDER "${CMAKE_SOURCE_DIR}/user_modifiable")
endif()
# Existing package subdirectories
add_subdirectory(arch/cmsis)
add_subdirectory(stm32c5xx_dfp)
add_subdirectory(stm32c5xx_drivers)
add_subdirectory(utilities/syscalls)
add_subdirectory(generated/hal)
add_subdirectory(generated/utilities)
# --- Add FreeRTOS subdirectory (CMakelists.txt) ---
add_subdirectory(middleware/freertos)
# Link low-level drivers and CMSIS targets
target_link_libraries(${CMAKE_PROJECT_NAME}
generated_STMicroelectronics_stm32c5xx_hal_drivers_0_0_1
generated_STMicroelectronics_syscalls_2_0_0
STMicroelectronics_CMSIS_6_3_0
STMicroelectronics_stm32c5xx_dfp_2_0_0
STMicroelectronics_stm32c5xx_hal_drivers_2_0_0
STMicroelectronics_syscalls_2_0_0
# --- Link FreeRTOS interface target ---
STMicroelectronics_freertos_0_9_1
)
if("Cvendor:STMicroelectronics#Cclass:RTOS#Cgroup:FreeRTOS#Csub:Core#Cversion:11.2.0" IN_LIST CMSIS_COMPONENTS_LIST)
# add kernel sources, includes, portable layer…
endif()
if("Cvendor:STMicroelectronics#Cclass:RTOS#Cgroup:FreeRTOS#Csub:MemMang#Cvariant:Heap_4#Cversion:11.2.0" IN_LIST CMSIS_COMPONENTS_LIST)
# add heap_4.c
endif()
By linking STMicroelectronics_freertos_0_9_1 into ${CMAKE_PROJECT_NAME}, your application automatically gets:
You avoid manual file lists in your own CMake.
A project-specific FreeRTOSConfig.h must be provided. Create a generated/middleware folder and add FreeRTOSConfig.h. Start from a reference configuration from the STM32C5 package or a standard FreeRTOS™ Cortex® M33 example. To make this header visible to the application code, add an include path in the CMake configuration, typically in the top-level CMakeLists.txt.
Create a generated/middleware folder and a configuration header FreeRTOSConfig.h, for example:
<ProjectRoot>/generated/middleware/FreeRTOSConfig.h
Start from a reference configuration from the STM32C5 package or from a standard FreeRTOS™ Cortex®‑M33 example. For this example, the FreeRTOSConfig.h, mx_freertos_app.c, and mx_freertos_app.h are attached.
To make this header visible to your application code, add an include path in your CMake configuration. A typical approach is to add it to your top-level CMakeLists.txt:
In the top-level CMakeLists.txt file, add a source file where tasks are created and the scheduler is started:
Create mx_freertos_app.c and implement a basic LED task, for this example you can use the attached mx_freertos_app.c and mx_freertos_app.h and paste inside generated/middleware:
Then, call in main.c after the HAL and peripherals initialization:
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "mx_freertos_app.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private functions prototype -----------------------------------------------*/
/**
* brief: The application entry point.
* retval: none but we specify int to comply with C99 standard
*/
int main(void)
{
/** System Init: this code placed in targets folder initializes your system.
* It calls the initialization (and sets the initial configuration) of the peripherals.
* You can use STM32CubeMX to generate and call this code or not in this project.
* It also contains the HAL initialization and the initial clock configuration.
*/
if (mx_system_init() != SYSTEM_OK)
{
return (-1);
}
else
{
/*
* You can start your application code here
*/
app_synctasks_init ();
vTaskStartScheduler();
while (1) {}
}
} /* end main */
Given that:
The scheduler should start and the LED should toggle at the expected interval.
The integration flow used for FreeRTOS™ is not specific to RTOS middleware. It can be applied to other STM32Cube middleware that follows the same CMSIS component + CMake package model.
Applying the same pattern to other middleware
To see what middleware is available and how to enable it:
This gives you a searchable “catalog” of middleware components that can be enabled without copying files manually.
This article has provided a practical guide on how to integrate middleware that is not directly exposed in the STM32CubeMX2 GUI. It uses FreeRTOS™ from the STM32C5 package as a concrete example on the NUCLEO-C562RE.
By following the step-by-step instructions, you have seen how to:
Using the CMake integration delivered with the STM32Cube packages avoids manual source management. It keeps the project aligned with the MX2 generated organization, and makes it easier to update or extend the configuration. Combined with the CMake based MX2 flow and Visual Studio Code, this approach offers a maintainable and scalable way to add advanced middleware such as: RTOS, USB, FatFs or LwIP to STM32 applications, while preserving a clean and modular project structure.