STM32CubeMX2 Can't Add CMSIS-DSP Properly? Manual Integration Using CMake and Project Structure Optimization
STM32CubeMX2 Unable to Add CMSIS-DSP Properly? Manual Integration Using CMake and Project Structure Optimization
I. Background of the Issue
I recently used the STM32C542RCT6 development board to conduct trigonometric function performance tests. The development environment is as follows:
| Project | Version or Configuration |
|---|---|
| MCU | STM32C542RCT6 |
| Development Environment | VS Code |
| Project Generation Tool | STM32CubeMX2 1.1.1 |
| Build System | CMake |
| CMSIS | 6.3.0 |
| CMSIS-DSP | 1.17.1 |
| Toolchain | GCC |
The goal of this test is to compare the computational performance of the STM32C5 hardware CORDIC, CMSIS-DSP, and the standard math library’s `sinf()` function.
The CMSIS and CMSIS-DSP packages were installed in the CubeMX2 Pack Manager, but a problem arose when generating the project: while the CMSIS Core integrated successfully, the CMSIS-DSP was not generated in the project directory as expected.
Even after manually modifying the .ioc2 project configuration to include the CMSIS-DSP component in the project settings and rebuilding, the expected `arch/cmsis_dsp` directory was still missing from the project directory.
This indicates that installing the Pack, declaring components in the project configuration, and actually incorporating the component source code into the CMake build are three distinct steps.
II. Analysis of the CMake Project Generated by CubeMX2
The project generated by CubeMX2 primarily consists of the following structure:
Project09_sine/
├── Application/
│ ├── CMakeLists.txt
│ ├── app/
│ ├── bsp/
│ ├── tool/
│ └── cmake/
├── arch/
├── generated/
├── stm32c5xx_drivers/
├── user_modifiable/
├── cmake/
│ ├── components.cmake
│ ├── files.cmake
│ ├── flags.cmake
│ └── target.cmake
├── CMakeLists.txt
└── Project09_sine.ioc2
In particular, the top-level `CMakeLists.txt` file serves as the project entry point, while `cmake/components.cmake` is responsible for organizing the list of components, subdirectories, and related targets.
In `components.cmake`, you can see code similar to the following:
set(CMSIS_COMPONENTS_LIST )
if(${CMAKE_BUILD_TYPE} STREQUAL "debug_GCC_STM32C542RCT6")
list(APPEND CMSIS_COMPONENTS_LIST
"Cvendor:STMicroelectronics#Cclass:CMSIS#Cgroup:CORE#Cversion:6.2.0"
)
# 其他组件配置
endif()
add_subdirectory(arch/cmsis)
add_subdirectory(stm32c5xx_dfp)
add_subdirectory(stm32c5xx_drivers)
# 其他组件目录
target_link_libraries(${CMAKE_PROJECT_NAME}
# CubeMX2 生成的组件目标
)
There are two key points here:
- CMSIS_COMPONENTS_LIST is used to describe the CMSIS software components enabled in the current build.
- The package’s own CMakeLists.txt file can use the component list to determine which source files, header file directories, and compilation definitions to include.
Therefore, simply adding component declarations to `.ioc2` does not mean that the corresponding CMake targets, source code, and header file paths have all been incorporated into the build.
III. Verify that the CMSIS-DSP package itself supports CMake
The installed CMSIS-DSP 1.17.1 package is located at:
%LOCALAPPDATA%\stm32cube\packs\STMicroelectronics\CMSIS-DSP\1.17.1
This directory contains the package’s own CMakeLists.txt file.
This file creates a CMake target:
STMicroelectronics_CMSIS_DSP_1_17_1
and configures the corresponding header file paths and source files based on the DSP component identifiers in `CMSIS_COMPONENTS_LIST`.
Therefore, there is no need to copy the entire CMSIS-DSP software package to the Application directory, nor is it necessary to manually list all DSP source files. You can directly reuse the CMake configuration provided by the software package.
IV. Manual Integration of CMSIS-DSP
1. Verify the Software Package Path
First, verify that CMSIS-DSP 1.17.1 is installed on your computer and that the following files exist:
%LOCALAPPDATA%\stm32cube\packs\STMicroelectronics\CMSIS-DSP\1.17.1\CMakeLists.txt
2. Enable DSP in the component list
Add the following component identifiers to the original `cmake/components.cmake` file:
list(APPEND CMSIS_COMPONENTS_LIST
"Cvendor:STMicroelectronics#Cclass:CMSIS#Cgroup:DSP#Cvariant:Source#Cversion:1.17.1"
)
This step allows the CMake configuration of the CMSIS-DSP software package to recognize the currently enabled DSP components.
3. Add the CMSIS-DSP subdirectory
In `components.cmake`, add the following after `add_subdirectory(arch/cmsis)`:
add_subdirectory(
"$ENV{LOCALAPPDATA}/stm32cube/packs/STMicroelectronics/CMSIS-DSP/1.17.1"
"${CMAKE_BINARY_DIR}/cmsis_dsp"
)
4. Link the DSP target to the main project
Add the following to the existing `target_link_libraries()` function in `components.cmake`:
STMicroelectronics_CMSIS_DSP_1_17_1
For example:
target_link_libraries(${CMAKE_PROJECT_NAME}
# 原有的 CubeMX2 组件目标
STMicroelectronics_CMSIS_DSP_1_17_1
)
Note: The `target_link_libraries()` function generated by CubeMX2 uses a plain signature without keywords such as `PUBLIC` or `PRIVATE`. When adding targets, you should use the same format; do not mix the two signature types in different calls within the same target.
After making the above changes, reconfigure and recompile the project.
V. Verifying Successful Integration
Configuration command:
cmake --preset debug_GCC_STM32C542RCT6
Compilation commands:
cmake --build --preset debug_GCC_STM32C542RCT6
The following files appeared in the actual compilation log:
CMSIS-DSP/1.17.1/Source/BasicMathFunctions/BasicMathFunctions.c.obj
CMSIS-DSP/1.17.1/Source/FastMathFunctions/FastMathFunctions.c.obj
CMSIS-DSP/1.17.1/Source/CommonTables/CommonTables.c.obj
CMSIS-DSP/1.17.1/Source/TransformFunctions/TransformFunctions.c.obj
Final successful link:
[66/66] Linking C executable Project09_sine.elf
生成已完成,退出代码为 0
This confirms that the CMSIS-DSP source code has been incorporated into the actual compilation process, rather than simply being listed in the project configuration.
Next, add the following to your application code:
#include "arm_math.h"
Perform a minimum functional test:
float angle = 0.5f;
float result;
result = arm_sin_f32(angle);
printf("CMSIS-DSP sin(%f) = %f\r\n", angle, result);
Expected output is close to:
CMSIS-DSP sin(0.500000) = 0.479426
At this point, the basic verification of the CMSIS-DSP calls is complete.
VI. Further Optimization: Avoiding Modifications to CubeMX2-Autogenerated Files
The method described above has been verified as feasible, but it presents a project maintenance issue: `components.cmake` is an autogenerated file, and manually added content may be overwritten when the project is regenerated.
Therefore, we will further migrate the user-maintained build configuration to the `Application` directory.
Recommended structure:
Project09_sine/
├── Application/
│ ├── CMakeLists.txt
│ ├── cmake/
│ │ └── cmsis_dsp.cmake
│ ├── app/
│ ├── bsp/
│ └── tool/
├── cmake/ # CubeMX2 生成的构建配置
├── generated/
├── arch/
├── stm32c5xx_drivers/
└── CMakeLists.txt
Specifically:
- Application/CMakeLists.txt manages the application source files, header file directories, and user compilation configurations.
- Application/cmake/cmsis_dsp.cmake manages CMSIS-DSP integration.
- The top-level CMakeLists.txt retains the project entry point and the `add_subdirectory(Application)` directive.
- The `cmake/components.cmake` file automatically generated by CubeMX2 should not retain any manual modifications made by the user.
1. User-Maintained CMSIS-DSP Configuration
Create a new file named Application/cmake/cmsis_dsp.cmake:
# User-maintained CMSIS-DSP integration
set(CMSIS_DSP_VERSION "1.17.1")
set(CMSIS_DSP_ROOT
"$ENV{LOCALAPPDATA}/stm32cube/packs/STMicroelectronics/CMSIS-DSP/${CMSIS_DSP_VERSION}"
)
if(NOT EXISTS "${CMSIS_DSP_ROOT}/CMakeLists.txt")
message(FATAL_ERROR
"CMSIS-DSP not found: ${CMSIS_DSP_ROOT}"
)
endif()
list(APPEND CMSIS_COMPONENTS_LIST
"Cvendor:STMicroelectronics#Cclass:CMSIS#Cgroup:DSP#Cvariant:Source#Cversion:${CMSIS_DSP_VERSION}"
)
add_subdirectory(
"${CMSIS_DSP_ROOT}"
"${CMAKE_BINARY_DIR}/cmsis_dsp"
)
target_link_libraries(${CMAKE_PROJECT_NAME}
STMicroelectronics_CMSIS_DSP_1_17_1
)
2. CMake Management at the Application Layer
Add the following to Application/CMakeLists.txt:
include(
"${CMAKE_CURRENT_LIST_DIR}/cmake/cmsis_dsp.cmake"
)
The application code and compilation settings are also centralized in this file. For example:
target_sources(${CMAKE_PROJECT_NAME} PRIVATE
app/callbacks.c
app/app.c
bsp/bsp_BTN.c
bsp/bsp_MT6701.c
bsp/bsp_uart.c
tool/sys_DWT.c
)
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC
${CMAKE_CURRENT_LIST_DIR}/bsp
${CMAKE_CURRENT_LIST_DIR}/app
${CMAKE_CURRENT_LIST_DIR}/tool
)
target_compile_definitions(${CMAKE_PROJECT_NAME} PUBLIC
_PRINTF_FLOAT_ENABLE=1
)
target_link_options(${CMAKE_PROJECT_NAME} PUBLIC
-u _printf_float
)
This allows for centralized management of application code, compilation macros, linking options, and third-party library integration configurations, thereby reducing reliance on automatically generated files.
3. Special Attention Must Be Paid to the CMake Execution Order
The migration plan described above has one important prerequisite: CMSIS_COMPONENTS_LIST must be prepared before the `add_subdirectory()` function in the CMSIS-DSP package is executed.
In the current top-level execution sequence of a CubeMX2 project, `add_subdirectory(Application)` is originally located before `include(cmake/components.cmake)`. If the order is not adjusted, the DSP configuration within `Application` may execute before the component list is initialized.
Therefore, you should first ensure that the component list has been established before calling the user’s CMSIS-DSP configuration. To strictly ensure that only the `add_subdirectory(Application)` user extension remains at the top level, you must verify that CubeMX2’s generation mechanism allows for adjusting the execution order, or use a separate user extension entry point.
Additionally, after CubeMX2 regenerates, you should recheck the build order, component list, and DSP targets; you cannot assume integration has succeeded simply because the user CMake file still exists.
VII. Conclusion
The core issue here is not that CMSIS-DSP lacks CMake support, but rather that there is a coordination problem between the component configuration capabilities of the CubeMX2 graphical interface, the package’s own CMake mechanism, and the execution order of the generated project.
After troubleshooting, the following was confirmed:
The CMSIS-DSP 1.17.1 package itself provides CMake configuration.
By using the correct CMSIS_COMPONENTS_LIST flag, add_subdirectory(), and target links, the DSP source code can be included in the STM32C542 project.
The actual compilation logs confirmed that the DSP source files were included in the compilation, and the final ELF file was successfully linked.
To improve project maintainability, application code and custom build logic should be placed in the `Application` directory, minimizing modifications to the files automatically generated by CubeMX2.
After migrating the configuration to the user directory, it is still necessary to verify it through three steps—regenerating, reconfiguring, and recompiling—to ensure it does not fail due to the execution order or the component list being reset.
For developers currently using STM32C5, CubeMX2, VS Code, and CMake, I hope this practical guide provides a reproducible troubleshooting approach.
Final Note: This article verifies the compilation and basic function calls of CMSIS-DSP 1.17.1 in the aforementioned STM32C542 project. Component identifiers and CMake mechanisms may vary across different CubeMX2 versions, chip families, and software package versions; when implementing this in practice, refer to the CMakeLists.txt file of the corresponding software package.
*This post has been translated from Chinese to comply with the ST Community guidelines.
