1321: executor: add Pender, rework Cargo features. r=Dirbaio a=Dirbaio

This introduces a `Pender` struct with enum cases for thread-mode, interrupt-mode and
custom callback executors. This avoids calls through function pointers when using only
the thread or interrupt executors. Faster, and friendlier to `cargo-call-stack`.

`embassy-executor` now has `arch-xxx` Cargo features to select the arch and to enable
the builtin executors (thread and interrupt).

Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
This commit is contained in:
bors[bot] 2023-04-04 15:50:12 +00:00 committed by GitHub
commit 5923e143e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 673 additions and 532 deletions

View File

@ -6,7 +6,7 @@ version = "0.1.0"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-executor = { version = "0.1.0", path = "../../../../../embassy-executor", features = ["defmt", "nightly", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../../../../embassy-executor", features = ["defmt", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.1.0", path = "../../../../../embassy-time", features = ["defmt", "nightly"] } embassy-time = { version = "0.1.0", path = "../../../../../embassy-time", features = ["defmt", "nightly"] }
embassy-nrf = { version = "0.1.0", path = "../../../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "nightly"] } embassy-nrf = { version = "0.1.0", path = "../../../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "nightly"] }

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
cortex-m = "0.7" cortex-m = "0.7"
cortex-m-rt = "0.7" cortex-m-rt = "0.7"
embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"], default-features = false } embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"], default-features = false }
embassy-executor = { version = "0.1.0", default-features = false, features = ["nightly"] } embassy-executor = { version = "0.1.0", default-features = false, features = ["nightly", "arch-cortex-m", "executor-thread"] }
defmt = "0.3.0" defmt = "0.3.0"
defmt-rtt = "0.3.0" defmt-rtt = "0.3.0"

View File

@ -1,116 +0,0 @@
//! Executor specific to cortex-m devices.
use core::cell::UnsafeCell;
use core::mem::MaybeUninit;
use atomic_polyfill::{AtomicBool, Ordering};
use cortex_m::interrupt::InterruptNumber;
use cortex_m::peripheral::NVIC;
pub use embassy_executor::*;
#[derive(Clone, Copy)]
struct N(u16);
unsafe impl cortex_m::interrupt::InterruptNumber for N {
fn number(self) -> u16 {
self.0
}
}
fn pend_by_number(n: u16) {
cortex_m::peripheral::NVIC::pend(N(n))
}
/// Interrupt mode executor.
///
/// This executor runs tasks in interrupt mode. The interrupt handler is set up
/// to poll tasks, and when a task is woken the interrupt is pended from software.
///
/// This allows running async tasks at a priority higher than thread mode. One
/// use case is to leave thread mode free for non-async tasks. Another use case is
/// to run multiple executors: one in thread mode for low priority tasks and another in
/// interrupt mode for higher priority tasks. Higher priority tasks will preempt lower
/// priority ones.
///
/// It is even possible to run multiple interrupt mode executors at different priorities,
/// by assigning different priorities to the interrupts. For an example on how to do this,
/// See the 'multiprio' example for 'embassy-nrf'.
///
/// To use it, you have to pick an interrupt that won't be used by the hardware.
/// Some chips reserve some interrupts for this purpose, sometimes named "software interrupts" (SWI).
/// If this is not the case, you may use an interrupt from any unused peripheral.
///
/// It is somewhat more complex to use, it's recommended to use the thread-mode
/// [`Executor`] instead, if it works for your use case.
pub struct InterruptExecutor {
started: AtomicBool,
executor: UnsafeCell<MaybeUninit<raw::Executor>>,
}
unsafe impl Send for InterruptExecutor {}
unsafe impl Sync for InterruptExecutor {}
impl InterruptExecutor {
/// Create a new, not started `InterruptExecutor`.
#[inline]
pub const fn new() -> Self {
Self {
started: AtomicBool::new(false),
executor: UnsafeCell::new(MaybeUninit::uninit()),
}
}
/// Executor interrupt callback.
///
/// # Safety
///
/// You MUST call this from the interrupt handler, and from nowhere else.
pub unsafe fn on_interrupt(&'static self) {
let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
executor.poll();
}
/// Start the executor.
///
/// This initializes the executor, enables the interrupt, and returns.
/// The executor keeps running in the background through the interrupt.
///
/// This returns a [`SendSpawner`] you can use to spawn tasks on it. A [`SendSpawner`]
/// is returned instead of a [`Spawner`](embassy_executor::Spawner) because the executor effectively runs in a
/// different "thread" (the interrupt), so spawning tasks on it is effectively
/// sending them.
///
/// To obtain a [`Spawner`](embassy_executor::Spawner) for this executor, use [`Spawner::for_current_executor()`](embassy_executor::Spawner::for_current_executor()) from
/// a task running in it.
///
/// # Interrupt requirements
///
/// You must write the interrupt handler yourself, and make it call [`on_interrupt()`](Self::on_interrupt).
///
/// This method already enables (unmasks) the interrupt, you must NOT do it yourself.
///
/// You must set the interrupt priority before calling this method. You MUST NOT
/// do it after.
///
pub fn start(&'static self, irq: impl InterruptNumber) -> SendSpawner {
if self
.started
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_err()
{
panic!("InterruptExecutor::start() called multiple times on the same executor.");
}
unsafe {
(&mut *self.executor.get()).as_mut_ptr().write(raw::Executor::new(
|ctx| pend_by_number(ctx as u16),
irq.number() as *mut (),
))
}
let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
unsafe { NVIC::unmask(irq) }
executor.spawner().make_send()
}
}

View File

@ -5,6 +5,6 @@
// This mod MUST go first, so that the others see its macros. // This mod MUST go first, so that the others see its macros.
pub(crate) mod fmt; pub(crate) mod fmt;
pub mod executor; pub use embassy_executor as executor;
pub mod interrupt; pub mod interrupt;
pub mod peripheral; pub mod peripheral;

View File

@ -31,9 +31,22 @@ flavors = [
features = ["std", "nightly", "defmt"] features = ["std", "nightly", "defmt"]
[features] [features]
default = []
std = ["critical-section/std"] # Architecture
wasm = ["dep:wasm-bindgen", "dep:js-sys"] _arch = [] # some arch was picked
arch-std = ["_arch", "critical-section/std"]
arch-cortex-m = ["_arch", "dep:cortex-m"]
arch-xtensa = ["_arch"]
arch-riscv32 = ["_arch"]
arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"]
# Enable creating a `Pender` from an arbitrary function pointer callback.
pender-callback = []
# Enable the thread-mode executor (using WFE/SEV in Cortex-M, WFI in other embedded archs)
executor-thread = []
# Enable the interrupt-mode executor (available in Cortex-M only)
executor-interrupt = []
# Enable nightly-only features # Enable nightly-only features
nightly = [] nightly = []
@ -55,9 +68,11 @@ embassy-macros = { version = "0.1.0", path = "../embassy-macros" }
embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true} embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true}
atomic-polyfill = "1.0.1" atomic-polyfill = "1.0.1"
critical-section = "1.1" critical-section = "1.1"
cfg-if = "1.0.0"
static_cell = "1.0" static_cell = "1.0"
# WASM dependencies # arch-cortex-m dependencies
cortex-m = { version = "0.7.6", optional = true }
# arch-wasm dependencies
wasm-bindgen = { version = "0.2.82", optional = true } wasm-bindgen = { version = "0.2.82", optional = true }
js-sys = { version = "0.3", optional = true } js-sys = { version = "0.3", optional = true }

View File

@ -1,59 +1,209 @@
use core::arch::asm; #[cfg(feature = "executor-thread")]
use core::marker::PhantomData; pub use thread::*;
use core::ptr; #[cfg(feature = "executor-thread")]
mod thread {
use core::arch::asm;
use core::marker::PhantomData;
use super::{raw, Spawner}; #[cfg(feature = "nightly")]
pub use embassy_macros::main_cortex_m as main;
/// Thread mode executor, using WFE/SEV. use crate::raw::{Pender, PenderInner};
/// use crate::{raw, Spawner};
/// This is the simplest and most common kind of executor. It runs on
/// thread mode (at the lowest priority level), and uses the `WFE` ARM instruction
/// to sleep when it has no more work to do. When a task is woken, a `SEV` instruction
/// is executed, to make the `WFE` exit from sleep and poll the task.
///
/// This executor allows for ultra low power consumption for chips where `WFE`
/// triggers low-power sleep without extra steps. If your chip requires extra steps,
/// you may use [`raw::Executor`] directly to program custom behavior.
pub struct Executor {
inner: raw::Executor,
not_send: PhantomData<*mut ()>,
}
impl Executor { #[derive(Copy, Clone)]
/// Create a new Executor. pub(crate) struct ThreadPender;
pub fn new() -> Self {
Self { impl ThreadPender {
inner: raw::Executor::new(|_| unsafe { asm!("sev") }, ptr::null_mut()), pub(crate) fn pend(self) {
not_send: PhantomData, unsafe { core::arch::asm!("sev") }
} }
} }
/// Run the executor. /// Thread mode executor, using WFE/SEV.
/// ///
/// The `init` closure is called with a [`Spawner`] that spawns tasks on /// This is the simplest and most common kind of executor. It runs on
/// this executor. Use it to spawn the initial task(s). After `init` returns, /// thread mode (at the lowest priority level), and uses the `WFE` ARM instruction
/// the executor starts running the tasks. /// to sleep when it has no more work to do. When a task is woken, a `SEV` instruction
/// is executed, to make the `WFE` exit from sleep and poll the task.
/// ///
/// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`), /// This executor allows for ultra low power consumption for chips where `WFE`
/// for example by passing it as an argument to the initial tasks. /// triggers low-power sleep without extra steps. If your chip requires extra steps,
/// /// you may use [`raw::Executor`] directly to program custom behavior.
/// This function requires `&'static mut self`. This means you have to store the pub struct Executor {
/// Executor instance in a place where it'll live forever and grants you mutable inner: raw::Executor,
/// access. There's a few ways to do this: not_send: PhantomData<*mut ()>,
/// }
/// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
/// - a `static mut` (unsafe) impl Executor {
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) /// Create a new Executor.
/// pub fn new() -> Self {
/// This function never returns. Self {
pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender))),
init(self.inner.spawner()); not_send: PhantomData,
}
}
/// Run the executor.
///
/// The `init` closure is called with a [`Spawner`] that spawns tasks on
/// this executor. Use it to spawn the initial task(s). After `init` returns,
/// the executor starts running the tasks.
///
/// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`),
/// for example by passing it as an argument to the initial tasks.
///
/// This function requires `&'static mut self`. This means you have to store the
/// Executor instance in a place where it'll live forever and grants you mutable
/// access. There's a few ways to do this:
///
/// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
/// - a `static mut` (unsafe)
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
///
/// This function never returns.
pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
init(self.inner.spawner());
loop {
unsafe {
self.inner.poll();
asm!("wfe");
};
}
}
}
}
#[cfg(feature = "executor-interrupt")]
pub use interrupt::*;
#[cfg(feature = "executor-interrupt")]
mod interrupt {
use core::cell::UnsafeCell;
use core::mem::MaybeUninit;
use atomic_polyfill::{AtomicBool, Ordering};
use cortex_m::interrupt::InterruptNumber;
use cortex_m::peripheral::NVIC;
use crate::raw::{self, Pender, PenderInner};
#[derive(Clone, Copy)]
pub(crate) struct InterruptPender(u16);
impl InterruptPender {
pub(crate) fn pend(self) {
// STIR is faster, but is only available in v7 and higher.
#[cfg(not(armv6m))]
{
let mut nvic: cortex_m::peripheral::NVIC = unsafe { core::mem::transmute(()) };
nvic.request(self);
}
#[cfg(armv6m)]
cortex_m::peripheral::NVIC::pend(self);
}
}
unsafe impl cortex_m::interrupt::InterruptNumber for InterruptPender {
fn number(self) -> u16 {
self.0
}
}
/// Interrupt mode executor.
///
/// This executor runs tasks in interrupt mode. The interrupt handler is set up
/// to poll tasks, and when a task is woken the interrupt is pended from software.
///
/// This allows running async tasks at a priority higher than thread mode. One
/// use case is to leave thread mode free for non-async tasks. Another use case is
/// to run multiple executors: one in thread mode for low priority tasks and another in
/// interrupt mode for higher priority tasks. Higher priority tasks will preempt lower
/// priority ones.
///
/// It is even possible to run multiple interrupt mode executors at different priorities,
/// by assigning different priorities to the interrupts. For an example on how to do this,
/// See the 'multiprio' example for 'embassy-nrf'.
///
/// To use it, you have to pick an interrupt that won't be used by the hardware.
/// Some chips reserve some interrupts for this purpose, sometimes named "software interrupts" (SWI).
/// If this is not the case, you may use an interrupt from any unused peripheral.
///
/// It is somewhat more complex to use, it's recommended to use the thread-mode
/// [`Executor`] instead, if it works for your use case.
pub struct InterruptExecutor {
started: AtomicBool,
executor: UnsafeCell<MaybeUninit<raw::Executor>>,
}
unsafe impl Send for InterruptExecutor {}
unsafe impl Sync for InterruptExecutor {}
impl InterruptExecutor {
/// Create a new, not started `InterruptExecutor`.
#[inline]
pub const fn new() -> Self {
Self {
started: AtomicBool::new(false),
executor: UnsafeCell::new(MaybeUninit::uninit()),
}
}
/// Executor interrupt callback.
///
/// # Safety
///
/// You MUST call this from the interrupt handler, and from nowhere else.
pub unsafe fn on_interrupt(&'static self) {
let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
executor.poll();
}
/// Start the executor.
///
/// This initializes the executor, enables the interrupt, and returns.
/// The executor keeps running in the background through the interrupt.
///
/// This returns a [`SendSpawner`] you can use to spawn tasks on it. A [`SendSpawner`]
/// is returned instead of a [`Spawner`](embassy_executor::Spawner) because the executor effectively runs in a
/// different "thread" (the interrupt), so spawning tasks on it is effectively
/// sending them.
///
/// To obtain a [`Spawner`](embassy_executor::Spawner) for this executor, use [`Spawner::for_current_executor()`](embassy_executor::Spawner::for_current_executor()) from
/// a task running in it.
///
/// # Interrupt requirements
///
/// You must write the interrupt handler yourself, and make it call [`on_interrupt()`](Self::on_interrupt).
///
/// This method already enables (unmasks) the interrupt, you must NOT do it yourself.
///
/// You must set the interrupt priority before calling this method. You MUST NOT
/// do it after.
///
pub fn start(&'static self, irq: impl InterruptNumber) -> crate::SendSpawner {
if self
.started
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_err()
{
panic!("InterruptExecutor::start() called multiple times on the same executor.");
}
loop {
unsafe { unsafe {
self.inner.poll(); (&mut *self.executor.get())
asm!("wfe"); .as_mut_ptr()
}; .write(raw::Executor::new(Pender(PenderInner::Interrupt(InterruptPender(
irq.number(),
)))))
}
let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
unsafe { NVIC::unmask(irq) }
executor.spawner().make_send()
} }
} }
} }

View File

@ -1,72 +1,83 @@
use core::marker::PhantomData; #[cfg(feature = "executor-interrupt")]
use core::ptr; compile_error!("`executor-interrupt` is not supported with `arch-riscv32`.");
use core::sync::atomic::{AtomicBool, Ordering};
use super::{raw, Spawner}; #[cfg(feature = "executor-thread")]
pub use thread::*;
#[cfg(feature = "executor-thread")]
mod thread {
use core::marker::PhantomData;
use core::sync::atomic::{AtomicBool, Ordering};
/// global atomic used to keep track of whether there is work to do since sev() is not available on RISCV use crate::raw::{Pender, PenderInner};
/// use crate::{raw, Spawner};
static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false);
/// RISCV32 Executor #[derive(Copy, Clone)]
pub struct Executor { pub(crate) struct ThreadPender;
inner: raw::Executor,
not_send: PhantomData<*mut ()>,
}
impl Executor { impl ThreadPender {
/// Create a new Executor. #[allow(unused)]
pub fn new() -> Self { pub(crate) fn pend(self) {
Self { SIGNAL_WORK_THREAD_MODE.store(true, core::sync::atomic::Ordering::SeqCst);
// use Signal_Work_Thread_Mode as substitute for local interrupt register
inner: raw::Executor::new(
|_| {
SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst);
},
ptr::null_mut(),
),
not_send: PhantomData,
} }
} }
/// Run the executor. /// global atomic used to keep track of whether there is work to do since sev() is not available on RISCV
/// static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false);
/// The `init` closure is called with a [`Spawner`] that spawns tasks on
/// this executor. Use it to spawn the initial task(s). After `init` returns,
/// the executor starts running the tasks.
///
/// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`),
/// for example by passing it as an argument to the initial tasks.
///
/// This function requires `&'static mut self`. This means you have to store the
/// Executor instance in a place where it'll live forever and grants you mutable
/// access. There's a few ways to do this:
///
/// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
/// - a `static mut` (unsafe)
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
///
/// This function never returns.
pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
init(self.inner.spawner());
loop { /// RISCV32 Executor
unsafe { pub struct Executor {
self.inner.poll(); inner: raw::Executor,
// we do not care about race conditions between the load and store operations, interrupts not_send: PhantomData<*mut ()>,
//will only set this value to true. }
critical_section::with(|_| {
// if there is work to do, loop back to polling impl Executor {
// TODO can we relax this? /// Create a new Executor.
if SIGNAL_WORK_THREAD_MODE.load(Ordering::SeqCst) { pub fn new() -> Self {
SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst); Self {
} inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender))),
// if not, wait for interrupt not_send: PhantomData,
else { }
core::arch::asm!("wfi"); }
}
}); /// Run the executor.
// if an interrupt occurred while waiting, it will be serviced here ///
/// The `init` closure is called with a [`Spawner`] that spawns tasks on
/// this executor. Use it to spawn the initial task(s). After `init` returns,
/// the executor starts running the tasks.
///
/// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`),
/// for example by passing it as an argument to the initial tasks.
///
/// This function requires `&'static mut self`. This means you have to store the
/// Executor instance in a place where it'll live forever and grants you mutable
/// access. There's a few ways to do this:
///
/// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
/// - a `static mut` (unsafe)
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
///
/// This function never returns.
pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
init(self.inner.spawner());
loop {
unsafe {
self.inner.poll();
// we do not care about race conditions between the load and store operations, interrupts
//will only set this value to true.
critical_section::with(|_| {
// if there is work to do, loop back to polling
// TODO can we relax this?
if SIGNAL_WORK_THREAD_MODE.load(Ordering::SeqCst) {
SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst);
}
// if not, wait for interrupt
else {
core::arch::asm!("wfi");
}
});
// if an interrupt occurred while waiting, it will be serviced here
}
} }
} }
} }

View File

@ -1,84 +1,100 @@
use std::marker::PhantomData; #[cfg(feature = "executor-interrupt")]
use std::sync::{Condvar, Mutex}; compile_error!("`executor-interrupt` is not supported with `arch-std`.");
use super::{raw, Spawner}; #[cfg(feature = "executor-thread")]
pub use thread::*;
#[cfg(feature = "executor-thread")]
mod thread {
use std::marker::PhantomData;
use std::sync::{Condvar, Mutex};
/// Single-threaded std-based executor. #[cfg(feature = "nightly")]
pub struct Executor { pub use embassy_macros::main_std as main;
inner: raw::Executor,
not_send: PhantomData<*mut ()>,
signaler: &'static Signaler,
}
impl Executor { use crate::raw::{Pender, PenderInner};
/// Create a new Executor. use crate::{raw, Spawner};
pub fn new() -> Self {
let signaler = &*Box::leak(Box::new(Signaler::new())); #[derive(Copy, Clone)]
Self { pub(crate) struct ThreadPender(&'static Signaler);
inner: raw::Executor::new(
|p| unsafe { impl ThreadPender {
let s = &*(p as *const () as *const Signaler); #[allow(unused)]
s.signal() pub(crate) fn pend(self) {
}, self.0.signal()
signaler as *const _ as _,
),
not_send: PhantomData,
signaler,
} }
} }
/// Run the executor. /// Single-threaded std-based executor.
/// pub struct Executor {
/// The `init` closure is called with a [`Spawner`] that spawns tasks on inner: raw::Executor,
/// this executor. Use it to spawn the initial task(s). After `init` returns, not_send: PhantomData<*mut ()>,
/// the executor starts running the tasks. signaler: &'static Signaler,
///
/// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`),
/// for example by passing it as an argument to the initial tasks.
///
/// This function requires `&'static mut self`. This means you have to store the
/// Executor instance in a place where it'll live forever and grants you mutable
/// access. There's a few ways to do this:
///
/// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
/// - a `static mut` (unsafe)
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
///
/// This function never returns.
pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
init(self.inner.spawner());
loop {
unsafe { self.inner.poll() };
self.signaler.wait()
}
} }
}
struct Signaler { impl Executor {
mutex: Mutex<bool>, /// Create a new Executor.
condvar: Condvar, pub fn new() -> Self {
} let signaler = &*Box::leak(Box::new(Signaler::new()));
Self {
inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender(signaler)))),
not_send: PhantomData,
signaler,
}
}
impl Signaler { /// Run the executor.
fn new() -> Self { ///
Self { /// The `init` closure is called with a [`Spawner`] that spawns tasks on
mutex: Mutex::new(false), /// this executor. Use it to spawn the initial task(s). After `init` returns,
condvar: Condvar::new(), /// the executor starts running the tasks.
///
/// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`),
/// for example by passing it as an argument to the initial tasks.
///
/// This function requires `&'static mut self`. This means you have to store the
/// Executor instance in a place where it'll live forever and grants you mutable
/// access. There's a few ways to do this:
///
/// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
/// - a `static mut` (unsafe)
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
///
/// This function never returns.
pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
init(self.inner.spawner());
loop {
unsafe { self.inner.poll() };
self.signaler.wait()
}
} }
} }
fn wait(&self) { struct Signaler {
let mut signaled = self.mutex.lock().unwrap(); mutex: Mutex<bool>,
while !*signaled { condvar: Condvar,
signaled = self.condvar.wait(signaled).unwrap();
}
*signaled = false;
} }
fn signal(&self) { impl Signaler {
let mut signaled = self.mutex.lock().unwrap(); fn new() -> Self {
*signaled = true; Self {
self.condvar.notify_one(); mutex: Mutex::new(false),
condvar: Condvar::new(),
}
}
fn wait(&self) {
let mut signaled = self.mutex.lock().unwrap();
while !*signaled {
signaled = self.condvar.wait(signaled).unwrap();
}
*signaled = false;
}
fn signal(&self) {
let mut signaled = self.mutex.lock().unwrap();
*signaled = true;
self.condvar.notify_one();
}
} }
} }

View File

@ -1,74 +1,88 @@
use core::marker::PhantomData; #[cfg(feature = "executor-interrupt")]
compile_error!("`executor-interrupt` is not supported with `arch-wasm`.");
use js_sys::Promise; #[cfg(feature = "executor-thread")]
use wasm_bindgen::prelude::*; pub use thread::*;
#[cfg(feature = "executor-thread")]
mod thread {
use super::raw::util::UninitCell; use core::marker::PhantomData;
use super::raw::{self};
use super::Spawner;
/// WASM executor, wasm_bindgen to schedule tasks on the JS event loop. #[cfg(feature = "nightly")]
pub struct Executor { pub use embassy_macros::main_wasm as main;
inner: raw::Executor, use js_sys::Promise;
ctx: &'static WasmContext, use wasm_bindgen::prelude::*;
not_send: PhantomData<*mut ()>,
}
pub(crate) struct WasmContext { use crate::raw::util::UninitCell;
promise: Promise, use crate::raw::{Pender, PenderInner};
closure: UninitCell<Closure<dyn FnMut(JsValue)>>, use crate::{raw, Spawner};
}
impl WasmContext { /// WASM executor, wasm_bindgen to schedule tasks on the JS event loop.
pub fn new() -> Self { pub struct Executor {
Self { inner: raw::Executor,
promise: Promise::resolve(&JsValue::undefined()), ctx: &'static WasmContext,
closure: UninitCell::uninit(), not_send: PhantomData<*mut ()>,
}
} }
}
impl Executor { pub(crate) struct WasmContext {
/// Create a new Executor. promise: Promise,
pub fn new() -> Self { closure: UninitCell<Closure<dyn FnMut(JsValue)>>,
let ctx = &*Box::leak(Box::new(WasmContext::new())); }
let inner = raw::Executor::new(
|p| unsafe { #[derive(Copy, Clone)]
let ctx = &*(p as *const () as *const WasmContext); pub(crate) struct ThreadPender(&'static WasmContext);
let _ = ctx.promise.then(ctx.closure.as_mut());
}, impl ThreadPender {
ctx as *const _ as _, #[allow(unused)]
); pub(crate) fn pend(self) {
Self { let _ = self.0.promise.then(unsafe { self.0.closure.as_mut() });
inner,
not_send: PhantomData,
ctx,
} }
} }
/// Run the executor. impl WasmContext {
/// pub fn new() -> Self {
/// The `init` closure is called with a [`Spawner`] that spawns tasks on Self {
/// this executor. Use it to spawn the initial task(s). After `init` returns, promise: Promise::resolve(&JsValue::undefined()),
/// the executor starts running the tasks. closure: UninitCell::uninit(),
/// }
/// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`), }
/// for example by passing it as an argument to the initial tasks. }
///
/// This function requires `&'static mut self`. This means you have to store the impl Executor {
/// Executor instance in a place where it'll live forever and grants you mutable /// Create a new Executor.
/// access. There's a few ways to do this: pub fn new() -> Self {
/// let ctx = &*Box::leak(Box::new(WasmContext::new()));
/// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe) Self {
/// - a `static mut` (unsafe) inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender(ctx)))),
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) not_send: PhantomData,
pub fn start(&'static mut self, init: impl FnOnce(Spawner)) { ctx,
unsafe { }
let executor = &self.inner; }
self.ctx.closure.write(Closure::new(move |_| {
executor.poll(); /// Run the executor.
})); ///
init(self.inner.spawner()); /// The `init` closure is called with a [`Spawner`] that spawns tasks on
/// this executor. Use it to spawn the initial task(s). After `init` returns,
/// the executor starts running the tasks.
///
/// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`),
/// for example by passing it as an argument to the initial tasks.
///
/// This function requires `&'static mut self`. This means you have to store the
/// Executor instance in a place where it'll live forever and grants you mutable
/// access. There's a few ways to do this:
///
/// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
/// - a `static mut` (unsafe)
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
pub fn start(&'static mut self, init: impl FnOnce(Spawner)) {
unsafe {
let executor = &self.inner;
self.ctx.closure.write(Closure::new(move |_| {
executor.poll();
}));
init(self.inner.spawner());
}
} }
} }
} }

View File

@ -1,73 +1,84 @@
use core::marker::PhantomData; #[cfg(feature = "executor-interrupt")]
use core::ptr; compile_error!("`executor-interrupt` is not supported with `arch-xtensa`.");
use core::sync::atomic::{AtomicBool, Ordering};
use super::{raw, Spawner}; #[cfg(feature = "executor-thread")]
pub use thread::*;
#[cfg(feature = "executor-thread")]
mod thread {
use core::marker::PhantomData;
use core::sync::atomic::{AtomicBool, Ordering};
/// global atomic used to keep track of whether there is work to do since sev() is not available on Xtensa use crate::raw::{Pender, PenderInner};
/// use crate::{raw, Spawner};
static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false);
/// Xtensa Executor #[derive(Copy, Clone)]
pub struct Executor { pub(crate) struct ThreadPender;
inner: raw::Executor,
not_send: PhantomData<*mut ()>,
}
impl Executor { impl ThreadPender {
/// Create a new Executor. #[allow(unused)]
pub fn new() -> Self { pub(crate) fn pend(self) {
Self { SIGNAL_WORK_THREAD_MODE.store(true, core::sync::atomic::Ordering::SeqCst);
// use Signal_Work_Thread_Mode as substitute for local interrupt register
inner: raw::Executor::new(
|_| {
SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst);
},
ptr::null_mut(),
),
not_send: PhantomData,
} }
} }
/// Run the executor. /// global atomic used to keep track of whether there is work to do since sev() is not available on Xtensa
/// static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false);
/// The `init` closure is called with a [`Spawner`] that spawns tasks on
/// this executor. Use it to spawn the initial task(s). After `init` returns,
/// the executor starts running the tasks.
///
/// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`),
/// for example by passing it as an argument to the initial tasks.
///
/// This function requires `&'static mut self`. This means you have to store the
/// Executor instance in a place where it'll live forever and grants you mutable
/// access. There's a few ways to do this:
///
/// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
/// - a `static mut` (unsafe)
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
///
/// This function never returns.
pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
init(self.inner.spawner());
loop { /// Xtensa Executor
unsafe { pub struct Executor {
self.inner.poll(); inner: raw::Executor,
// we do not care about race conditions between the load and store operations, interrupts not_send: PhantomData<*mut ()>,
// will only set this value to true. }
// if there is work to do, loop back to polling
// TODO can we relax this? impl Executor {
critical_section::with(|_| { /// Create a new Executor.
if SIGNAL_WORK_THREAD_MODE.load(Ordering::SeqCst) { pub fn new() -> Self {
SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst); Self {
} else { inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender))),
// waiti sets the PS.INTLEVEL when slipping into sleep not_send: PhantomData,
// because critical sections in Xtensa are implemented via increasing }
// PS.INTLEVEL the critical section ends here }
// take care not add code after `waiti` if it needs to be inside the CS
core::arch::asm!("waiti 0"); // critical section ends here /// Run the executor.
} ///
}); /// The `init` closure is called with a [`Spawner`] that spawns tasks on
/// this executor. Use it to spawn the initial task(s). After `init` returns,
/// the executor starts running the tasks.
///
/// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`),
/// for example by passing it as an argument to the initial tasks.
///
/// This function requires `&'static mut self`. This means you have to store the
/// Executor instance in a place where it'll live forever and grants you mutable
/// access. There's a few ways to do this:
///
/// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
/// - a `static mut` (unsafe)
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
///
/// This function never returns.
pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
init(self.inner.spawner());
loop {
unsafe {
self.inner.poll();
// we do not care about race conditions between the load and store operations, interrupts
// will only set this value to true.
// if there is work to do, loop back to polling
// TODO can we relax this?
critical_section::with(|_| {
if SIGNAL_WORK_THREAD_MODE.load(Ordering::SeqCst) {
SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst);
} else {
// waiti sets the PS.INTLEVEL when slipping into sleep
// because critical sections in Xtensa are implemented via increasing
// PS.INTLEVEL the critical section ends here
// take care not add code after `waiti` if it needs to be inside the CS
core::arch::asm!("waiti 0"); // critical section ends here
}
});
}
} }
} }
} }

View File

@ -1,5 +1,5 @@
#![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)] #![cfg_attr(not(any(feature = "arch-std", feature = "arch-wasm")), no_std)]
#![cfg_attr(all(feature = "nightly", target_arch = "xtensa"), feature(asm_experimental_arch))] #![cfg_attr(all(feature = "nightly", feature = "arch-xtensa"), feature(asm_experimental_arch))]
#![allow(clippy::new_without_default)] #![allow(clippy::new_without_default)]
#![doc = include_str!("../README.md")] #![doc = include_str!("../README.md")]
#![warn(missing_docs)] #![warn(missing_docs)]
@ -10,47 +10,43 @@ pub(crate) mod fmt;
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
pub use embassy_macros::task; pub use embassy_macros::task;
cfg_if::cfg_if! { macro_rules! check_at_most_one {
if #[cfg(cortex_m)] { (@amo [$($feats:literal)*] [] [$($res:tt)*]) => {
#[path="arch/cortex_m.rs"] #[cfg(any($($res)*))]
mod arch; compile_error!(concat!("At most one of these features can be enabled at the same time:", $(" `", $feats, "`",)*));
pub use arch::*; };
#[cfg(feature = "nightly")] (@amo $feats:tt [$curr:literal $($rest:literal)*] [$($res:tt)*]) => {
pub use embassy_macros::main_cortex_m as main; check_at_most_one!(@amo $feats [$($rest)*] [$($res)* $(all(feature=$curr, feature=$rest),)*]);
} };
else if #[cfg(target_arch="riscv32")] { ($($f:literal),*$(,)?) => {
#[path="arch/riscv32.rs"] check_at_most_one!(@amo [$($f)*] [$($f)*] []);
mod arch; };
pub use arch::*;
#[cfg(feature = "nightly")]
pub use embassy_macros::main_riscv as main;
}
else if #[cfg(all(target_arch="xtensa", feature = "nightly"))] {
#[path="arch/xtensa.rs"]
mod arch;
pub use arch::*;
}
else if #[cfg(feature="wasm")] {
#[path="arch/wasm.rs"]
mod arch;
pub use arch::*;
#[cfg(feature = "nightly")]
pub use embassy_macros::main_wasm as main;
}
else if #[cfg(feature="std")] {
#[path="arch/std.rs"]
mod arch;
pub use arch::*;
#[cfg(feature = "nightly")]
pub use embassy_macros::main_std as main;
}
} }
check_at_most_one!("arch-cortex-m", "arch-riscv32", "arch-xtensa", "arch-std", "arch-wasm",);
#[cfg(feature = "_arch")]
#[cfg_attr(feature = "arch-cortex-m", path = "arch/cortex_m.rs")]
#[cfg_attr(feature = "arch-riscv32", path = "arch/riscv32.rs")]
#[cfg_attr(feature = "arch-xtensa", path = "arch/xtensa.rs")]
#[cfg_attr(feature = "arch-std", path = "arch/std.rs")]
#[cfg_attr(feature = "arch-wasm", path = "arch/wasm.rs")]
mod arch;
#[cfg(feature = "_arch")]
pub use arch::*;
pub mod raw;
mod spawner;
pub use spawner::*;
/// Implementation details for embassy macros.
/// Do not use. Used for macros and HALs only. Not covered by semver guarantees.
#[doc(hidden)] #[doc(hidden)]
/// Implementation details for embassy macros. DO NOT USE. pub mod _export {
pub mod export {
#[cfg(feature = "rtos-trace")] #[cfg(feature = "rtos-trace")]
pub use rtos_trace::trace; pub use rtos_trace::trace;
pub use static_cell::StaticCell;
/// Expands the given block of code when `embassy-executor` is compiled with /// Expands the given block of code when `embassy-executor` is compiled with
/// the `rtos-trace-interrupt` feature. /// the `rtos-trace-interrupt` feature.
@ -70,14 +66,3 @@ pub mod export {
($($tt:tt)*) => {}; ($($tt:tt)*) => {};
} }
} }
pub mod raw;
mod spawner;
pub use spawner::*;
/// Do not use. Used for macros and HALs only. Not covered by semver guarantees.
#[doc(hidden)]
pub mod _export {
pub use static_cell::StaticCell;
}

View File

@ -19,7 +19,6 @@ use core::marker::PhantomData;
use core::mem; use core::mem;
use core::pin::Pin; use core::pin::Pin;
use core::ptr::NonNull; use core::ptr::NonNull;
use core::sync::atomic::AtomicPtr;
use core::task::{Context, Poll}; use core::task::{Context, Poll};
use atomic_polyfill::{AtomicU32, Ordering}; use atomic_polyfill::{AtomicU32, Ordering};
@ -290,10 +289,60 @@ impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
} }
} }
#[derive(Clone, Copy)]
pub(crate) enum PenderInner {
#[cfg(feature = "executor-thread")]
Thread(crate::arch::ThreadPender),
#[cfg(feature = "executor-interrupt")]
Interrupt(crate::arch::InterruptPender),
#[cfg(feature = "pender-callback")]
Callback { func: fn(*mut ()), context: *mut () },
}
unsafe impl Send for PenderInner {}
unsafe impl Sync for PenderInner {}
/// Platform/architecture-specific action executed when an executor has pending work.
///
/// When a task within an executor is woken, the `Pender` is called. This does a
/// platform/architecture-specific action to signal there is pending work in the executor.
/// When this happens, you must arrange for [`Executor::poll`] to be called.
///
/// You can think of it as a waker, but for the whole executor.
pub struct Pender(pub(crate) PenderInner);
impl Pender {
/// Create a `Pender` that will call an arbitrary function pointer.
///
/// # Arguments
///
/// - `func`: The function pointer to call.
/// - `context`: Opaque context pointer, that will be passed to the function pointer.
#[cfg(feature = "pender-callback")]
pub fn new_from_callback(func: fn(*mut ()), context: *mut ()) -> Self {
Self(PenderInner::Callback {
func,
context: context.into(),
})
}
}
impl Pender {
pub(crate) fn pend(&self) {
match self.0 {
#[cfg(feature = "executor-thread")]
PenderInner::Thread(x) => x.pend(),
#[cfg(feature = "executor-interrupt")]
PenderInner::Interrupt(x) => x.pend(),
#[cfg(feature = "pender-callback")]
PenderInner::Callback { func, context } => func(context),
}
}
}
pub(crate) struct SyncExecutor { pub(crate) struct SyncExecutor {
run_queue: RunQueue, run_queue: RunQueue,
signal_fn: fn(*mut ()), pender: Pender,
signal_ctx: AtomicPtr<()>,
#[cfg(feature = "integrated-timers")] #[cfg(feature = "integrated-timers")]
pub(crate) timer_queue: timer_queue::TimerQueue, pub(crate) timer_queue: timer_queue::TimerQueue,
@ -302,16 +351,13 @@ pub(crate) struct SyncExecutor {
} }
impl SyncExecutor { impl SyncExecutor {
pub(crate) fn new(signal_fn: fn(*mut ()), signal_ctx: *mut ()) -> Self { pub(crate) fn new(pender: Pender) -> Self {
#[cfg(feature = "integrated-timers")] #[cfg(feature = "integrated-timers")]
let alarm = unsafe { unwrap!(driver::allocate_alarm()) }; let alarm = unsafe { unwrap!(driver::allocate_alarm()) };
#[cfg(feature = "integrated-timers")]
driver::set_alarm_callback(alarm, signal_fn, signal_ctx);
Self { Self {
run_queue: RunQueue::new(), run_queue: RunQueue::new(),
signal_fn, pender,
signal_ctx: AtomicPtr::new(signal_ctx),
#[cfg(feature = "integrated-timers")] #[cfg(feature = "integrated-timers")]
timer_queue: timer_queue::TimerQueue::new(), timer_queue: timer_queue::TimerQueue::new(),
@ -332,10 +378,16 @@ impl SyncExecutor {
trace::task_ready_begin(task.as_ptr() as u32); trace::task_ready_begin(task.as_ptr() as u32);
if self.run_queue.enqueue(cs, task) { if self.run_queue.enqueue(cs, task) {
(self.signal_fn)(self.signal_ctx.load(Ordering::Relaxed)) self.pender.pend();
} }
} }
#[cfg(feature = "integrated-timers")]
fn alarm_callback(ctx: *mut ()) {
let this: &Self = unsafe { &*(ctx as *const Self) };
this.pender.pend();
}
pub(super) unsafe fn spawn(&'static self, task: TaskRef) { pub(super) unsafe fn spawn(&'static self, task: TaskRef) {
task.header().executor.set(Some(self)); task.header().executor.set(Some(self));
@ -351,6 +403,9 @@ impl SyncExecutor {
/// ///
/// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created. /// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created.
pub(crate) unsafe fn poll(&'static self) { pub(crate) unsafe fn poll(&'static self) {
#[cfg(feature = "integrated-timers")]
driver::set_alarm_callback(self.alarm, Self::alarm_callback, self as *const _ as *mut ());
#[allow(clippy::never_loop)] #[allow(clippy::never_loop)]
loop { loop {
#[cfg(feature = "integrated-timers")] #[cfg(feature = "integrated-timers")]
@ -417,14 +472,14 @@ impl SyncExecutor {
/// ///
/// - To get the executor to do work, call `poll()`. This will poll all queued tasks (all tasks /// - To get the executor to do work, call `poll()`. This will poll all queued tasks (all tasks
/// that "want to run"). /// that "want to run").
/// - You must supply a `signal_fn`. The executor will call it to notify you it has work /// - You must supply a [`Pender`]. The executor will call it to notify you it has work
/// to do. You must arrange for `poll()` to be called as soon as possible. /// to do. You must arrange for `poll()` to be called as soon as possible.
/// ///
/// `signal_fn` can be called from *any* context: any thread, any interrupt priority /// The [`Pender`] can be called from *any* context: any thread, any interrupt priority
/// level, etc. It may be called synchronously from any `Executor` method call as well. /// level, etc. It may be called synchronously from any `Executor` method call as well.
/// You must deal with this correctly. /// You must deal with this correctly.
/// ///
/// In particular, you must NOT call `poll` directly from `signal_fn`, as this violates /// In particular, you must NOT call `poll` directly from the pender callback, as this violates
/// the requirement for `poll` to not be called reentrantly. /// the requirement for `poll` to not be called reentrantly.
#[repr(transparent)] #[repr(transparent)]
pub struct Executor { pub struct Executor {
@ -437,15 +492,15 @@ impl Executor {
pub(crate) unsafe fn wrap(inner: &SyncExecutor) -> &Self { pub(crate) unsafe fn wrap(inner: &SyncExecutor) -> &Self {
mem::transmute(inner) mem::transmute(inner)
} }
/// Create a new executor. /// Create a new executor.
/// ///
/// When the executor has work to do, it will call `signal_fn` with /// When the executor has work to do, it will call the [`Pender`].
/// `signal_ctx` as argument.
/// ///
/// See [`Executor`] docs for details on `signal_fn`. /// See [`Executor`] docs for details on `Pender`.
pub fn new(signal_fn: fn(*mut ()), signal_ctx: *mut ()) -> Self { pub fn new(pender: Pender) -> Self {
Self { Self {
inner: SyncExecutor::new(signal_fn, signal_ctx), inner: SyncExecutor::new(pender),
_not_sync: PhantomData, _not_sync: PhantomData,
} }
} }
@ -468,16 +523,16 @@ impl Executor {
/// This loops over all tasks that are queued to be polled (i.e. they're /// This loops over all tasks that are queued to be polled (i.e. they're
/// freshly spawned or they've been woken). Other tasks are not polled. /// freshly spawned or they've been woken). Other tasks are not polled.
/// ///
/// You must call `poll` after receiving a call to `signal_fn`. It is OK /// You must call `poll` after receiving a call to the [`Pender`]. It is OK
/// to call `poll` even when not requested by `signal_fn`, but it wastes /// to call `poll` even when not requested by the `Pender`, but it wastes
/// energy. /// energy.
/// ///
/// # Safety /// # Safety
/// ///
/// You must NOT call `poll` reentrantly on the same executor. /// You must NOT call `poll` reentrantly on the same executor.
/// ///
/// In particular, note that `poll` may call `signal_fn` synchronously. Therefore, you /// In particular, note that `poll` may call the `Pender` synchronously. Therefore, you
/// must NOT directly call `poll()` from your `signal_fn`. Instead, `signal_fn` has to /// must NOT directly call `poll()` from the `Pender` callback. Instead, the callback has to
/// somehow schedule for `poll()` to be called later, at a time you know for sure there's /// somehow schedule for `poll()` to be called later, at a time you know for sure there's
/// no `poll()` already running. /// no `poll()` already running.
pub unsafe fn poll(&'static self) { pub unsafe fn poll(&'static self) {

View File

@ -10,12 +10,12 @@ pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
let (isr_enter, isr_exit) = ( let (isr_enter, isr_exit) = (
quote! { quote! {
::embassy_executor::rtos_trace_interrupt! { ::embassy_executor::rtos_trace_interrupt! {
::embassy_executor::export::trace::isr_enter(); ::embassy_executor::_export::trace::isr_enter();
} }
}, },
quote! { quote! {
::embassy_executor::rtos_trace_interrupt! { ::embassy_executor::rtos_trace_interrupt! {
::embassy_executor::export::trace::isr_exit(); ::embassy_executor::_export::trace::isr_exit();
} }
}, },
); );

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync" } embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly"] } embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly"] }
embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", "nightly"] } embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", "nightly"] }
embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot" } embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot" }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync" } embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly"] } embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly"] }
embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", "unstable-traits", "nightly"] } embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", "unstable-traits", "nightly"] }
embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp" } embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp" }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f303re", "time-driver-any", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f303re", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f767zi", "time-driver-any", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f767zi", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync" } embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32h743zi", "time-driver-any", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32h743zi", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l072cz", "time-driver-any", "exti", "memory-x"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l072cz", "time-driver-any", "exti", "memory-x"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l151cb-a", "time-driver-any", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l151cb-a", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l475vg", "time-driver-any", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l475vg", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32wl55jc-cm4", "time-driver-any", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32wl55jc-cm4", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" }

View File

@ -17,7 +17,7 @@ log = [
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync" } embassy-sync = { version = "0.1.0", path = "../../embassy-sync" }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features=["rtos-trace", "rtos-trace-interrupt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "rtos-trace-interrupt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time" } embassy-time = { version = "0.1.0", path = "../../embassy-time" }
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }

View File

@ -12,7 +12,7 @@ nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/night
[dependencies] [dependencies]
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true }

View File

@ -9,7 +9,7 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = [ embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = [
"defmt", "defmt",
] } ] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = [ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread",
"nightly", "nightly",
"defmt", "defmt",
"integrated-timers", "integrated-timers",

View File

@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "pio", "critical-section-impl"] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "pio", "critical-section-impl"] }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["log"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["log"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["log", "std", "nightly", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "std", "nightly"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "std", "nightly"] }
embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "tcp", "udp", "dns", "dhcpv4", "unstable-traits", "proto-ipv6"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "tcp", "udp", "dns", "dhcpv4", "unstable-traits", "proto-ipv6"] }
embassy-net-driver = { version = "0.1.0", path = "../../embassy-net-driver" } embassy-net-driver = { version = "0.1.0", path = "../../embassy-net-driver" }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] }

View File

@ -13,7 +13,7 @@ defmt = "0.3"
defmt-rtt = "0.4" defmt-rtt = "0.4"
panic-probe = "0.3" panic-probe = "0.3"
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti", "unstable-pac"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti", "unstable-pac"] }
static_cell = "1.0" static_cell = "1.0"

View File

@ -62,7 +62,7 @@ use core::mem;
use cortex_m::peripheral::NVIC; use cortex_m::peripheral::NVIC;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use defmt::*; use defmt::*;
use embassy_stm32::executor::{Executor, InterruptExecutor}; use embassy_executor::{Executor, InterruptExecutor};
use embassy_stm32::interrupt; use embassy_stm32::interrupt;
use embassy_stm32::pac::Interrupt; use embassy_stm32::pac::Interrupt;
use embassy_time::{Duration, Instant, Timer}; use embassy_time::{Duration, Instant, Timer};

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any"] }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }

View File

@ -62,7 +62,7 @@ use core::mem;
use cortex_m::peripheral::NVIC; use cortex_m::peripheral::NVIC;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use defmt::*; use defmt::*;
use embassy_stm32::executor::{Executor, InterruptExecutor}; use embassy_executor::{Executor, InterruptExecutor};
use embassy_stm32::interrupt; use embassy_stm32::interrupt;
use embassy_stm32::pac::Interrupt; use embassy_stm32::pac::Interrupt;
use embassy_time::{Duration, Instant, Timer}; use embassy_time::{Duration, Instant, Timer};

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers", "arch-cortex-m", "executor-thread", "executor-interrupt"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }

View File

@ -62,7 +62,7 @@ use core::mem;
use cortex_m::peripheral::NVIC; use cortex_m::peripheral::NVIC;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use defmt::*; use defmt::*;
use embassy_stm32::executor::{Executor, InterruptExecutor}; use embassy_executor::{Executor, InterruptExecutor};
use embassy_stm32::interrupt; use embassy_stm32::interrupt;
use embassy_stm32::pac::Interrupt; use embassy_stm32::pac::Interrupt;
use embassy_time::{Duration, Instant, Timer}; use embassy_time::{Duration, Instant, Timer};

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] }
embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] } embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] }
embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" } embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] }
embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] } embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] }

View File

@ -10,7 +10,7 @@ nightly = ["embassy-stm32/nightly", "embassy-lora", "lorawan-device", "lorawan",
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "unstable-traits", "memory-x"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "unstable-traits", "memory-x"] }
embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx127x", "time", "defmt"], optional = true} embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx127x", "time", "defmt"], optional = true}

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti", "unstable-traits"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti", "unstable-traits"] }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55cc", "time-driver-any", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55cc", "time-driver-any", "exti"] }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "subghz", "unstable-pac", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "subghz", "unstable-pac", "exti"] }
embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["stm32wl", "time", "defmt"] } embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["stm32wl", "time", "defmt"] }

View File

@ -9,7 +9,7 @@ crate-type = ["cdylib"]
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["log"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["log"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["log", "wasm", "nightly", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "wasm", "nightly"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "wasm", "nightly"] }
wasm-logger = "0.2.0" wasm-logger = "0.2.0"

View File

@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt", "nightly"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt", "nightly"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "nightly", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "nightly", "defmt-timestamp-uptime"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "nightly", "defmt-timestamp-uptime"] }
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nightly", "unstable-traits", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nightly", "unstable-traits", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
embedded-io = { version = "0.4.0", features = ["async"] } embedded-io = { version = "0.4.0", features = ["async"] }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] }
embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl"] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl"] }
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }

View File

@ -15,7 +15,7 @@ stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board
[dependencies] [dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-tim2"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-tim2"] }