aboutsummaryrefslogtreecommitdiff
path: root/embassy-cortex-m
diff options
context:
space:
mode:
authorQuentin Smith <[email protected]>2023-07-17 21:31:43 -0400
committerQuentin Smith <[email protected]>2023-07-17 21:31:43 -0400
commit6f02403184eb7fb7990fb88fc9df9c4328a690a3 (patch)
tree748f510e190bb2724750507a6e69ed1a8e08cb20 /embassy-cortex-m
parentd896f80405aa8963877049ed999e4aba25d6e2bb (diff)
parent6b5df4523aa1c4902f02e803450ae4b418e0e3ca (diff)
Merge remote-tracking branch 'origin/main' into nrf-pdm
Diffstat (limited to 'embassy-cortex-m')
-rw-r--r--embassy-cortex-m/Cargo.toml46
-rw-r--r--embassy-cortex-m/build.rs29
-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.rs822
-rw-r--r--embassy-cortex-m/src/lib.rs10
-rw-r--r--embassy-cortex-m/src/peripheral.rs144
7 files changed, 0 insertions, 1368 deletions
diff --git a/embassy-cortex-m/Cargo.toml b/embassy-cortex-m/Cargo.toml
deleted file mode 100644
index 7efced669..000000000
--- a/embassy-cortex-m/Cargo.toml
+++ /dev/null
@@ -1,46 +0,0 @@
1[package]
2name = "embassy-cortex-m"
3version = "0.1.0"
4edition = "2021"
5
6[package.metadata.embassy_docs]
7src_base = "https://github.com/embassy-rs/embassy/blob/embassy-cortex-m-v$VERSION/embassy-cortex-m/src/"
8src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-cortex-m/src/"
9features = ["prio-bits-3"]
10flavors = [
11 { name = "thumbv6m-none-eabi", target = "thumbv6m-none-eabi", features = [] },
12 { name = "thumbv7m-none-eabi", target = "thumbv7m-none-eabi", features = [] },
13 { name = "thumbv7em-none-eabi", target = "thumbv7em-none-eabi", features = [] },
14 { name = "thumbv7em-none-eabihf", target = "thumbv7em-none-eabihf", features = [] },
15 { name = "thumbv8m.base-none-eabi", target = "thumbv8m.base-none-eabi", features = [] },
16 { name = "thumbv8m.main-none-eabi", target = "thumbv8m.main-none-eabi", features = [] },
17 { name = "thumbv8m.main-none-eabihf", target = "thumbv8m.main-none-eabihf", features = [] },
18]
19
20[features]
21default = []
22
23# Define the number of NVIC priority bits.
24prio-bits-0 = []
25prio-bits-1 = []
26prio-bits-2 = []
27prio-bits-3 = []
28prio-bits-4 = []
29prio-bits-5 = []
30prio-bits-6 = []
31prio-bits-7 = []
32prio-bits-8 = []
33
34[dependencies]
35defmt = { version = "0.3", optional = true }
36log = { version = "0.4.14", optional = true }
37
38embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
39embassy-executor = { version = "0.1.0", path = "../embassy-executor"}
40embassy-macros = { version = "0.1.0", path = "../embassy-macros"}
41embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common"}
42atomic-polyfill = "1.0.1"
43critical-section = "1.1"
44cfg-if = "1.0.0"
45cortex-m = "0.7.6"
46
diff --git a/embassy-cortex-m/build.rs b/embassy-cortex-m/build.rs
deleted file mode 100644
index 6fe82b44f..000000000
--- a/embassy-cortex-m/build.rs
+++ /dev/null
@@ -1,29 +0,0 @@
1use std::env;
2
3fn main() {
4 let target = env::var("TARGET").unwrap();
5
6 if target.starts_with("thumbv6m-") {
7 println!("cargo:rustc-cfg=cortex_m");
8 println!("cargo:rustc-cfg=armv6m");
9 } else if target.starts_with("thumbv7m-") {
10 println!("cargo:rustc-cfg=cortex_m");
11 println!("cargo:rustc-cfg=armv7m");
12 } else if target.starts_with("thumbv7em-") {
13 println!("cargo:rustc-cfg=cortex_m");
14 println!("cargo:rustc-cfg=armv7m");
15 println!("cargo:rustc-cfg=armv7em"); // (not currently used)
16 } else if target.starts_with("thumbv8m.base") {
17 println!("cargo:rustc-cfg=cortex_m");
18 println!("cargo:rustc-cfg=armv8m");
19 println!("cargo:rustc-cfg=armv8m_base");
20 } else if target.starts_with("thumbv8m.main") {
21 println!("cargo:rustc-cfg=cortex_m");
22 println!("cargo:rustc-cfg=armv8m");
23 println!("cargo:rustc-cfg=armv8m_main");
24 }
25
26 if target.ends_with("-eabihf") {
27 println!("cargo:rustc-cfg=has_fpu");
28 }
29}
diff --git a/embassy-cortex-m/src/executor.rs b/embassy-cortex-m/src/executor.rs
deleted file mode 100644
index 0d1745d8a..000000000
--- a/embassy-cortex-m/src/executor.rs
+++ /dev/null
@@ -1,89 +0,0 @@
1//! Executor specific to cortex-m devices.
2use core::marker::PhantomData;
3
4pub use embassy_executor::*;
5
6use crate::interrupt::{Interrupt, InterruptExt};
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`](embassy_executor::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`](embassy_executor::Spawner) for this executor, use [`Spawner::for_current_executor()`](embassy_executor::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 [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (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
deleted file mode 100644
index f8bb0a035..000000000
--- a/embassy-cortex-m/src/fmt.rs
+++ /dev/null
@@ -1,228 +0,0 @@
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
deleted file mode 100644
index 1df8671b9..000000000
--- a/embassy-cortex-m/src/interrupt.rs
+++ /dev/null
@@ -1,822 +0,0 @@
1//! Interrupt handling for cortex-m devices.
2use core::{mem, ptr};
3
4use atomic_polyfill::{compiler_fence, AtomicPtr, Ordering};
5use cortex_m::peripheral::NVIC;
6use embassy_hal_common::Peripheral;
7pub use embassy_macros::cortex_m_interrupt_take as take;
8
9/// Do not use. Used for macros and HALs only. Not covered by semver guarantees.
10#[doc(hidden)]
11pub mod _export {
12 pub use atomic_polyfill as atomic;
13 pub use embassy_macros::{cortex_m_interrupt as interrupt, cortex_m_interrupt_declare as declare};
14}
15
16/// Implementation detail, do not use outside embassy crates.
17#[doc(hidden)]
18pub struct Handler {
19 pub func: AtomicPtr<()>,
20 pub ctx: AtomicPtr<()>,
21}
22
23impl Handler {
24 pub const fn new() -> Self {
25 Self {
26 func: AtomicPtr::new(ptr::null_mut()),
27 ctx: AtomicPtr::new(ptr::null_mut()),
28 }
29 }
30}
31
32#[derive(Clone, Copy)]
33pub(crate) struct NrWrap(pub(crate) u16);
34unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap {
35 fn number(self) -> u16 {
36 self.0
37 }
38}
39
40/// Represents an interrupt type that can be configured by embassy to handle
41/// interrupts.
42pub unsafe trait Interrupt: Peripheral<P = Self> {
43 /// Return the NVIC interrupt number for this interrupt.
44 fn number(&self) -> u16;
45 /// Steal an instance of this interrupt
46 ///
47 /// # Safety
48 ///
49 /// This may panic if the interrupt has already been stolen and configured.
50 unsafe fn steal() -> Self;
51
52 /// Implementation detail, do not use outside embassy crates.
53 #[doc(hidden)]
54 unsafe fn __handler(&self) -> &'static Handler;
55}
56
57/// Represents additional behavior for all interrupts.
58pub trait InterruptExt: Interrupt {
59 /// Configure the interrupt handler for this interrupt.
60 ///
61 /// # Safety
62 ///
63 /// It is the responsibility of the caller to ensure the handler
64 /// points to a valid handler as long as interrupts are enabled.
65 fn set_handler(&self, func: unsafe fn(*mut ()));
66
67 /// Remove the interrupt handler for this interrupt.
68 fn remove_handler(&self);
69
70 /// Set point to a context that is passed to the interrupt handler when
71 /// an interrupt is pending.
72 ///
73 /// # Safety
74 ///
75 /// It is the responsibility of the caller to ensure the context
76 /// points to a valid handler as long as interrupts are enabled.
77 fn set_handler_context(&self, ctx: *mut ());
78
79 /// Enable the interrupt. Once enabled, the interrupt handler may
80 /// be called "any time".
81 fn enable(&self);
82
83 /// Disable the interrupt.
84 fn disable(&self);
85
86 /// Check if interrupt is being handled.
87 #[cfg(not(armv6m))]
88 fn is_active(&self) -> bool;
89
90 /// Check if interrupt is enabled.
91 fn is_enabled(&self) -> bool;
92
93 /// Check if interrupt is pending.
94 fn is_pending(&self) -> bool;
95
96 /// Set interrupt pending.
97 fn pend(&self);
98
99 /// Unset interrupt pending.
100 fn unpend(&self);
101
102 /// Get the priority of the interrupt.
103 fn get_priority(&self) -> Priority;
104
105 /// Set the interrupt priority.
106 fn set_priority(&self, prio: Priority);
107}
108
109impl<T: Interrupt + ?Sized> InterruptExt for T {
110 fn set_handler(&self, func: unsafe fn(*mut ())) {
111 compiler_fence(Ordering::SeqCst);
112 let handler = unsafe { self.__handler() };
113 handler.func.store(func as *mut (), Ordering::Relaxed);
114 compiler_fence(Ordering::SeqCst);
115 }
116
117 fn remove_handler(&self) {
118 compiler_fence(Ordering::SeqCst);
119 let handler = unsafe { self.__handler() };
120 handler.func.store(ptr::null_mut(), Ordering::Relaxed);
121 compiler_fence(Ordering::SeqCst);
122 }
123
124 fn set_handler_context(&self, ctx: *mut ()) {
125 let handler = unsafe { self.__handler() };
126 handler.ctx.store(ctx, Ordering::Relaxed);
127 }
128
129 #[inline]
130 fn enable(&self) {
131 compiler_fence(Ordering::SeqCst);
132 unsafe {
133 NVIC::unmask(NrWrap(self.number()));
134 }
135 }
136
137 #[inline]
138 fn disable(&self) {
139 NVIC::mask(NrWrap(self.number()));
140 compiler_fence(Ordering::SeqCst);
141 }
142
143 #[inline]
144 #[cfg(not(armv6m))]
145 fn is_active(&self) -> bool {
146 NVIC::is_active(NrWrap(self.number()))
147 }
148
149 #[inline]
150 fn is_enabled(&self) -> bool {
151 NVIC::is_enabled(NrWrap(self.number()))
152 }
153
154 #[inline]
155 fn is_pending(&self) -> bool {
156 NVIC::is_pending(NrWrap(self.number()))
157 }
158
159 #[inline]
160 fn pend(&self) {
161 NVIC::pend(NrWrap(self.number()))
162 }
163
164 #[inline]
165 fn unpend(&self) {
166 NVIC::unpend(NrWrap(self.number()))
167 }
168
169 #[inline]
170 fn get_priority(&self) -> Priority {
171 Priority::from(NVIC::get_priority(NrWrap(self.number())))
172 }
173
174 #[inline]
175 fn set_priority(&self, prio: Priority) {
176 unsafe {
177 let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(());
178 nvic.set_priority(NrWrap(self.number()), prio.into())
179 }
180 }
181}
182
183impl From<u8> for Priority {
184 fn from(priority: u8) -> Self {
185 unsafe { mem::transmute(priority & PRIO_MASK) }
186 }
187}
188
189impl From<Priority> for u8 {
190 fn from(p: Priority) -> Self {
191 p as u8
192 }
193}
194
195#[cfg(feature = "prio-bits-0")]
196const PRIO_MASK: u8 = 0x00;
197#[cfg(feature = "prio-bits-1")]
198const PRIO_MASK: u8 = 0x80;
199#[cfg(feature = "prio-bits-2")]
200const PRIO_MASK: u8 = 0xc0;
201#[cfg(feature = "prio-bits-3")]
202const PRIO_MASK: u8 = 0xe0;
203#[cfg(feature = "prio-bits-4")]
204const PRIO_MASK: u8 = 0xf0;
205#[cfg(feature = "prio-bits-5")]
206const PRIO_MASK: u8 = 0xf8;
207#[cfg(feature = "prio-bits-6")]
208const PRIO_MASK: u8 = 0xfc;
209#[cfg(feature = "prio-bits-7")]
210const PRIO_MASK: u8 = 0xfe;
211#[cfg(feature = "prio-bits-8")]
212const PRIO_MASK: u8 = 0xff;
213
214/// The interrupt priority level.
215///
216/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature.
217#[cfg(feature = "prio-bits-0")]
218#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
219#[cfg_attr(feature = "defmt", derive(defmt::Format))]
220#[repr(u8)]
221#[allow(missing_docs)]
222pub enum Priority {
223 P0 = 0x0,
224}
225
226/// The interrupt priority level.
227///
228/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature.
229#[cfg(feature = "prio-bits-1")]
230#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
231#[cfg_attr(feature = "defmt", derive(defmt::Format))]
232#[repr(u8)]
233#[allow(missing_docs)]
234pub enum Priority {
235 P0 = 0x0,
236 P1 = 0x80,
237}
238
239/// The interrupt priority level.
240///
241/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature.
242#[cfg(feature = "prio-bits-2")]
243#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
244#[cfg_attr(feature = "defmt", derive(defmt::Format))]
245#[repr(u8)]
246#[allow(missing_docs)]
247pub enum Priority {
248 P0 = 0x0,
249 P1 = 0x40,
250 P2 = 0x80,
251 P3 = 0xc0,
252}
253
254/// The interrupt priority level.
255///
256/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature.
257#[cfg(feature = "prio-bits-3")]
258#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
259#[cfg_attr(feature = "defmt", derive(defmt::Format))]
260#[repr(u8)]
261#[allow(missing_docs)]
262pub enum Priority {
263 P0 = 0x0,
264 P1 = 0x20,
265 P2 = 0x40,
266 P3 = 0x60,
267 P4 = 0x80,
268 P5 = 0xa0,
269 P6 = 0xc0,
270 P7 = 0xe0,
271}
272
273/// The interrupt priority level.
274///
275/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature.
276#[cfg(feature = "prio-bits-4")]
277#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
278#[cfg_attr(feature = "defmt", derive(defmt::Format))]
279#[repr(u8)]
280#[allow(missing_docs)]
281pub enum Priority {
282 P0 = 0x0,
283 P1 = 0x10,
284 P2 = 0x20,
285 P3 = 0x30,
286 P4 = 0x40,
287 P5 = 0x50,
288 P6 = 0x60,
289 P7 = 0x70,
290 P8 = 0x80,
291 P9 = 0x90,
292 P10 = 0xa0,
293 P11 = 0xb0,
294 P12 = 0xc0,
295 P13 = 0xd0,
296 P14 = 0xe0,
297 P15 = 0xf0,
298}
299
300/// The interrupt priority level.
301///
302/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature.
303#[cfg(feature = "prio-bits-5")]
304#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
305#[cfg_attr(feature = "defmt", derive(defmt::Format))]
306#[repr(u8)]
307#[allow(missing_docs)]
308pub enum Priority {
309 P0 = 0x0,
310 P1 = 0x8,
311 P2 = 0x10,
312 P3 = 0x18,
313 P4 = 0x20,
314 P5 = 0x28,
315 P6 = 0x30,
316 P7 = 0x38,
317 P8 = 0x40,
318 P9 = 0x48,
319 P10 = 0x50,
320 P11 = 0x58,
321 P12 = 0x60,
322 P13 = 0x68,
323 P14 = 0x70,
324 P15 = 0x78,
325 P16 = 0x80,
326 P17 = 0x88,
327 P18 = 0x90,
328 P19 = 0x98,
329 P20 = 0xa0,
330 P21 = 0xa8,
331 P22 = 0xb0,
332 P23 = 0xb8,
333 P24 = 0xc0,
334 P25 = 0xc8,
335 P26 = 0xd0,
336 P27 = 0xd8,
337 P28 = 0xe0,
338 P29 = 0xe8,
339 P30 = 0xf0,
340 P31 = 0xf8,
341}
342
343/// The interrupt priority level.
344///
345/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature.
346#[cfg(feature = "prio-bits-6")]
347#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
348#[cfg_attr(feature = "defmt", derive(defmt::Format))]
349#[repr(u8)]
350#[allow(missing_docs)]
351pub enum Priority {
352 P0 = 0x0,
353 P1 = 0x4,
354 P2 = 0x8,
355 P3 = 0xc,
356 P4 = 0x10,
357 P5 = 0x14,
358 P6 = 0x18,
359 P7 = 0x1c,
360 P8 = 0x20,
361 P9 = 0x24,
362 P10 = 0x28,
363 P11 = 0x2c,
364 P12 = 0x30,
365 P13 = 0x34,
366 P14 = 0x38,
367 P15 = 0x3c,
368 P16 = 0x40,
369 P17 = 0x44,
370 P18 = 0x48,
371 P19 = 0x4c,
372 P20 = 0x50,
373 P21 = 0x54,
374 P22 = 0x58,
375 P23 = 0x5c,
376 P24 = 0x60,
377 P25 = 0x64,
378 P26 = 0x68,
379 P27 = 0x6c,
380 P28 = 0x70,
381 P29 = 0x74,
382 P30 = 0x78,
383 P31 = 0x7c,
384 P32 = 0x80,
385 P33 = 0x84,
386 P34 = 0x88,
387 P35 = 0x8c,
388 P36 = 0x90,
389 P37 = 0x94,
390 P38 = 0x98,
391 P39 = 0x9c,
392 P40 = 0xa0,
393 P41 = 0xa4,
394 P42 = 0xa8,
395 P43 = 0xac,
396 P44 = 0xb0,
397 P45 = 0xb4,
398 P46 = 0xb8,
399 P47 = 0xbc,
400 P48 = 0xc0,
401 P49 = 0xc4,
402 P50 = 0xc8,
403 P51 = 0xcc,
404 P52 = 0xd0,
405 P53 = 0xd4,
406 P54 = 0xd8,
407 P55 = 0xdc,
408 P56 = 0xe0,
409 P57 = 0xe4,
410 P58 = 0xe8,
411 P59 = 0xec,
412 P60 = 0xf0,
413 P61 = 0xf4,
414 P62 = 0xf8,
415 P63 = 0xfc,
416}
417
418/// The interrupt priority level.
419///
420/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature.
421#[cfg(feature = "prio-bits-7")]
422#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
423#[cfg_attr(feature = "defmt", derive(defmt::Format))]
424#[repr(u8)]
425#[allow(missing_docs)]
426pub enum Priority {
427 P0 = 0x0,
428 P1 = 0x2,
429 P2 = 0x4,
430 P3 = 0x6,
431 P4 = 0x8,
432 P5 = 0xa,
433 P6 = 0xc,
434 P7 = 0xe,
435 P8 = 0x10,
436 P9 = 0x12,
437 P10 = 0x14,
438 P11 = 0x16,
439 P12 = 0x18,
440 P13 = 0x1a,
441 P14 = 0x1c,
442 P15 = 0x1e,
443 P16 = 0x20,
444 P17 = 0x22,
445 P18 = 0x24,
446 P19 = 0x26,
447 P20 = 0x28,
448 P21 = 0x2a,
449 P22 = 0x2c,
450 P23 = 0x2e,
451 P24 = 0x30,
452 P25 = 0x32,
453 P26 = 0x34,
454 P27 = 0x36,
455 P28 = 0x38,
456 P29 = 0x3a,
457 P30 = 0x3c,
458 P31 = 0x3e,
459 P32 = 0x40,
460 P33 = 0x42,
461 P34 = 0x44,
462 P35 = 0x46,
463 P36 = 0x48,
464 P37 = 0x4a,
465 P38 = 0x4c,
466 P39 = 0x4e,
467 P40 = 0x50,
468 P41 = 0x52,
469 P42 = 0x54,
470 P43 = 0x56,
471 P44 = 0x58,
472 P45 = 0x5a,
473 P46 = 0x5c,
474 P47 = 0x5e,
475 P48 = 0x60,
476 P49 = 0x62,
477 P50 = 0x64,
478 P51 = 0x66,
479 P52 = 0x68,
480 P53 = 0x6a,
481 P54 = 0x6c,
482 P55 = 0x6e,
483 P56 = 0x70,
484 P57 = 0x72,
485 P58 = 0x74,
486 P59 = 0x76,
487 P60 = 0x78,
488 P61 = 0x7a,
489 P62 = 0x7c,
490 P63 = 0x7e,
491 P64 = 0x80,
492 P65 = 0x82,
493 P66 = 0x84,
494 P67 = 0x86,
495 P68 = 0x88,
496 P69 = 0x8a,
497 P70 = 0x8c,
498 P71 = 0x8e,
499 P72 = 0x90,
500 P73 = 0x92,
501 P74 = 0x94,
502 P75 = 0x96,
503 P76 = 0x98,
504 P77 = 0x9a,
505 P78 = 0x9c,
506 P79 = 0x9e,
507 P80 = 0xa0,
508 P81 = 0xa2,
509 P82 = 0xa4,
510 P83 = 0xa6,
511 P84 = 0xa8,
512 P85 = 0xaa,
513 P86 = 0xac,
514 P87 = 0xae,
515 P88 = 0xb0,
516 P89 = 0xb2,
517 P90 = 0xb4,
518 P91 = 0xb6,
519 P92 = 0xb8,
520 P93 = 0xba,
521 P94 = 0xbc,
522 P95 = 0xbe,
523 P96 = 0xc0,
524 P97 = 0xc2,
525 P98 = 0xc4,
526 P99 = 0xc6,
527 P100 = 0xc8,
528 P101 = 0xca,
529 P102 = 0xcc,
530 P103 = 0xce,
531 P104 = 0xd0,
532 P105 = 0xd2,
533 P106 = 0xd4,
534 P107 = 0xd6,
535 P108 = 0xd8,
536 P109 = 0xda,
537 P110 = 0xdc,
538 P111 = 0xde,
539 P112 = 0xe0,
540 P113 = 0xe2,
541 P114 = 0xe4,
542 P115 = 0xe6,
543 P116 = 0xe8,
544 P117 = 0xea,
545 P118 = 0xec,
546 P119 = 0xee,
547 P120 = 0xf0,
548 P121 = 0xf2,
549 P122 = 0xf4,
550 P123 = 0xf6,
551 P124 = 0xf8,
552 P125 = 0xfa,
553 P126 = 0xfc,
554 P127 = 0xfe,
555}
556
557/// The interrupt priority level.
558///
559/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature.
560#[cfg(feature = "prio-bits-8")]
561#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
562#[cfg_attr(feature = "defmt", derive(defmt::Format))]
563#[repr(u8)]
564#[allow(missing_docs)]
565pub enum Priority {
566 P0 = 0x0,
567 P1 = 0x1,
568 P2 = 0x2,
569 P3 = 0x3,
570 P4 = 0x4,
571 P5 = 0x5,
572 P6 = 0x6,
573 P7 = 0x7,
574 P8 = 0x8,
575 P9 = 0x9,
576 P10 = 0xa,
577 P11 = 0xb,
578 P12 = 0xc,
579 P13 = 0xd,
580 P14 = 0xe,
581 P15 = 0xf,
582 P16 = 0x10,
583 P17 = 0x11,
584 P18 = 0x12,
585 P19 = 0x13,
586 P20 = 0x14,
587 P21 = 0x15,
588 P22 = 0x16,
589 P23 = 0x17,
590 P24 = 0x18,
591 P25 = 0x19,
592 P26 = 0x1a,
593 P27 = 0x1b,
594 P28 = 0x1c,
595 P29 = 0x1d,
596 P30 = 0x1e,
597 P31 = 0x1f,
598 P32 = 0x20,
599 P33 = 0x21,
600 P34 = 0x22,
601 P35 = 0x23,
602 P36 = 0x24,
603 P37 = 0x25,
604 P38 = 0x26,
605 P39 = 0x27,
606 P40 = 0x28,
607 P41 = 0x29,
608 P42 = 0x2a,
609 P43 = 0x2b,
610 P44 = 0x2c,
611 P45 = 0x2d,
612 P46 = 0x2e,
613 P47 = 0x2f,
614 P48 = 0x30,
615 P49 = 0x31,
616 P50 = 0x32,
617 P51 = 0x33,
618 P52 = 0x34,
619 P53 = 0x35,
620 P54 = 0x36,
621 P55 = 0x37,
622 P56 = 0x38,
623 P57 = 0x39,
624 P58 = 0x3a,
625 P59 = 0x3b,
626 P60 = 0x3c,
627 P61 = 0x3d,
628 P62 = 0x3e,
629 P63 = 0x3f,
630 P64 = 0x40,
631 P65 = 0x41,
632 P66 = 0x42,
633 P67 = 0x43,
634 P68 = 0x44,
635 P69 = 0x45,
636 P70 = 0x46,
637 P71 = 0x47,
638 P72 = 0x48,
639 P73 = 0x49,
640 P74 = 0x4a,
641 P75 = 0x4b,
642 P76 = 0x4c,
643 P77 = 0x4d,
644 P78 = 0x4e,
645 P79 = 0x4f,
646 P80 = 0x50,
647 P81 = 0x51,
648 P82 = 0x52,
649 P83 = 0x53,
650 P84 = 0x54,
651 P85 = 0x55,
652 P86 = 0x56,
653 P87 = 0x57,
654 P88 = 0x58,
655 P89 = 0x59,
656 P90 = 0x5a,
657 P91 = 0x5b,
658 P92 = 0x5c,
659 P93 = 0x5d,
660 P94 = 0x5e,
661 P95 = 0x5f,
662 P96 = 0x60,
663 P97 = 0x61,
664 P98 = 0x62,
665 P99 = 0x63,
666 P100 = 0x64,
667 P101 = 0x65,
668 P102 = 0x66,
669 P103 = 0x67,
670 P104 = 0x68,
671 P105 = 0x69,
672 P106 = 0x6a,
673 P107 = 0x6b,
674 P108 = 0x6c,
675 P109 = 0x6d,
676 P110 = 0x6e,
677 P111 = 0x6f,
678 P112 = 0x70,
679 P113 = 0x71,
680 P114 = 0x72,
681 P115 = 0x73,
682 P116 = 0x74,
683 P117 = 0x75,
684 P118 = 0x76,
685 P119 = 0x77,
686 P120 = 0x78,
687 P121 = 0x79,
688 P122 = 0x7a,
689 P123 = 0x7b,
690 P124 = 0x7c,
691 P125 = 0x7d,
692 P126 = 0x7e,
693 P127 = 0x7f,
694 P128 = 0x80,
695 P129 = 0x81,
696 P130 = 0x82,
697 P131 = 0x83,
698 P132 = 0x84,
699 P133 = 0x85,
700 P134 = 0x86,
701 P135 = 0x87,
702 P136 = 0x88,
703 P137 = 0x89,
704 P138 = 0x8a,
705 P139 = 0x8b,
706 P140 = 0x8c,
707 P141 = 0x8d,
708 P142 = 0x8e,
709 P143 = 0x8f,
710 P144 = 0x90,
711 P145 = 0x91,
712 P146 = 0x92,
713 P147 = 0x93,
714 P148 = 0x94,
715 P149 = 0x95,
716 P150 = 0x96,
717 P151 = 0x97,
718 P152 = 0x98,
719 P153 = 0x99,
720 P154 = 0x9a,
721 P155 = 0x9b,
722 P156 = 0x9c,
723 P157 = 0x9d,
724 P158 = 0x9e,
725 P159 = 0x9f,
726 P160 = 0xa0,
727 P161 = 0xa1,
728 P162 = 0xa2,
729 P163 = 0xa3,
730 P164 = 0xa4,
731 P165 = 0xa5,
732 P166 = 0xa6,
733 P167 = 0xa7,
734 P168 = 0xa8,
735 P169 = 0xa9,
736 P170 = 0xaa,
737 P171 = 0xab,
738 P172 = 0xac,
739 P173 = 0xad,
740 P174 = 0xae,
741 P175 = 0xaf,
742 P176 = 0xb0,
743 P177 = 0xb1,
744 P178 = 0xb2,
745 P179 = 0xb3,
746 P180 = 0xb4,
747 P181 = 0xb5,
748 P182 = 0xb6,
749 P183 = 0xb7,
750 P184 = 0xb8,
751 P185 = 0xb9,
752 P186 = 0xba,
753 P187 = 0xbb,
754 P188 = 0xbc,
755 P189 = 0xbd,
756 P190 = 0xbe,
757 P191 = 0xbf,
758 P192 = 0xc0,
759 P193 = 0xc1,
760 P194 = 0xc2,
761 P195 = 0xc3,
762 P196 = 0xc4,
763 P197 = 0xc5,
764 P198 = 0xc6,
765 P199 = 0xc7,
766 P200 = 0xc8,
767 P201 = 0xc9,
768 P202 = 0xca,
769 P203 = 0xcb,
770 P204 = 0xcc,
771 P205 = 0xcd,
772 P206 = 0xce,
773 P207 = 0xcf,
774 P208 = 0xd0,
775 P209 = 0xd1,
776 P210 = 0xd2,
777 P211 = 0xd3,
778 P212 = 0xd4,
779 P213 = 0xd5,
780 P214 = 0xd6,
781 P215 = 0xd7,
782 P216 = 0xd8,
783 P217 = 0xd9,
784 P218 = 0xda,
785 P219 = 0xdb,
786 P220 = 0xdc,
787 P221 = 0xdd,
788 P222 = 0xde,
789 P223 = 0xdf,
790 P224 = 0xe0,
791 P225 = 0xe1,
792 P226 = 0xe2,
793 P227 = 0xe3,
794 P228 = 0xe4,
795 P229 = 0xe5,
796 P230 = 0xe6,
797 P231 = 0xe7,
798 P232 = 0xe8,
799 P233 = 0xe9,
800 P234 = 0xea,
801 P235 = 0xeb,
802 P236 = 0xec,
803 P237 = 0xed,
804 P238 = 0xee,
805 P239 = 0xef,
806 P240 = 0xf0,
807 P241 = 0xf1,
808 P242 = 0xf2,
809 P243 = 0xf3,
810 P244 = 0xf4,
811 P245 = 0xf5,
812 P246 = 0xf6,
813 P247 = 0xf7,
814 P248 = 0xf8,
815 P249 = 0xf9,
816 P250 = 0xfa,
817 P251 = 0xfb,
818 P252 = 0xfc,
819 P253 = 0xfd,
820 P254 = 0xfe,
821 P255 = 0xff,
822}
diff --git a/embassy-cortex-m/src/lib.rs b/embassy-cortex-m/src/lib.rs
deleted file mode 100644
index fba23367b..000000000
--- a/embassy-cortex-m/src/lib.rs
+++ /dev/null
@@ -1,10 +0,0 @@
1//! Embassy executor and interrupt handling specific to cortex-m devices.
2#![no_std]
3#![warn(missing_docs)]
4
5// This mod MUST go first, so that the others see its macros.
6pub(crate) mod fmt;
7
8pub mod executor;
9pub mod interrupt;
10pub mod peripheral;
diff --git a/embassy-cortex-m/src/peripheral.rs b/embassy-cortex-m/src/peripheral.rs
deleted file mode 100644
index e2f295579..000000000
--- a/embassy-cortex-m/src/peripheral.rs
+++ /dev/null
@@ -1,144 +0,0 @@
1//! Peripheral interrupt handling specific to cortex-m devices.
2use core::mem::MaybeUninit;
3
4use cortex_m::peripheral::scb::VectActive;
5use cortex_m::peripheral::{NVIC, SCB};
6use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
7
8use crate::interrupt::{Interrupt, InterruptExt, Priority};
9
10/// A type which can be used as state with `PeripheralMutex`.
11///
12/// It needs to be `Send` because `&mut` references are sent back and forth between the 'thread' which owns the `PeripheralMutex` and the interrupt,
13/// and `&mut T` is only `Send` where `T: Send`.
14pub trait PeripheralState: Send {
15 /// The interrupt that is used for this peripheral.
16 type Interrupt: Interrupt;
17
18 /// The interrupt handler that should be invoked for the peripheral. Implementations need to clear the appropriate interrupt flags to ensure the handle will not be called again.
19 fn on_interrupt(&mut self);
20}
21
22/// A type for storing the state of a peripheral that can be stored in a static.
23pub struct StateStorage<S>(MaybeUninit<S>);
24
25impl<S> StateStorage<S> {
26 /// Create a new instance for storing peripheral state.
27 pub const fn new() -> Self {
28 Self(MaybeUninit::uninit())
29 }
30}
31
32/// A type for a peripheral that keeps the state of a peripheral that can be accessed from thread mode and an interrupt handler in
33/// a safe way.
34pub struct PeripheralMutex<'a, S: PeripheralState> {
35 state: *mut S,
36 irq: PeripheralRef<'a, S::Interrupt>,
37}
38
39/// Whether `irq` can be preempted by the current interrupt.
40pub(crate) fn can_be_preempted(irq: &impl Interrupt) -> bool {
41 match SCB::vect_active() {
42 // Thread mode can't preempt anything.
43 VectActive::ThreadMode => false,
44 // Exceptions don't always preempt interrupts,
45 // but there isn't much of a good reason to be keeping a `PeripheralMutex` in an exception anyway.
46 VectActive::Exception(_) => true,
47 VectActive::Interrupt { irqn } => {
48 #[derive(Clone, Copy)]
49 struct NrWrap(u16);
50 unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap {
51 fn number(self) -> u16 {
52 self.0
53 }
54 }
55 NVIC::get_priority(NrWrap(irqn.into())) < irq.get_priority().into()
56 }
57 }
58}
59
60impl<'a, S: PeripheralState> PeripheralMutex<'a, S> {
61 /// Create a new `PeripheralMutex` wrapping `irq`, with `init` initializing the initial state.
62 ///
63 /// Registers `on_interrupt` as the `irq`'s handler, and enables it.
64 pub fn new(
65 irq: impl Peripheral<P = S::Interrupt> + 'a,
66 storage: &'a mut StateStorage<S>,
67 init: impl FnOnce() -> S,
68 ) -> Self {
69 into_ref!(irq);
70
71 if can_be_preempted(&*irq) {
72 panic!(
73 "`PeripheralMutex` cannot be created in an interrupt with higher priority than the interrupt it wraps"
74 );
75 }
76
77 let state_ptr = storage.0.as_mut_ptr();
78
79 // Safety: The pointer is valid and not used by anyone else
80 // because we have the `&mut StateStorage`.
81 unsafe { state_ptr.write(init()) };
82
83 irq.disable();
84 irq.set_handler(|p| unsafe {
85 // Safety: it's OK to get a &mut to the state, since
86 // - We checked that the thread owning the `PeripheralMutex` can't preempt us in `new`.
87 // Interrupts' priorities can only be changed with raw embassy `Interrupts`,
88 // which can't safely store a `PeripheralMutex` across invocations.
89 // - We can't have preempted a with() call because the irq is disabled during it.
90 let state = &mut *(p as *mut S);
91 state.on_interrupt();
92 });
93 irq.set_handler_context(state_ptr as *mut ());
94 irq.enable();
95
96 Self { irq, state: state_ptr }
97 }
98
99 /// Access the peripheral state ensuring interrupts are disabled so that the state can be
100 /// safely accessed.
101 pub fn with<R>(&mut self, f: impl FnOnce(&mut S) -> R) -> R {
102 self.irq.disable();
103
104 // Safety: it's OK to get a &mut to the state, since the irq is disabled.
105 let state = unsafe { &mut *self.state };
106 let r = f(state);
107
108 self.irq.enable();
109
110 r
111 }
112
113 /// Returns whether the wrapped interrupt is currently in a pending state.
114 pub fn is_pending(&self) -> bool {
115 self.irq.is_pending()
116 }
117
118 /// Forces the wrapped interrupt into a pending state.
119 pub fn pend(&self) {
120 self.irq.pend()
121 }
122
123 /// Forces the wrapped interrupt out of a pending state.
124 pub fn unpend(&self) {
125 self.irq.unpend()
126 }
127
128 /// Gets the priority of the wrapped interrupt.
129 pub fn priority(&self) -> Priority {
130 self.irq.get_priority()
131 }
132}
133
134impl<'a, S: PeripheralState> Drop for PeripheralMutex<'a, S> {
135 fn drop(&mut self) {
136 self.irq.disable();
137 self.irq.remove_handler();
138
139 // safety:
140 // - we initialized the state in `new`, so we know it's initialized.
141 // - the irq is disabled, so it won't preempt us while dropping.
142 unsafe { self.state.drop_in_place() }
143 }
144}