STM32L552基于VScode+CubeMX开发环境搭建
[W01/16] 开发环境搭建:从零到 VSCode 能点亮 NUCLEO-L552ZE-Q 的 LD1
《Cortex-M33 内核与 RTOS 源码学习》系列第 1 篇
硬件:NUCLEO-L552ZE-Q · 主机:Windows 11
目标:装完工具链 → CubeMX 生成工程 → VSCode 编译烧录 → LD1 闪起来
开篇:为什么折腾 VSCode,而不是直接用 CubeIDE
先把结论摆前面:CubeIDE 能用,但它不是我想要的日常环境。
三个理由:
- AI 插件生态。VSCode 里能挂各种代码助手、clangd、Copilot,看源码效率比 CubeIDE 高一个量级。后面读 RTX5 和 FreeRTOS 源码的时候你会感谢自己这个选择。
- 工具链解耦。CubeIDE 把 GCC、OpenOCD、Eclipse、CubeMX 全绑一起,想换编译器或换调试器都得费劲。VSCode + CMake + arm-none-eabi-gcc 是业界通用组合,跳到别的芯片、别的 RTOS 都能复用。
- 轻。CubeIDE 启动 10 秒 vs VSCode 2 秒。这个差距每天累积很可观。
但 CubeIDE 还是要装——当 VSCode 出问题时它是第二参照,官方例程也是它打开最顺手。我把它定位成"备用 IDE + 应急调试器"。
最终技术栈:
STM32CubeMX → 图形化生成初始化代码 + CMake 工程骨架
STM32CubeCLT → 命令行工具链(arm-none-eabi-gcc + OpenOCD + ST-LINK 驱动)
STM32CubeIDE → 备用 IDE(可选,但推荐装)
STM32CubeProgrammer→ 烧录和 Option Byte 查看(TrustZone 调参必备)
VSCode → 主力编辑器
└─ 插件:STM32 VS Code Extension / C-C++ / clangd / Cortex-Debug
一、硬件准备
1.1 板子
NUCLEO-L552ZE-Q,STMicroelectronics 官方开发板。
关键参数:
| 项 | 内容 |
|---|---|
| 主芯片 | STM32L552ZET6Q(Cortex-M33,110 MHz) |
| Flash / RAM | 512 KB / 256 KB |
| 板载调试器 | ST-LINK/V3E |
| 供电 | USB Type-C 或外部 |
| 特色 | 支持 TrustZone、Arduino Uno V3 扩展接口、SMPS 低功耗 |
1.2 线材
一条 USB Type-C 数据线,插 CN1(STLINK USB)。注意两件事:
- 必须是数据线,不是充电线。部分廉价 Type-C 线只有电源没有 D+/D-,插上去板子能亮灯但电脑识别不到 ST-LINK。
- 插 CN1 不是 USB USER。板子上有两个 Type-C 口,CN1 带 “STLINK” 丝印,只有它走 ST-LINK/V3E;CN8(USB USER)是给用户 USB 外设用的,插错了不报错但烧不进去。
1.3 上电验证
线插好后,板子上应该看到:
- LD4 红色常亮(电源指示)
- LD6 绿色(COM LED,ST-LINK 通信时闪烁)
Windows 设备管理器里应多出:
- USB 串行设备(一个虚拟 COM 口,ST-LINK/V3E 的 VCP)
- USB 大容量存储设备(NOD_L552ZE-Q 盘符,拖 .bin 文件到里面即可烧录——这是 ST-LINK 的 Mass Storage 模式)
如果这三样没到位,大概率是线或驱动问题,先解决这里再往下走。
二、软件清单与下载顺序
顺序很重要,装错顺序会导致 VSCode 找不到工具链。
| # | 软件 | 大小 | 下载地址 |
|---|---|---|---|
| 1 | STM32CubeCLT | ~500 MB | ST 官网 → st.com/en/development-tools/stm32cubeclt.html |
| 2 | STM32CubeMX | ~400 MB | ST 官网 → stm32cubemx |
| 3 | STM32CubeProgrammer | ~300 MB | ST 官网 → stm32cubeprog |
| 4 | STM32CubeIDE(可选) | ~1 GB | ST 官网 → stm32cubeide |
| 5 | VSCode | ~100 MB | code.visualstudio.com |
| 6 | Git for Windows | ~60 MB | git-scm.com |
⚠️ 下载要注册 ST 账号,免费,但邮箱激活链接有时进垃圾箱。
推荐装到非 C 盘非中文非空格路径,比如 D:\ST\。后面 CMake 路径调用对空格和中文敏感,早期图省事后期难排查。
三、安装步骤详解
3.1 STM32CubeCLT(先装这个!)
这是整个 VSCode 方案的灵魂——它提供了:
arm-none-eabi-gcc(交叉编译器)cmake/ninjaopenocd(烧录调试后端)STM32_Programmer_CLI(命令行烧录)
安装要点:
- 默认路径
C:\ST\STM32CubeCLT_<版本>可以用。 - 安装最后一步勾选 “Add to PATH”,否则 VSCode 找不到。
- 装完打开 PowerShell 验证:
arm-none-eabi-gcc --version
# 应输出:arm-none-eabi-gcc (GNU Tools for STM32 xx.x.xxx) 12.x.x
没输出就是 PATH 没生效,重启电脑或手动在环境变量里把 C:\ST\STM32CubeCLT_<版本>\GNU-tools-for-STM32\bin 加进去。
3.2 STM32CubeMX
- 安装过程中会要求装 JRE,同意。
- 首次启动会提示更新 MCU 库,选择更新。网速慢可以先跳过,用的时候再装。
- 首次启动 File → Manage embedded software packages → 下载 STM32Cube FW_L5 固件包(对应 L552)。
3.3 STM32CubeProgrammer
- 一路下一步。
- 装完打开能连接 ST-LINK/V3E 就算成功。这工具看 Option Bytes(TrustZone 的 TZEN 位就在这里)时会非常好用,第 5 周讲 TrustZone 必装。
3.4 VSCode + 插件
VSCode 本体装完后,在 Extensions 面板按顺序装:
| 插件 | 发布者 | 作用 |
|---|---|---|
| STM32 VS Code Extension | STMicroelectronics | 官方插件,一键识别 CubeMX 工程 |
| C/C++ | Microsoft | 基础 IntelliSense |
| clangd | LLVM | 真正好用的补全(和 C/C++ 二选一,后面讲如何切换) |
| Cortex-Debug | marus25 | GDB 调试前端 |
| CMake Tools | Microsoft | CMake 集成(STM32 插件会自动装) |
关键一步:装完 STM32 扩展后,按 Ctrl+Shift+P → STM32 VS Code Extension: Check system requirements。
如果看到:
Arm Tools: 0
说明 CubeCLT 没被识别。两个办法:
- Command Palette → STM32 VS Code Extension: Set up STM32CubeCLT path,手动指到
C:\ST\STM32CubeCLT_<版本>。 - 检查环境变量
STM32_CUBE_CLT_PATH是否存在。
看到 Arm Tools: ✓ 才算通。
四、CubeMX 生成第一个 VSCode 工程
4.1 新建工程
- CubeMX 启动 →
ACCESS TO BOARD SELECTOR - 搜索
NUCLEO-L552ZE-Q→ 选中 →Start Project - 弹窗"Initialize all peripherals with their default Mode?"——选 Yes,LED/按键会自动配好。
4.2 ⚠️ 三个必调项(第 1 周关键)
这三个不调好,后面所有的麻烦都会翻倍。
① Project Manager → Project → Toolchain / IDE:选 CMake
这是 VSCode 方案的命门。默认是 MDK-ARM,选错了生成出来的工程 VSCode 认不出来。
② System Core → TrustZone:Disabled(第 1 周暂时关掉)
很多人不知不觉就把 TrustZone 开了——标志是生成的工程名带 _S 和 _NS 后缀、有两套 main.c。第 1 周先关掉,专注搞通基础链路;第 5 周(Module D)再正式研究。
验证方法:CubeMX 左上角芯片框不应该有 “TrustZone” 字样。如果有,去 System Core → TrustZone 关掉。
③ Middleware → FreeRTOS:Disabled(第 1 周暂时关掉)
CubeMX 的 FreeRTOS 不是我们要学的那个——它是 CMSIS-RTOS2 封装过的版本,学源码反而碍事。第 3 周讲上下文切换时我们从 GitHub 拉原版 FreeRTOS 源码手动集成。
4.3 其他该确认的
| 位置 | 设置 | 说明 |
|---|---|---|
| System Core → SYS → Timebase Source | SysTick | 第 1 周裸机无 RTOS,SysTick 就够了;后期上 RTOS 会改成 TIM6 |
| System Core → CORTEX_M33_NS → ICACHE | Enabled | ST 强烈推荐,Flash 访问加速 |
| Clock Configuration | HCLK = 110 MHz | 板子最高频,用 MSI + PLL |
| Project Manager → Code Generator → Generate peripheral init as pair of .c/.h | 勾选 | 代码清晰,每个外设一个文件 |
4.4 生成代码
Project Manager → Project:
- Project Name:
L552_W01_Blinky(或你喜欢的任何名,避免空格和中文) - Project Location:
D:\stm32_projects\(同上,避免中文和空格) - Toolchain/IDE:
CMake(再次确认!)
点右上角 GENERATE CODE。
生成成功后会弹窗:“Open Folder with VS Code”——点 Yes。
五、在 VSCode 里编译、烧录、调试
5.1 编译
VSCode 打开工程后,左下角状态栏:
- Build preset:
Debug(默认) - Kit:
arm-none-eabi(应该自动识别,没识别就手动选)
按 Ctrl+Shift+P → STM32 VS Code Extension: Build,或者直接点状态栏的齿轮图标。
成功输出:
[build] [100%] Linking C executable L552_W01_Blinky.elf
[build] Build finished with exit code 0
生成文件在 build/Debug/L552_W01_Blinky.elf。
想要 .bin/.hex? 打开 CMakeLists.txt,找到:
# 在文件末尾加:
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -O binary $<TARGET_FILE:${CMAKE_PROJECT_NAME}> $<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>/${CMAKE_PROJECT_NAME}.bin
COMMAND ${CMAKE_OBJCOPY} -O ihex $<TARGET_FILE:${CMAKE_PROJECT_NAME}> $<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>/${CMAKE_PROJECT_NAME}.hex
COMMENT "Generating .bin and .hex"
)
重新 Build,同目录下就会有 .bin 和 .hex。
5.2 烧录
三种方式,按推荐度排序:
方式 A:拖 .bin 到 U 盘(最简单)
打开资源管理器,找到 NOD_L552ZE-Q 盘,把 L552_W01_Blinky.bin 拖进去。LD6 闪几下,自动烧录 + 复位。零工具、零配置,适合快速验证。
方式 B:VSCode 一键烧录
Ctrl+Shift+P → STM32 VS Code Extension: Flash,调用 OpenOCD 烧录。生产环境推荐这个,能和 CI 结合。
方式 C:STM32CubeProgrammer
图形化工具,看 Option Byte 和调 TrustZone 时必用,日常烧录有点杀鸡焉用牛刀。
5.3 调试:单步操作完整手册
这一节是重点,也是读者真正想学的部分。我按「配置 → 启动 → 基本单步 → 断点 → 观察窗口 → 进阶观测」六步写,每步都能直接照做。
5.3.1 确认 Build Type 是 Debug
左下角状态栏点 Release → 选 Debug,或 Ctrl+Shift+P → CMake: Select Variant → Debug。
Release 模式下编译器会优化掉大量中间变量,单步时光标会乱跳,看起来像见鬼。第 1 周到第 16 周,日常调试一律用 Debug 模式。
5.3.2 生成或检查 launch.json
左侧调试面板(Ctrl+Shift+D)→ 如果看到 create a launch.json file 就点它 → 选 Cortex Debug。
自动生成的 .vscode/launch.json 应该长这样(关键字段):
{
"version": "0.2.0",
"configurations": [
{
"name": "STM32 Debug (ST-LINK)",
"type": "cortex-debug",
"request": "launch",
"servertype": "stlink",
"cwd": "${workspaceFolder}",
"executable": "${workspaceFolder}/build/Debug/L552_Template_Base.elf",
"device": "STM32L552ZE",
"interface": "swd",
"runToEntryPoint": "main",
"svdFile": "${workspaceFolder}/STM32L552.svd",
"showDevDebugOutput": "none"
}
]
}
两个关键字段解释:
runToEntryPoint: "main"—— F5 启动后自动跑到main()暂停。想从Reset_Handler第一条指令看起(第 2 周要干的事),把它改成"Reset_Handler"。svdFile—— 指向 STM32L552 的 SVD 文件(寄存器描述),有了它 Cortex Peripherals 窗口才能按名字显示 NVIC/SCB/SysTick。从 ST 官网 CMSIS Pack 里能找到。没有这个文件第 2 周会很难受。
5.3.3 启动调试(F5)
确保板子插好 USB-C、ST-LINK/V3E 识别正常,按 F5 或点左上角绿色三角。
正常流程:
- 底部状态栏变橙色,显示
Cortex-Debug: Flash ... - OpenOCD 把 elf 烧进 Flash(几秒)
- CPU 复位 → 跑到
main()入口第一行暂停 - 左侧自动出现 CALL STACK / VARIABLES / WATCH / BREAKPOINTS 等面板
此时你应该看到:
- 编辑器里
main.c的第一行左边出现一个黄色箭头 ▶ - CALL STACK 里只有
main @ main.c:XX - 顶部浮动工具栏出现 6 个图标:⏸ ▶ ⟲ ⬇ ↪ ↩ ■
5.3.4 单步键位表(背下来这张)
| 快捷键 | 动作 | 什么时候用 |
|---|---|---|
| F5 | Continue 继续运行 | 跑到下一个断点,或自由运行 |
| F10 | Step Over 单步跳过 | 遇到函数调用不进去,直接执行完看结果 |
| F11 | Step Into 单步进入 | 遇到函数调用跳进去看里面怎么跑的 |
| Shift+F11 | Step Out 单步跳出 | 跳进函数了但不想看,直接跑完返回上一层 |
| Ctrl+Shift+F5 | Restart 重启调试 | 想从头再来 |
| Shift+F5 | Stop 停止调试 | 结束这次会话 |
| F9 | Toggle Breakpoint | 在光标所在行加/删断点 |
90% 的调试场景只用 F5 / F10 / F11 / F9 这 4 个键。
5.3.5 断点
普通行断点:
- 编辑器行号左边点一下(空白处,不是行号本身)→ 出现红圆点 → 设断点
- 或光标停在那行按 F9
- 再点一下 / 再按一次 F9 → 取消
条件断点(RTOS 调试神器):
- 右键红圆点 → Edit Breakpoint → 输入条件,如
thread_count > 5→ 只有命中这个条件才停 - 用途:调度器跑了几百次才出问题时,用条件断点只停"出问题那次"
函数断点(不用先翻代码找行号):
- BREAKPOINTS 面板右上
+→ 输入函数名,如PendSV_Handler→ 任何跳进这个函数的时刻都会停 - 用途:第 6 周读 PendSV 时用这个比翻源码找行号快十倍
数据断点 / 观察点(Data Breakpoint):
- VARIABLES 面板右键变量 → Break on Value Change
- 用途:某个变量被改了但不知道谁改的——例如 RTOS 的
osRtxInfo.thread.run.curr被异常改写,用数据断点抓现场 - ARMv8-M 只有 2–4 个硬件 watchpoint,省着用
5.3.6 六大观察窗口
按调试深度从浅到深排:
① VARIABLES(左侧面板上方)
- 自动显示当前作用域的局部变量和函数参数
- 鼠标悬停在代码里的变量上也能看到值
- 右键 → Set Value 可以直接改变量,不用重编译
② WATCH(左侧面板中部)
- 加入想持续追踪的表达式:
osRtxInfo.thread.run.curr->name、*(volatile uint32_t*)0xE000ED08(VTOR 地址)、HAL_GetTick() - 每次停下都会刷新
- RTOS 学习主力窗口
③ CALL STACK(左侧面板顶部)
- 显示调用链:
PendSV_Handler → osRtxPendSV → osRtxThreadSwitch → ... - 点任意一层会切到那层的源码和局部变量——读 RTX5 源码时极其关键
④ Cortex Registers(点左侧面板里的 XPERIPHERALS → Cortex Live Watch,或 Ctrl+Shift+P → Cortex-Debug: Registers)
- 显示 R0–R15、xPSR、MSP、PSP、PRIMASK、BASEPRI、FAULTMASK、CONTROL
- RTOS 内核学习的核心观测窗口。第 2 周要看的"上电 MSP 初值从哪里来"就靠这个
⑤ Cortex Peripherals(SVD 外设视图)
- 左侧面板下方 CORTEX PERIPHERALS → 展开 NVIC / SCB / SysTick / GPIO
- 能看到每个寄存器的每个位域的名字和当前值
- 第 4 周讲
SCB->CCR.STKALIGN、SCB->VTOR、第 5 周讲 NVIC 优先级都要反复用 - 没有 svdFile 这个窗口就是空的
⑥ Disassembly 反汇编视图
Ctrl+Shift+P→Open Disassembly View- 显示当前 PC 附近的反汇编(带源码交叉对照)
- 按 F10 会进行"汇编级单步",一条 Thumb 指令一步
- 第 6 周读
PendSV_Handler汇编时必开
5.3.7 第一次调试练习(不写代码,只练操作)
照做一遍,熟悉手感:
- F5 启动,停在
main()第一行 - 打开 Cortex Registers 窗口,记下当前 MSP 和 PSP 的值(写在纸上)
- 打开 Cortex Peripherals → 展开 SCB → 找到
VTOR,记下它的值(应该是0x08000000,你的 Flash 起始地址) - 在
HAL_Init();那行按 F9 加断点 - 按 F10 几下,看黄色箭头一行一行往下走
- 按 F5 继续,停在
HAL_Init()那行 - 按 F11 进入
HAL_Init,看 CALL STACK 多了一层 - 按 Shift+F11 跳出
- 按 Shift+F5 结束
做完这 9 步,你就掌握了 80% 的日常调试操作。第 2 周我们会把步骤 2 和 3 的观测升级——用它们来解剖整个启动过程。
5.3.8 调试常见错误
| 报错 | 原因 | 解决 |
|---|---|---|
No ST-LINK detected |
ST-LINK 被 CubeProgrammer / CubeIDE 占用 | 关掉那些窗口 |
Error: unable to open CMSIS-DAP device |
驱动没装 / 线松了 | 重插 USB、装 CubeProgrammer(带驱动) |
| F5 启动后停在汇编而非 C 代码 | elf 里没调试符号 | 确认 Build Type 是 Debug 不是 Release |
| 单步时光标乱跳 | Release 优化 / -O2 级别高 |
同上,切回 Debug |
svdFile not found |
SVD 文件路径错 | 下载 STM32L552.svd 放到 ${workspaceFolder} |
| 断点打了没停 | 代码被优化掉了 / 编的不是当前 elf | 清 build 目录重新编 |
六、验证:让 LD1 闪起来
默认 CubeMX 模板不会自动闪灯,需要手动改一行。打开 Core/Src/main.c,找到 while (1) 主循环:
while (1)
{
HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
HAL_Delay(500);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
注意 要写在 USER CODE BEGIN 3 和 USER CODE END 3 之间,否则下次 CubeMX 重新生成会清掉你的代码。
Build → Flash → 板子上 LD1(绿色)应该以 1 Hz 闪烁。
看到 LD1 闪起来的那一刻,第 1 周的主线任务就完成了。
七、常见坑汇总
| 现象 | 原因 | 解决 |
|---|---|---|
Arm Tools: 0 |
CubeCLT 路径没识别 | 手动 Set up STM32CubeCLT path,或加环境变量 |
| VSCode 编译时一堆 undefined reference | TrustZone 被意外开启,生成了两套工程 | CubeMX 里 TrustZone→Disabled,重新生成 |
工程文件名带 _NS 后缀 |
同上 | 同上 |
| 烧录失败"Target not found" | USB 线不对 / 插错 USB 口 | 换数据线 / 插 CN1 |
| clangd 找不到头文件 | 没有 compile_commands.json | Build 一次后 clangd 会自动识别;或在 settings 里指到 build/Debug/compile_commands.json |
| LD1 不闪 | CubeMX 默认没有闪灯代码 | 上面第 6 节手动加 |
| 调试进不了 main,停在 Reset_Handler | 正常!启动代码在 startup_stm32l552xx.s,单步 si 能一路走到 main |
—— |
更多推荐
所有评论(0)