嵌入式 Rust 编程:C 工程师的 Embassy 入门与进阶
Part0 大纲
《嵌入式 Rust 编程:C 工程师的 Embassy 入门与进阶》#
目标读者:熟悉 C 语言的嵌入式工程师,希望学习 Rust 嵌入式开发,特别是 Embassy 异步框架。
书籍定位:从 C 工程师的认知出发,通过类比、对比和实践,帮助读者建立 Rust 嵌入式的完整认知体系,掌握 Embassy 框架的核心用法。
全书结构:Part 1(6 章)建立 Rust 嵌入式基础认知 → Part 2(5 章)深入 Embassy 框架核心 → Part 3(4 章)工程落地与生态全景,共 15 章 + 4 个附录。
主力平台:全书代码示例以 STM32 为主力平台(C 工程师最熟悉),RP2040/RP2350 作为辅助对比平台。
与现有资源的区别:
资源 定位 与本书的关系 The Embedded Rust Book(官方) 通用入门,不针对特定读者群 本书可作为其”C 工程师视角”的补充 MicroRust micro:bit 入门,面向零基础 本书假设读者有嵌入式经验,起点更高 DigiKey 教程系列 碎片化实践教程 本书提供完整体系 本书 C 工程师 → Embassy 的系统路径 填补中文市场空白
Part 1:通用基础#
Part 1 定位:从零开始建立 Rust 嵌入式的核心认知。先帮 C 工程师跨越 Rust 语言障碍,再围绕 Rust 的优势和特点展开讲解,帮助读者理解”为什么 Rust 适合嵌入式开发”,并掌握裸机开发的基础工具和概念。
学习目标:掌握 C 工程师最需要的 Rust 核心概念(所有权、trait、枚举、泛型);理解 Rust 嵌入式的核心优势(内存安全、并发安全、零成本抽象);掌握裸机工程的完整结构和工具链使用;建立并发基础概念,为 Embassy 的学习做好理论准备;理解嵌入式 Rust 的生态层次划分。
第 1 章:为什么是 Rust?——嵌入式开发的新选择#
本章要回答的问题:Rust 在嵌入式领域解决什么问题?它相比 C 有什么优势?本书的讨论范围是什么?
- 1.1 一个 C 工程师的日常
- 野指针、缓冲区溢出、数据竞争——那些”理论上不该出现”的 bug
- 一个真实案例:并发 bug 如何在量产固件中潜伏三年
- 1.2 嵌入式语言版图
- C 的统治地位与历史原因
- C++ 在嵌入式中的尴尬处境
- MicroPython / Lua 等脚本语言的适用边界
- Rust 的定位:系统级语言,但更安全
- 1.3 Rust 的核心优势
- 内存安全:没有
malloc/free,没有悬垂指针 - 并发安全:编译器阻止数据竞争
- 零成本抽象:高级语法,底层性能
- 与 C 的互操作性:FFI 与混合编程
- 内存安全:没有
- 1.4 两种 Rust:
std环境与no_std环境- 什么是
no_std?为什么嵌入式需要它? core、alloc、std三层标准库- 与 C 的”裸机 vs Linux 应用”类比
- 什么是
- 1.5 Rust 在嵌入式领域的采用情况(2026 年现状)
- 行业数据:Rust 首次进入 TIOBE 前十(2026 年 7 月,1.34%)
- 全球超过六成科技企业已将 Rust 纳入技术路线图
- Ferrocene 通过 ISO 26262 ASIL D 认证——安全关键领域的里程碑
- 乐鑫(Espressif)将 Rust 提升为官方一等 SDK,Embassy 为默认框架
- Rust 1.94:6 倍编译速度提升 + 29 项 RISC-V 特性稳定化
- Linux 内核中的 Rust 驱动(从实验到生产)
- 1.6 本书的边界与阅读前提
- 本书覆盖:裸机 Rust + Embassy 异步框架
- 本书不覆盖:Linux 应用 Rust、Rust Web 开发、Rust 编译器原理
- 阅读前提:熟悉 C 语言、了解基本嵌入式概念(寄存器、中断、外设)
- 不要求:预先掌握 Rust(第 2 章会速成)
- 1.7 本章小结与全书预览
第 2 章:Rust 速成——C 工程师最需要的 20% 语法#
本章要回答的问题:C 工程师需要掌握哪些 Rust 概念才能读懂后续章节?这些概念和 C 的什么机制对应?
本章定位:这不是完整的 Rust 教程,而是”C 工程师的最小必要知识集”。只讲后续章节会用到的概念,用 C 的类比帮助理解。
- 2.1 所有权与借用:为什么没有
malloc/free- C 的痛点:谁负责
free? - Rust 的所有权规则:每个值有且仅有一个所有者
- 借用(
&和&mut):类比 C 的指针,但有编译期约束 - 生命周期:编译器如何保证引用有效
- 实际代码对比:C 的链表 vs Rust 的
Vec
- C 的痛点:谁负责
- 2.2 Trait:Rust 的”接口”与 C 的函数指针表
- C 的做法:
struct+ 函数指针(模拟面向对象) - Rust 的 Trait:编译期多态 vs 运行时多态
impl Trait for Type:为类型实现行为- 与 C 的回调函数表对比
- C 的做法:
- 2.3 枚举与模式匹配:替代
union + switch- C 的
enum:只是整数常量 - Rust 的
enum:可以携带数据(代数数据类型) Option<T>:替代 NULL 指针match:比switch更强大的模式匹配- 实际代码对比:C 的错误码 vs Rust 的
Result
- C 的
- 2.4 泛型与单态化:为什么”模板”不会膨胀
- C 的”泛型”:
void*或宏 - C++ 的模板:编译期代码生成
- Rust 的泛型:单态化(monomorphization)
- 为什么嵌入式中泛型不会导致代码膨胀(编译器优化)
- C 的”泛型”:
- 2.5 错误处理:
Result替代错误码- C 的做法:返回
-1,检查errno - Rust 的
Result<T, E>:错误是值,不是异常 ?操作符:优雅的错误传播panic!:不可恢复错误(类比 C 的assert+abort)
- C 的做法:返回
- 2.6 闭包与迭代器:嵌入式中的零成本用法
- C 的函数指针 vs Rust 的闭包
- 迭代器链:编译器会优化为与手写循环相同的代码
- 在嵌入式中的典型用法:
map、filter、for_each
- 2.7 模块系统与
use:替代#include- C 的
#include:文本替换 - Rust 的
mod+use:命名空间与可见性 pub与封装:比static更精细的访问控制
- C 的
- 2.8 本章小结
- 速查表:C → Rust 概念对照(见附录 A)
- 后续章节中会遇到的 Rust 特性预告
- 推荐深入学习资源
第 3 章:开始上路——第一个裸机工程#
本章要回答的问题:Rust 裸机工程长什么样?每个文件的作用是什么?怎么编译、烧录、调试?
- 3.1 从 C 到 Rust:工程结构的映射
- C 工程:
main.c+startup.s+linker.ld+Makefile - Rust 工程:
main.rs+memory.x+Cargo.toml+.cargo/config.toml - 逐项对照表
- C 工程:
- 3.2 创建项目与配置依赖
cargo new与项目模板Cargo.toml中的关键依赖:cortex-m-rt、panic-halt、defmt- Feature flag 的概念(类比 C 的
#ifdef)
- 3.3 交叉编译与 target triple
- 什么是 target triple?(
thumbv7em-none-eabihf的含义) - 与 C 的交叉编译工具链对比(
arm-none-eabi-gcc) rustup target add与.cargo/config.toml配置
- 什么是 target triple?(
- 3.4 配置工程文件
.cargo/config.toml:默认 target、runner、rustflagsmemory.x:简要说明(详细内容见第 12 章)build.rs:构建脚本的作用
- 3.5
cortex-m-rt的简要说明- 它做了什么:设置向量表、定义入口点
Reset_Handler、初始化.bss - 与 C 的
startup.s的对应关系 - 深度解析留到第 12 章
- 它做了什么:设置向量表、定义入口点
- 3.6 异常与中断的简要说明
#[exception]和#[interrupt]宏- 与 C 的中断服务函数对比
- 优先级配置的基本概念
- 3.7 查看编译产物
cargo build --releasecargo size:查看 Flash 和 RAM 占用cargo objdump:反汇编查看- 与 C 的
arm-none-eabi-size/objdump对比
- 3.8 烧录与 RTT 输出
- probe-rs:新一代调试探针工具
cargo run一键编译 + 烧录 + 日志- RTT(Real-Time Transfer)原理
- 与 C 的 OpenOCD + GDB 流程对比
- 3.9 工具链层次全景图
- 从源码到芯片的完整链路概览
- 各层工具的职责(详细展开在第 12 章)
- 3.10 Rust 库生态与使用方式
- crates.io:Rust 的包管理器
- 与 C 的”手动下载源码 + 加入工程”对比
- 版本管理与
Cargo.lock
- 3.11 本章小结
第 4 章:零成本抽象——当类型系统遇见寄存器#
本章要回答的问题:Rust 的高级语法会不会让程序变慢?类型状态模式是什么?unsafe 在嵌入式中的角色是什么?
- 4.1 一个 C 工程师的合理疑虑
- “这么多抽象层,编译出来不会比 C 慢吧?”
- 用数据说话:同一功能的 C 代码 vs Rust 代码的反汇编对比
- 4.2 GPIO 的类型状态抽象
- C 的做法:直接操作寄存器地址
- Rust 的做法:
Pin<Output<PushPull>>类型状态 - 类型状态模式:用类型编码硬件状态,编译期阻止非法操作
- 代码对比:C 的”忘记配置 GPIO 模式”vs Rust 的”编译不通过”
- 4.3 零成本抽象的编译结果
- 反汇编对比:类型状态 Rust 代码 vs 直接寄存器操作 C 代码
- 结论:生成的机器码完全相同
- 与 C 的
inline函数和#define宏的对比
- 4.4 单例模式
- 为什么外设是单例?(一个芯片只有一个 GPIOA)
- C 的做法:全局变量 + 约定
- Rust 的做法:
take()/Peripherals单例 - 编译期保证:不可能同时获取两个 GPIOA
- 4.5
unsafe在嵌入式中的角色- 什么时候必须用
unsafe?(直接寄存器操作、DMA 缓冲区、FFI) unsafe不是”关闭检查”,而是”我向编译器保证”- 最佳实践:将
unsafe封装在安全 API 内部 - 与 C 的对比:C 中”所有代码都是 unsafe 的”
- 什么时候必须用
- 4.6 本章小结
第 5 章:并发基础——从轮询到抢占#
本章要回答的问题:嵌入式并发是什么?抢占式和协作式有什么区别?C 和 Rust 各自怎么处理并发?
本章定位:严格限定在概念层面,不涉及 Rust/Embassy 的具体实现。为第 9 章(Embassy 运行时)做理论准备。
- 5.1 并发与并行的概念
- 并发:多个任务”交替执行”(单核 MCU 的常态)
- 并行:多个任务”同时执行”(多核 MCU)
- 为什么单核 MCU 也需要并发?(响应性 + 吞吐量)
- 5.2 嵌入式并发的三种经典做法
- 超级循环(Super Loop):最简单,但响应性差
- 中断驱动:响应性好,但逻辑碎片化
- RTOS:功能完整,但引入复杂性和资源开销
- 各方案的适用场景与代价
- 5.3 抢占式调度与协作式调度
- 抢占式:调度器强制切换(RTOS 的典型做法)
- 协作式:任务主动让出(状态机的本质)
- 各自的优缺点
- 5.4 临界区与原子操作
- 什么是竞态条件?(用 C 代码举例)
- 临界区:关中断保护共享资源
- 原子操作:无锁的并发原语
- C 的做法:
__disable_irq()/__enable_irq() - Rust 的对应:
critical-sectioncrate /core::sync::atomic
- 5.5 中断的简要介绍
- 中断的本质:硬件触发的函数调用
- 中断优先级与嵌套
- 中断中的限制:不能阻塞、不能分配内存
- 与后续 Embassy 中断处理的关联预告
- 5.6 本章小结
第 6 章:可移植性与生态层次#
本章要回答的问题:embedded-hal 是什么?Rust 嵌入式生态的层次结构是怎样的?有哪些并发框架可选?
- 6.1 问题:不同芯片的外设 API 不同,驱动怎么复用?
- C 的困境:STM32 HAL 和 nRF SDK 的 API 完全不同
- 驱动开发者的痛苦:每换一个平台就要重写
- 6.2
embedded-hal的设计哲学- 核心思想:定义 trait(接口),不定义实现
embedded-hal1.0 的关键变化:引入 async trait- 与 C 的”函数指针表”类比
- 实际例子:一个
embedded-hal兼容的传感器驱动
- 6.3 抽象层次结构
- 完整层次图:芯片 → PAC → HAL →
embedded-hal→ 驱动 → 应用 - 各层的职责与边界
- 与 C 生态的对应:CMSIS → 厂商 HAL → 第三方驱动 → 应用
- 完整层次图:芯片 → PAC → HAL →
- 6.5 并发框架选型:Embassy vs RTIC vs 传统 RTOS
- Embassy:异步协作式,适合 I/O 密集型
- RTIC:中断驱动抢占式,适合硬实时场景
- 传统 RTOS 绑定(FreeRTOS-rs 等):适合已有 RTOS 经验迁移
- 三者对比表:调度模型、实时性、学习曲线、生态成熟度
- 本书选择 Embassy 的理由
- 6.6 本章小结与 Part 1 总结
- Part 1 知识图谱回顾
- 从 Part 1 到 Part 2 的桥梁:为什么 Embassy 是”下一步”
Part 2:Embassy 核心编程#
Part 2 定位:从 Embassy 的核心思想开始,逐步深入到实践、原理和生态。这是全书的核心部分,读者将完整掌握 Embassy 框架。
学习目标:理解 Embassy 的范式转变及其代价;掌握 Embassy 工程的创建、HAL 使用、运行时调度、任务间通信等核心技能;对 Embassy 生态(USB、网络、蓝牙、Bootloader)有完整认知。
第 7 章:Embassy 入门——思想、对比与代价#
本章要回答的问题:Embassy 是什么?它和传统裸机开发有什么不同?用 Embassy 需要付出什么代价?
- 7.1 回顾:传统裸机并发的三种做法及其代价
- 超级循环:简单但无法高效等待
- 中断驱动:响应快但逻辑碎片化
- RTOS:功能全但资源开销大
- 共同痛点:C 语言缺乏安全的并发抽象
- 7.2 Embassy 的核心思想
- 异步/等待(async/await):用同步的写法实现并发
- 零开销:没有 RTOS 内核,没有上下文切换
- 编译期安全:Rust 类型系统保证并发正确性
- 与 C 状态机的对比:Embassy 是”编译器帮你写状态机”
- 7.3 采用 Embassy 的代价
- 学习曲线:async/await + Future 的心智模型
- 编译时间:Rust 编译比 C 慢
- 生态限制:并非所有 C 库都有 Rust 等价物
- 调试复杂度:异步调用栈比同步更难追踪
- 硬实时限制:协作式调度不适合严格截止时间的场景
- 7.4 本章小结
第 8 章:第一个 Embassy 工程#
本章要回答的问题:Embassy 工程和裸机工程有什么不同?#[embassy_executor::main] 是什么?怎么使用 HAL 和定时器?
- 8.1 创建 Embassy 工程与配置 Cargo.toml
- 与裸机工程的依赖差异
- 关键依赖:
embassy-executor、embassy-time、embassy-stm32 - Feature flag 配置:芯片型号、时钟源、外设使能
- 8.2 Embassy 工程的独特结构
#[embassy_executor::main]宏做了什么?Spawner:任务生成器- 与裸机
#[cortex_m_rt::entry]的对比
- 8.3 Embassy HAL 的使用
- GPIO:
Output、Input的异步版本 - UART:异步读写
- SPI / I2C:异步传输
- 与裸机 HAL 的 API 对比
- GPIO:
- 8.4 DMA 与异步传输
- DMA 的本质:让外设自己搬数据,CPU 去做别的事
- C 的 DMA:配置 + 中断回调
- Embassy 的 DMA:
await一个传输完成 - 实际例子:UART DMA 接收
- 为什么 DMA 是 Embassy 异步模型的最佳搭档
- 8.5
embassy-time:异步定时器Timer::after_millis():非阻塞延时- 与 C 的
HAL_Delay()对比:不阻塞 CPU Ticker:周期性任务- 时间驱动源配置
- 8.6 错误处理与 Panic 行为
- Embassy 中的
Result处理 panic在嵌入式中意味着什么?defmt::panic配置- 看门狗与故障恢复策略
- Embassy 中的
- 8.7 编译、烧录与 defmt 日志
cargo run一键流程- defmt 日志级别与过滤
- 与 C 的
printf+ 串口对比
- 8.8 本章小结
第 9 章:Embassy 运行时——协作与抢占#
本章要回答的问题:Embassy 的任务是怎么调度的?Future 和 Waker 是什么?协作式和抢占式有什么区别?怎么配置?
- 9.1 Future 与 Waker:异步任务的基础
- Future 是什么?(一个”尚未完成的计算”)
- 与 C 状态机的类比:Future = 状态机的编译期版本
- Waker:谁来唤醒一个等待中的任务?
poll模型:调度器如何驱动 Future
- 9.2 Embassy 的 Executor 架构
- Executor 的职责:轮询所有就绪的 Future
- 任务(Task):
#[embassy_executor::task]宏 - 任务栈:静态分配,编译期确定大小
- 与 RTOS 调度器的对比:没有上下文切换
- 9.3 协作式调度
- 工作原理:任务在
.await点主动让出 - 优点:零开销、确定性
- 缺点:一个任务不让出,其他任务饿死
- 适用场景:I/O 密集型、大多数嵌入式应用
- 工作原理:任务在
- 9.4 抢占式调度
- Embassy 的抢占式:基于中断优先级
- 配置方法:
InterruptExecutor - 与 RTOS 抢占式的区别:仍然没有上下文切换
- 适用场景:需要硬实时响应的关键任务
- 9.5 实战选择
- 决策树:什么时候用协作式?什么时候用抢占式?
- 混合使用:高优先级任务抢占 + 低优先级任务协作
- 常见误区:不要为了”实时性”盲目使用抢占式
- 9.6 本章小结
第 10 章:任务间通信——embassy-sync 库#
本章要回答的问题:Embassy 的任务之间怎么安全通信?Signal、Channel、Mutex 各自适合什么场景?
- 10.1 为什么需要任务间通信?
- 任务隔离:每个任务有自己的栈和状态
- 共享数据的需求:传感器数据 → 处理任务 → 通信任务
- 与 C 的全局变量 + 中断回调对比
- 10.2
Signal——单生产者单消费者信号- 语义:最新的值覆盖旧值
- 与 C 的
volatile标志位对比 - 适用场景:状态通知、最新值传递
- 10.3
Watch——多消费者信号- 语义:多个读者观察同一个值的变化
- 与 C 的”多个中断读取同一个全局变量”对比
- 适用场景:配置变更通知、传感器数据广播
- 10.4
Channel——MPMC 队列- 语义:生产者-消费者队列
- 与 FreeRTOS 的
xQueueSend/xQueueReceive对比 - 适用场景:数据流处理、命令队列
- 10.5
PriorityChannel——优先级通道- 语义:高优先级消息插队
- 适用场景:紧急命令、报警信号
- 10.6
PubSubChannel——发布-订阅通道- 语义:一对多广播,每个订阅者独立消费
- 与 C 的回调函数列表对比
- 适用场景:事件广播、日志分发
- 10.7
Mutex——异步互斥锁- 与 C 的
pthread_mutex/ FreeRTOSxSemaphore对比 - 异步 Mutex 的特殊性:持有锁时不能
.await(死锁风险) RefCell替代方案:单线程场景
- 与 C 的
- 10.8 与 FreeRTOS 通信原语的完整对比表
- Signal ↔ Task Notification
- Channel ↔ Queue
- Mutex ↔ Mutex Semaphore
- PubSub ↔ Event Group(部分对应)
- 10.9 常见死锁与饥饿问题
- 异步 Mutex 的死锁模式(与 C 不同)
- Channel 满/空时的阻塞行为
- 优先级反转问题
- 最佳实践与规避策略
- 10.10 选型指南
- 决策表:根据场景选择通信原语
- 性能对比:各原语的 RAM 开销和延迟
- 10.11 本章小结
第 11 章:Embassy 生态与视野拓展#
本章要回答的问题:除了 embassy-sync,Embassy 生态还有哪些强大的库?我能用 Embassy 做什么?后续怎么深入学习?
本章定位:概览性质。每个主题只介绍”是什么 + 一个最小示例 + 去哪里深入”,不展开完整教程。
- 11.1 Embassy 生态全景
- 生态架构图:executor + time + sync + hal + 协议栈
- 各组件的成熟度评估
- 11.2
embassy-usb:USB 设备栈- 支持的设备类:CDC(串口)、HID(键鼠)、MSC(存储)
- 最小示例:USB CDC 回显
- 与 C 的 USB 库(TinyUSB、STM32 USB 库)对比
- 11.3
embassy-net:网络协议栈- 支持的协议:TCP/UDP、DHCP、DNS、mDNS
- 底层驱动:以太网、WiFi(通过
cyw43等) - 最小示例:TCP echo server
- 与 LwIP 的对比
- 11.4
embassy-boot:安全 Bootloader- OTA 更新的基本流程
embassy-boot的 A/B 分区方案- 与 C 的 MCUboot 对比
- 11.5 蓝牙生态:
trouble与nrf-softdevicetrouble:Embassy 官方的 BLE 协议栈nrf-softdevice:Nordic 芯片的 SoftDevice 绑定- 当前成熟度与限制
- 11.6 ESP32 与
esp-rs生态- 乐鑫官方将 Embassy 作为默认异步框架
esp-hal+esp-wifi+esp-ble的组合- 与 STM32 生态的成熟度对比
- 11.7 真实世界项目案例
- 开源项目推荐与分析
- 从原型到产品的考量
- 11.8 社区资源与学习路径
- 官方文档、Matrix 聊天室、GitHub Discussions
- 推荐的进阶学习顺序
- 中文社区资源
- 11.9 Part 2 总结
- Part 2 知识图谱回顾
- 从”会用 Embassy”到”理解 Embassy”的桥梁
Part 3:工程实践与生态全景#
Part 3 定位:从理论学习转向工程实践。帮助读者理解工具链的每一层、学会跨平台移植、掌握性能优化方法、了解生态全貌。
学习目标:理解从源码到芯片运行的完整链路;了解各厂商 HAL 的成熟度差异,掌握移植的基本思路;掌握性能与体积优化方法;对 Rust 嵌入式生态有完整认知,知道后续学习和使用的方向。
第 12 章:工具链深度——从链接脚本到调试链路#
本章要回答的问题:memory.x 里面每一行是什么意思?从 cargo build 到芯片运行之间发生了什么?调试链路是怎么构成的?
- 12.1 链接脚本是什么?
- C 工程师熟悉的
linker.ld - Rust 中链接脚本的角色
memory.x与主链接脚本的关系
- C 工程师熟悉的
- 12.2
memory.x详解MEMORY段:FLASH 和 RAM 的地址与大小- 如何从芯片 datasheet 中获取这些信息
- 多 Bank Flash 的处理
- 实际例子:STM32F407 的
memory.x
- 12.3
cortex-m-rt深度解析- 向量表的生成
Reset_Handler的完整流程:.data初始化、.bss清零、调用main- 与 C 的
startup.s逐行对比 - 中断向量的注册机制
- 12.4 调试链路:从 VSCode 到芯片
- 完整链路:VSCode → probe-rs → SWD/JTAG → 芯片
- probe-rs 的角色:替代 OpenOCD + GDB
- 断点、单步、变量查看
- 与 C 的 Keil / IAR 调试体验对比
- 12.5
defmt:高效的嵌入式日志框架- 为什么不用
println!?(no_std没有标准输出) - defmt 的原理:日志格式在主机端解析,固件只传索引
- 与 C 的
printf+ 串口对比:体积和速度优势 - 日志级别与运行时过滤
- 为什么不用
- 12.6 完整链路回顾
- 从
cargo build到芯片运行的每一步 - 全景图:rustc → LLVM → linker → probe-rs → 芯片
- 各层可替换性说明
- 从
- 12.7 本章小结
第 13 章:多平台移植与厂商生态#
本章要回答的问题:Embassy 支持哪些芯片?各厂商的支持程度如何?从一个平台移植到另一个平台需要改什么?
- 13.1 Embassy 支持的芯片平台概览
- 官方支持 vs 社区支持
- 各平台的成熟度评级
- 13.2 STM32:最成熟的 Embassy HAL
- 支持的系列:F0/F1/F2/F3/F4/F7/H7/L0/L1/L4/L5/G0/G4/U5/WB/WL
- 外设覆盖度
- 已知限制与 workaround
- 为什么推荐 C 工程师从 STM32 开始
- 13.3 nRF:无线功能的旗舰支持
- nRF52 / nRF53 / nRF54 系列
- BLE、802.15.4、NFC 的支持
nrf-softdevice与trouble的选择
- 13.4 RP2040/RP2350:性价比之选
- 双核 Cortex-M0+ / 双核 Cortex-M33 + RISC-V
- PIO(Programmable I/O)的 Rust 支持
- 社区活跃度与文档质量
- 13.5 ESP32:官方一等支持的 Rust 生态
- 乐鑫
esp-rs生态:esp-hal+esp-wifi+esp-ble - Embassy 作为默认异步框架
- 支持的芯片:ESP32 / S2 / S3 / C3 / C6 / H2
- 与 STM32 生态的差异(Xtensa vs RISC-V 工具链)
- 乐鑫
- 13.6 RISC-V 平台的新机遇
- Rust 1.94 稳定了 29 项 RISC-V 特性
- 支持的 RISC-V 芯片:ESP32-C3/C6/H2、CH32V、GD32V 等
- RISC-V 对 Rust 嵌入式的战略意义
- 13.7 平台移植指南
- 移植清单:需要修改的文件和配置
- HAL API 差异的处理
- 时钟配置的差异
- 实际案例:从 STM32F4 移植到 nRF52
- 13.8 本章小结
第 14 章:性能与体积优化#
本章要回答的问题:如何控制固件体积?如何优化性能?异步运行时的开销有多大?常见的陷阱和解决方案是什么?
- 14.1 编译优化配置
[profile.release]关键配置:opt-level、lto、codegen-unitspanic = "abort":移除 unwind 代码strip与debug配置- 与 C 的
-Os/-O2/-flto对比
- 14.2 代码体积分析
cargo size与cargo bloat- 各部分的体积占比:应用代码 vs HAL vs 运行时
- 与同等功能 C 代码的体积对比(实际数据)
- 减小体积的实用技巧
- 14.3 异步运行时的开销分析
- Embassy Executor 的 RAM 开销
- 每个任务的栈开销
.await的运行时成本(答案:几乎为零)- 与 RTOS 的资源开销对比
- 与裸机轮询的性能对比
- 14.4 运行时性能优化
- 关键路径的优化策略
#[inline]与#[inline(always)]- DMA 减少 CPU 负载
- 中断优先级调优
- 14.5 常见陷阱与解决方案
- 陷阱 1:在
.await循环中忘记yield - 陷阱 2:任务栈溢出(静态分配的栈没有保护)
- 陷阱 3:
defmt日志在 Release 模式下的体积影响 - 陷阱 4:泛型单态化导致的代码膨胀
- 陷阱 5:
Mutex持有时间过长
- 陷阱 1:在
- 14.6 本章小结
第 15 章:生态全景与库推荐#
本章要回答的问题:除了 Embassy,Rust 嵌入式生态还有哪些重要的库?不同场景下怎么选型?安全关键领域怎么用 Rust?全书如何总结?
- 15.1 静态存储与延迟初始化
static mut的问题与替代方案once_cell/lazy_static在no_std中的用法portable-atomic:在无原子指令的 MCU 上使用原子操作critical-section:跨平台的临界区抽象
- 15.2 无堆分配的数据结构
heapless:固定容量的Vec、String、Queuearrayvec:栈上的数组向量- 与 C 的固定数组 + 手动管理对比
- 选型建议:什么时候用哪个
- 15.3 测试与质量保证
- 单元测试:
#[cfg(test)]在no_std下的用法 - 硬件在环测试(HIL):probe-rs 的测试集成
- Embassy 项目的 CI/CD 配置
- 静态分析:
clippy、miri - 与 C 的 Unity / Ceedling 测试框架对比
- 单元测试:
- 15.4 安全关键与功能认证
- Ferrocene:通过 ISO 26262 ASIL D 认证的 Rust 工具链
- Eclipse S-CORE:面向汽车的安全 Rust 运行时
- Rust 官方安全关键路线图
- 对 C 工程师的启示:Rust 在安全关键领域的未来
- 当前限制:不是所有场景都适合
- 15.5 从 C 项目迁移到 Rust 的策略
- 渐进式迁移:FFI 桥接,逐模块替换
- 全新开发:从头用 Rust 重写
- 混合编程:C 库的 Rust 绑定(
bindgen) - 决策框架:什么时候迁移?什么时候不迁移?
- 15.6 选型建议
- 按场景推荐:IoT 传感器 / 电机控制 / 通信网关 / 安全关键
- 按团队推荐:个人项目 / 小团队 / 企业级
- 按平台推荐:STM32 / nRF / ESP32 / RP2040
- 15.7 给 C 工程师的最后建议
- 不要试图写”C 风格的 Rust”
- 拥抱编译器:错误信息是你的朋友
- 从小项目开始:LED → UART → 传感器 → 完整产品
- 加入社区:Rust 嵌入式社区非常友好
- 15.8 全书总结
- 知识体系回顾
- 从第 1 章到第 15 章的成长路径
- 嵌入式 Rust 的未来展望
附录#
附录 A:C → Rust 语法速查表#
- 数据类型对照
- 控制流对照
- 指针/引用对照
- 结构体/枚举对照
- 函数/宏对照
- 内存管理对照
- 并发原语对照
附录 B:常用 Cargo 配置与 Feature Flag 速查#
.cargo/config.toml模板- 常用
Cargo.toml配置 - Embassy 各 crate 的 Feature Flag 说明
- 编译优化配置模板
附录 C:Embassy 常见编译错误与解决方案#
- 生命周期错误
Send/Sync约束错误- Feature flag 冲突
- 链接错误
- 各错误的含义与修复方法
附录 D:推荐硬件与调试器清单#
- 开发板推荐(按平台分类)
- 调试探针推荐(ST-Link、J-Link、DAPLink)
- 必备配件
- 购买建议