搭建 Rust 嵌入式开发环境:从零到能烧录
说实话,嵌入式开发的第一步往往不是写代码,而是把环境折腾好。我见过太多新手卡在工具链安装上,一卡就是半天。今天咱们就把这事彻底搞定。
我们的目标很明确:装好 Rust 工具链,加上 ARM Cortex-M4F 的目标支持,配置一个能用的 Cargo 项目,最后用 probe-rs 把程序烧进去、跑起来。整个过程我大概会花 20 分钟讲完,但你跟着做可能需要 40 分钟——因为网络下载是个变量。
安装 Rust 工具链
如果你机器上还没有 Rust,去 rustup.rs 下载安装器就行。我个人习惯用这条命令:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
装完之后检查一下版本:
rustc --version
cargo --version
嗯,看到类似 rustc 1.77.0 这样的输出就对了。我遇到过有人装完发现 rustc 找不到,多半是没把 ~/.cargo/bin 加到 PATH 里。重启终端或者手动加一下就好。
~/.cargo/config.toml 里加上 registry 镜像,能省不少下载时间。
添加嵌入式目标:thumbv7em-none-eabihf
Rust 默认只装了宿主机的目标(比如 x86_64-unknown-linux-gnu)。我们要给 ARM Cortex-M4F 加目标支持。这个目标名叫 thumbv7em-none-eabihf,拆开来看:
- thumbv7em — ARMv7E-M 架构,带 DSP 扩展
- none — 没有操作系统(bare-metal)
- eabihf — 硬浮点 ABI,用硬件 FPU 算浮点数
添加目标很简单:
rustup target add thumbv7em-none-eabihf
等几秒钟下载完,用这条命令确认:
rustc --print target-list | grep thumbv7em
你应该能看到 thumbv7em-none-eabihf 在列表里。我曾经手滑输成 thumbv7em-none-eabi(少了个 hf),结果编译出来的程序在板子上跑起来浮点运算全乱套。所以千万注意这个 hf 后缀,它代表硬浮点。
| 目标三元组 | 架构 | 浮点支持 | 典型芯片 |
|---|---|---|---|
| thumbv6m-none-eabi | Cortex-M0/M0+/M1 | 无 | STM32F0, nRF51822 |
| thumbv7m-none-eabi | Cortex-M3 | 无 | STM32F1, LPC1768 |
| thumbv7em-none-eabihf | Cortex-M4F/M7 | 硬浮点 | STM32F4, nRF52840 |
| thumbv8m.main-none-eabihf | Cortex-M33 | 硬浮点 | STM32L5, nRF5340 |
配置 Cargo 项目
现在创建一个新项目:
cargo new --bin rust-rtos-demo
cd rust-rtos-demo
然后编辑 .cargo/config.toml(没有就新建),告诉 Cargo 默认用哪个目标:
[build]
target = "thumbv7em-none-eabihf"
[target.thumbv7em-none-eabihf]
runner = "probe-rs run --chip STM32F407VGTx"
这里我以 STM32F407 为例。你用的芯片不一样,把 --chip 后面的型号换成你自己的就行。我手头这块板子是 STM32F407VGT6,所以这么写。
接下来要加一个关键依赖——cortex-m-rt,它提供启动代码和中断向量表。打开 Cargo.toml:
[dependencies]
cortex-m-rt = "0.7"
cortex-m-semihosting = "0.5"
panic-halt = "0.2"
[profile.release]
lto = true
codegen-units = 1
opt-level = "s"
这里我顺手加了 cortex-m-semihosting 用于调试输出,panic-halt 让 panic 时直接死循环——嵌入式环境里 panic 后你也不想它继续跑吧?
codegen-units = 1 和 lto = true 很重要。前者保证链接顺序可控,后者能大幅减小二进制体积。我见过有人没设这两项,编译出来的固件大了 30%,还莫名其妙跑飞了。
写个简单的 src/main.rs 验证一下:
#![no_std]
#![no_main]
use cortex_m_rt::entry;
use panic_halt as _;
#[entry]
fn main() -> ! {
loop {
// 先空转,后面加任务调度
}
}
用 cargo build 编译。如果一切顺利,你会看到 target/thumbv7em-none-eabihf/debug/rust-rtos-demo 生成出来。用 cargo build --release 可以编译优化版本。
使用 probe-rs 烧录与调试
probe-rs 是目前 Rust 嵌入式生态里最顺手的烧录调试工具。安装它:
cargo install probe-rs --features cli
装好后插上调试器(J-Link、ST-Link 或 DAP-Link 都行),运行:
probe-rs list
你应该能看到类似这样的输出:
[0]: STLink v3 (VID: 0483, PID: 374e, Serial: 123456)
如果啥都没有,检查驱动和接线。我踩过最大的坑是 ST-Link 的 SWD 线序接反了——GND、SWDIO、SWCLK 三根线,接错一根就认不到芯片。
烧录命令很简单:
probe-rs run --chip STM32F407VGTx target/thumbv7em-none-eabihf/release/rust-rtos-demo
看到 Finished in 0.123s 和 Running... 就说明烧进去了。程序会在芯片上跑起来,但因为我们的 main 是个空循环,所以看不出效果。
想调试的话,用 GDB 模式:
probe-rs gdb --chip STM32F407VGTx target/thumbv7em-none-eabihf/debug/rust-rtos-demo
然后在另一个终端启动 gdb-multiarch,连上 localhost:3333 就能打断点了。我个人习惯用 VS Code 的 Cortex-Debug 插件,图形化界面更直观。
- 安装 Rust 工具链 →
rustup - 添加嵌入式目标 →
rustup target add thumbv7em-none-eabihf - 配置 Cargo 项目 → 设置 target、依赖 cortex-m-rt
- 安装 probe-rs →
cargo install probe-rs - 编译 + 烧录 →
cargo build --release && probe-rs run ...
环境搭好之后,下一步就是写真正的 RTOS 内核了。不过在那之前,我建议你先用 cargo build --release 编译一下,看看生成的二进制有多大。一个空循环的固件大概 2KB 左右,如果超过 10KB,说明哪里配置有问题。
嗯,今天就到这儿。把环境跑通,后面的事情就顺了。