embassy book

Embassy 执行器

Embassy 执行器是一个为嵌入式使用而设计的 async/await 执行器,同时支持中断和定时器功能。

特性

  • alloc,无需堆。任务是静态分配的。
  • 无"固定容量"数据结构,执行器可以处理 1 个或 1000 个任务,而无需配置/调整。
  • 集成定时器队列:睡眠很容易,只需执行 Timer::after_secs(1).await;
  • 无忙循环轮询:当没有工作要做时,CPU 进入睡眠状态,使用中断或 WFE/SEV
  • 高效轮询:唤醒只会轮询被唤醒的任务,而不是所有任务。
  • 公平:即使任务不断被唤醒,也不会垄断 CPU 时间。在给定任务第二次被轮询之前,所有其他任务都有机会运行。
  • 支持创建多个执行器实例,以在不同的优先级级别运行任务。这允许更高优先级的任务抢占较低优先级的任务。

执行器

执行器函数如下所述。执行器维护一个它应该轮询的任务队列。当创建一个任务时,它会被轮询 (1)。任务将尝试取得进展,直到达到它会被阻塞的点。每当任务 .await 一个异步函数时,都可能发生这种情况。当这种情况发生时,任务通过 (2) 返回 Poll::Pending 来让出执行权。一旦任务让出,执行器会将任务排队到运行队列的末尾,并继续 (3) 轮询队列中的下一个任务。当任务完成或取消时,它将不会再次排队。

重要提示:执行器依赖于任务不会无限期阻塞,因为这会阻止执行器重新获得控制权并调度另一个任务。

执行器模型

如果在你的应用程序中使用 #[embassy_executor::main] 宏,它会为你创建 Executor 并生成主入口点作为第一个任务。你也可以手动创建 Executor,实际上你可以创建多个 Executor。

中断

中断是外围设备发出某些操作完成信号的常用方式,并且非常适合异步执行模型。下图描述了一个典型的应用程序流程,其中 (1) 任务被轮询并尝试取得进展。然后,任务 (2) 指示外围设备执行某些操作,并等待。经过一段时间后,(3) 产生中断,标记操作完成。

然后,外围设备 HAL (4) 确保中断信号被路由到外围设备,并使用操作结果更新外围设备状态。然后,执行器 (5) 被通知应该轮询任务,它将执行此操作。

中断处理

注意:存在一个名为 InterruptExecutor 的特殊执行器,它可以由中断驱动。这可以通过创建多个 InterruptExecutor 实例来用于驱动不同优先级级别的任务。

时间

Embassy 具有由 time 功能标志启用的内部定时器队列。启用后,Embassy 假定平台存在时间 Driver 实现。Embassy 为 nRF、STM32、RPi Pico、WASM 和 Std 平台提供时间驱动程序。

嵌入式平台的时间驱动程序实现可能仅支持可以设置的固定数量的警报。确保你期望同时使用定时器的任务数量不超过此限制。

定时器速度可在编译时使用 time-tick-<frequency> 进行配置。目前,定时器可以配置为以 1000 Hz、32768 Hz 或 1 MHz 运行。在更改默认值之前,请确保目标 HAL 支持特定的频率设置。

注意:如果你的应用程序不需要定时器,不启用 time 功能可以节省一些 CPU 周期并降低功耗。