执行器 Executor#

原文: https://embassy.dev/book/dev/runtime.html

Embassy 执行器(executor)是一个为嵌入式设计的异步/等待(async/await)执行器,支持中断和定时器。

功能特性#

  • 无需手动分配,不需要堆;任务都是静态分配的。

  • 动态大小;无需配置或调整,执行器就可以1到1000个任务;

  • 集成的定时队列:很简单就可以实现休眠,只需要Timer::after_secs(1).await;

  • 无需一直轮询:没有任务时,配合中断或WFE/SEV (Wait For Event/Wait For Interrupt),CPU可以进入休眠状态;

  • 高效轮询:执行器只会轮询已经被唤醒的任务,而不是所有任务;

  • 公平:即使给定任务不断被唤醒,给定任务也不会独占CPU时间。在给定任务第二次轮询之前,其他任务都有机会运行。

  • 支持创建多个执行器实例,并以不同优先级运行任务。遇到优先级低的任务,较高优先级的任务可以抢占运行。

执行器#

执行器功能的描述如下:

  • 执行器保存一个它需要轮询的任务队列.

  • 当一个任务被创建时,执行器执行器Poll(1).

  • 该任务将尝试运行,取得进展,直到被阻. 当任务正在等待异步函数时,就可能会发生这种情况。但这种情况发生时,任务通过(2)返回 Poll::Pending.

  • 一旦任务让出,执行器就会将改任务加入运行队列的末尾,并继续执行(3)来拉取队列中的下一个任务。当任务完成或取消时,它无需再次入队;

执行器依赖于不会一直阻塞的任务,因为这会阻止执行器重新获得控制权来调度另一个任务。

Executor model

如果在你的应用程序中使用了#[embassy_executor::main]宏,那它就会为你创建执行器,并创建主入口点来作为第一个任务。你也可以手动创建执行器,而且可以创建多个执行器。

中断#

中断是外设发出操作完成信号的通用机制,这种机制很适合异步执行模型。下图描述一个典型的应用执行流程:

  • (1)任务被轮询,并尝试取得进展。

  • (2)任务知识外设执行某些操作,并等待。

  • 经过一段时间后,(3)发出中断,标志这操作完成。

  • 然后(4)HAL 确保中断信号被路由到外设,使用操作的结果来更新外设的状态。

  • 然后(5)执行器收到通知,任务可以继续被轮询。

Interrupt handling

这里有一个叫InterruptExecutor的特殊执行器,他由中断驱动。通过创建多个InterruptExecutor实例,可以驱动不同优先级的任务。

定时#

Embassy 有一个内部的定时器队列,可以通过设置time特性标记来启用。启用后,Embassy 假定平台已经存在一个计时器的驱动的实现。Embassy 为 nRF、STM32、RPi Pico、WASM 和 Std 平台提供了时间驱动程序。

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

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

如果您的应用程序不需要计时器,则不要启用time功能,这样可以节省一些 CPU 周期并降低功耗。