STM32CubeMX2 无法正常添加 CMSIS-DSP?基于 CMake 的手动集成与工程结构优化
一、问题背景
最近使用 STM32C542RCT6 开发板进行三角函数性能测试,开发环境如下:
| 项目 |
版本或配置 |
| MCU |
STM32C542RCT6 |
| 开发环境 |
VS Code |
| 工程生成工具 |
STM32CubeMX2 1.1.1 |
| 构建系统 |
CMake |
| CMSIS |
6.3.0 |
| CMSIS-DSP |
1.17.1 |
| 工具链 |
GCC |
测试的目标是比较 STM32C5 硬件 CORDIC、CMSIS-DSP 和标准数学库 sinf() 的计算性能。
在 CubeMX2 的 Pack Manager 中安装了 CMSIS 和 CMSIS-DSP 软件包,但生成工程时遇到了问题:CMSIS Core 可以正常集成,CMSIS-DSP 却没有按照预期生成到工程目录中。
即使手动修改 .ioc2 工程配置,让 CMSIS-DSP 组件出现在项目设置中,重新生成后,工程目录下仍然没有得到预期的 arch/cmsis_dsp 目录。
这说明:安装 Pack、在工程配置中声明组件,以及实际把组件源码加入 CMake 构建,是三个不同的环节。
二、分析 CubeMX2 生成的 CMake 工程
CubeMX2 生成的工程主要包含以下结构:
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
其中,顶层 CMakeLists.txt 是工程入口,cmake/components.cmake 负责组件列表、子目录及相关目标的组织。
在 components.cmake 中,可以看到类似以下代码:
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 生成的组件目标
)
这里有两个关键点:
CMSIS_COMPONENTS_LIST 用来描述当前构建启用的 CMSIS 软件组件。
- 软件包自身的
CMakeLists.txt 可以根据组件列表决定添加哪些源文件、头文件目录和编译定义。
因此,仅仅在 .ioc2 中添加组件声明,并不意味着对应的 CMake 目标、源码和头文件路径已经全部接入构建。
三、确认 CMSIS-DSP 软件包自身支持 CMake
安装的 CMSIS-DSP 1.17.1 软件包位于:
%LOCALAPPDATA%\stm32cube\packs\STMicroelectronics\CMSIS-DSP\1.17.1
其中存在软件包自己的 CMakeLists.txt。
该文件会创建一个 CMake 目标:
STMicroelectronics_CMSIS_DSP_1_17_1
并根据 CMSIS_COMPONENTS_LIST 中的 DSP 组件标识,配置相应的头文件路径及源文件。
因此,没有必要把整个 CMSIS-DSP 软件包复制到 Application 目录,也不必手动列出所有 DSP 源文件。可以直接复用软件包提供的 CMake 配置。
四、手动集成 CMSIS-DSP
1. 确认软件包路径
首先确认本机已经安装 CMSIS-DSP 1.17.1,并且存在:
%LOCALAPPDATA%\stm32cube\packs\STMicroelectronics\CMSIS-DSP\1.17.1\CMakeLists.txt
2. 在组件列表中启用 DSP
在原先的 cmake/components.cmake 中加入以下组件标识:
list(APPEND CMSIS_COMPONENTS_LIST
"Cvendor:STMicroelectronics#Cclass:CMSIS#Cgroup:DSP#Cvariant:Source#Cversion:1.17.1"
)
这一步让 CMSIS-DSP 软件包的 CMake 配置能够识别当前启用的 DSP 组件。
3. 加入 CMSIS-DSP 子目录
在 components.cmake 中,add_subdirectory(arch/cmsis) 后加入:
add_subdirectory(
"$ENV{LOCALAPPDATA}/stm32cube/packs/STMicroelectronics/CMSIS-DSP/1.17.1"
"${CMAKE_BINARY_DIR}/cmsis_dsp"
)
4. 将 DSP 目标链接到主工程
在 components.cmake 原有的 target_link_libraries() 中加入:
STMicroelectronics_CMSIS_DSP_1_17_1
例如:
target_link_libraries(${CMAKE_PROJECT_NAME}
# 原有的 CubeMX2 组件目标
STMicroelectronics_CMSIS_DSP_1_17_1
)
注意: CubeMX2 生成的 target_link_libraries() 使用的是不带 PUBLIC、PRIVATE 等关键字的 plain signature。添加目标时应沿用相同形式,不能在同一目标的不同调用中混用两种签名。
完成以上修改后,重新配置并编译工程。
五、验证是否集成成功
配置命令:
cmake --preset debug_GCC_STM32C542RCT6
编译命令:
cmake --build --preset debug_GCC_STM32C542RCT6
实际编译日志中出现了如下文件:
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
最后成功链接:
[66/66] Linking C executable Project09_sine.elf
生成已完成,退出代码为 0
这证明 CMSIS-DSP 的源码已经进入实际编译流程,而不只是把软件包显示在项目配置中。
接下来,在应用代码中加入:
#include "arm_math.h"
进行最小功能测试:
float angle = 0.5f;
float result;
result = arm_sin_f32(angle);
printf("CMSIS-DSP sin(%f) = %f\r\n", angle, result);
预期输出接近:
CMSIS-DSP sin(0.500000) = 0.479426
至此,CMSIS-DSP 的基本调用验证完成。
六、进一步优化:避免修改 CubeMX2 自动生成文件
上面的方式已经验证可行,但存在一个工程维护问题:components.cmake 是自动生成文件,重新生成工程时,手动添加的内容可能被覆盖。
因此,进一步把用户维护的构建配置迁移到 Application 目录。
推荐结构:
Project09_sine/
├── Application/
│ ├── CMakeLists.txt
│ ├── cmake/
│ │ └── cmsis_dsp.cmake
│ ├── app/
│ ├── bsp/
│ └── tool/
├── cmake/ # CubeMX2 生成的构建配置
├── generated/
├── arch/
├── stm32c5xx_drivers/
└── CMakeLists.txt
其中:
Application/CMakeLists.txt 管理应用源文件、头文件目录及用户编译配置。
Application/cmake/cmsis_dsp.cmake 管理 CMSIS-DSP 接入。
- 顶层
CMakeLists.txt 保留工程入口及 add_subdirectory(Application)。
- CubeMX2 自动生成的
cmake/components.cmake 尽量不保留用户手工修改。
1. 用户维护的 CMSIS-DSP 配置
新建 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 管理
在 Application/CMakeLists.txt 中加入:
include(
"${CMAKE_CURRENT_LIST_DIR}/cmake/cmsis_dsp.cmake"
)
应用代码和编译配置也统一放在这个文件中,例如:
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
)
这样可以把应用代码、编译宏、链接选项以及第三方库接入配置集中管理,减少对自动生成文件的依赖。
3. 需要特别注意 CMake 执行顺序
上述迁移方案有一个重要前提:CMSIS_COMPONENTS_LIST 必须在 CMSIS-DSP 软件包的 add_subdirectory() 执行前准备好。
CubeMX2 当前工程的顶层执行顺序中,add_subdirectory(Application) 原本位于 include(cmake/components.cmake) 之前。若不调整顺序,Application 内的 DSP 配置可能在组件列表初始化前执行。
因此,应先保证组件列表已经建立,再调用用户的 CMSIS-DSP 配置。若要严格做到顶层只保留 add_subdirectory(Application) 这一句用户扩展,就需要确认 CubeMX2 的生成机制允许调整执行顺序,或采用单独的用户扩展入口。
此外,CubeMX2 重新生成后应重新检查构建顺序、组件列表及 DSP 目标,不能**用户 CMake 文件仍然存在就认定集成一定成功。
七、总结
这次问题的核心并不是 CMSIS-DSP 缺少 CMake 支持,而是 CubeMX2 图形界面的组件配置能力、软件包自身的 CMake 机制,以及生成工程的执行顺序之间存在衔接问题。
排查后确认:
- CMSIS-DSP 1.17.1 软件包本身提供 CMake 配置。
- 通过正确的
CMSIS_COMPONENTS_LIST 标识、add_subdirectory() 和目标链接,可以将 DSP 源码加入 STM32C542 工程。
- 实际编译日志确认了 DSP 源文件参与编译,最终 ELF 成功链接。
- 为了提高工程可维护性,应把应用代码及自定义构建逻辑放入
Application,尽量减少对 CubeMX2 自动生成文件的修改。
- 将配置迁移到用户目录后,仍需通过重新生成、重新配置、重新编译三步验证,确认不会因为执行顺序或组件列表被重置而失效。
对于正在使用 STM32C5、CubeMX2、VS Code 和 CMake 的开发者,希望这次实践能够提供一个可复现的排查思路。
最后说明: 本文验证的是 CMSIS-DSP 1.17.1 在上述 STM32C542 工程中的编译与基本函数调用。不同 CubeMX2 版本、不同芯片系列及不同软件包版本的组件标识和 CMake 机制可能有所不同,实际使用时应以对应软件包的 CMakeLists.txt 为准。