diff options
| author | Dummyc0m <[email protected]> | 2024-10-06 23:23:33 -0700 |
|---|---|---|
| committer | Dummyc0m <[email protected]> | 2024-10-06 23:33:34 -0700 |
| commit | 9e6e09a8d747ec90aae215df8471dfe349993487 (patch) | |
| tree | 0cd116be26fea69f9b770b3f36c87fc1273ae20b /embassy-executor/src | |
| parent | 8f273497453d3ca3f297465b67820d4d36705d11 (diff) | |
executor/spin: introduce an architecture agnostic executor
Spin polls the raw executor and never sleeps. It is useful for disabling
any power features associated with wfi/wfe-like instructions.
When implementing support for the CH32V30x MCU, the wfi instruction
had issues interacting with the USB OTG peripheral and appeared to be
non-spec-compliant.
1. When sending a USB Data-in packet, the USB peripheral appears to be
unable to read the system main memory while in WFI. This manifests in
the USB peripheral sending all or partially zeroed DATA packets.
Disabling WFI works around this issue.
2. The WFI instruction does not wake up the processor when MIE is
disabled. The MCU provides a WFITOWFE bit to emulate the WFE instruction
on arm, which, when enabled, ignores the MIE and allows the processor to
wake up. This works around the non-compliant WFI implementation.
Co-authored-by: Codetector <[email protected]>
Co-authored-by: Dummyc0m <[email protected]>
Diffstat (limited to 'embassy-executor/src')
| -rw-r--r-- | embassy-executor/src/arch/spin.rs | 58 | ||||
| -rw-r--r-- | embassy-executor/src/lib.rs | 10 |
2 files changed, 67 insertions, 1 deletions
diff --git a/embassy-executor/src/arch/spin.rs b/embassy-executor/src/arch/spin.rs new file mode 100644 index 000000000..340023620 --- /dev/null +++ b/embassy-executor/src/arch/spin.rs | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | #[cfg(feature = "executor-interrupt")] | ||
| 2 | compile_error!("`executor-interrupt` is not supported with `arch-spin`."); | ||
| 3 | |||
| 4 | #[cfg(feature = "executor-thread")] | ||
| 5 | pub use thread::*; | ||
| 6 | #[cfg(feature = "executor-thread")] | ||
| 7 | mod thread { | ||
| 8 | use core::marker::PhantomData; | ||
| 9 | |||
| 10 | pub use embassy_executor_macros::main_spin as main; | ||
| 11 | |||
| 12 | use crate::{raw, Spawner}; | ||
| 13 | |||
| 14 | #[export_name = "__pender"] | ||
| 15 | fn __pender(_context: *mut ()) {} | ||
| 16 | |||
| 17 | /// Spin Executor | ||
| 18 | pub struct Executor { | ||
| 19 | inner: raw::Executor, | ||
| 20 | not_send: PhantomData<*mut ()>, | ||
| 21 | } | ||
| 22 | |||
| 23 | impl Executor { | ||
| 24 | /// Create a new Executor. | ||
| 25 | pub fn new() -> Self { | ||
| 26 | Self { | ||
| 27 | inner: raw::Executor::new(core::ptr::null_mut()), | ||
| 28 | not_send: PhantomData, | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | /// Run the executor. | ||
| 33 | /// | ||
| 34 | /// The `init` closure is called with a [`Spawner`] that spawns tasks on | ||
| 35 | /// this executor. Use it to spawn the initial task(s). After `init` returns, | ||
| 36 | /// the executor starts running the tasks. | ||
| 37 | /// | ||
| 38 | /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`), | ||
| 39 | /// for example by passing it as an argument to the initial tasks. | ||
| 40 | /// | ||
| 41 | /// This function requires `&'static mut self`. This means you have to store the | ||
| 42 | /// Executor instance in a place where it'll live forever and grants you mutable | ||
| 43 | /// access. There's a few ways to do this: | ||
| 44 | /// | ||
| 45 | /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe) | ||
| 46 | /// - a `static mut` (unsafe) | ||
| 47 | /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) | ||
| 48 | /// | ||
| 49 | /// This function never returns. | ||
| 50 | pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { | ||
| 51 | init(self.inner.spawner()); | ||
| 52 | |||
| 53 | loop { | ||
| 54 | unsafe { self.inner.poll() }; | ||
| 55 | } | ||
| 56 | } | ||
| 57 | } | ||
| 58 | } | ||
diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs index 6a2e493a2..d816539ac 100644 --- a/embassy-executor/src/lib.rs +++ b/embassy-executor/src/lib.rs | |||
| @@ -23,7 +23,14 @@ macro_rules! check_at_most_one { | |||
| 23 | check_at_most_one!(@amo [$($f)*] [$($f)*] []); | 23 | check_at_most_one!(@amo [$($f)*] [$($f)*] []); |
| 24 | }; | 24 | }; |
| 25 | } | 25 | } |
| 26 | check_at_most_one!("arch-avr", "arch-cortex-m", "arch-riscv32", "arch-std", "arch-wasm",); | 26 | check_at_most_one!( |
| 27 | "arch-avr", | ||
| 28 | "arch-cortex-m", | ||
| 29 | "arch-riscv32", | ||
| 30 | "arch-std", | ||
| 31 | "arch-wasm", | ||
| 32 | "arch-spin", | ||
| 33 | ); | ||
| 27 | 34 | ||
| 28 | #[cfg(feature = "_arch")] | 35 | #[cfg(feature = "_arch")] |
| 29 | #[cfg_attr(feature = "arch-avr", path = "arch/avr.rs")] | 36 | #[cfg_attr(feature = "arch-avr", path = "arch/avr.rs")] |
| @@ -31,6 +38,7 @@ check_at_most_one!("arch-avr", "arch-cortex-m", "arch-riscv32", "arch-std", "arc | |||
| 31 | #[cfg_attr(feature = "arch-riscv32", path = "arch/riscv32.rs")] | 38 | #[cfg_attr(feature = "arch-riscv32", path = "arch/riscv32.rs")] |
| 32 | #[cfg_attr(feature = "arch-std", path = "arch/std.rs")] | 39 | #[cfg_attr(feature = "arch-std", path = "arch/std.rs")] |
| 33 | #[cfg_attr(feature = "arch-wasm", path = "arch/wasm.rs")] | 40 | #[cfg_attr(feature = "arch-wasm", path = "arch/wasm.rs")] |
| 41 | #[cfg_attr(feature = "arch-spin", path = "arch/spin.rs")] | ||
| 34 | mod arch; | 42 | mod arch; |
| 35 | 43 | ||
| 36 | #[cfg(feature = "_arch")] | 44 | #[cfg(feature = "_arch")] |
