aboutsummaryrefslogtreecommitdiff
path: root/embassy-cortex-m/src
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-06-11 05:08:57 +0200
committerDario Nieuwenhuis <[email protected]>2022-06-12 21:45:38 +0200
commit5085100df2845745f13715669c18a785a374a879 (patch)
treed24d264b23753d628e58fa3b92da77a78e28ce35 /embassy-cortex-m/src
parentdb344c2bda55bd0352a43720788185cc4d3a420e (diff)
Add embassy-cortex-m crate.
- Move Interrupt and InterruptExecutor from `embassy` to `embassy-cortex-m`. - Move Unborrow from `embassy` to `embassy-hal-common` (nothing in `embassy` requires it anymore) - Move PeripheralMutex from `embassy-hal-common` to `embassy-cortex-m`.
Diffstat (limited to 'embassy-cortex-m/src')
-rw-r--r--embassy-cortex-m/src/executor.rs89
-rw-r--r--embassy-cortex-m/src/fmt.rs228
-rw-r--r--embassy-cortex-m/src/interrupt.rs735
-rw-r--r--embassy-cortex-m/src/lib.rs8
-rw-r--r--embassy-cortex-m/src/peripheral.rs134
5 files changed, 1194 insertions, 0 deletions
diff --git a/embassy-cortex-m/src/executor.rs b/embassy-cortex-m/src/executor.rs
new file mode 100644
index 000000000..63a1519cf
--- /dev/null
+++ b/embassy-cortex-m/src/executor.rs
@@ -0,0 +1,89 @@
1use core::marker::PhantomData;
2
3use crate::interrupt::{Interrupt, InterruptExt};
4use embassy::executor::{raw, SendSpawner};
5
6pub use embassy::executor::Executor;
7
8fn 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))
17}
18
19/// Interrupt mode executor.
20///
21/// This executor runs tasks in interrupt mode. The interrupt handler is set up
22/// to poll tasks, and when a task is woken the interrupt is pended from software.
23///
24/// This allows running async tasks at a priority higher than thread mode. One
25/// use case is to leave thread mode free for non-async tasks. Another use case is
26/// to run multiple executors: one in thread mode for low priority tasks and another in
27/// interrupt mode for higher priority tasks. Higher priority tasks will preempt lower
28/// priority ones.
29///
30/// It is even possible to run multiple interrupt mode executors at different priorities,
31/// by assigning different priorities to the interrupts. For an example on how to do this,
32/// See the 'multiprio' example for 'embassy-nrf'.
33///
34/// To use it, you have to pick an interrupt that won't be used by the hardware.
35/// Some chips reserve some interrupts for this purpose, sometimes named "software interrupts" (SWI).
36/// If this is not the case, you may use an interrupt from any unused peripheral.
37///
38/// 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.
40pub struct InterruptExecutor<I: Interrupt> {
41 irq: I,
42 inner: raw::Executor,
43 not_send: PhantomData<*mut ()>,
44}
45
46impl<I: Interrupt> InterruptExecutor<I> {
47 /// Create a new Executor.
48 pub fn new(irq: I) -> Self {
49 let ctx = irq.number() as *mut ();
50 Self {
51 irq,
52 inner: raw::Executor::new(|ctx| pend_by_number(ctx as u16), ctx),
53 not_send: PhantomData,
54 }
55 }
56
57 /// Start the executor.
58 ///
59 /// This initializes the executor, configures and enables the interrupt, and returns.
60 /// The executor keeps running in the background through the interrupt.
61 ///
62 /// This returns a [`SendSpawner`] you can use to spawn tasks on it. A [`SendSpawner`]
63 /// is returned instead of a [`Spawner`] because the executor effectively runs in a
64 /// different "thread" (the interrupt), so spawning tasks on it is effectively
65 /// sending them.
66 ///
67 /// To obtain a [`Spawner`] for this executor, use [`Spawner::for_current_executor`] from
68 /// a task running in it.
69 ///
70 /// This function requires `&'static mut self`. This means you have to store the
71 /// Executor instance in a place where it'll live forever and grants you mutable
72 /// access. There's a few ways to do this:
73 ///
74 /// - a [Forever](crate::util::Forever) (safe)
75 /// - a `static mut` (unsafe)
76 /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
77 pub fn start(&'static mut self) -> SendSpawner {
78 self.irq.disable();
79
80 self.irq.set_handler(|ctx| unsafe {
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
87 self.inner.spawner().make_send()
88 }
89}
diff --git a/embassy-cortex-m/src/fmt.rs b/embassy-cortex-m/src/fmt.rs
new file mode 100644
index 000000000..f8bb0a035
--- /dev/null
+++ b/embassy-cortex-m/src/fmt.rs
@@ -0,0 +1,228 @@
1#![macro_use]
2#![allow(unused_macros)]
3
4#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features.");
6
7macro_rules! assert {
8 ($($x:tt)*) => {
9 {
10 #[cfg(not(feature = "defmt"))]
11 ::core::assert!($($x)*);
12 #[cfg(feature = "defmt")]
13 ::defmt::assert!($($x)*);
14 }
15 };
16}
17
18macro_rules! assert_eq {
19 ($($x:tt)*) => {
20 {
21 #[cfg(not(feature = "defmt"))]
22 ::core::assert_eq!($($x)*);
23 #[cfg(feature = "defmt")]
24 ::defmt::assert_eq!($($x)*);
25 }
26 };
27}
28
29macro_rules! assert_ne {
30 ($($x:tt)*) => {
31 {
32 #[cfg(not(feature = "defmt"))]
33 ::core::assert_ne!($($x)*);
34 #[cfg(feature = "defmt")]
35 ::defmt::assert_ne!($($x)*);
36 }
37 };
38}
39
40macro_rules! debug_assert {
41 ($($x:tt)*) => {
42 {
43 #[cfg(not(feature = "defmt"))]
44 ::core::debug_assert!($($x)*);
45 #[cfg(feature = "defmt")]
46 ::defmt::debug_assert!($($x)*);
47 }
48 };
49}
50
51macro_rules! debug_assert_eq {
52 ($($x:tt)*) => {
53 {
54 #[cfg(not(feature = "defmt"))]
55 ::core::debug_assert_eq!($($x)*);
56 #[cfg(feature = "defmt")]
57 ::defmt::debug_assert_eq!($($x)*);
58 }
59 };
60}
61
62macro_rules! debug_assert_ne {
63 ($($x:tt)*) => {
64 {
65 #[cfg(not(feature = "defmt"))]
66 ::core::debug_assert_ne!($($x)*);
67 #[cfg(feature = "defmt")]
68 ::defmt::debug_assert_ne!($($x)*);
69 }
70 };
71}
72
73macro_rules! todo {
74 ($($x:tt)*) => {
75 {
76 #[cfg(not(feature = "defmt"))]
77 ::core::todo!($($x)*);
78 #[cfg(feature = "defmt")]
79 ::defmt::todo!($($x)*);
80 }
81 };
82}
83
84macro_rules! unreachable {
85 ($($x:tt)*) => {
86 {
87 #[cfg(not(feature = "defmt"))]
88 ::core::unreachable!($($x)*);
89 #[cfg(feature = "defmt")]
90 ::defmt::unreachable!($($x)*);
91 }
92 };
93}
94
95macro_rules! panic {
96 ($($x:tt)*) => {
97 {
98 #[cfg(not(feature = "defmt"))]
99 ::core::panic!($($x)*);
100 #[cfg(feature = "defmt")]
101 ::defmt::panic!($($x)*);
102 }
103 };
104}
105
106macro_rules! trace {
107 ($s:literal $(, $x:expr)* $(,)?) => {
108 {
109 #[cfg(feature = "log")]
110 ::log::trace!($s $(, $x)*);
111 #[cfg(feature = "defmt")]
112 ::defmt::trace!($s $(, $x)*);
113 #[cfg(not(any(feature = "log", feature="defmt")))]
114 let _ = ($( & $x ),*);
115 }
116 };
117}
118
119macro_rules! debug {
120 ($s:literal $(, $x:expr)* $(,)?) => {
121 {
122 #[cfg(feature = "log")]
123 ::log::debug!($s $(, $x)*);
124 #[cfg(feature = "defmt")]
125 ::defmt::debug!($s $(, $x)*);
126 #[cfg(not(any(feature = "log", feature="defmt")))]
127 let _ = ($( & $x ),*);
128 }
129 };
130}
131
132macro_rules! info {
133 ($s:literal $(, $x:expr)* $(,)?) => {
134 {
135 #[cfg(feature = "log")]
136 ::log::info!($s $(, $x)*);
137 #[cfg(feature = "defmt")]
138 ::defmt::info!($s $(, $x)*);
139 #[cfg(not(any(feature = "log", feature="defmt")))]
140 let _ = ($( & $x ),*);
141 }
142 };
143}
144
145macro_rules! warn {
146 ($s:literal $(, $x:expr)* $(,)?) => {
147 {
148 #[cfg(feature = "log")]
149 ::log::warn!($s $(, $x)*);
150 #[cfg(feature = "defmt")]
151 ::defmt::warn!($s $(, $x)*);
152 #[cfg(not(any(feature = "log", feature="defmt")))]
153 let _ = ($( & $x ),*);
154 }
155 };
156}
157
158macro_rules! error {
159 ($s:literal $(, $x:expr)* $(,)?) => {
160 {
161 #[cfg(feature = "log")]
162 ::log::error!($s $(, $x)*);
163 #[cfg(feature = "defmt")]
164 ::defmt::error!($s $(, $x)*);
165 #[cfg(not(any(feature = "log", feature="defmt")))]
166 let _ = ($( & $x ),*);
167 }
168 };
169}
170
171#[cfg(feature = "defmt")]
172macro_rules! unwrap {
173 ($($x:tt)*) => {
174 ::defmt::unwrap!($($x)*)
175 };
176}
177
178#[cfg(not(feature = "defmt"))]
179macro_rules! unwrap {
180 ($arg:expr) => {
181 match $crate::fmt::Try::into_result($arg) {
182 ::core::result::Result::Ok(t) => t,
183 ::core::result::Result::Err(e) => {
184 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
185 }
186 }
187 };
188 ($arg:expr, $($msg:expr),+ $(,)? ) => {
189 match $crate::fmt::Try::into_result($arg) {
190 ::core::result::Result::Ok(t) => t,
191 ::core::result::Result::Err(e) => {
192 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
193 }
194 }
195 }
196}
197
198#[cfg(feature = "defmt-timestamp-uptime")]
199defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() }
200
201#[derive(Debug, Copy, Clone, Eq, PartialEq)]
202pub struct NoneError;
203
204pub trait Try {
205 type Ok;
206 type Error;
207 fn into_result(self) -> Result<Self::Ok, Self::Error>;
208}
209
210impl<T> Try for Option<T> {
211 type Ok = T;
212 type Error = NoneError;
213
214 #[inline]
215 fn into_result(self) -> Result<T, NoneError> {
216 self.ok_or(NoneError)
217 }
218}
219
220impl<T, E> Try for Result<T, E> {
221 type Ok = T;
222 type Error = E;
223
224 #[inline]
225 fn into_result(self) -> Self {
226 self
227 }
228}
diff --git a/embassy-cortex-m/src/interrupt.rs b/embassy-cortex-m/src/interrupt.rs
new file mode 100644
index 000000000..df2aad0ec
--- /dev/null
+++ b/embassy-cortex-m/src/interrupt.rs
@@ -0,0 +1,735 @@
1use atomic_polyfill::{compiler_fence, AtomicPtr, Ordering};
2use core::mem;
3use core::ptr;
4use cortex_m::peripheral::NVIC;
5use embassy_hal_common::Unborrow;
6
7pub use embassy_macros::cortex_m_interrupt_take as take;
8
9/// Implementation detail, do not use outside embassy crates.
10#[doc(hidden)]
11pub struct Handler {
12 pub func: AtomicPtr<()>,
13 pub ctx: AtomicPtr<()>,
14}
15
16impl Handler {
17 pub const fn new() -> Self {
18 Self {
19 func: AtomicPtr::new(ptr::null_mut()),
20 ctx: AtomicPtr::new(ptr::null_mut()),
21 }
22 }
23}
24
25#[derive(Clone, Copy)]
26pub(crate) struct NrWrap(pub(crate) u16);
27unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap {
28 fn number(self) -> u16 {
29 self.0
30 }
31}
32
33pub unsafe trait Interrupt: Unborrow<Target = Self> {
34 fn number(&self) -> u16;
35 unsafe fn steal() -> Self;
36
37 /// Implementation detail, do not use outside embassy crates.
38 #[doc(hidden)]
39 unsafe fn __handler(&self) -> &'static Handler;
40}
41
42pub trait InterruptExt: Interrupt {
43 fn set_handler(&self, func: unsafe fn(*mut ()));
44 fn remove_handler(&self);
45 fn set_handler_context(&self, ctx: *mut ());
46 fn enable(&self);
47 fn disable(&self);
48 #[cfg(not(armv6m))]
49 fn is_active(&self) -> bool;
50 fn is_enabled(&self) -> bool;
51 fn is_pending(&self) -> bool;
52 fn pend(&self);
53 fn unpend(&self);
54 fn get_priority(&self) -> Priority;
55 fn set_priority(&self, prio: Priority);
56}
57
58impl<T: Interrupt + ?Sized> InterruptExt for T {
59 fn set_handler(&self, func: unsafe fn(*mut ())) {
60 compiler_fence(Ordering::SeqCst);
61 let handler = unsafe { self.__handler() };
62 handler.func.store(func as *mut (), Ordering::Relaxed);
63 compiler_fence(Ordering::SeqCst);
64 }
65
66 fn remove_handler(&self) {
67 compiler_fence(Ordering::SeqCst);
68 let handler = unsafe { self.__handler() };
69 handler.func.store(ptr::null_mut(), Ordering::Relaxed);
70 compiler_fence(Ordering::SeqCst);
71 }
72
73 fn set_handler_context(&self, ctx: *mut ()) {
74 let handler = unsafe { self.__handler() };
75 handler.ctx.store(ctx, Ordering::Relaxed);
76 }
77
78 #[inline]
79 fn enable(&self) {
80 compiler_fence(Ordering::SeqCst);
81 unsafe {
82 NVIC::unmask(NrWrap(self.number()));
83 }
84 }
85
86 #[inline]
87 fn disable(&self) {
88 NVIC::mask(NrWrap(self.number()));
89 compiler_fence(Ordering::SeqCst);
90 }
91
92 #[inline]
93 #[cfg(not(armv6m))]
94 fn is_active(&self) -> bool {
95 NVIC::is_active(NrWrap(self.number()))
96 }
97
98 #[inline]
99 fn is_enabled(&self) -> bool {
100 NVIC::is_enabled(NrWrap(self.number()))
101 }
102
103 #[inline]
104 fn is_pending(&self) -> bool {
105 NVIC::is_pending(NrWrap(self.number()))
106 }
107
108 #[inline]
109 fn pend(&self) {
110 NVIC::pend(NrWrap(self.number()))
111 }
112
113 #[inline]
114 fn unpend(&self) {
115 NVIC::unpend(NrWrap(self.number()))
116 }
117
118 #[inline]
119 fn get_priority(&self) -> Priority {
120 Priority::from(NVIC::get_priority(NrWrap(self.number())))
121 }
122
123 #[inline]
124 fn set_priority(&self, prio: Priority) {
125 unsafe {
126 let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(());
127 nvic.set_priority(NrWrap(self.number()), prio.into())
128 }
129 }
130}
131
132impl From<u8> for Priority {
133 fn from(priority: u8) -> Self {
134 unsafe { mem::transmute(priority & PRIO_MASK) }
135 }
136}
137
138impl From<Priority> for u8 {
139 fn from(p: Priority) -> Self {
140 p as u8
141 }
142}
143
144#[cfg(feature = "prio-bits-0")]
145const PRIO_MASK: u8 = 0x00;
146#[cfg(feature = "prio-bits-1")]
147const PRIO_MASK: u8 = 0x80;
148#[cfg(feature = "prio-bits-2")]
149const PRIO_MASK: u8 = 0xc0;
150#[cfg(feature = "prio-bits-3")]
151const PRIO_MASK: u8 = 0xe0;
152#[cfg(feature = "prio-bits-4")]
153const PRIO_MASK: u8 = 0xf0;
154#[cfg(feature = "prio-bits-5")]
155const PRIO_MASK: u8 = 0xf8;
156#[cfg(feature = "prio-bits-6")]
157const PRIO_MASK: u8 = 0xfc;
158#[cfg(feature = "prio-bits-7")]
159const PRIO_MASK: u8 = 0xfe;
160#[cfg(feature = "prio-bits-8")]
161const PRIO_MASK: u8 = 0xff;
162
163#[cfg(feature = "prio-bits-0")]
164#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
165#[cfg_attr(feature = "defmt", derive(defmt::Format))]
166#[repr(u8)]
167pub enum Priority {
168 P0 = 0x0,
169}
170
171#[cfg(feature = "prio-bits-1")]
172#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
173#[cfg_attr(feature = "defmt", derive(defmt::Format))]
174#[repr(u8)]
175pub enum Priority {
176 P0 = 0x0,
177 P1 = 0x80,
178}
179
180#[cfg(feature = "prio-bits-2")]
181#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
182#[cfg_attr(feature = "defmt", derive(defmt::Format))]
183#[repr(u8)]
184pub enum Priority {
185 P0 = 0x0,
186 P1 = 0x40,
187 P2 = 0x80,
188 P3 = 0xc0,
189}
190
191#[cfg(feature = "prio-bits-3")]
192#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
193#[cfg_attr(feature = "defmt", derive(defmt::Format))]
194#[repr(u8)]
195pub enum Priority {
196 P0 = 0x0,
197 P1 = 0x20,
198 P2 = 0x40,
199 P3 = 0x60,
200 P4 = 0x80,
201 P5 = 0xa0,
202 P6 = 0xc0,
203 P7 = 0xe0,
204}
205
206#[cfg(feature = "prio-bits-4")]
207#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
208#[cfg_attr(feature = "defmt", derive(defmt::Format))]
209#[repr(u8)]
210pub enum Priority {
211 P0 = 0x0,
212 P1 = 0x10,
213 P2 = 0x20,
214 P3 = 0x30,
215 P4 = 0x40,
216 P5 = 0x50,
217 P6 = 0x60,
218 P7 = 0x70,
219 P8 = 0x80,
220 P9 = 0x90,
221 P10 = 0xa0,
222 P11 = 0xb0,
223 P12 = 0xc0,
224 P13 = 0xd0,
225 P14 = 0xe0,
226 P15 = 0xf0,
227}
228
229#[cfg(feature = "prio-bits-5")]
230#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
231#[cfg_attr(feature = "defmt", derive(defmt::Format))]
232#[repr(u8)]
233pub enum Priority {
234 P0 = 0x0,
235 P1 = 0x8,
236 P2 = 0x10,
237 P3 = 0x18,
238 P4 = 0x20,
239 P5 = 0x28,
240 P6 = 0x30,
241 P7 = 0x38,
242 P8 = 0x40,
243 P9 = 0x48,
244 P10 = 0x50,
245 P11 = 0x58,
246 P12 = 0x60,
247 P13 = 0x68,
248 P14 = 0x70,
249 P15 = 0x78,
250 P16 = 0x80,
251 P17 = 0x88,
252 P18 = 0x90,
253 P19 = 0x98,
254 P20 = 0xa0,
255 P21 = 0xa8,
256 P22 = 0xb0,
257 P23 = 0xb8,
258 P24 = 0xc0,
259 P25 = 0xc8,
260 P26 = 0xd0,
261 P27 = 0xd8,
262 P28 = 0xe0,
263 P29 = 0xe8,
264 P30 = 0xf0,
265 P31 = 0xf8,
266}
267
268#[cfg(feature = "prio-bits-6")]
269#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
270#[cfg_attr(feature = "defmt", derive(defmt::Format))]
271#[repr(u8)]
272pub enum Priority {
273 P0 = 0x0,
274 P1 = 0x4,
275 P2 = 0x8,
276 P3 = 0xc,
277 P4 = 0x10,
278 P5 = 0x14,
279 P6 = 0x18,
280 P7 = 0x1c,
281 P8 = 0x20,
282 P9 = 0x24,
283 P10 = 0x28,
284 P11 = 0x2c,
285 P12 = 0x30,
286 P13 = 0x34,
287 P14 = 0x38,
288 P15 = 0x3c,
289 P16 = 0x40,
290 P17 = 0x44,
291 P18 = 0x48,
292 P19 = 0x4c,
293 P20 = 0x50,
294 P21 = 0x54,
295 P22 = 0x58,
296 P23 = 0x5c,
297 P24 = 0x60,
298 P25 = 0x64,
299 P26 = 0x68,
300 P27 = 0x6c,
301 P28 = 0x70,
302 P29 = 0x74,
303 P30 = 0x78,
304 P31 = 0x7c,
305 P32 = 0x80,
306 P33 = 0x84,
307 P34 = 0x88,
308 P35 = 0x8c,
309 P36 = 0x90,
310 P37 = 0x94,
311 P38 = 0x98,
312 P39 = 0x9c,
313 P40 = 0xa0,
314 P41 = 0xa4,
315 P42 = 0xa8,
316 P43 = 0xac,
317 P44 = 0xb0,
318 P45 = 0xb4,
319 P46 = 0xb8,
320 P47 = 0xbc,
321 P48 = 0xc0,
322 P49 = 0xc4,
323 P50 = 0xc8,
324 P51 = 0xcc,
325 P52 = 0xd0,
326 P53 = 0xd4,
327 P54 = 0xd8,
328 P55 = 0xdc,
329 P56 = 0xe0,
330 P57 = 0xe4,
331 P58 = 0xe8,
332 P59 = 0xec,
333 P60 = 0xf0,
334 P61 = 0xf4,
335 P62 = 0xf8,
336 P63 = 0xfc,
337}
338
339#[cfg(feature = "prio-bits-7")]
340#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
341#[cfg_attr(feature = "defmt", derive(defmt::Format))]
342#[repr(u8)]
343pub enum Priority {
344 P0 = 0x0,
345 P1 = 0x2,
346 P2 = 0x4,
347 P3 = 0x6,
348 P4 = 0x8,
349 P5 = 0xa,
350 P6 = 0xc,
351 P7 = 0xe,
352 P8 = 0x10,
353 P9 = 0x12,
354 P10 = 0x14,
355 P11 = 0x16,
356 P12 = 0x18,
357 P13 = 0x1a,
358 P14 = 0x1c,
359 P15 = 0x1e,
360 P16 = 0x20,
361 P17 = 0x22,
362 P18 = 0x24,
363 P19 = 0x26,
364 P20 = 0x28,
365 P21 = 0x2a,
366 P22 = 0x2c,
367 P23 = 0x2e,
368 P24 = 0x30,
369 P25 = 0x32,
370 P26 = 0x34,
371 P27 = 0x36,
372 P28 = 0x38,
373 P29 = 0x3a,
374 P30 = 0x3c,
375 P31 = 0x3e,
376 P32 = 0x40,
377 P33 = 0x42,
378 P34 = 0x44,
379 P35 = 0x46,
380 P36 = 0x48,
381 P37 = 0x4a,
382 P38 = 0x4c,
383 P39 = 0x4e,
384 P40 = 0x50,
385 P41 = 0x52,
386 P42 = 0x54,
387 P43 = 0x56,
388 P44 = 0x58,
389 P45 = 0x5a,
390 P46 = 0x5c,
391 P47 = 0x5e,
392 P48 = 0x60,
393 P49 = 0x62,
394 P50 = 0x64,
395 P51 = 0x66,
396 P52 = 0x68,
397 P53 = 0x6a,
398 P54 = 0x6c,
399 P55 = 0x6e,
400 P56 = 0x70,
401 P57 = 0x72,
402 P58 = 0x74,
403 P59 = 0x76,
404 P60 = 0x78,
405 P61 = 0x7a,
406 P62 = 0x7c,
407 P63 = 0x7e,
408 P64 = 0x80,
409 P65 = 0x82,
410 P66 = 0x84,
411 P67 = 0x86,
412 P68 = 0x88,
413 P69 = 0x8a,
414 P70 = 0x8c,
415 P71 = 0x8e,
416 P72 = 0x90,
417 P73 = 0x92,
418 P74 = 0x94,
419 P75 = 0x96,
420 P76 = 0x98,
421 P77 = 0x9a,
422 P78 = 0x9c,
423 P79 = 0x9e,
424 P80 = 0xa0,
425 P81 = 0xa2,
426 P82 = 0xa4,
427 P83 = 0xa6,
428 P84 = 0xa8,
429 P85 = 0xaa,
430 P86 = 0xac,
431 P87 = 0xae,
432 P88 = 0xb0,
433 P89 = 0xb2,
434 P90 = 0xb4,
435 P91 = 0xb6,
436 P92 = 0xb8,
437 P93 = 0xba,
438 P94 = 0xbc,
439 P95 = 0xbe,
440 P96 = 0xc0,
441 P97 = 0xc2,
442 P98 = 0xc4,
443 P99 = 0xc6,
444 P100 = 0xc8,
445 P101 = 0xca,
446 P102 = 0xcc,
447 P103 = 0xce,
448 P104 = 0xd0,
449 P105 = 0xd2,
450 P106 = 0xd4,
451 P107 = 0xd6,
452 P108 = 0xd8,
453 P109 = 0xda,
454 P110 = 0xdc,
455 P111 = 0xde,
456 P112 = 0xe0,
457 P113 = 0xe2,
458 P114 = 0xe4,
459 P115 = 0xe6,
460 P116 = 0xe8,
461 P117 = 0xea,
462 P118 = 0xec,
463 P119 = 0xee,
464 P120 = 0xf0,
465 P121 = 0xf2,
466 P122 = 0xf4,
467 P123 = 0xf6,
468 P124 = 0xf8,
469 P125 = 0xfa,
470 P126 = 0xfc,
471 P127 = 0xfe,
472}
473
474#[cfg(feature = "prio-bits-8")]
475#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
476#[cfg_attr(feature = "defmt", derive(defmt::Format))]
477#[repr(u8)]
478pub enum Priority {
479 P0 = 0x0,
480 P1 = 0x1,
481 P2 = 0x2,
482 P3 = 0x3,
483 P4 = 0x4,
484 P5 = 0x5,
485 P6 = 0x6,
486 P7 = 0x7,
487 P8 = 0x8,
488 P9 = 0x9,
489 P10 = 0xa,
490 P11 = 0xb,
491 P12 = 0xc,
492 P13 = 0xd,
493 P14 = 0xe,
494 P15 = 0xf,
495 P16 = 0x10,
496 P17 = 0x11,
497 P18 = 0x12,
498 P19 = 0x13,
499 P20 = 0x14,
500 P21 = 0x15,
501 P22 = 0x16,
502 P23 = 0x17,
503 P24 = 0x18,
504 P25 = 0x19,
505 P26 = 0x1a,
506 P27 = 0x1b,
507 P28 = 0x1c,
508 P29 = 0x1d,
509 P30 = 0x1e,
510 P31 = 0x1f,
511 P32 = 0x20,
512 P33 = 0x21,
513 P34 = 0x22,
514 P35 = 0x23,
515 P36 = 0x24,
516 P37 = 0x25,
517 P38 = 0x26,
518 P39 = 0x27,
519 P40 = 0x28,
520 P41 = 0x29,
521 P42 = 0x2a,
522 P43 = 0x2b,
523 P44 = 0x2c,
524 P45 = 0x2d,
525 P46 = 0x2e,
526 P47 = 0x2f,
527 P48 = 0x30,
528 P49 = 0x31,
529 P50 = 0x32,
530 P51 = 0x33,
531 P52 = 0x34,
532 P53 = 0x35,
533 P54 = 0x36,
534 P55 = 0x37,
535 P56 = 0x38,
536 P57 = 0x39,
537 P58 = 0x3a,
538 P59 = 0x3b,
539 P60 = 0x3c,
540 P61 = 0x3d,
541 P62 = 0x3e,
542 P63 = 0x3f,
543 P64 = 0x40,
544 P65 = 0x41,
545 P66 = 0x42,
546 P67 = 0x43,
547 P68 = 0x44,
548 P69 = 0x45,
549 P70 = 0x46,
550 P71 = 0x47,
551 P72 = 0x48,
552 P73 = 0x49,
553 P74 = 0x4a,
554 P75 = 0x4b,
555 P76 = 0x4c,
556 P77 = 0x4d,
557 P78 = 0x4e,
558 P79 = 0x4f,
559 P80 = 0x50,
560 P81 = 0x51,
561 P82 = 0x52,
562 P83 = 0x53,
563 P84 = 0x54,
564 P85 = 0x55,
565 P86 = 0x56,
566 P87 = 0x57,
567 P88 = 0x58,
568 P89 = 0x59,
569 P90 = 0x5a,
570 P91 = 0x5b,
571 P92 = 0x5c,
572 P93 = 0x5d,
573 P94 = 0x5e,
574 P95 = 0x5f,
575 P96 = 0x60,
576 P97 = 0x61,
577 P98 = 0x62,
578 P99 = 0x63,
579 P100 = 0x64,
580 P101 = 0x65,
581 P102 = 0x66,
582 P103 = 0x67,
583 P104 = 0x68,
584 P105 = 0x69,
585 P106 = 0x6a,
586 P107 = 0x6b,
587 P108 = 0x6c,
588 P109 = 0x6d,
589 P110 = 0x6e,
590 P111 = 0x6f,
591 P112 = 0x70,
592 P113 = 0x71,
593 P114 = 0x72,
594 P115 = 0x73,
595 P116 = 0x74,
596 P117 = 0x75,
597 P118 = 0x76,
598 P119 = 0x77,
599 P120 = 0x78,
600 P121 = 0x79,
601 P122 = 0x7a,
602 P123 = 0x7b,
603 P124 = 0x7c,
604 P125 = 0x7d,
605 P126 = 0x7e,
606 P127 = 0x7f,
607 P128 = 0x80,
608 P129 = 0x81,
609 P130 = 0x82,
610 P131 = 0x83,
611 P132 = 0x84,
612 P133 = 0x85,
613 P134 = 0x86,
614 P135 = 0x87,
615 P136 = 0x88,
616 P137 = 0x89,
617 P138 = 0x8a,
618 P139 = 0x8b,
619 P140 = 0x8c,
620 P141 = 0x8d,
621 P142 = 0x8e,
622 P143 = 0x8f,
623 P144 = 0x90,
624 P145 = 0x91,
625 P146 = 0x92,
626 P147 = 0x93,
627 P148 = 0x94,
628 P149 = 0x95,
629 P150 = 0x96,
630 P151 = 0x97,
631 P152 = 0x98,
632 P153 = 0x99,
633 P154 = 0x9a,
634 P155 = 0x9b,
635 P156 = 0x9c,
636 P157 = 0x9d,
637 P158 = 0x9e,
638 P159 = 0x9f,
639 P160 = 0xa0,
640 P161 = 0xa1,
641 P162 = 0xa2,
642 P163 = 0xa3,
643 P164 = 0xa4,
644 P165 = 0xa5,
645 P166 = 0xa6,
646 P167 = 0xa7,
647 P168 = 0xa8,
648 P169 = 0xa9,
649 P170 = 0xaa,
650 P171 = 0xab,
651 P172 = 0xac,
652 P173 = 0xad,
653 P174 = 0xae,
654 P175 = 0xaf,
655 P176 = 0xb0,
656 P177 = 0xb1,
657 P178 = 0xb2,
658 P179 = 0xb3,
659 P180 = 0xb4,
660 P181 = 0xb5,
661 P182 = 0xb6,
662 P183 = 0xb7,
663 P184 = 0xb8,
664 P185 = 0xb9,
665 P186 = 0xba,
666 P187 = 0xbb,
667 P188 = 0xbc,
668 P189 = 0xbd,
669 P190 = 0xbe,
670 P191 = 0xbf,
671 P192 = 0xc0,
672 P193 = 0xc1,
673 P194 = 0xc2,
674 P195 = 0xc3,
675 P196 = 0xc4,
676 P197 = 0xc5,
677 P198 = 0xc6,
678 P199 = 0xc7,
679 P200 = 0xc8,
680 P201 = 0xc9,
681 P202 = 0xca,
682 P203 = 0xcb,
683 P204 = 0xcc,
684 P205 = 0xcd,
685 P206 = 0xce,
686 P207 = 0xcf,
687 P208 = 0xd0,
688 P209 = 0xd1,
689 P210 = 0xd2,
690 P211 = 0xd3,
691 P212 = 0xd4,
692 P213 = 0xd5,
693 P214 = 0xd6,
694 P215 = 0xd7,
695 P216 = 0xd8,
696 P217 = 0xd9,
697 P218 = 0xda,
698 P219 = 0xdb,
699 P220 = 0xdc,
700 P221 = 0xdd,
701 P222 = 0xde,
702 P223 = 0xdf,
703 P224 = 0xe0,
704 P225 = 0xe1,
705 P226 = 0xe2,
706 P227 = 0xe3,
707 P228 = 0xe4,
708 P229 = 0xe5,
709 P230 = 0xe6,
710 P231 = 0xe7,
711 P232 = 0xe8,
712 P233 = 0xe9,
713 P234 = 0xea,
714 P235 = 0xeb,
715 P236 = 0xec,
716 P237 = 0xed,
717 P238 = 0xee,
718 P239 = 0xef,
719 P240 = 0xf0,
720 P241 = 0xf1,
721 P242 = 0xf2,
722 P243 = 0xf3,
723 P244 = 0xf4,
724 P245 = 0xf5,
725 P246 = 0xf6,
726 P247 = 0xf7,
727 P248 = 0xf8,
728 P249 = 0xf9,
729 P250 = 0xfa,
730 P251 = 0xfb,
731 P252 = 0xfc,
732 P253 = 0xfd,
733 P254 = 0xfe,
734 P255 = 0xff,
735}
diff --git a/embassy-cortex-m/src/lib.rs b/embassy-cortex-m/src/lib.rs
new file mode 100644
index 000000000..143c56f39
--- /dev/null
+++ b/embassy-cortex-m/src/lib.rs
@@ -0,0 +1,8 @@
1#![no_std]
2
3// This mod MUST go first, so that the others see its macros.
4pub(crate) mod fmt;
5
6pub mod executor;
7pub mod interrupt;
8pub mod peripheral;
diff --git a/embassy-cortex-m/src/peripheral.rs b/embassy-cortex-m/src/peripheral.rs
new file mode 100644
index 000000000..40277691c
--- /dev/null
+++ b/embassy-cortex-m/src/peripheral.rs
@@ -0,0 +1,134 @@
1use core::marker::PhantomData;
2use core::mem::MaybeUninit;
3use cortex_m::peripheral::scb::VectActive;
4use cortex_m::peripheral::{NVIC, SCB};
5
6use crate::interrupt::{Interrupt, InterruptExt, Priority};
7
8/// A type which can be used as state with `PeripheralMutex`.
9///
10/// It needs to be `Send` because `&mut` references are sent back and forth between the 'thread' which owns the `PeripheralMutex` and the interrupt,
11/// and `&mut T` is only `Send` where `T: Send`.
12pub trait PeripheralState: Send {
13 type Interrupt: Interrupt;
14 fn on_interrupt(&mut self);
15}
16
17pub struct StateStorage<S>(MaybeUninit<S>);
18
19impl<S> StateStorage<S> {
20 pub const fn new() -> Self {
21 Self(MaybeUninit::uninit())
22 }
23}
24
25pub struct PeripheralMutex<'a, S: PeripheralState> {
26 state: *mut S,
27 _phantom: PhantomData<&'a mut S>,
28 irq: S::Interrupt,
29}
30
31/// Whether `irq` can be preempted by the current interrupt.
32pub(crate) fn can_be_preempted(irq: &impl Interrupt) -> bool {
33 match SCB::vect_active() {
34 // Thread mode can't preempt anything.
35 VectActive::ThreadMode => false,
36 // Exceptions don't always preempt interrupts,
37 // but there isn't much of a good reason to be keeping a `PeripheralMutex` in an exception anyway.
38 VectActive::Exception(_) => true,
39 VectActive::Interrupt { irqn } => {
40 #[derive(Clone, Copy)]
41 struct NrWrap(u16);
42 unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap {
43 fn number(self) -> u16 {
44 self.0
45 }
46 }
47 NVIC::get_priority(NrWrap(irqn.into())) < irq.get_priority().into()
48 }
49 }
50}
51
52impl<'a, S: PeripheralState> PeripheralMutex<'a, S> {
53 /// Create a new `PeripheralMutex` wrapping `irq`, with `init` initializing the initial state.
54 ///
55 /// Registers `on_interrupt` as the `irq`'s handler, and enables it.
56 pub fn new(
57 irq: S::Interrupt,
58 storage: &'a mut StateStorage<S>,
59 init: impl FnOnce() -> S,
60 ) -> Self {
61 if can_be_preempted(&irq) {
62 panic!("`PeripheralMutex` cannot be created in an interrupt with higher priority than the interrupt it wraps");
63 }
64
65 let state_ptr = storage.0.as_mut_ptr();
66
67 // Safety: The pointer is valid and not used by anyone else
68 // because we have the `&mut StateStorage`.
69 unsafe { state_ptr.write(init()) };
70
71 irq.disable();
72 irq.set_handler(|p| unsafe {
73 // Safety: it's OK to get a &mut to the state, since
74 // - We checked that the thread owning the `PeripheralMutex` can't preempt us in `new`.
75 // Interrupts' priorities can only be changed with raw embassy `Interrupts`,
76 // which can't safely store a `PeripheralMutex` across invocations.
77 // - We can't have preempted a with() call because the irq is disabled during it.
78 let state = &mut *(p as *mut S);
79 state.on_interrupt();
80 });
81 irq.set_handler_context(state_ptr as *mut ());
82 irq.enable();
83
84 Self {
85 irq,
86 state: state_ptr,
87 _phantom: PhantomData,
88 }
89 }
90
91 pub fn with<R>(&mut self, f: impl FnOnce(&mut S) -> R) -> R {
92 self.irq.disable();
93
94 // Safety: it's OK to get a &mut to the state, since the irq is disabled.
95 let state = unsafe { &mut *self.state };
96 let r = f(state);
97
98 self.irq.enable();
99
100 r
101 }
102
103 /// Returns whether the wrapped interrupt is currently in a pending state.
104 pub fn is_pending(&self) -> bool {
105 self.irq.is_pending()
106 }
107
108 /// Forces the wrapped interrupt into a pending state.
109 pub fn pend(&self) {
110 self.irq.pend()
111 }
112
113 /// Forces the wrapped interrupt out of a pending state.
114 pub fn unpend(&self) {
115 self.irq.unpend()
116 }
117
118 /// Gets the priority of the wrapped interrupt.
119 pub fn priority(&self) -> Priority {
120 self.irq.get_priority()
121 }
122}
123
124impl<'a, S: PeripheralState> Drop for PeripheralMutex<'a, S> {
125 fn drop(&mut self) {
126 self.irq.disable();
127 self.irq.remove_handler();
128
129 // safety:
130 // - we initialized the state in `new`, so we know it's initialized.
131 // - the irq is disabled, so it won't preempt us while dropping.
132 unsafe { self.state.drop_in_place() }
133 }
134}