本章要回答的问题:除了 embassy-sync,Embassy 生态还有哪些强大的库?我能用 Embassy 做什么?后续怎么深入学习?
本章定位:概览性质。每个主题只介绍”是什么 + 一个最小示例 + 去哪里深入”,不展开完整教程。读完本章,你将获得 Embassy 生态的完整地图,知道每个方向”能做什么”和”去哪里学”。
11.1 Embassy 生态全景#
经过前面四章的学习,你已经掌握了 Embassy 的核心:Executor(第 9 章)、HAL(第 8 章)、同步原语(第 10 章)。但 Embassy 远不止这些——它是一个完整的嵌入式开发生态系统。
生态架构图#
┌─────────────────────────────────────────────────────────────┐
│ 应用层 (Application) │
├─────────────────────────────────────────────────────────────┤
│ 协议栈层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
│ │embassy- │ │embassy- │ │ trouble │ │ 第三方驱动 │ │
│ │ net │ │ usb │ │ (BLE) │ │ (embedded-hal)│ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └──────┬────────┘ │
├───────┼─────────────┼────────────┼──────────────┼───────────┤
│ 框架核心层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
│ │embassy- │ │embassy- │ │embassy- │ │embassy- │ │
│ │ executor │ │ time │ │ sync │ │ embedded-hal │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └──────┬────────┘ │
├───────┼─────────────┼────────────┼──────────────┼───────────┤
│ HAL 层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
│ │embassy- │ │embassy- │ │embassy- │ │ esp-hal │ │
│ │ stm32 │ │ nrf │ │ rp │ │ (乐鑫官方) │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └──────┬────────┘ │
├───────┼─────────────┼────────────┼──────────────┼───────────┤
│ 硬件层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
│ │ STM32 │ │ nRF52/ │ │ RP2040/ │ │ ESP32 系列 │ │
│ │ 系列 │ │ 53/54 │ │ RP2350 │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ └───────────────┘ │
└─────────────────────────────────────────────────────────────┘plaintext各组件的成熟度评估#
| 组件 | 功能 | 成熟度 | 说明 |
|---|---|---|---|
embassy-executor | 异步运行时 | ⭐⭐⭐⭐⭐ | 生产就绪,API 稳定 |
embassy-time | 时间管理 | ⭐⭐⭐⭐⭐ | 生产就绪 |
embassy-sync | 同步原语 | ⭐⭐⭐⭐⭐ | 生产就绪 |
embassy-stm32 | STM32 HAL | ⭐⭐⭐⭐⭐ | 覆盖最广,最成熟 |
embassy-nrf | nRF HAL | ⭐⭐⭐⭐☆ | 无线功能完善 |
embassy-rp | RP2040/2350 HAL | ⭐⭐⭐⭐☆ | PIO 支持优秀 |
embassy-usb | USB 设备栈 | ⭐⭐⭐⭐☆ | CDC/HID/MSC 可用 |
embassy-net | 网络协议栈 | ⭐⭐⭐⭐☆ | TCP/UDP/DHCP/DNS 完善 |
embassy-boot | Bootloader | ⭐⭐⭐⭐☆ | A/B 分区方案成熟 |
trouble | BLE 协议栈 | ⭐⭐⭐☆☆ | 快速发展中,尚未完全认证 |
embassy-embedded-hal | 适配层 | ⭐⭐⭐⭐☆ | 桥接 embedded-hal 生态 |
embassy-futures | 异步工具 | ⭐⭐⭐⭐☆ | select/join 等组合子 |
C 工程师视角:如果把 Embassy 类比为 C 的生态,那么
embassy-executor≈ FreeRTOS 内核,embassy-stm32≈ STM32 HAL 库,embassy-net≈ LwIP,embassy-usb≈ TinyUSB/STM32 USB 库。区别在于,Embassy 的所有组件共享同一个异步模型,天然协同工作。
11.2 embassy-usb:USB 设备栈#
是什么#
embassy-usb 是 Embassy 生态中的 USB 设备(Device)协议栈,完全用 Rust 编写,基于异步模型。它支持常见的 USB 设备类:
- CDC-ACM(Communication Device Class - Abstract Control Model):虚拟串口,最常用的调试和通信方式
- HID(Human Interface Device):键盘、鼠标、游戏手柄等
- MSC(Mass Storage Class):U 盘模拟
- 自定义类:通过实现 trait 创建任意 USB 设备
与 C 的 USB 库对比#
| 特性 | embassy-usb | TinyUSB (C) | STM32 USB 库 (C) |
|---|---|---|---|
| 语言 | Rust | C | C |
| 异步支持 | 原生 async/await | 回调/轮询 | 中断回调 |
| 内存安全 | 编译期保证 | 手动管理 | 手动管理 |
| 多类复合设备 | 支持 | 支持 | 部分支持 |
| 平台支持 | STM32/nRF/RP2040/ESP32 | 极广 | 仅 STM32 |
| 学习曲线 | 中等(需理解 async) | 中等 | 较陡(CubeMX 依赖) |
最小示例:USB CDC 回显#
这个示例将 STM32 变成一个 USB 虚拟串口设备,接收 PC 发来的数据并原样返回:
#![no_std]
#![no_main]
use embassy_executor::Spawner;
use embassy_stm32::usb::{Driver, Instance};
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
use embassy_usb::UsbDevice;
use {defmt_rtt as _, panic_probe as _};
// USB 设备描述符配置
static CONFIG_DESCRIPTOR: [u8; 256] = [0; 256];
static BOS_DESCRIPTOR: [u8; 256] = [0; 256];
static CONTROL_BUF: [u8; 64] = [0; 64];
// CDC 类的状态缓冲区
static mut STATE: State = State::new();
#[embassy_executor::main]
async fn main(spawner: Spawner) {
let p = embassy_stm32::init(Default::default());
// 创建 USB 驱动(使用 PA11/PA12,即 USB DM/DP)
let driver = Driver::new(p.USB, p.PA12, p.PA11);
// 配置 USB 设备
let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
config.manufacturer = Some("Embassy");
config.product = Some("CDC-ACM Example");
config.serial_number = Some("12345678");
// 构建 USB 设备
let mut builder = embassy_usb::Builder::new(
driver,
config,
&mut CONFIG_DESCRIPTOR,
&mut BOS_DESCRIPTOR,
&mut [], // msos_descriptor
&mut CONTROL_BUF,
);
// 创建 CDC-ACM 类实例
let state = unsafe { &mut STATE };
let mut class = CdcAcmClass::new(&mut builder, state, 64);
let mut usb = builder.build();
// 启动 USB 设备(在独立任务中运行)
spawner.spawn(usb_task(usb)).unwrap();
// 主循环:回显数据
let mut buf = [0u8; 64];
loop {
// 异步等待接收数据
match class.read_packet(&mut buf).await {
Ok(n) => {
defmt::info!("Received {} bytes", n);
// 将收到的数据原样发回
class.write_packet(&buf[..n]).await.unwrap();
}
Err(e) => {
defmt::warn!("USB read error: {:?}", e);
}
}
}
}
// USB 设备运行任务
#[embassy_executor::task]
async fn usb_task(mut device: UsbDevice<'static, Driver<'static, embassy_stm32::peripherals::USB>>) {
device.run().await;
}rust关键点解析:
Driver::new():绑定具体的 USB 外设和引脚,类型系统保证不会用错引脚CdcAcmClass::new():创建 CDC 类实例,自动处理 USB 描述符read_packet().await:异步等待数据到达,CPU 在等待期间可以执行其他任务usb_task:USB 协议栈的事件循环必须在独立任务中运行
与 C 的对比:在 C 中实现同样的功能,你需要手动配置 USB 描述符、处理中断回调、管理接收缓冲区。Embassy 将这些封装为类型安全的异步 API,编译器会阻止你犯”忘记初始化 USB 时钟”之类的错误。
去哪里深入#
- 官方示例:
embassy/examples/std/src/bin/usb_serial.rs - HID 示例:
embassy/examples/nrf52840/src/bin/usb_hid_keyboard.rs - 文档:
docs.embassy.dev/embassy-usb
11.3 embassy-net:网络协议栈#
是什么#
embassy-net 是 Embassy 生态的异步网络协议栈,底层基于 smoltcp(一个纯 Rust 的 TCP/IP 实现)。它提供了完全异步的网络 API:
支持的协议:
- IPv4 / IPv6
- TCP / UDP
- DHCP(自动获取 IP)
- DNS(域名解析)
- mDNS(本地网络服务发现)
- ICMP(Ping)
支持的底层驱动:
- 以太网(STM32 ETH 外设、W5500 SPI 芯片等)
- WiFi(通过
cyw43驱动支持 RP2040 + CYW43439,通过esp-wifi支持 ESP32)
与 LwIP 的对比#
| 特性 | embassy-net | LwIP (C) |
|---|---|---|
| 语言 | Rust | C |
| 编程模型 | async/await | 回调 / RAW API / Socket API |
| 内存分配 | 零堆分配(静态缓冲) | 可选静态或堆分配 |
| 线程安全 | 编译期保证 | 需要 SYS_LIGHTWEIGHT_PROT |
| 协议完整性 | TCP/UDP/DHCP/DNS/mDNS | 更完整(含 PPP、SNMP 等) |
| 代码体积 | 较小(按需编译) | 可配置裁剪 |
| 生态集成 | 与 Embassy 无缝集成 | 需要 RTOS 或超级循环驱动 |
C 工程师的经验:如果你用过 LwIP 的 RAW API(基于回调),那么
embassy-net的 async API 会让你感到如释重负——不再需要在回调中管理状态机,代码读起来就像顺序执行的逻辑。
最小示例:TCP Echo Server#
#![no_std]
#![no_main]
use embassy_executor::Spawner;
use embassy_net::tcp::TcpSocket;
use embassy_net::{Config, StackResources};
use embassy_stm32::eth::{Ethernet, PacketQueue};
use embassy_stm32::peripherals::ETH;
use embassy_stm32::rng::Rng;
use embassy_stm32::{bind_interrupts, eth, peripherals, rng};
use static_cell::StaticCell;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
ETH => eth::InterruptHandler;
RNG => rng::InterruptHandler<peripherals::RNG>;
});
// 静态分配网络资源(零堆分配)
static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new();
static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
#[embassy_executor::main]
async fn main(spawner: Spawner) {
let p = embassy_stm32::init(Default::default());
// 初始化以太网 MAC + PHY
let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
let device = Ethernet::new(
PACKETS.init(PacketQueue::<4, 4>::new()),
p.ETH,
Irqs,
p.PA1, p.PA2, p.PC1, p.PA7, p.PC4, p.PC5,
p.PG13, p.PB13, p.PG11,
// PHY 地址,根据硬件原理图确定
0,
mac_addr,
);
// 配置网络:使用 DHCP
let config = Config::dhcpv4(Default::default());
// 初始化网络栈
let seed = 1234; // 实际应用中应使用真随机数
let stack = &*embassy_net::new(
device,
config,
RESOURCES.init(StackResources::<3>::new()),
seed,
);
// 等待 DHCP 获取 IP
defmt::info!("Waiting for DHCP...");
stack.wait_config_up().await;
defmt::info!("Network up! IP: {:?}", stack.config_v4());
// 启动 TCP echo 任务
spawner.spawn(net_task(stack)).unwrap();
}
#[embassy_executor::task]
async fn net_task(stack: &'static embassy_net::Stack<Ethernet<'static>>) {
stack.run().await;
}
// 在实际应用中,TCP echo 会在另一个任务中:
// #[embassy_executor::task]
// async fn echo_task(stack: &'static embassy_net::Stack<...>) {
// let mut rx_buf = [0u8; 1024];
// let mut tx_buf = [0u8; 1024];
// let mut socket = TcpSocket::new(stack, &mut rx_buf, &mut tx_buf);
//
// loop {
// // 监听端口 1234
// socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
// if let Err(e) = socket.accept(1234).await {
// defmt::warn!("Accept error: {:?}", e);
// continue;
// }
// defmt::info!("Client connected!");
//
// // 回显循环
// let mut buf = [0u8; 256];
// loop {
// match socket.read(&mut buf).await {
// Ok(0) => break, // 连接关闭
// Ok(n) => {
// socket.write_all(&buf[..n]).await.unwrap();
// }
// Err(_) => break,
// }
// }
// defmt::info!("Client disconnected");
// }
// }rust关键点解析:
StackResources<3>:泛型参数3表示最多同时打开 3 个 socket,编译期确定资源上限Config::dhcpv4():自动获取 IP,也支持Config::ipv4_static()手动配置stack.run().await:网络栈的事件循环,必须在独立任务中永远运行- 零堆分配:所有缓冲区都是静态分配的
&mut [u8],没有malloc
去哪里深入#
- 官方示例:
embassy/examples/stm32f4/src/bin/eth_tcp_echo.rs - WiFi 示例(RP2040):
embassy/examples/rp/src/bin/wifi_tcp_echo.rs smoltcp文档:了解底层协议实现embassy-netAPI 文档:docs.embassy.dev/embassy-net
11.4 embassy-boot:安全 Bootloader#
是什么#
embassy-boot 是一个轻量级的引导加载程序(Bootloader),专为嵌入式系统设计,核心功能是断电安全的固件 OTA 更新。
核心特性:
- A/B 分区方案:两个固件槽位交替写入,更新失败可回滚
- 断电保护:即使在写入过程中断电,设备也不会变砖
- 固件回滚:新固件启动失败时自动回退到旧版本
- 轻量级:代码体积极小,适合 Flash 有限的 MCU
OTA 更新的基本流程#
┌─────────────────────────────────────────────────────────┐
│ Flash 布局 │
├──────────┬──────────┬──────────┬────────────────────────┤
│Bootloader│ Slot A │ Slot B │ DFU 区域 │
│ (固定) │ (活跃) │ (备用) │ (接收新固件) │
└──────────┴──────────┴──────────┴────────────────────────┘
更新流程:
1. 应用通过 UART/USB/WiFi 接收新固件 → 写入 DFU 区域
2. 应用调用 embassy-boot API 标记"有待更新固件"
3. 设备重启 → Bootloader 检测到更新标记
4. Bootloader 将 DFU 区域的固件复制到 Slot B
5. Bootloader 交换 A/B 槽位,从新固件启动
6. 新固件启动成功 → 标记为"已确认"
7. 新固件启动失败(看门狗超时)→ 下次重启自动回滚到旧固件plaintext与 MCUboot 的对比#
| 特性 | embassy-boot | MCUboot (C) |
|---|---|---|
| 语言 | Rust | C |
| 签名验证 | 支持(ed25519) | 支持(RSA/ECDSA/ed25519) |
| 加密传输 | 支持 | 支持 |
| 压缩 | 支持 | 支持 |
| 多镜像 | 支持 | 支持 |
| 与 Embassy 集成 | 原生 | 需要额外适配 |
| 代码体积 | 更小 | 较大(功能更全) |
| 生态成熟度 | 较新 | 非常成熟(Zephyr 默认) |
最小示例:应用端触发更新#
use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
use embassy_stm32::flash::Flash;
// 在应用中接收新固件并写入
async fn perform_ota_update(flash: Flash<'_>, firmware_data: &[u8]) {
let config = FirmwareUpdaterConfig::from_linkerfile_blocking(
flash, // 用于写入 DFU 区域
flash, // 用于操作状态分区
);
let mut magic = AlignedBuffer([0; 4]);
let mut updater = FirmwareUpdater::new(config, &mut magic.0);
// 分块写入新固件
let mut offset = 0;
for chunk in firmware_data.chunks(4096) {
updater.write_firmware(offset, chunk).await.unwrap();
offset += chunk.len();
}
// 标记更新完成,下次重启时 Bootloader 会应用更新
updater.mark_updated().await.unwrap();
defmt::info!("OTA update staged, rebooting...");
// 触发系统复位
cortex_m::peripheral::SCB::sys_reset();
}rust去哪里深入#
- 官方示例:
embassy/examples/bootloader/ - 文档:
docs.embassy.dev/embassy-boot - 完整 OTA 方案(含传输协议)需要结合
embassy-net或embassy-usb使用
11.5 蓝牙生态:trouble 与 nrf-softdevice#
蓝牙在 Embassy 生态中的位置#
蓝牙(特别是 BLE)是嵌入式无线通信的主流方案之一。Embassy 生态中有两种 BLE 方案:
trouble:Embassy 官方的 BLE 协议栈#
是什么:trouble(原名 bleps)是一个纯 Rust 的 BLE Host 层实现,由 Embassy 团队维护。它的设计目标是:
- 完全用 Rust 编写,无 C 代码依赖
- 基于
bt-hcicrate 与 BLE Controller 通信 - 支持 L2CAP 面向连接的通道(CoC)
- 支持 GATT(Generic Attribute Profile)
- 未来目标:通过蓝牙 SIG 认证(Qualification)
当前状态(2026 年):
- 支持 BLE 4.2 / 5.0 的核心功能
- 广播、扫描、连接、GATT Server/Client 基本可用
- L2CAP CoC 支持已实现
- 尚未通过蓝牙 SIG 官方认证(产品使用需注意合规风险)
- 主要验证平台:nRF52840、ESP32-C3/C6/S3
最小示例:BLE GATT Server(广播 + 自定义服务)
// 概念性示例,展示 trouble 的 API 风格
use trouble::gatt::{GattServer, ServiceBuilder};
use trouble::host::{BleHost, BleHostResources};
use trouble::types::{Address, Uuid};
// 创建一个自定义 GATT 服务
// 包含一个可读可写的特征值(Characteristic)
async fn ble_gatt_server_example() {
// 初始化 BLE Controller(平台相关)
// let controller = ...;
// 创建 Host 资源
// let mut resources = BleHostResources::new();
// 构建 GATT 服务表
// let mut server = GattServer::new(&mut resources);
// let mut service = ServiceBuilder::new(Uuid::new_long([
// 0x00, 0x00, 0x12, 0x34, // 自定义 UUID
// 0x00, 0x00, 0x10, 0x00,
// 0x80, 0x00, 0x00, 0x80,
// 0x5F, 0x9B, 0x34, 0xFB,
// ]));
//
// let my_char = service.add_characteristic(
// Uuid::new_short(0x2A00),
// CharacteristicProps::READ | CharacteristicProps::WRITE,
// [0u8; 20], // 初始值
// );
//
// server.add_service(service);
// 开始广播
// host.advertise(&Default::default(), Advertisement::ConnectableScannableUndirected {
// adv_data: &[...],
// scan_data: &[...],
// }).await;
// 等待连接并处理 GATT 请求
// let mut conn = host.next_connection().await;
// loop {
// match server.next_event(&mut conn).await {
// GattEvent::Read(handle) => { /* 返回特征值 */ }
// GattEvent::Write(handle, data) => { /* 处理写入 */ }
// }
// }
}rust注意:
trouble仍在快速迭代中,API 可能变化。请以 GitHub 仓库的最新示例为准。
nrf-softdevice:Nordic 芯片的 SoftDevice 绑定#
是什么:nrf-softdevice 是 Nordic 官方 SoftDevice(预编译的 BLE 协议栈二进制)的 Rust 绑定。它不是纯 Rust 实现,而是通过 FFI 调用 Nordic 的 C 库。
特点:
- 功能完整:经过蓝牙 SIG 认证,可直接用于产品
- 平台限制:仅支持 nRF52/nRF53 系列
- 与 Embassy 集成:提供异步 API
- 代价:SoftDevice 占用较多 Flash 和 RAM(约 150KB Flash + 8KB RAM)
选择建议:
| 场景 | 推荐方案 |
|---|---|
| nRF 芯片 + 需要认证 + 产品级 | nrf-softdevice |
| nRF 芯片 + 学习/原型 | trouble 或 nrf-softdevice |
| ESP32 芯片 + BLE | esp-ble(基于 ESP-IDF 的 NimBLE) |
| 追求纯 Rust + 未来认证 | trouble(等待成熟) |
去哪里深入#
troubleGitHub:github.com/embassy-rs/troublenrf-softdeviceGitHub:github.com/embassy-rs/nrf-softdevice- 示例:
nrf-softdevice/examples/src/bin/ble_gatt_server.rs
11.6 ESP32 与 esp-rs 生态#
乐鑫的 Rust 战略#
2025-2026 年,乐鑫(Espressif)将 Rust 提升为官方一等 SDK,与 C(ESP-IDF)并列。这意味着:
- 乐鑫官方维护 Rust HAL(
esp-hal) - Embassy 被选为默认异步框架
- 官方文档和示例同时提供 C 和 Rust 版本
- WiFi/BLE 驱动有官方 Rust 绑定
esp-rs 生态组件#
┌─────────────────────────────────────────────────┐
│ esp-rs 生态全景 │
├─────────────────────────────────────────────────┤
│ esp-hal 裸机 HAL(no_std) │
│ esp-wifi WiFi 驱动(async) │
│ esp-ble BLE 驱动(基于 NimBLE) │
│ esp-alloc 堆分配器(可选) │
│ esp-println 日志输出 │
│ esp-storage Flash 存储抽象 │
│ esp-backtrace 崩溃回溯 │
├─────────────────────────────────────────────────┤
│ Embassy 集成 │
│ esp-hal 原生支持 Embassy executor │
│ esp-wifi 提供 embassy-net 兼容驱动 │
└─────────────────────────────────────────────────┘plaintext支持的芯片#
| 芯片 | 架构 | WiFi | BLE | Embassy 支持 |
|---|---|---|---|---|
| ESP32 | Xtensa LX6 双核 | 2.4G | 4.2 | ✅ |
| ESP32-S2 | Xtensa LX7 单核 | 2.4G | ❌ | ✅ |
| ESP32-S3 | Xtensa LX7 双核 | 2.4G | 5.0 | ✅ |
| ESP32-C3 | RISC-V 单核 | 2.4G | 5.0 | ✅ |
| ESP32-C6 | RISC-V 单核 | 2.4G+5G | 5.0 | ✅ |
| ESP32-H2 | RISC-V 单核 | ❌ | 5.0 + 802.15.4 | ✅ |
与 STM32 生态的成熟度对比#
| 维度 | STM32 (embassy-stm32) | ESP32 (esp-hal) |
|---|---|---|
| HAL 覆盖度 | 非常完整 | 基本完整,部分外设缺失 |
| 文档质量 | 优秀 | 良好,快速改善中 |
| 示例数量 | 非常丰富 | 丰富 |
| 无线功能 | 无(需外挂模块) | 原生 WiFi + BLE |
| 工具链 | 标准 Rust(ARM target) | Xtensa 需 esp 工具链,RISC-V 用标准 |
| 社区活跃度 | 高 | 非常高(乐鑫官方推动) |
最小示例:ESP32-C3 + Embassy 点灯#
#![no_std]
#![no_main]
use embassy_executor::Spawner;
use embassy_time::{Duration, Timer};
use esp_hal::gpio::{Io, Level, Output};
use esp_hal::timer::timg::TimerGroup;
use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
// 初始化 ESP32-C3 外设
let peripherals = esp_hal::init(esp_hal::Config::default());
// 配置 GPIO8 为输出(ESP32-C3-DevKitM-1 的板载 LED)
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
let mut led = Output::new(io.pins.gpio8, Level::Low);
// 配置 Embassy 时间驱动
let timg0 = TimerGroup::new(peripherals.TIMG0);
esp_hal_embassy::init(timg0.timer0);
// 闪烁循环
loop {
led.toggle();
Timer::after(Duration::from_millis(500)).await;
}
}rust注意:ESP32 的 Xtensa 架构(ESP32/S2/S3)需要使用乐鑫维护的 Rust 工具链(
espchannel),而 RISC-V 架构(C3/C6/H2)可以使用标准 Rust 工具链。这是 ESP32 生态与 STM32 生态的一个显著差异。
去哪里深入#
- The Rust on ESP Book:
esp-rs.github.io/book/ esp-hal文档:docs.esp-rs.org/esp-hal/- 示例仓库:
github.com/esp-rs/esp-hal/tree/main/examples - 乐鑫 Rust 论坛:
github.com/esp-rs/esp-hal/discussions
11.7 真实世界项目案例#
开源项目推荐#
以下项目展示了 Embassy 在不同场景中的实际应用:
| 项目 | 描述 | 平台 | 亮点 |
|---|---|---|---|
| Embassy 官方示例 | 覆盖所有外设和协议栈 | 多平台 | 最佳学习起点 |
| probe-rs | 调试探针工具(部分嵌入式组件) | - | 展示 Rust 工具链生态 |
| ratatui | 终端 UI(非嵌入式,但展示 async 模式) | - | 异步架构参考 |
| esp-rs 示例集 | WiFi/BLE/USB 完整示例 | ESP32 | 乐鑫官方维护 |
| nrf-softdevice 示例 | BLE 完整应用 | nRF52 | 产品级 BLE 参考 |
典型应用场景#
场景 1:IoT 传感器节点
传感器 → I2C/SPI 读取 → 数据处理 → WiFi/BLE 上报 → 低功耗睡眠
(embassy HAL) (async task) (embassy-net) (embassy-time)plaintext场景 2:USB 数据采集设备
ADC 采样 → DMA 传输 → 数据缓冲 → USB CDC 上传到 PC
(embassy HAL) (async) (Channel) (embassy-usb)plaintext场景 3:OTA 可更新的网关设备
以太网/WiFi → TCP 连接 → 接收固件 → 写入 Flash → 重启更新
(embassy-net) (async) (Channel) (embassy-boot)plaintext从原型到产品的考量#
| 阶段 | 关注点 | Embassy 生态支持 |
|---|---|---|
| 原型验证 | 快速迭代、功能验证 | 丰富的示例、async 简化开发 |
| 小批量 | 稳定性、基本 OTA | embassy-boot、defmt 日志 |
| 量产 | 认证、安全、长期维护 | Ferrocene(安全认证)、签名验证 |
| 产品运维 | 远程诊断、批量更新 | OTA + 日志 + 看门狗 |
11.8 社区资源与学习路径#
官方资源#
| 资源 | 链接 | 用途 |
|---|---|---|
| Embassy GitHub | github.com/embassy-rs/embassy | 源码、Issue、PR |
| Embassy 文档 | docs.embassy.dev | API 参考 |
| Matrix 聊天室 | matrix.to/#/#embassy-rs:matrix.org | 实时问答(最活跃) |
| GitHub Discussions | 仓库内 Discussions 标签 | 深度讨论 |
| The Embedded Rust Book | docs.rust-embedded.org/book/ | 通用嵌入式 Rust 入门 |
| The Rust on ESP Book | esp-rs.github.io/book/ | ESP32 Rust 开发 |
推荐的进阶学习顺序#
第 1 阶段:巩固基础(1-2 周)
├── 完成 Embassy 官方 examples 中的 blinky、button、uart
├── 理解 async/await 在嵌入式中的行为
└── 熟练使用 defmt 日志
第 2 阶段:外设与通信(2-4 周)
├── I2C/SPI 传感器驱动
├── DMA + UART 高速通信
├── 多任务协作(Channel + Mutex)
└── 定时器与 PWM 控制
第 3 阶段:协议栈(4-8 周)
├── USB CDC(调试 + 通信)
├── 以太网/WiFi + TCP/UDP
├── BLE(GATT Server)
└── OTA 更新(embassy-boot)
第 4 阶段:产品化(持续)
├── 低功耗设计
├── 错误处理与看门狗
├── 生产测试方案
└── 安全启动与签名plaintext中文社区资源#
| 资源 | 说明 |
|---|---|
| Rust 嵌入式工作组 | 翻译和维护中文文档 |
| 稀土掘金 / CSDN | 中文教程和实战文章 |
| B 站 | Embassy 实战视频教程 |
| 知乎专栏 | 深度技术分析 |
| 本书配套代码 | 随书示例,逐步进阶 |
获取帮助的渠道#
- Matrix 聊天室(推荐):响应最快,核心开发者活跃
- GitHub Issues:报告 bug 或提出功能请求
- GitHub Discussions:提问和分享经验
- Stack Overflow:标记
[rust]+[embedded]
给 C 工程师的建议:不要害怕提问。Rust 嵌入式社区以友好著称,很多核心开发者自己就是从 C/C++ 转过来的,他们理解你的困惑。
11.9 Part 2 总结#
Part 2 知识图谱回顾#
Part 2:Embassy 核心编程
│
├── 第 7 章:思想与代价
│ ├── async/await 范式
│ ├── 零开销异步
│ └── 协作式 vs 抢占式
│
├── 第 8 章:第一个工程
│ ├── 工程结构与依赖
│ ├── HAL 使用(GPIO/UART/SPI/I2C)
│ ├── DMA 与异步传输
│ └── embassy-time 定时器
│
├── 第 9 章:运行时
│ ├── Future 与 Waker
│ ├── Executor 架构
│ ├── 协作式调度
│ └── 抢占式调度(InterruptExecutor)
│
├── 第 10 章:任务间通信
│ ├── Signal / Watch
│ ├── Channel / PriorityChannel
│ ├── PubSubChannel
│ ├── Mutex
│ └── 死锁与饥饿规避
│
└── 第 11 章:生态与视野(本章)
├── embassy-usb(USB 设备栈)
├── embassy-net(网络协议栈)
├── embassy-boot(安全 Bootloader)
├── trouble / nrf-softdevice(BLE)
├── esp-rs(ESP32 生态)
└── 社区与学习路径plaintext从”会用 Embassy”到”理解 Embassy”的桥梁#
经过 Part 2 的学习,你已经能够:
- ✅ 创建和配置 Embassy 工程
- ✅ 使用异步 HAL 操作外设
- ✅ 设计多任务架构
- ✅ 选择合适的任务间通信方式
- ✅ 了解 USB、网络、BLE、OTA 的可能性
但你可能还有这些疑问:
memory.x里面每一行到底是什么意思?→ 第 12 章- 换一个芯片平台需要改什么?→ 第 13 章
- 怎么让固件更小、跑得更快?→ 第 14 章
- 除了 Embassy,还有什么库值得用?→ 第 15 章
这些问题的答案在 Part 3 等着你。
本章核心要点#
- Embassy 是一个完整的生态系统,不仅仅是异步运行时。它覆盖了从 HAL 到协议栈的完整链路。
- 各组件共享异步模型,天然协同工作。这是相比 C 生态(各库风格迥异)的最大优势。
- 生态成熟度不均匀:核心运行时和 STM32 HAL 已经生产就绪;BLE(trouble)仍在快速迭代中。
- ESP32 的加入极大地扩展了 Embassy 的应用范围,特别是 WiFi + BLE 的 IoT 场景。
- 社区活跃且友好,Matrix 聊天室是获取帮助的最佳渠道。
下一章预告:第 12 章将深入工具链的每一个环节——从
memory.x的每一行含义,到cortex-m-rt的启动流程,再到defmt日志的工作原理。如果你曾经好奇”从cargo build到芯片运行之间到底发生了什么”,下一章会给你完整的答案。