搭建 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 后你也不想它继续跑吧?

注意:release 配置里 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 插件,图形化界面更直观。

核心流程总结:
  1. 安装 Rust 工具链 → rustup
  2. 添加嵌入式目标 → rustup target add thumbv7em-none-eabihf
  3. 配置 Cargo 项目 → 设置 target、依赖 cortex-m-rt
  4. 安装 probe-rs → cargo install probe-rs
  5. 编译 + 烧录 → cargo build --release && probe-rs run ...
Rust 嵌入式开发环境搭建流程 安装 Rust 工具链 添加嵌入式目标 配置 Cargo 项目 安装 probe-rs 编译固件 烧录与调试 整个流程走通后,你就有了一个可编译、可烧录、可调试的 Rust 嵌入式开发环境

环境搭好之后,下一步就是写真正的 RTOS 内核了。不过在那之前,我建议你先用 cargo build --release 编译一下,看看生成的二进制有多大。一个空循环的固件大概 2KB 左右,如果超过 10KB,说明哪里配置有问题。

嗯,今天就到这儿。把环境跑通,后面的事情就顺了。