embassy-executor/README.md
An async/await executor designed for embedded usage.
alloc, no heap needed.static, with the exact size to hold the task (or multiple instances of it, if using pool_size) calculated automatically at compile time. If tasks don't fit in RAM, this is detected at compile time by the linker. Runtime panics due to running out of memory are not possible.Timer::after_secs(1).await;.WFE/SEV.The executor requires a "platform" to be defined to work. A platform defines the following things:
The embassy-executor crate ships with support for some commonly used platforms, see the crate's feature documentation.
Chip-specific executor platform implementations are maintained in their respective HALs:
embassy-rp: multicore support. Enabled with the executor-interrupt or executor-thread features.embassy-stm32: automatic low-power sleep support. Enabled with the executor-interrupt or executor-thread features.embassy-mcxa: automatic low-power sleep support. Enabled with the executor-platform feature.esp-rtos: ESP32 RTOS support, multicore support. Enabled with the embassy feature.To use the executor, you must provide exactly one platform implementation, either from this crate, a HAL crate, or a custom one.
To implement your own custom platform, e.g. on top of an RTOS, do the following:
__pender callback.#[unsafe(export_name = "__pender")]
fn __pender(context: *mut ()) {
// `context` is the argument passed to `raw::Executor::new`. Here we're using it
// to pass a handle to the RTOS task but you can use it for anything.
my_rtos::notify_task(context as _);
}
raw::Executor into your own Executor struct that defines the main loop.pub struct Executor {
inner: raw::Executor,
not_send: PhantomData<*mut ()>,
}
impl Executor {
pub fn new() -> Self {
Self {
inner: raw::Executor::new(my_rtos::task_get_current() as _),
not_send: PhantomData,
}
}
pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
init(self.inner.spawner());
loop {
unsafe { self.inner.poll() }
my_rtos::task_wait_for_notification();
}
}
}