1. Rust嵌入式开发环境搭建:安装Rust工具链、配置交叉编译目标、使用probe-rs与调试器

嵌入式Rust开发,第一步就是搭环境。这事儿说难不难,说简单吧,坑也不少。我这些年帮团队搭建过不下二十次开发环境,从STM32到ESP32再到RISC-V,每次都能遇到点新花样。今天咱们就把这套流程捋清楚。

1.1 安装Rust工具链

如果你还没装Rust,直接用官方推荐的rustup。我个人习惯用这条命令:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

装完之后,确认一下版本:

rustc --version
cargo --version
rustup --version

嗯,这里要注意。如果你在Windows上开发,建议用WSL2或者直接装MSVC版本的toolchain。我曾经在Windows原生环境下折腾过一整天,最后发现是路径问题——Rust的链接器找不到某些库。后来切到WSL2,十分钟搞定。

我的建议:Linux/macOS用户直接用默认安装。Windows用户优先考虑WSL2,或者安装时选择"default host triple"为x86_64-pc-windows-msvc。

1.2 配置交叉编译目标

嵌入式开发嘛,你的代码不是在x86上跑的。你得告诉Rust:我要给ARM Cortex-M编译,或者给RISC-V编译。这就是交叉编译目标。

先看看Rust支持哪些嵌入式目标:

rustup target list | grep thumb

你会看到一堆类似这样的:

目标三元组 适用架构 典型芯片
thumbv6m-none-eabi Cortex-M0, M0+ STM32F0, nRF51822
thumbv7m-none-eabi Cortex-M3 STM32F1, LPC1768
thumbv7em-none-eabi Cortex-M4, M7 STM32F4, nRF52840
thumbv8m.main-none-eabi Cortex-M33, M55 STM32L5, nRF5340

安装目标很简单,比如我要给STM32F407(Cortex-M4)编译:

rustup target add thumbv7em-none-eabi

你想想看,这一步其实就是在你的Rust工具链里加了一套标准库的交叉编译版本。没有它,你的代码连链接都过不去。

避坑指南:我曾经在给nRF52840(Cortex-M4F)配置目标时,选了thumbv7em-none-eabi,结果浮点运算一直出问题。后来才发现,带FPU的芯片应该用thumbv7em-none-eabihf。多一个"hf"表示硬件浮点。选错了,软件浮点库会拖慢性能,而且某些外设驱动可能编译不过。

1.3 安装probe-rs与调试器

环境搭好了,怎么把程序烧进去?怎么调试?probe-rs就是干这个的。它支持J-Link、ST-Link、DAPLink等常见调试器,而且纯Rust实现,不需要装OpenOCD那种庞然大物。

安装probe-rs:

cargo install probe-rs --features cli

装完之后,接上你的调试器,运行:

probe-rs list

如果看到类似下面的输出,说明调试器被识别了:

Probing target via JTAG

Debug probe found:
  STLink V3 (VID: 0x0483, PID: 0x374e, Serial: 003F001F3138511438383133)

我刚开始用probe-rs时,遇到一个很诡异的问题——ST-Link V2识别不到。折腾了半天,发现是固件版本太旧。升级到V2.J37.S7之后就好了。所以如果你遇到类似问题,先检查调试器固件。

1.4 创建并烧录第一个嵌入式Rust项目

环境都齐了,咱们来跑个Hello World——不过嵌入式世界的Hello World是点灯。

创建一个新项目:

cargo new --bin blinky
cd blinky

编辑Cargo.toml,添加依赖:

[package]
name = "blinky"
version = "0.1.0"
edition = "2021"

[dependencies]
cortex-m-rt = "0.7"
cortex-m-semihosting = "0.5"
panic-halt = "0.2"

[[bin]]
name = "blinky"
path = "src/main.rs"

在项目根目录创建.cargo/config.toml,指定交叉编译器和链接脚本:

[target.thumbv7em-none-eabi]
rustflags = ["-C", "link-arg=-Tlink.x"]

[build]
target = "thumbv7em-none-eabi"

然后写个最简单的main.rs:

#![no_std]
#![no_main]

use panic_halt as _;
use cortex_m_rt::entry;

#[entry]
fn main() -> ! {
    loop {}
}

编译:

cargo build

烧录:

probe-rs run --chip STM32F407VGTx target/thumbv7em-none-eabi/debug/blinky
核心要点:probe-rs的run命令会烧录并自动复位运行。如果你只想烧录不运行,用probe-rs download。调试的话,probe-rs gdb可以启动GDB服务器,然后你用arm-none-eabi-gdb连接上去。

1.5 知识体系总览

下面这张图把整个环境搭建的脉络理清楚了。你照着这个流程走,基本不会迷路。

嵌入式Rust开发环境搭建流程 安装Rust工具链 配置交叉编译目标 安装probe-rs rustup安装 选择默认toolchain 验证版本 rustup target add 选择目标三元组 注意eabi/eabihf区别 cargo install probe-rs 连接调试器 probe-rs list验证 创建嵌入式Rust项目 cargo new → 配置Cargo.toml → 设置.cargo/config.toml 编译 cargo build --release 烧录与调试 probe-rs run / probe-rs gdb ✅ 开发环境就绪

1.6 常见问题与排查

搭环境这件事,一次过是运气,踩坑才是常态。我整理了几个高频问题:

问题现象 可能原因 解决方案
probe-rs list找不到调试器 驱动未安装 / 权限不足 Linux下添加udev规则;Windows下装Zadig驱动
编译报错"file not found for link.x" 缺少链接脚本或memory.x 检查.cargo/config.toml路径,或使用cortex-m-quickstart模板
烧录后芯片不运行 启动文件配置错误 / 时钟未初始化 检查vector table地址,确认boot引脚电平
GDB连接后无法单步 优化级别过高 / 调试符号缺失 debug模式编译,或加-C debuginfo=2
曾经踩过的坑:有一次我在Linux下用probe-rs烧录STM32G0,每次烧完程序就跑飞。查了两天,最后发现是芯片的Option Bytes里把读保护打开了。probe-rs烧录时没自动解锁,导致代码被加密了。解决办法是用STM32CubeProgrammer先全片擦除,或者用probe-rs的--unlock-bank0参数。

1.7 开发环境验证清单

环境搭完,别急着写代码。先跑一遍这个清单,确认每个环节都通了:

  1. 工具链验证:rustc --version 和 cargo --version 能正常输出
  2. 交叉编译目标:rustup target list --installed 包含你的目标三元组
  3. 调试器识别:probe-rs list 能看到你的调试器型号和序列号
  4. 编译测试:cargo build --release 能生成elf文件,没有链接错误
  5. 烧录测试:probe-rs run 能把程序烧进去,芯片开始运行
  6. 调试测试:probe-rs gdb 能启动GDB服务器,arm-none-eabi-gdb能连接并打断点

这六步都过了,恭喜你,环境算是稳了。后面咱们就可以开始真正玩SPI和I2C了。