简介
Embassy 是一个使 async/await 成为嵌入式开发一流选择的项目。
什么是 async?
在处理 I/O 时,软件必须调用阻塞程序执行的函数,直到 I/O 操作完成。当在 Linux 等操作系统中运行时,此类函数通常将控制权转移到内核,以便可以执行另一个任务(称为"线程"),或者可以将 CPU 置于睡眠状态,直到另一个任务准备就绪。
由于操作系统不能假定线程会协同工作,因此线程是相对资源密集型的,如果它们没有在分配的时间内将控制权转移回内核,则可能会被强制中断。如果可以假定任务会协同工作,或者至少不会恶意行为,那么与传统的 OS 线程相比,创建看起来几乎是免费的任务是可能的。
在其他编程语言中,这些轻量级任务被称为"协程"或"goroutines"。在 Rust 中,它们是用 async 实现的。Async-await 的工作原理是将每个异步函数转换为一个称为 future 的对象。当 future 在 I/O 上阻塞时,future 会让步,调度程序(称为执行器)可以选择要执行的其他 future。
与 RTOS 等替代方案相比,async 可以产生更好的性能和更低的功耗,因为执行器不必猜测 future 何时准备好执行。但是,程序大小可能比其他替代方案更高,这对于某些内存非常有限的特定空间受限设备来说可能是个问题。在 Embassy 支持的设备上,例如 stm32 和 nrf,内存通常足够大,可以容纳适度增加的程序大小。
什么是 Embassy?
Embassy 项目由几个可以一起使用或独立使用的 crate 组成:
执行器
embassy-executor 是一个 async/await 执行器,通常执行固定数量的任务,这些任务在启动时分配,尽管以后可以添加更多任务。执行器还可以提供一个系统计时器,您可以将其用于异步和阻塞延迟。对于小于一微秒的情况,应使用阻塞延迟,因为上下文切换的成本太高,并且执行器将无法提供准确的计时。
硬件抽象层
HAL 实现了安全的 Rust API,可让您使用 USART、UART、I2C、SPI、CAN 和 USB 等外设,而无需直接操作寄存器。
Embassy 在有意义的地方提供了异步和阻塞 API 的实现。DMA(直接内存访问)是一个适合异步的示例,而 GPIO 状态更适合阻塞 API。
Embassy 项目为选定的硬件维护 HAL,但您仍然可以将 Embassy 与其他项目中的 HAL 一起使用。
- embassy-stm32,适用于所有 STM32 微控制器系列。
- embassy-nrf,适用于 Nordic Semiconductor nRF52、nRF53、nRF91 系列。
- embassy-rp,适用于 Raspberry Pi RP2040 微控制器。
- esp-rs,适用于 Espressif Systems ESP32 系列芯片。
- ch32-hal,适用于 WCH 32 位 RISC-V(CH32V) 系列芯片。
注意:一个常见的问题是是否可以独立使用 Embassy HAL。是的,这是可能的!HAL 中没有对执行器的依赖。您甚至可以在没有 async 的情况下使用它们,因为它们同时实现了 Embedded HAL 阻塞和异步特性。
网络
embassy-net 网络堆栈实现了广泛的网络功能,包括以太网、IP、TCP、UDP、ICMP 和 DHCP。Async drastically simplifies managing timeouts and serving multiple connections concurrently. 可以找到几个用于 WiFi 和以太网芯片的驱动程序。
蓝牙
nrf-softdevice crate 为 nRF52 微控制器提供蓝牙低功耗 4.x 和 5.x 支持。
LoRa
lora-rs 支持在各种 LoRa 无线电上进行 LoRa 组网,并与 Rust LoRaWAN 实现完全集成。它提供了四个 crate -- lora-phy、lora-modulation、lorawan-encoding 和 lorawan-device -- 以及各种开发板的基本示例。它支持 STM32WL 无线微控制器或 Semtech SX127x 收发器等。
USB
embassy-usb 实现了一个设备端 USB 堆栈。提供了 USB 串行 (CDC ACM) 和 USB HID 等常见类的实现,并且丰富的构建器 API 允许您构建自己的实现。
引导加载程序和 DFU
embassy-boot 是一个轻量级引导加载程序,支持以电源故障安全的方式进行固件应用程序升级,并具有试用引导和回滚功能。
什么是 DMA?
对于嵌入式设备中的大多数 I/O,外设并不直接支持一次传输多个字节,CAN 是一个明显的例外。相反,MCU 必须一次写入一个字节,然后等待外设准备好发送下一个字节。对于高 I/O 速率,如果 MCU 必须花费越来越多的时间来处理每个字节,这可能会带来问题。解决此问题的方法是使用直接内存访问控制器。
直接内存访问控制器 (DMA) 是 Embassy 支持的 MCU(包括 stm32 和 nrf)中存在的一种控制器。DMA 允许 MCU 设置传输(发送或接收),然后等待传输完成。使用 DMA,一旦启动,在传输完成之前无需 MCU 干预,这意味着 MCU 可以在传输进行时执行其他计算或设置其他 I/O。对于高 I/O 速率,DMA 可以将 MCU 处理 I/O 的时间减少一半以上。但是,由于 DMA 的设置更为复杂,因此在嵌入式社区中使用较少。Embassy 旨在通过将 DMA 作为首选而不是最后选择来改变这种状况。使用 Embassy,一旦 I/O 速率增加,就不需要额外的调整,因为您的应用程序已经设置为处理它们。
示例
Embassy 为所有支持的 HAL 提供了示例。您可以在 examples/
文件夹中找到它们。
主循环示例
use embassy_executor::Spawner;
use embassy_time::Timer;
use log::*;
#[embassy_executor::task]
async fn run() {
loop {
info!("tick");
Timer::after_secs(1).await;
}
}
#[embassy_executor::main]
async fn main(spawner: Spawner) {
env_logger::builder()
.filter_level(log::LevelFilter::Debug)
.format_timestamp_nanos()
.init();
spawner.spawn(run()).unwrap();
}
实际应用中的 Embassy
以下是使用 Embassy 的真实项目的已知示例。欢迎 添加更多!
-
基于 Raspberry Pi Pico 2 的简单履带机器人
- 一个业余项目,构建了一个具有基本自主和手动驾驶模式的履带机器人。
-
- 一个业余项目,围绕 Pi Pico W 构建了一个闹钟,包括代码、组件列表和外壳设计文件。
-
- RMK 具有内置层支持、无线 (BLE) 支持、使用 vial 的实时按键编辑支持等等!
- 目标 STM32、RP2040、nRF52 和 ESP32 MCU
-
Printhor:高度可靠但不一定能正常工作的 3D 打印机固件
- 目标一些 STM32 MCU
-
Card/IO 固件 - 开源 ECG 设备的固件
- 目标 ESP32-S3 或 ESP32-C6 MCU
-
- 目标 nRF52 并使用 nrf-softdevice
-
YLab Edge Go 和 YLab Edge Pro 项目开发固件(RP2040、STM32),用于在行为科学研究中捕获生理数据。到目前为止包括:
- 生物电位(模拟端口)
- 运动捕捉(6 轴加速度计)
- 空气质量(CO2、温度、湿度)
- 附带一个用于捕获和可视化数据的应用程序 Ystudio
资源
有关异步 Rust 和 Embassy 的更多阅读材料:
视频: