如何基于CMake实现STM32双核心项目的跨核心启动调试?
解决STM32H757I-Eval双核项目在Visual Studio中通过CMake复现跨核心启动逻辑的方案
核心思路调整
放弃将CM4设为库并静态链接到CM7的方案——这种方式会把CM4代码合并到CM7固件中,不符合双核独立执行的原生逻辑。正确的做法是:
- 单独编译CM4生成独立的二进制镜像(.bin/.hex)
- 让CM7在启动阶段将CM4镜像加载到其专属内存区域,再触发CM4启动
- 通过CMake构建流程建立CM7对CM4产物的依赖,同时在调试配置中复现CubeIDE的跨核心加载逻辑
具体CMake配置步骤
1. 根目录CMakeLists.txt组织项目
用add_subdirectory分别引入CM4和CM7子项目,明确构建依赖关系:
cmake_minimum_required(VERSION 3.20) project(STM32H7_DualCore_Project) # 引入CM4子项目,指定构建目录 add_subdirectory(CM4 ${CMAKE_BINARY_DIR}/CM4) # 引入CM7子项目,依赖CM4构建完成 add_subdirectory(CM7 ${CMAKE_BINARY_DIR}/CM7) add_dependencies(CM7_Project CM4_Project)
2. CM4子项目配置:生成独立二进制镜像
将CM4设为可执行目标,编译后用arm-none-eabi-objcopy生成.bin文件,供CM7使用:
# CM4/CMakeLists.txt add_executable(CM4_Project ${CM4_SOURCES} ${CM4_INCLUDES}) target_link_libraries(CM4_Project ${CM4_LIBRARIES}) # 生成CM4二进制镜像 add_custom_command(TARGET CM4_Project POST_BUILD COMMAND ${CMAKE_OBJCOPY} -O binary $<TARGET_FILE:CM4_Project> ${CMAKE_CURRENT_BINARY_DIR}/CM4_Project.bin COMMAND ${CMAKE_OBJCOPY} -O ihex $<TARGET_FILE:CM4_Project> ${CMAKE_CURRENT_BINARY_DIR}/CM4_Project.hex COMMENT "Generating CM4 bin/hex images" ) # 为CM4指定专属工具链参数 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -T${CMAKE_CURRENT_SOURCE_DIR}/STM32H757IITX_CM4.ld")
3. CM7子项目配置:嵌入CM4镜像并添加启动逻辑
将CM4的.bin文件转换为C头文件嵌入CM7项目,同时在CM7代码中实现CM4的加载与启动逻辑:
# CM7/CMakeLists.txt add_executable(CM7_Project ${CM7_SOURCES} ${CM7_INCLUDES}) target_link_libraries(CM7_Project ${CM7_LIBRARIES}) # 将CM4 bin文件转为C头文件,方便嵌入 set(CM4_BIN_PATH ${CMAKE_SOURCE_DIR}/CM4/build/CM4_Project.bin) add_custom_command(OUTPUT cm4_bin.c COMMAND xxd -i ${CM4_BIN_PATH} cm4_bin.c DEPENDS ${CM4_BIN_PATH} COMMENT "Generating CM4 bin header file" ) target_sources(CM7_Project PRIVATE cm4_bin.c) # 为CM7指定专属工具链参数 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -T${CMAKE_CURRENT_SOURCE_DIR}/STM32H757IITX_CM7.ld")
在CM7的启动代码或初始化函数中添加CM4启动逻辑:
#include "cm4_bin.h" #include "stm32h7xx_hal.h" void launch_cm4(void) { // 1. 使能CM4时钟 __HAL_RCC_CM4_CLK_ENABLE(); // 2. 将CM4镜像复制到其专属Flash起始地址(0x8000000) memcpy((void*)0x8000000, cm4_bin, cm4_bin_len); // 3. 设置CM4的向量表偏移 *((volatile uint32_t*)0xE00ED008) = 0x8000000; // 4. 触发CM4启动:设置栈顶指针,跳转至复位向量 __DSB(); __ISB(); ((void (*)(void))(*((volatile uint32_t*)0x8000004)))(); }
4. 工具链模块调整
修改gcc-arm-none-eabi.cmake和st-project.cmake,支持按子项目区分核心配置:
- 在子项目中通过
set覆盖全局的CMAKE_C_FLAGS、CMAKE_EXE_LINKER_FLAGS等参数,确保CM4和CM7使用各自的CPU架构、FPU配置和链接脚本
复现跨核心调试配置
在Visual Studio中创建launch.json,配合OpenOCD实现类似CubeIDE的跨核心调试:
{ "version": "0.2.0", "configurations": [ { "name": "STM32H7 Dual Core Debug", "type": "cppvsdbg", "request": "launch", "program": "${workspaceFolder}/CM7/build/CM7_Project.elf", "stopAtEntry": true, "cwd": "${workspaceFolder}", "MIMode": "gdb", "miDebuggerPath": "${env:ARM_GCC_PATH}/bin/arm-none-eabi-gdb.exe", "setupCommands": [ {"text": "target extended-remote localhost:3333"}, {"text": "monitor reset halt"}, {"text": "load ${workspaceFolder}/CM7/build/CM7_Project.elf"}, {"text": "load ${workspaceFolder}/CM4/build/CM4_Project.elf 0x8000000"}, {"text": "monitor arm7 semihosting enable"}, {"text": "monitor arm4 semihosting enable"}, {"text": "break launch_cm4"}, {"text": "continue"} ], "preLaunchTask": "Build All", "postDebugTask": "Stop OpenOCD" } ] }
同时配置tasks.json启动/停止OpenOCD:
{ "version": "2.0.0", "tasks": [ { "label": "Start OpenOCD", "type": "shell", "command": "${env:OPENOCD_PATH}/bin/openocd.exe -f interface/stlink.cfg -f target/stm32h7x.cfg", "isBackground": true, "problemMatcher": { "pattern": { "regexp": "." }, "background": { "activeOnStart": true, "beginsPattern": "Info : Listening on port 3333 for gdb connections", "endsPattern": "." } } }, { "label": "Stop OpenOCD", "type": "shell", "command": "taskkill /f /im openocd.exe" }, { "label": "Build All", "dependsOn": [ "Start OpenOCD", "Build CM4", "Build CM7" ] } ] }
关键注意事项
- 确保CM4和CM7的链接脚本内存布局无重叠,CM4默认使用0x8000000起始的Flash区域,CM7使用0x08020000及以上区域(根据板卡Flash大小调整)
- 调试时使用最新版本的OpenOCD,确保支持STM32H7的双核调试
- 启动CM4前必须完成时钟使能和向量表配置,否则CM4无法正常运行
内容的提问来源于stack exchange,提问作者Kelv
相关产品推荐
相关产品推荐

