1. Rust嵌入式开发环境搭建
嵌入式开发的第一步,说白了就是搭好你的"兵器库"。我见过太多初学者卡在环境配置上,代码写好了却烧不进去,那种挫败感我太懂了。这一章咱们就把 Rust 嵌入式开发环境从头到尾捋一遍,确保你手里的工具链是趁手的。
1.1 安装Rust工具链
Rust 的安装其实很简单,但有几个细节我得提醒你。我个人习惯用 rustup 来管理工具链,它就像 Rust 版本的"瑞士军刀"。
核心步骤:
- 打开终端,执行
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh - 安装完成后,运行
source $HOME/.cargo/env刷新环境变量 - 验证安装:
rustc --version和cargo --version
嗯,这里要注意:如果你在 Windows 上开发,建议用 WSL2 或者直接装 MSVC 工具链。我之前在 Windows 裸机上折腾过,踩了不少坑——链接器报错、路径问题层出不穷。后来切到 WSL2,世界清净了。
1.2 配置交叉编译目标
嵌入式开发跟桌面开发最大的区别是什么?说白了就是"交叉编译"。你的代码在 x86 电脑上写,但最终要跑到 ARM 或 RISC-V 芯片上。所以必须告诉编译器:"嘿,目标不是你自己!"
以最常见的 ARM Cortex-M 系列为例,我们需要添加对应的 target:
rustup target add thumbv7em-none-eabihf # Cortex-M4/M7 带硬件浮点
rustup target add thumbv6m-none-eabi # Cortex-M0/M0+
rustup target add thumbv7em-none-eabi # Cortex-M4 不带硬件浮点
你可能会问:"我怎么知道该选哪个?" 看芯片手册的 Core 字段就行。比如 STM32F407 是 Cortex-M4F,那就用 thumbv7em-none-eabihf。我刚开始做 STM32 项目时,就因为这个选错了 target,编译出来的程序跑起来直接 HardFault,查了半天才发现是浮点单元没对上。
| 目标三元组 | 适用架构 | 典型芯片 |
|---|---|---|
| thumbv6m-none-eabi | Cortex-M0/M0+/M1 | STM32F0, nRF51822 |
| thumbv7m-none-eabi | Cortex-M3 | STM32F1, LPC1768 |
| thumbv7em-none-eabi | Cortex-M4 (无FPU) | STM32F3 |
| thumbv7em-none-eabihf | Cortex-M4F/M7 (有FPU) | STM32F4, STM32F7 |
| riscv32imac-unknown-none-elf | RISC-V 32位 | GD32VF103, CH32V307 |
小技巧: 如果你不确定芯片的 FPU 情况,可以先选不带 hf 的版本。等程序跑通了,再切到 hf 版本做性能优化。这样能少走弯路。
1.3 安装probe-rs和openocd
工具链配好了,接下来得解决"怎么把程序烧进去"的问题。目前主流方案有两个:probe-rs 和 openocd。我个人的建议是:
- probe-rs:纯 Rust 实现,安装简单,支持 CMSIS-DAP、ST-Link、J-Link。适合新手和纯 Rust 项目。
- openocd:老牌工具,功能强大,但配置复杂。适合需要调试复杂场景的老手。
安装 probe-rs 只需要一行命令:
cargo install probe-rs --features cli
安装完成后,用 probe-rs list 检查是否能识别你的调试器。我记得第一次用 ST-Link 时,怎么都识别不到,后来发现是驱动没装好。Windows 上需要装 Zadig 把驱动换成 WinUSB,Linux 上则要配置 udev 规则。
如果你更习惯 openocd,可以这样安装:
# Ubuntu/Debian
sudo apt install openocd
# macOS
brew install openocd
# Windows
# 从 https://openocd.org/ 下载安装包
避坑指南: 我曾经在 Ubuntu 上直接用 apt 装 openocd,结果版本太旧(0.10.x),不支持新出的调试器。后来改成从源码编译,才解决了问题。建议你装之前先 openocd --version 看看版本,低于 0.11 的最好升级一下。
1.4 搭建第一个裸机项目
环境都齐了,咱们来写个"Hello World"——不过嵌入式里的 Hello World 不是打印字符串,而是让 LED 闪起来。这才是嵌入式工程师的浪漫。
先创建一个新项目:
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"
test = false
bench = false
接着创建 .cargo/config.toml,指定编译目标:
[target.thumbv7em-none-eabihf]
runner = "probe-rs run --chip STM32F407VGTx"
[build]
target = "thumbv7em-none-eabihf"
最后是 src/main.rs 的核心代码:
#![no_std]
#![no_main]
use panic_halt as _;
use cortex_m_rt::entry;
#[entry]
fn main() -> ! {
// 这里先留空,后续章节会填上GPIO控制逻辑
loop {}
}
关键点解释:
#![no_std]:告诉 Rust 我们不用标准库,因为嵌入式环境没有操作系统支持。#![no_main]:不用常规的 main 函数入口,改用#[entry]属性宏。panic_halt:发生 panic 时让程序挂起,避免未定义行为。
编译试试:
cargo build
如果一切顺利,你会在 target/thumbv7em-none-eabihf/debug/ 下看到一个 blinky 文件。这就是你的第一个嵌入式程序——虽然它什么都不做,但至少证明工具链是通的。
个人经验: 我第一次编译裸机项目时,卡在链接阶段报错 "Linking with `cc` failed"。后来发现是没装 ARM 交叉编译器。Ubuntu 上装 gcc-arm-none-eabi 就能解决。如果你用 probe-rs,它自带链接器,一般不会出这个问题。
1.5 本章知识体系
下面这张图帮你理清整个环境搭建的脉络:
这张图把整个环境搭建拆成了四个层次。你从最顶层的 Rust 工具链开始,一路往下走,每一步都验证通过再继续。我当年就是按这个顺序来的,虽然中间也踩过坑,但整体还算顺利。