背景:Cortex-M 调试为什么要绕一层 OpenOCD
嵌入式开发者调试 Cortex-M 芯片,链路通常是这样的:
IDE / GDB → OpenOCD → 调试器驱动(ST-Link / J-Link / CMSIS-DAP)→ SWD/JTAG → 目标芯片
调试器在物理层只做一件事:把 SWD/JTAG 协议翻译成 GDB 认识的 RSP(Remote Serial Protocol)。传统做法把这个翻译放在 PC 上,还要再套一层 OpenOCD 做中间件。于是每次新项目都要维护一份 openocd.cfg,interface、target、adapter speed 逐个改,改错一个参数 GDB 就对着连不上的端口报 timeout;pyOCD 路线则要配一套 Python 环境。
probe-rs 的思路是把这个中间层去掉:它用 Rust 写的驱动直接跟调试器对话,flash 烧写算法、RTT 日志、GDB stub 全部内建在一个二进制里,不需要 .cfg,不需要额外软件。
一、probe-rs 是什么
probe-rs 是一套用 Rust 编写的开源嵌入式调试工具链,截至本文版本 v0.31.0(2026 年 1 月发布)。核心能力一句话:插上调试器,一行命令烧写并调试 ARM/RISC-V/Xtensa 芯片。
bash
$ probe-rs run target/thumbv7em-none-eabihf/release/my-app
Erasing ✔ [00:00:01] [################################################] 64.00 KiB/64.00 KiB
Programming ✔ [00:00:02] [################################################] 64.00 KiB/64.00 KiB
Finished in 3.01s
自动识别调试器、自动识别芯片型号、烧写、复位运行,全程不需要配置文件。
它与传统方案的区别,本质在「协议转换发生在哪一层」:
| 方案 | 协议转换位置 | 需要的中间件 |
|---|---|---|
| ST-Link + OpenOCD | PC 上 | OpenOCD + .cfg + 驱动 |
| J-Link | PC 上 | Segger 闭源 JLinkGDBServer |
| CMSIS-DAP + pyOCD | PC 上 | pyOCD + Python 环境 |
| probe-rs | 单个 Rust 二进制内 | 无独立中间件 |
二、环境准备
安装(三选一,Linux / macOS / Windows 均支持):
bash
# 方法一:一键安装脚本(Linux/macOS)
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/probe-rs/probe-rs/releases/latest/download/probe-rs-tools-installer.sh | sh
# 方法二:cargo 安装(从源码编译)
cargo install probe-rs-tools --locked
# 方法三:下载预编译二进制
# 到 GitHub Releases 页面下载对应平台 tar.gz,解压加入 PATH
装完验证调试器是否被识别:
bash
$ probe-rs list
The following debug probes were found:
[0]: DAPLink CMSIS-DAP (VID: 0x0d28, PID: 0x0204, Serial: ..., CmsisDapVersion: V2)
插上的调试器自动识别,不需要手动指定 VID/PID。
三、上手:三个核心命令
3.1 probe-rs run ------ 烧写 + 运行
bash
# 自动检测调试器、自动识别芯片、烧写 ELF
probe-rs run --chip STM32F407VGTx ./firmware.elf
# 烧写后附加 RTT 终端看日志
probe-rs run --chip STM32F407VGTx ./firmware.elf --rtt
支持 ELF、BIN、IHEX 三种格式。注意它不挑语言------C/CMake 编译的固件只要产出 ELF 就能烧,不只是 Rust 项目。
3.2 probe-rs attach ------ 不烧写,只调试
固件已经在跑,只想挂上去看状态时用 attach。它不复位芯片、不擦 Flash:
bash
probe-rs attach --chip STM32F407VGTx
进入后可读写内存、查看寄存器、单步执行。此外还有独立的 probe-rs erase(只擦不烧)、probe-rs read/write(读写内存),以及 probe-rs gdb(启动 GDB server,默认监听 127.0.0.1:1337,供标准 arm-none-eabi-gdb 直连)。
3.3 cargo-embed ------ Rust 项目一键启动
Rust 项目里,一个 Embed.toml 配置文件即可搞定烧写、RTT 日志、GDB stub:
toml
[default.probe]
protocol = "Swd"
[default.rtt]
enabled = true
up_buffer_size = 1024
[default.gdb]
enabled = true
项目目录下执行 cargo embed,编译、烧写、RTT 日志全自动连上。
四、VSCode 集成
probe-rs 实现了 Microsoft 的 Debug Adapter Protocol(DAP),VSCode 可直接连接,F5 一键烧写 + 断点调试:
json
// .vscode/launch.json
{
"type": "probe-rs-debug",
"request": "launch",
"name": "probe-rs Launch",
"chip": "STM32F407VGTx",
"flashingConfig": {
"flashingEnabled": true,
"haltAfterReset": true
}
}
变量查看、调用栈、断点、条件断点齐全。对比 OpenOCD + GDB 的组合(需要同时维护 .cfg 和 GDB init 脚本),probe-rs 把二者合并成一个 JSON,配置量减少 80% 以上。
五、RTT 日志与 defmt
RTT(Real-Time Transfer)经调试器直接读 MCU 内存,延迟比串口 printf 低一个数量级。配合 defmt(延迟求值的日志框架,格式化在宿主机完成,MCU 只传原始数据),日志带宽比 printf 高 10 倍以上。
rust
// MCU 端
defmt::info!("ADC reading: {} mV", adc_value);
probe-rs 的 RTT 终端直接显示格式化结果。这个差距对时间敏感代码是致命的:printf 经 UART 发 "hello\r\n" 约 700µs(115200 波特率),defmt 经 RTT 同样信息约 70µs------在中断处理函数里,这就是「能定位 bug」和「加了日志 bug 反而消失」的区别。
六、支持范围与已知局限
支持范围:
- 调试器:CMSIS-DAP(含 DAPLink、PicoProbe)、ST-Link v2/v3、J-Link、FTDI、ESP32-Prog、Black Magic Probe、WLink
- 芯片架构:ARM Cortex-M、RISC-V、Xtensa(ESP32 系列)
- 宿主平台:Linux、macOS、Windows;Linux 上可用树莓派 GPIO 模拟 SWD 协议
错误信息也比 OpenOCD 友好------连不上目标板时直接提示 The target voltage is too low (0.0V). Check the target's power supply.,而不是给一堆寄存器 dump。
已知局限:
- J-Link 高级功能不支持:RTT 终端、SystemView 实时追踪、无限数量 Flash 断点等 Segger 闭源增值功能,重度依赖 J-Link 全家桶的场景继续用 Segger 工具链。
- 不支持 8/16 位架构:PIC、AVR、MSP430 不覆盖,去用 avrdude 或 MPLAB。
- 批量生产烧录弱于 OpenOCD:v0.31 暂无内建多 probe 并行烧写,量产多目标并行烧录仍是单通道,团队流水线若绑定 OpenOCD 需评估迁移成本。
- 不支持 ARM Semihosting:替代方案是用 RTT 或 defmt 做日志,性能反而更好。
七、总结
probe-rs 把嵌入式调试从「配环境半小时、调 bug 五分钟」拉回「即插即用」:一行命令、零配置文件、VSCode 一键调试。它的核心价值在于架构选择------干掉 GDB 协议的中间层,直接跟调试器对话,换来比 OpenOCD 快、比 pyOCD 简单、比 Segger 工具链开放的体验。
如果你的调试器是 CMSIS-DAP(市面上几乎所有廉价 ARM 调试器都是),基本可以即装即用。下一步就是插上调试器,跑一遍 probe-rs run。