VSCode Cmake GCC STM32开发环境搭建(寄存器版本程序移植)
一、插件安装
目前安装的插件,可能有重复功能插件,需自行判断
- STM32CubeIDE for Visual Studio Code(安装后会将涉及的插件均安装)
- Chinese (Simplified) (简体中文) Language Pack for Visual Studio Code(中文包)
- CMake Tools(Cmake编译工具,STM32CubeIDE插件安装后也会有Cmake插件,可不安装)
- C/C++(C语言插件)
- Cortex-Debug(调试插件)
- MemoryView(内存查看插件)
- Peripheral Viewer(通过SVD插件查看寄存器内容)
- Memory Inspector(内存查看)
- Hex Editor(十六进制显示编辑)
- debug-tracker-vscode(调试跟踪)
- MASM(汇编查看)
二、工程生成
- 使用 STM32Cube 插件生成空项目
- 输入工程名称
- 选择从芯片新建
- 选择芯片
- 保存路径
- 生成后的目录
三、工程配置
CMakeLists.txt配置
1、修改工程名称随文件夹名称变动
# Core project settings
# project("STM32F103VCT6")
# enable_language(C CXX ASM)
get_filename_component(PROJECT_DIR_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
set(CMAKE_PROJECT_NAME ${PROJECT_DIR_NAME})
2、修改实际源文件及对应头文件目录
# Sources
set(sources_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/Src/main.c
${CMAKE_CURRENT_SOURCE_DIR}/Src/system/gpio.c
${CMAKE_CURRENT_SOURCE_DIR}/Src/system/iic1.c
)
# Include directories for all compilers
set(include_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/Inc
)
3、定义链接目录和链接名称,主要修改链接库需要带参数 m
# Link directories and names of libraries
set(link_DIRS)
set(link_LIBS m)
4、定义输出文件名为项目名称
# Add support for blank char as part of project name
set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES OUTPUT_NAME ${CMAKE_PROJECT_NAME})
5、增加系统默认宏定义STM32F103XX
# Add project symbols (macros)
target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE
${symbols_SYMB}
$<$<COMPILE_LANGUAGE:C>: ${symbols_c_SYMB}>
$<$<COMPILE_LANGUAGE:CXX>: ${symbols_cxx_SYMB}>
$<$<COMPILE_LANGUAGE:ASM>: ${symbols_asm_SYMB}>
# Configuration specific
$<$<CONFIG:Debug>:DEBUG>
$<$<CONFIG:Release>: >
STM32F103XX
)
6、修改编译选项和链接选项,已经过多次尝试优化,编译文件尺寸已和keil接近,感兴趣的可自行研究
# Compiler options
target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE
${cpu_PARAMS}
${compiler_OPTS}
# -Wall
# -Wextra
# -Wpedantic
# -Wno-unused-parameter
$<$<COMPILE_LANGUAGE:C>:
-Wall
-fdata-sections
-ffunction-sections>
$<$<COMPILE_LANGUAGE:CXX>:
# -Wno-volatile
# -Wold-style-cast
# -Wuseless-cast
# -Wsuggest-override
-fno-rtti
-fno-exceptions
-fno-threadsafe-statics
>
$<$<COMPILE_LANGUAGE:ASM>:-x assembler-with-cpp -MMD -MP>
$<$<CONFIG:Debug>:-O0 -g3 -ggdb>
$<$<CONFIG:Release>:-Os>
)
# Linker options
target_link_options(${CMAKE_PROJECT_NAME} PRIVATE
-T${linker_script_SRC}
${cpu_PARAMS}
${linker_OPTS}
-Wl,-Map=${CMAKE_PROJECT_NAME}.map
# -u _printf_float # STDIO float formatting support (remove if not used)
# --specs=nosys.specs
--specs=nano.specs #
# -Wl,--start-group
# -lc
-lm
# -lstdc++
# -lsupc++
# -Wl,--end-group
# -Wl,-z,max-page-size=8 # Allow good software remapping across address space (with proper GCC section making)
-Wl,--print-memory-usage
)
gnu-tools-for-stm32.cmake
一般不要修改
vscode_generated.cmake配置
链接文件和头文件等文件变化时才需要修改
# Linker script
set(linker_script_SRC ${linker_script_SRC}
${CMAKE_CURRENT_SOURCE_DIR}/stm32f103xc_flash.ld
)
# Sources
set(sources_SRCS ${sources_SRCS}
${CMAKE_CURRENT_SOURCE_DIR}/Src/syscall.c
${CMAKE_CURRENT_SOURCE_DIR}/Src/sysmem.c
${CMAKE_CURRENT_SOURCE_DIR}/Src/startup_stm32f103xx.S
)
CMakePresets.json修改配置
1、一般不要修改,如果不想新建工程文件,只是芯片改了,记得来这里修改芯片型号,否则调试会报错
"CMSIS_Dname": "STM32F103VBT6",
编译
1、工程项目一定设置为debug模式,release模式编译出来的文件有问题
2、windows系统下新建clean_build.bat批处理文件清除编译缓存,代码内容如下:
del /q /f /s build\*
rmdir /s /q build\Debug
3、通过cmake编译生成执行文件

调试
1、点击调试自动生成,或者使用配置好的文件直接复制过来,配置调试文件
2、launch.json需要注意以下几个地方
{
"version": "0.2.0",
"configurations": [//cortex-debuge内的jlink
{
"cwd": "${workspaceFolder}",
"executable": "./build/Debug/${workspaceRootFolderName}.elf",
"name": "JLink6.20",
"request": "launch",
"type": "cortex-debug",
"device": "STM32F103VCT6", //芯片型号必须和Jlink软件中的型号一致
"runToEntryPoint": "main",
"showDevDebugOutput": "raw",
"servertype": "jlink",
"serverpath": "C:/Program Files (x86)/SEGGER/JLink_V620/JLinkGDBServerCL.exe",//JLinkGDBServerCL.exe自定义路径
"svdFile": "${workspaceRoot}/STM32F103xx.svd",//指定SVD文件路径,查看寄存器内容
"liveWatch": {
"enabled": true,//使能实时查看变量功能
"samplesPerSecond": 2//2秒采集一次数据
}
},
{//stm for vscode 内的stlink
"type": "stlinkgdbtarget",
"request": "launch",
"name": "STM32Cube: STM32 Launch ST-Link GDB Server",
"origin": "snippet",
"cwd": "${workspaceFolder}",
"preBuild": "${command:st-stm32-ide-debug-launch.build}",
"runEntry": "main",
"imagesAndSymbols": [
{
"imageFileName": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}"
}
]
}
]
}
2、settings.json需要注意以下几个地方
{
"cmake.cmakePath": "cube-cmake",
"cmake.configureArgs": [
"-DCMAKE_COMMAND=cube-cmake"
],
"cmake.preferredGenerators": [
"Ninja"
],
"stm32cube-ide-clangd.path": "cube",
"stm32cube-ide-clangd.arguments": [
"starm-clangd",
"--query-driver=${env:CUBE_BUNDLE_PATH}/gnu-tools-for-stm32/13.3.1+st.9/bin/arm-none-eabi-gcc.exe",
"--query-driver=${env:CUBE_BUNDLE_PATH}/gnu-tools-for-stm32/13.3.1+st.9/bin/arm-none-eabi-g++.exe"
],
"files.encoding": "gb2312"
}
3、SVD文件需要去自行下载,下载后放到主目录,svd可以去官方给的驱动包文件中找

4、调试时,通过.launch文件使能live watch功能,可实时查看变量值。
四、代码移植
.ld链接文件修改
1、主要修改配置RAM和FLASH起始地址及大小
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K-1
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 20K
}
2、涉及特殊FLASH和RAM配置的需单独配置,比如需要实现远程IAP更新,在写自身flash时需要将flash写函数搬运到RAM中,需要上电后把写flash函数和变量搬运到RAM中,需要单独定义FLASH和RAM空间,以便写flash时自身代码和变量存储区域丢失也不影响函数功能
.s启动文件修改
1、注释掉通过库函数初始化函数启动,直接通过主函数启动
/* Call the clock system initialization function.*/
; bl SystemInit
2、配套上面描述的IAP更新需要在启动main函数前搬运程序
源文件及头文件复制
1、可以按照原来的目录格式直接复制过来,但要记得在Cmake文件中添加对应的源文件及目录
部分截图
2、如果是ARMCC编译器移植过来的代码,注意ARMCC和GCC有语法区别,目前涉及到的有以下几个
- 内联汇编写法不一样
gcc写法
void WFI_SET(void)
{
__asm__ volatile ("WFI");
}
armcc写法
__asm void WFI_SET(void)
{
WFI;
}
- __packed支持不一样
gcc写法
typedef union __attribute__((aligned(2), packed)) {
uint8_t v[6];
struct __attribute__((packed)){//注意此处,arm-gcc编译器与armcc编译器对__packed的支持不一样
uint16_t ByteCount;
}
armcc写法
typedef union __attribute__((aligned(2), packed)) {
uint8_t v[6];
__packed struct {
uint16_t ByteCount;
}
五、其他注意事项
- vscode使用技巧
1、可以针对不同的开发环境,配置不同的插件
2、AI代码补全插件,下载这个插件,很好用
3、堆栈大小一定要设置合理,设置不合理,程序会跑飞,堆栈大小可以按下面的方法估算
栈大小 = (最大调用深度 × 平均栈帧大小) + (最大中断嵌套层数 × 中断栈开销) + 安全余量
网络协议栈最大8层,栈帧大小平均128字节
还要考虑函数局部变量最大值,假如定义了1个1000字节的局部变量,那么栈大小要考虑调用这个函数时会占用的栈空间
堆大小 = 显式分配需求 + 隐式分配需求 + 安全余量
显示分配:malloc/calloc/free 调用
标准库使用:printf/sprintf 等内部可能使用堆
是否有自定义内存管理
4、调试程序时一定要将launch.json中配置的芯片型号写对,要和jlink中对应的芯片型号对应,比如STM32F103CBT6,实际在jlink中是STM32F103CB;其次STM32F103CB和STM32F103C8也要区分,不能通用,可能导致程序跑飞
更多推荐



所有评论(0)