1. 嵌入式Rust开发环境搭建

说实话,嵌入式Rust开发的门槛,有一半都在环境搭建上。我刚开始接触那会儿,光是搞清楚工具链怎么配、目标平台怎么选,就折腾了两三天。但一旦把这条路走通,后面就顺畅多了。

这一章,我们就来一步步把环境搭好。你跟着我走,应该不会踩太多坑。

1.1 安装Rust工具链

首先,你得有Rust。这个很简单,打开终端,敲一行命令:

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

安装完成后,重启终端,验证一下:

rustc --version
cargo --version

看到版本号,就说明装好了。我个人习惯用稳定版,因为嵌入式开发对稳定性要求高,nightly 虽然有些新特性,但偶尔会出幺蛾子。

小提示:如果你在 Windows 上开发,建议用 WSL2(Ubuntu 22.04 或更新版本)。我在项目中试过原生 Windows 环境,遇到不少链接器问题,换成 WSL2 后基本没再折腾过。

1.2 目标平台配置

嵌入式开发跟桌面开发最大的区别,就是交叉编译。你的电脑是 x86_64 架构,但目标芯片可能是 ARM Cortex-M、RISC-V 或者其他。所以,你得告诉 Rust:我要编译成什么架构的代码。

常用的目标平台有这些:

目标平台 架构 常见芯片 添加命令
thumbv6m-none-eabi Cortex-M0, M0+ STM32F0, nRF51822 rustup target add thumbv6m-none-eabi
thumbv7m-none-eabi Cortex-M3 STM32F1, LPC1768 rustup target add thumbv7m-none-eabi
thumbv7em-none-eabi Cortex-M4, M7 STM32F4, nRF52840 rustup target add thumbv7em-none-eabi
riscv32imac-unknown-none-elf RISC-V 32位 GD32VF103, CH32V307 rustup target add riscv32imac-unknown-none-elf
riscv64imac-unknown-none-elf RISC-V 64位 K210, D1 rustup target add riscv64imac-unknown-none-elf

举个例子,如果你用的是 STM32F103(Cortex-M3),就执行:

rustup target add thumbv7m-none-eabi

然后,在项目根目录创建 .cargo/config.toml 文件,写入:

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

这样,每次 cargo build 就会自动交叉编译到目标平台。嗯,这里要注意:别写错 target 名字,我刚开始就手抖写成了 thumbv7em,结果编译出来的程序在 M3 上跑不起来,查了半天才发现。

1.3 嵌入式标准库与 no_std 环境

桌面 Rust 程序默认依赖 std 标准库,它提供了文件系统、网络、线程等功能。但嵌入式芯片通常没有操作系统,也没有堆内存管理,所以标准库的大部分功能都用不了。

这时候,我们就需要 #![no_std] 属性。它告诉编译器:我不要标准库,只用核心库 core。

一个典型的嵌入式 Rust 项目入口是这样的:

#![no_std]
#![no_main]

use core::panic::PanicInfo;

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

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

这里有几个关键点:

  • #![no_std]:禁用标准库。
  • #![no_main]:禁用默认的 main 函数入口,因为嵌入式环境没有操作系统来调用 main。
  • #[panic_handler]:定义 panic 时的行为。我一般会在里面加个 LED 闪烁或者串口打印,方便调试。
  • #[entry]:来自 cortex-m-rt 或 riscv-rt 库,标记程序入口点。
注意:no_std 环境下,你不能使用 println!、Vec、String 等标准库类型。如果需要打印调试信息,得用 cortex-m-semihosting 或 rtt 这类库。我曾经在项目里忘了这一点,写了一大堆 println!,编译直接报错,尴尬得很。

1.4 调试工具:probe-rs 与 OpenOCD

写嵌入式程序,调试是逃不掉的。我推荐两个工具:probe-rs 和 OpenOCD。

1.4.1 probe-rs

probe-rs 是 Rust 社区开发的调试工具,原生支持 Rust,用起来非常顺手。安装很简单:

cargo install probe-rs --features cli

然后,用 probe-rs list 查看连接的调试器:

$ probe-rs list
The following devices were found:
[0]: J-Link (VID: 1366, PID: 0101, Serial: 123456789)

烧录和调试可以一条命令搞定:

probe-rs run --chip STM32F103C8 target/thumbv7m-none-eabi/debug/my-app

我个人特别喜欢 probe-rs 的 probe-rs debug 命令,它启动一个 GDB 服务器,然后你可以用 VSCode 或者命令行 GDB 进行断点调试。我在项目中用它调试过一个诡异的定时器中断问题,效率比用串口打印高太多了。

1.4.2 OpenOCD

OpenOCD 是老牌工具,支持各种调试器和芯片。安装方式因系统而异:

  • Ubuntu/Debian: sudo apt install openocd
  • macOS: brew install openocd
  • Windows: 从官网下载安装包,或者用 scoop install openocd

启动 OpenOCD 连接调试器:

openocd -f interface/jlink.cfg -f target/stm32f1x.cfg

然后,在另一个终端用 GDB 连接:

gdb-multiarch target/thumbv7m-none-eabi/debug/my-app
(gdb) target remote :3333
(gdb) load
(gdb) continue
我的建议:新手优先用 probe-rs,它跟 Rust 生态集成得更好,配置少,出错概率低。OpenOCD 虽然功能强大,但配置文件和命令参数比较多,容易踩坑。我刚开始用 OpenOCD 时,光配置文件就折腾了一下午。

1.5 知识体系总览

下面这张图,把整个环境搭建的流程和关系梳理了一下。你跟着这个结构走,就不会乱。

嵌入式Rust开发环境搭建知识体系 Rust工具链 目标平台配置 no_std环境 调试工具 Cortex-M RISC-V core库 panic处理 probe-rs OpenOCD rustup target add .cargo/config.toml cargo install probe-rs openocd 核心原则:先装工具链 → 配目标平台 → 建no_std项目 → 选调试工具 每一步都验证通过,再走下一步,避免问题堆积

1.6 验证环境

环境搭好之后,最好跑一个简单的例子验证一下。我一般用 cortex-m-quickstart 模板:

cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart

然后编译:

cargo build

如果编译通过,没有报错,说明环境基本没问题。接下来,你可以用 probe-rs 或者 OpenOCD 烧录到开发板上,看到 LED 闪烁或者串口输出,就大功告成了。

避坑指南:我曾经在编译时遇到 LINKER 相关的错误,原因是没安装 arm-none-eabi-gcc 或者链接器脚本没配置对。解决方案是:sudo apt install gcc-arm-none-eabi,然后在 .cargo/config.toml 里指定链接器。

好了,环境搭建就到这里。记住,这一步虽然繁琐,但值得花时间把它搞扎实。后面写驱动、调外设的时候,你会发现今天花的时间都是值得的。