aboutsummaryrefslogtreecommitdiff
path: root/embassy-cortex-m/src/executor.rs
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-03-01 22:38:27 +0100
committerGitHub <[email protected]>2023-03-01 22:38:27 +0100
commitc4f4aa10f9af2fafe4b3c01a0b0358883cf96b14 (patch)
tree927fde03a44c2a36b2a0be34166f17093f56dea2 /embassy-cortex-m/src/executor.rs
parent206b4b597edabb0e4243d6bd847940b7ec415cfd (diff)
parent4dfa32b1e0572c03a5f97f0ed4a4a0acd6f12cca (diff)
Merge pull request #1244 from embassy-rs/interruptexecutor
cortex-m/executor: don't use the owned interrupts system.
Diffstat (limited to 'embassy-cortex-m/src/executor.rs')
-rw-r--r--embassy-cortex-m/src/executor.rs99
1 files changed, 63 insertions, 36 deletions
diff --git a/embassy-cortex-m/src/executor.rs b/embassy-cortex-m/src/executor.rs
index 0d1745d8a..558539e73 100644
--- a/embassy-cortex-m/src/executor.rs
+++ b/embassy-cortex-m/src/executor.rs
@@ -1,18 +1,22 @@
1//! Executor specific to cortex-m devices. 1//! Executor specific to cortex-m devices.
2use core::marker::PhantomData;
3 2
3use core::cell::UnsafeCell;
4use core::mem::MaybeUninit;
5
6use atomic_polyfill::{AtomicBool, Ordering};
7use cortex_m::interrupt::InterruptNumber;
8use cortex_m::peripheral::NVIC;
4pub use embassy_executor::*; 9pub use embassy_executor::*;
5 10
6use crate::interrupt::{Interrupt, InterruptExt}; 11#[derive(Clone, Copy)]
12struct N(u16);
13unsafe impl cortex_m::interrupt::InterruptNumber for N {
14 fn number(self) -> u16 {
15 self.0
16 }
17}
7 18
8fn pend_by_number(n: u16) { 19fn pend_by_number(n: u16) {
9 #[derive(Clone, Copy)]
10 struct N(u16);
11 unsafe impl cortex_m::interrupt::InterruptNumber for N {
12 fn number(self) -> u16 {
13 self.0
14 }
15 }
16 cortex_m::peripheral::NVIC::pend(N(n)) 20 cortex_m::peripheral::NVIC::pend(N(n))
17} 21}
18 22
@@ -37,26 +41,37 @@ fn pend_by_number(n: u16) {
37/// 41///
38/// It is somewhat more complex to use, it's recommended to use the thread-mode 42/// It is somewhat more complex to use, it's recommended to use the thread-mode
39/// [`Executor`] instead, if it works for your use case. 43/// [`Executor`] instead, if it works for your use case.
40pub struct InterruptExecutor<I: Interrupt> { 44pub struct InterruptExecutor {
41 irq: I, 45 started: AtomicBool,
42 inner: raw::Executor, 46 executor: UnsafeCell<MaybeUninit<raw::Executor>>,
43 not_send: PhantomData<*mut ()>,
44} 47}
45 48
46impl<I: Interrupt> InterruptExecutor<I> { 49unsafe impl Send for InterruptExecutor {}
47 /// Create a new Executor. 50unsafe impl Sync for InterruptExecutor {}
48 pub fn new(irq: I) -> Self { 51
49 let ctx = irq.number() as *mut (); 52impl InterruptExecutor {
53 /// Create a new, not started `InterruptExecutor`.
54 #[inline]
55 pub const fn new() -> Self {
50 Self { 56 Self {
51 irq, 57 started: AtomicBool::new(false),
52 inner: raw::Executor::new(|ctx| pend_by_number(ctx as u16), ctx), 58 executor: UnsafeCell::new(MaybeUninit::uninit()),
53 not_send: PhantomData,
54 } 59 }
55 } 60 }
56 61
62 /// Executor interrupt callback.
63 ///
64 /// # Safety
65 ///
66 /// You MUST call this from the interrupt handler, and from nowhere else.
67 pub unsafe fn on_interrupt(&'static self) {
68 let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
69 executor.poll();
70 }
71
57 /// Start the executor. 72 /// Start the executor.
58 /// 73 ///
59 /// This initializes the executor, configures and enables the interrupt, and returns. 74 /// This initializes the executor, enables the interrupt, and returns.
60 /// The executor keeps running in the background through the interrupt. 75 /// The executor keeps running in the background through the interrupt.
61 /// 76 ///
62 /// This returns a [`SendSpawner`] you can use to spawn tasks on it. A [`SendSpawner`] 77 /// This returns a [`SendSpawner`] you can use to spawn tasks on it. A [`SendSpawner`]
@@ -67,23 +82,35 @@ impl<I: Interrupt> InterruptExecutor<I> {
67 /// To obtain a [`Spawner`](embassy_executor::Spawner) for this executor, use [`Spawner::for_current_executor()`](embassy_executor::Spawner::for_current_executor()) from 82 /// To obtain a [`Spawner`](embassy_executor::Spawner) for this executor, use [`Spawner::for_current_executor()`](embassy_executor::Spawner::for_current_executor()) from
68 /// a task running in it. 83 /// a task running in it.
69 /// 84 ///
70 /// This function requires `&'static mut self`. This means you have to store the 85 /// # Interrupt requirements
71 /// Executor instance in a place where it'll live forever and grants you mutable 86 ///
72 /// access. There's a few ways to do this: 87 /// You must write the interrupt handler yourself, and make it call [`on_interrupt()`](Self::on_interrupt).
88 ///
89 /// This method already enables (unmasks) the interrupt, you must NOT do it yourself.
90 ///
91 /// You must set the interrupt priority before calling this method. You MUST NOT
92 /// do it after.
73 /// 93 ///
74 /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe) 94 pub fn start(&'static self, irq: impl InterruptNumber) -> SendSpawner {
75 /// - a `static mut` (unsafe) 95 if self
76 /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) 96 .started
77 pub fn start(&'static mut self) -> SendSpawner { 97 .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
78 self.irq.disable(); 98 .is_err()
99 {
100 panic!("InterruptExecutor::start() called multiple times on the same executor.");
101 }
102
103 unsafe {
104 (&mut *self.executor.get()).as_mut_ptr().write(raw::Executor::new(
105 |ctx| pend_by_number(ctx as u16),
106 irq.number() as *mut (),
107 ))
108 }
109
110 let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
79 111
80 self.irq.set_handler(|ctx| unsafe { 112 unsafe { NVIC::unmask(irq) }
81 let executor = &*(ctx as *const raw::Executor);
82 executor.poll();
83 });
84 self.irq.set_handler_context(&self.inner as *const _ as _);
85 self.irq.enable();
86 113
87 self.inner.spawner().make_send() 114 executor.spawner().make_send()
88 } 115 }
89} 116}