From 4dfa32b1e0572c03a5f97f0ed4a4a0acd6f12cca Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 27 Feb 2023 01:08:16 +0100 Subject: cortex-m/executor: don't use the owned interrupts system. Preparation for #1224. --- embassy-cortex-m/src/executor.rs | 99 +++++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 36 deletions(-) (limited to 'embassy-cortex-m/src') 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 @@ //! Executor specific to cortex-m devices. -use core::marker::PhantomData; +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::*; -use crate::interrupt::{Interrupt, InterruptExt}; +#[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) { - #[derive(Clone, Copy)] - struct N(u16); - unsafe impl cortex_m::interrupt::InterruptNumber for N { - fn number(self) -> u16 { - self.0 - } - } cortex_m::peripheral::NVIC::pend(N(n)) } @@ -37,26 +41,37 @@ fn pend_by_number(n: u16) { /// /// 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 { - irq: I, - inner: raw::Executor, - not_send: PhantomData<*mut ()>, +pub struct InterruptExecutor { + started: AtomicBool, + executor: UnsafeCell>, } -impl InterruptExecutor { - /// Create a new Executor. - pub fn new(irq: I) -> Self { - let ctx = irq.number() as *mut (); +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 { - irq, - inner: raw::Executor::new(|ctx| pend_by_number(ctx as u16), ctx), - not_send: PhantomData, + 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, configures and enables the interrupt, and returns. + /// 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`] @@ -67,23 +82,35 @@ impl InterruptExecutor { /// 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. /// - /// 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: + /// # 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. /// - /// - 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) -> SendSpawner { - self.irq.disable(); + 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() }; - self.irq.set_handler(|ctx| unsafe { - let executor = &*(ctx as *const raw::Executor); - executor.poll(); - }); - self.irq.set_handler_context(&self.inner as *const _ as _); - self.irq.enable(); + unsafe { NVIC::unmask(irq) } - self.inner.spawner().make_send() + executor.spawner().make_send() } } -- cgit From a054891263cbd17315cdf85ecdcc6359313063bc Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 21 Feb 2023 22:19:06 +0100 Subject: cortex-m: rename Handler to DynHandler. I want to use the name Handler for the new interrupt binding macro. --- embassy-cortex-m/src/interrupt.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'embassy-cortex-m/src') diff --git a/embassy-cortex-m/src/interrupt.rs b/embassy-cortex-m/src/interrupt.rs index 1df8671b9..ead9d52fe 100644 --- a/embassy-cortex-m/src/interrupt.rs +++ b/embassy-cortex-m/src/interrupt.rs @@ -15,12 +15,12 @@ pub mod _export { /// Implementation detail, do not use outside embassy crates. #[doc(hidden)] -pub struct Handler { +pub struct DynHandler { pub func: AtomicPtr<()>, pub ctx: AtomicPtr<()>, } -impl Handler { +impl DynHandler { pub const fn new() -> Self { Self { func: AtomicPtr::new(ptr::null_mut()), @@ -51,7 +51,7 @@ pub unsafe trait Interrupt: Peripheral

{ /// Implementation detail, do not use outside embassy crates. #[doc(hidden)] - unsafe fn __handler(&self) -> &'static Handler; + unsafe fn __handler(&self) -> &'static DynHandler; } /// Represents additional behavior for all interrupts. -- cgit From 42c13c8c3d9514866c2842009f76e88e8cb01b22 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 26 Feb 2023 22:42:22 +0100 Subject: nrf: add new interrupt binding traits and macro. --- embassy-cortex-m/src/interrupt.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'embassy-cortex-m/src') diff --git a/embassy-cortex-m/src/interrupt.rs b/embassy-cortex-m/src/interrupt.rs index ead9d52fe..3a82726df 100644 --- a/embassy-cortex-m/src/interrupt.rs +++ b/embassy-cortex-m/src/interrupt.rs @@ -13,6 +13,36 @@ pub mod _export { pub use embassy_macros::{cortex_m_interrupt as interrupt, cortex_m_interrupt_declare as declare}; } +/// Interrupt handler trait. +/// +/// Drivers that need to handle interrupts implement this trait. +/// The user must ensure `on_interrupt()` is called every time the interrupt fires. +/// Drivers must use use [`Binding`] to assert at compile time that the user has done so. +pub trait Handler { + /// Interrupt handler function. + /// + /// Must be called every time the `I` interrupt fires, synchronously from + /// the interrupt handler context. + /// + /// # Safety + /// + /// This function must ONLY be called from the interrupt handler for `I`. + unsafe fn on_interrupt(); +} + +/// Compile-time assertion that an interrupt has been bound to a handler. +/// +/// For the vast majority of cases, you should use the `bind_interrupts!` +/// macro instead of writing `unsafe impl`s of this trait. +/// +/// # Safety +/// +/// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()` +/// to be called every time the `I` interrupt fires. +/// +/// This allows drivers to check bindings at compile-time. +pub unsafe trait Binding> {} + /// Implementation detail, do not use outside embassy crates. #[doc(hidden)] pub struct DynHandler { -- cgit From d3c4e4a20a05085eae8d568c7efdbe09bada9cf5 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 3 Apr 2023 01:18:27 +0200 Subject: executor: add Pender, rework Cargo features. 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). --- embassy-cortex-m/src/executor.rs | 116 --------------------------------------- embassy-cortex-m/src/lib.rs | 2 +- 2 files changed, 1 insertion(+), 117 deletions(-) delete mode 100644 embassy-cortex-m/src/executor.rs (limited to 'embassy-cortex-m/src') diff --git a/embassy-cortex-m/src/executor.rs b/embassy-cortex-m/src/executor.rs deleted file mode 100644 index 558539e73..000000000 --- a/embassy-cortex-m/src/executor.rs +++ /dev/null @@ -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>, -} - -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() - } -} diff --git a/embassy-cortex-m/src/lib.rs b/embassy-cortex-m/src/lib.rs index fba23367b..e4b713a06 100644 --- a/embassy-cortex-m/src/lib.rs +++ b/embassy-cortex-m/src/lib.rs @@ -5,6 +5,6 @@ // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; -pub mod executor; +pub use embassy_executor as executor; pub mod interrupt; pub mod peripheral; -- cgit From 2a435e53b761182dabf9496963052f8323125f3a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 1 Jun 2023 02:22:31 +0200 Subject: cortex-m: remove PeripheralMutex. --- embassy-cortex-m/src/lib.rs | 1 - embassy-cortex-m/src/peripheral.rs | 144 ------------------------------------- 2 files changed, 145 deletions(-) delete mode 100644 embassy-cortex-m/src/peripheral.rs (limited to 'embassy-cortex-m/src') diff --git a/embassy-cortex-m/src/lib.rs b/embassy-cortex-m/src/lib.rs index e4b713a06..7bc16d3ba 100644 --- a/embassy-cortex-m/src/lib.rs +++ b/embassy-cortex-m/src/lib.rs @@ -7,4 +7,3 @@ pub(crate) mod fmt; pub use embassy_executor as executor; pub mod interrupt; -pub 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 @@ -//! Peripheral interrupt handling specific to cortex-m devices. -use core::mem::MaybeUninit; - -use cortex_m::peripheral::scb::VectActive; -use cortex_m::peripheral::{NVIC, SCB}; -use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; - -use crate::interrupt::{Interrupt, InterruptExt, Priority}; - -/// A type which can be used as state with `PeripheralMutex`. -/// -/// It needs to be `Send` because `&mut` references are sent back and forth between the 'thread' which owns the `PeripheralMutex` and the interrupt, -/// and `&mut T` is only `Send` where `T: Send`. -pub trait PeripheralState: Send { - /// The interrupt that is used for this peripheral. - type Interrupt: Interrupt; - - /// 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. - fn on_interrupt(&mut self); -} - -/// A type for storing the state of a peripheral that can be stored in a static. -pub struct StateStorage(MaybeUninit); - -impl StateStorage { - /// Create a new instance for storing peripheral state. - pub const fn new() -> Self { - Self(MaybeUninit::uninit()) - } -} - -/// A type for a peripheral that keeps the state of a peripheral that can be accessed from thread mode and an interrupt handler in -/// a safe way. -pub struct PeripheralMutex<'a, S: PeripheralState> { - state: *mut S, - irq: PeripheralRef<'a, S::Interrupt>, -} - -/// Whether `irq` can be preempted by the current interrupt. -pub(crate) fn can_be_preempted(irq: &impl Interrupt) -> bool { - match SCB::vect_active() { - // Thread mode can't preempt anything. - VectActive::ThreadMode => false, - // Exceptions don't always preempt interrupts, - // but there isn't much of a good reason to be keeping a `PeripheralMutex` in an exception anyway. - VectActive::Exception(_) => true, - VectActive::Interrupt { irqn } => { - #[derive(Clone, Copy)] - struct NrWrap(u16); - unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap { - fn number(self) -> u16 { - self.0 - } - } - NVIC::get_priority(NrWrap(irqn.into())) < irq.get_priority().into() - } - } -} - -impl<'a, S: PeripheralState> PeripheralMutex<'a, S> { - /// Create a new `PeripheralMutex` wrapping `irq`, with `init` initializing the initial state. - /// - /// Registers `on_interrupt` as the `irq`'s handler, and enables it. - pub fn new( - irq: impl Peripheral

+ 'a, - storage: &'a mut StateStorage, - init: impl FnOnce() -> S, - ) -> Self { - into_ref!(irq); - - if can_be_preempted(&*irq) { - panic!( - "`PeripheralMutex` cannot be created in an interrupt with higher priority than the interrupt it wraps" - ); - } - - let state_ptr = storage.0.as_mut_ptr(); - - // Safety: The pointer is valid and not used by anyone else - // because we have the `&mut StateStorage`. - unsafe { state_ptr.write(init()) }; - - irq.disable(); - irq.set_handler(|p| unsafe { - // Safety: it's OK to get a &mut to the state, since - // - We checked that the thread owning the `PeripheralMutex` can't preempt us in `new`. - // Interrupts' priorities can only be changed with raw embassy `Interrupts`, - // which can't safely store a `PeripheralMutex` across invocations. - // - We can't have preempted a with() call because the irq is disabled during it. - let state = &mut *(p as *mut S); - state.on_interrupt(); - }); - irq.set_handler_context(state_ptr as *mut ()); - irq.enable(); - - Self { irq, state: state_ptr } - } - - /// Access the peripheral state ensuring interrupts are disabled so that the state can be - /// safely accessed. - pub fn with(&mut self, f: impl FnOnce(&mut S) -> R) -> R { - self.irq.disable(); - - // Safety: it's OK to get a &mut to the state, since the irq is disabled. - let state = unsafe { &mut *self.state }; - let r = f(state); - - self.irq.enable(); - - r - } - - /// Returns whether the wrapped interrupt is currently in a pending state. - pub fn is_pending(&self) -> bool { - self.irq.is_pending() - } - - /// Forces the wrapped interrupt into a pending state. - pub fn pend(&self) { - self.irq.pend() - } - - /// Forces the wrapped interrupt out of a pending state. - pub fn unpend(&self) { - self.irq.unpend() - } - - /// Gets the priority of the wrapped interrupt. - pub fn priority(&self) -> Priority { - self.irq.get_priority() - } -} - -impl<'a, S: PeripheralState> Drop for PeripheralMutex<'a, S> { - fn drop(&mut self) { - self.irq.disable(); - self.irq.remove_handler(); - - // safety: - // - we initialized the state in `new`, so we know it's initialized. - // - the irq is disabled, so it won't preempt us while dropping. - unsafe { self.state.drop_in_place() } - } -} -- cgit From 404aa292890503806a32eac5ae518dbeeadd60eb Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 1 Jun 2023 02:22:46 +0200 Subject: cortex-m: remove owned interrupts. --- embassy-cortex-m/src/interrupt.rs | 160 ++++++++------------------------------ 1 file changed, 33 insertions(+), 127 deletions(-) (limited to 'embassy-cortex-m/src') diff --git a/embassy-cortex-m/src/interrupt.rs b/embassy-cortex-m/src/interrupt.rs index 3a82726df..0e790eaaf 100644 --- a/embassy-cortex-m/src/interrupt.rs +++ b/embassy-cortex-m/src/interrupt.rs @@ -1,10 +1,8 @@ //! Interrupt handling for cortex-m devices. -use core::{mem, ptr}; +use core::mem; +use core::sync::atomic::{compiler_fence, Ordering}; -use atomic_polyfill::{compiler_fence, AtomicPtr, Ordering}; use cortex_m::peripheral::NVIC; -use embassy_hal_common::Peripheral; -pub use embassy_macros::cortex_m_interrupt_take as take; /// Do not use. Used for macros and HALs only. Not covered by semver guarantees. #[doc(hidden)] @@ -43,22 +41,6 @@ pub trait Handler { /// This allows drivers to check bindings at compile-time. pub unsafe trait Binding> {} -/// Implementation detail, do not use outside embassy crates. -#[doc(hidden)] -pub struct DynHandler { - pub func: AtomicPtr<()>, - pub ctx: AtomicPtr<()>, -} - -impl DynHandler { - pub const fn new() -> Self { - Self { - func: AtomicPtr::new(ptr::null_mut()), - ctx: AtomicPtr::new(ptr::null_mut()), - } - } -} - #[derive(Clone, Copy)] pub(crate) struct NrWrap(pub(crate) u16); unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap { @@ -69,144 +51,68 @@ unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap { /// Represents an interrupt type that can be configured by embassy to handle /// interrupts. -pub unsafe trait Interrupt: Peripheral

{ +pub unsafe trait Interrupt { /// Return the NVIC interrupt number for this interrupt. - fn number(&self) -> u16; - /// Steal an instance of this interrupt - /// - /// # Safety - /// - /// This may panic if the interrupt has already been stolen and configured. - unsafe fn steal() -> Self; - - /// Implementation detail, do not use outside embassy crates. - #[doc(hidden)] - unsafe fn __handler(&self) -> &'static DynHandler; -} - -/// Represents additional behavior for all interrupts. -pub trait InterruptExt: Interrupt { - /// Configure the interrupt handler for this interrupt. - /// - /// # Safety - /// - /// It is the responsibility of the caller to ensure the handler - /// points to a valid handler as long as interrupts are enabled. - fn set_handler(&self, func: unsafe fn(*mut ())); - - /// Remove the interrupt handler for this interrupt. - fn remove_handler(&self); - - /// Set point to a context that is passed to the interrupt handler when - /// an interrupt is pending. - /// - /// # Safety - /// - /// It is the responsibility of the caller to ensure the context - /// points to a valid handler as long as interrupts are enabled. - fn set_handler_context(&self, ctx: *mut ()); - - /// Enable the interrupt. Once enabled, the interrupt handler may - /// be called "any time". - fn enable(&self); - - /// Disable the interrupt. - fn disable(&self); - - /// Check if interrupt is being handled. - #[cfg(not(armv6m))] - fn is_active(&self) -> bool; - - /// Check if interrupt is enabled. - fn is_enabled(&self) -> bool; - - /// Check if interrupt is pending. - fn is_pending(&self) -> bool; - - /// Set interrupt pending. - fn pend(&self); - - /// Unset interrupt pending. - fn unpend(&self); - - /// Get the priority of the interrupt. - fn get_priority(&self) -> Priority; - - /// Set the interrupt priority. - fn set_priority(&self, prio: Priority); -} - -impl InterruptExt for T { - fn set_handler(&self, func: unsafe fn(*mut ())) { - compiler_fence(Ordering::SeqCst); - let handler = unsafe { self.__handler() }; - handler.func.store(func as *mut (), Ordering::Relaxed); - compiler_fence(Ordering::SeqCst); - } - - fn remove_handler(&self) { - compiler_fence(Ordering::SeqCst); - let handler = unsafe { self.__handler() }; - handler.func.store(ptr::null_mut(), Ordering::Relaxed); - compiler_fence(Ordering::SeqCst); - } - - fn set_handler_context(&self, ctx: *mut ()) { - let handler = unsafe { self.__handler() }; - handler.ctx.store(ctx, Ordering::Relaxed); - } + fn number() -> u16; + /// Enable the interrupt. #[inline] - fn enable(&self) { + unsafe fn enable() { compiler_fence(Ordering::SeqCst); - unsafe { - NVIC::unmask(NrWrap(self.number())); - } + NVIC::unmask(NrWrap(Self::number())) } + /// Disable the interrupt. #[inline] - fn disable(&self) { - NVIC::mask(NrWrap(self.number())); + fn disable() { + NVIC::mask(NrWrap(Self::number())); compiler_fence(Ordering::SeqCst); } + /// Check if interrupt is being handled. #[inline] #[cfg(not(armv6m))] - fn is_active(&self) -> bool { - NVIC::is_active(NrWrap(self.number())) + fn is_active() -> bool { + NVIC::is_active(NrWrap(Self::number())) } + /// Check if interrupt is enabled. #[inline] - fn is_enabled(&self) -> bool { - NVIC::is_enabled(NrWrap(self.number())) + fn is_enabled() -> bool { + NVIC::is_enabled(NrWrap(Self::number())) } + /// Check if interrupt is pending. #[inline] - fn is_pending(&self) -> bool { - NVIC::is_pending(NrWrap(self.number())) + fn is_pending() -> bool { + NVIC::is_pending(NrWrap(Self::number())) } + /// Set interrupt pending. #[inline] - fn pend(&self) { - NVIC::pend(NrWrap(self.number())) + fn pend() { + NVIC::pend(NrWrap(Self::number())) } + /// Unset interrupt pending. #[inline] - fn unpend(&self) { - NVIC::unpend(NrWrap(self.number())) + fn unpend() { + NVIC::unpend(NrWrap(Self::number())) } + /// Get the priority of the interrupt. #[inline] - fn get_priority(&self) -> Priority { - Priority::from(NVIC::get_priority(NrWrap(self.number()))) + fn get_priority() -> Priority { + Priority::from(NVIC::get_priority(NrWrap(Self::number()))) } + /// Set the interrupt priority. #[inline] - fn set_priority(&self, prio: Priority) { - unsafe { + fn set_priority(prio: Priority) { + critical_section::with(|_| unsafe { let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(()); - nvic.set_priority(NrWrap(self.number()), prio.into()) - } + nvic.set_priority(NrWrap(Self::number()), prio.into()) + }) } } -- cgit From 921780e6bfb9bcb2cd087b8aa8b094d792c99fa2 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 8 Jun 2023 16:08:40 +0200 Subject: Make interrupt module more standard. - Move typelevel interrupts to a special-purpose mod: `embassy_xx::interrupt::typelevel`. - Reexport the PAC interrupt enum in `embassy_xx::interrupt`. This has a few advantages: - The `embassy_xx::interrupt` module is now more "standard". - It works with `cortex-m` functions for manipulating interrupts, for example. - It works with RTIC. - the interrupt enum allows holding value that can be "any interrupt at runtime", this can't be done with typelevel irqs. - When "const-generics on enums" is stable, we can remove the typelevel interrupts without disruptive changes to `embassy_xx::interrupt`. --- embassy-cortex-m/src/interrupt.rs | 213 +++++++++++++++++++++++++++----------- 1 file changed, 150 insertions(+), 63 deletions(-) (limited to 'embassy-cortex-m/src') diff --git a/embassy-cortex-m/src/interrupt.rs b/embassy-cortex-m/src/interrupt.rs index 0e790eaaf..8e45c36c7 100644 --- a/embassy-cortex-m/src/interrupt.rs +++ b/embassy-cortex-m/src/interrupt.rs @@ -2,120 +2,207 @@ use core::mem; use core::sync::atomic::{compiler_fence, Ordering}; +use cortex_m::interrupt::InterruptNumber; use cortex_m::peripheral::NVIC; -/// Do not use. Used for macros and HALs only. Not covered by semver guarantees. -#[doc(hidden)] -pub mod _export { - pub use atomic_polyfill as atomic; - pub use embassy_macros::{cortex_m_interrupt as interrupt, cortex_m_interrupt_declare as declare}; -} +/// Generate a standard `mod interrupt` for a HAL. +#[macro_export] +macro_rules! interrupt_mod { + ($($irqs:ident),* $(,)?) => { + pub use cortex_m_rt::interrupt; -/// Interrupt handler trait. -/// -/// Drivers that need to handle interrupts implement this trait. -/// The user must ensure `on_interrupt()` is called every time the interrupt fires. -/// Drivers must use use [`Binding`] to assert at compile time that the user has done so. -pub trait Handler { - /// Interrupt handler function. - /// - /// Must be called every time the `I` interrupt fires, synchronously from - /// the interrupt handler context. - /// - /// # Safety - /// - /// This function must ONLY be called from the interrupt handler for `I`. - unsafe fn on_interrupt(); -} + /// Interrupt definitions. + pub mod interrupt { + pub use embassy_cortex_m::interrupt::{InterruptExt, Priority}; + pub use crate::pac::interrupt::*; + pub use crate::pac::Interrupt; -/// Compile-time assertion that an interrupt has been bound to a handler. -/// -/// For the vast majority of cases, you should use the `bind_interrupts!` -/// macro instead of writing `unsafe impl`s of this trait. -/// -/// # Safety -/// -/// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()` -/// to be called every time the `I` interrupt fires. -/// -/// This allows drivers to check bindings at compile-time. -pub unsafe trait Binding> {} - -#[derive(Clone, Copy)] -pub(crate) struct NrWrap(pub(crate) u16); -unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap { - fn number(self) -> u16 { - self.0 - } + /// Type-level interrupt infrastructure. + /// + /// This module contains one *type* per interrupt. This is used for checking at compile time that + /// the interrupts are correctly bound to HAL drivers. + /// + /// As an end user, you shouldn't need to use this module directly. Use the [`crate::bind_interrupts!`] macro + /// to bind interrupts, and the [`crate::interrupt`] module to manually register interrupt handlers and manipulate + /// interrupts directly (pending/unpending, enabling/disabling, setting the priority, etc...) + pub mod typelevel { + use super::InterruptExt; + + mod sealed { + pub trait Interrupt {} + } + + /// Type-level interrupt. + /// + /// This trait is implemented for all typelevel interrupt types in this module. + pub trait Interrupt: sealed::Interrupt { + + /// Interrupt enum variant. + /// + /// This allows going from typelevel interrupts (one type per interrupt) to + /// non-typelevel interrupts (a single `Interrupt` enum type, with one variant per interrupt). + const IRQ: super::Interrupt; + + /// Enable the interrupt. + #[inline] + unsafe fn enable() { + Self::IRQ.enable() + } + + /// Disable the interrupt. + #[inline] + fn disable() { + Self::IRQ.disable() + } + + /// Check if interrupt is enabled. + #[inline] + fn is_enabled() -> bool { + Self::IRQ.is_enabled() + } + + /// Check if interrupt is pending. + #[inline] + fn is_pending() -> bool { + Self::IRQ.is_pending() + } + + /// Set interrupt pending. + #[inline] + fn pend() { + Self::IRQ.pend() + } + + /// Unset interrupt pending. + #[inline] + fn unpend() { + Self::IRQ.unpend() + } + + /// Get the priority of the interrupt. + #[inline] + fn get_priority() -> crate::interrupt::Priority { + Self::IRQ.get_priority() + } + + /// Set the interrupt priority. + #[inline] + fn set_priority(prio: crate::interrupt::Priority) { + Self::IRQ.set_priority(prio) + } + } + + $( + #[allow(non_camel_case_types)] + #[doc=stringify!($irqs)] + #[doc=" typelevel interrupt."] + pub enum $irqs {} + impl sealed::Interrupt for $irqs{} + impl Interrupt for $irqs { + const IRQ: super::Interrupt = super::Interrupt::$irqs; + } + )* + + /// Interrupt handler trait. + /// + /// Drivers that need to handle interrupts implement this trait. + /// The user must ensure `on_interrupt()` is called every time the interrupt fires. + /// Drivers must use use [`Binding`] to assert at compile time that the user has done so. + pub trait Handler { + /// Interrupt handler function. + /// + /// Must be called every time the `I` interrupt fires, synchronously from + /// the interrupt handler context. + /// + /// # Safety + /// + /// This function must ONLY be called from the interrupt handler for `I`. + unsafe fn on_interrupt(); + } + + /// Compile-time assertion that an interrupt has been bound to a handler. + /// + /// For the vast majority of cases, you should use the `bind_interrupts!` + /// macro instead of writing `unsafe impl`s of this trait. + /// + /// # Safety + /// + /// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()` + /// to be called every time the `I` interrupt fires. + /// + /// This allows drivers to check bindings at compile-time. + pub unsafe trait Binding> {} + } + } + }; } /// Represents an interrupt type that can be configured by embassy to handle /// interrupts. -pub unsafe trait Interrupt { - /// Return the NVIC interrupt number for this interrupt. - fn number() -> u16; - +pub unsafe trait InterruptExt: InterruptNumber + Copy { /// Enable the interrupt. #[inline] - unsafe fn enable() { + unsafe fn enable(self) { compiler_fence(Ordering::SeqCst); - NVIC::unmask(NrWrap(Self::number())) + NVIC::unmask(self) } /// Disable the interrupt. #[inline] - fn disable() { - NVIC::mask(NrWrap(Self::number())); + fn disable(self) { + NVIC::mask(self); compiler_fence(Ordering::SeqCst); } /// Check if interrupt is being handled. #[inline] #[cfg(not(armv6m))] - fn is_active() -> bool { - NVIC::is_active(NrWrap(Self::number())) + fn is_active(self) -> bool { + NVIC::is_active(self) } /// Check if interrupt is enabled. #[inline] - fn is_enabled() -> bool { - NVIC::is_enabled(NrWrap(Self::number())) + fn is_enabled(self) -> bool { + NVIC::is_enabled(self) } /// Check if interrupt is pending. #[inline] - fn is_pending() -> bool { - NVIC::is_pending(NrWrap(Self::number())) + fn is_pending(self) -> bool { + NVIC::is_pending(self) } /// Set interrupt pending. #[inline] - fn pend() { - NVIC::pend(NrWrap(Self::number())) + fn pend(self) { + NVIC::pend(self) } /// Unset interrupt pending. #[inline] - fn unpend() { - NVIC::unpend(NrWrap(Self::number())) + fn unpend(self) { + NVIC::unpend(self) } /// Get the priority of the interrupt. #[inline] - fn get_priority() -> Priority { - Priority::from(NVIC::get_priority(NrWrap(Self::number()))) + fn get_priority(self) -> Priority { + Priority::from(NVIC::get_priority(self)) } /// Set the interrupt priority. #[inline] - fn set_priority(prio: Priority) { + fn set_priority(self, prio: Priority) { critical_section::with(|_| unsafe { let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(()); - nvic.set_priority(NrWrap(Self::number()), prio.into()) + nvic.set_priority(self, prio.into()) }) } } +unsafe impl InterruptExt for T {} + impl From for Priority { fn from(priority: u8) -> Self { unsafe { mem::transmute(priority & PRIO_MASK) } -- cgit From 8c93805ab5a13c784e072c8e6e59b354ee902d99 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 8 Jun 2023 18:00:19 +0200 Subject: Add `rt` feature to HALs, cfg out interrupt handling when not set. --- embassy-cortex-m/src/interrupt.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'embassy-cortex-m/src') diff --git a/embassy-cortex-m/src/interrupt.rs b/embassy-cortex-m/src/interrupt.rs index 8e45c36c7..e9fa43e87 100644 --- a/embassy-cortex-m/src/interrupt.rs +++ b/embassy-cortex-m/src/interrupt.rs @@ -9,12 +9,13 @@ use cortex_m::peripheral::NVIC; #[macro_export] macro_rules! interrupt_mod { ($($irqs:ident),* $(,)?) => { + #[cfg(feature = "rt")] pub use cortex_m_rt::interrupt; /// Interrupt definitions. pub mod interrupt { pub use embassy_cortex_m::interrupt::{InterruptExt, Priority}; - pub use crate::pac::interrupt::*; + pub use crate::pac::Interrupt::*; pub use crate::pac::Interrupt; /// Type-level interrupt infrastructure. -- cgit From 3465452a93719cdb46a2af4b6d893da3aacc0a15 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 9 Jun 2023 03:33:39 +0200 Subject: fmt: remove unused defmt::timestamp! --- embassy-cortex-m/src/fmt.rs | 3 --- 1 file changed, 3 deletions(-) (limited to 'embassy-cortex-m/src') diff --git a/embassy-cortex-m/src/fmt.rs b/embassy-cortex-m/src/fmt.rs index f8bb0a035..066970813 100644 --- a/embassy-cortex-m/src/fmt.rs +++ b/embassy-cortex-m/src/fmt.rs @@ -195,9 +195,6 @@ macro_rules! unwrap { } } -#[cfg(feature = "defmt-timestamp-uptime")] -defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() } - #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct NoneError; -- cgit From 98c821ac39c65903057c2d8ed320d1616e9f23ae Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 9 Jun 2023 16:14:13 +0200 Subject: Remove embassy-cortex-m crate, move stuff to embassy-hal-common. --- embassy-cortex-m/src/fmt.rs | 225 ---------- embassy-cortex-m/src/interrupt.rs | 846 -------------------------------------- embassy-cortex-m/src/lib.rs | 9 - 3 files changed, 1080 deletions(-) delete mode 100644 embassy-cortex-m/src/fmt.rs delete mode 100644 embassy-cortex-m/src/interrupt.rs delete mode 100644 embassy-cortex-m/src/lib.rs (limited to 'embassy-cortex-m/src') diff --git a/embassy-cortex-m/src/fmt.rs b/embassy-cortex-m/src/fmt.rs deleted file mode 100644 index 066970813..000000000 --- a/embassy-cortex-m/src/fmt.rs +++ /dev/null @@ -1,225 +0,0 @@ -#![macro_use] -#![allow(unused_macros)] - -#[cfg(all(feature = "defmt", feature = "log"))] -compile_error!("You may not enable both `defmt` and `log` features."); - -macro_rules! assert { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::assert!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::assert!($($x)*); - } - }; -} - -macro_rules! assert_eq { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::assert_eq!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::assert_eq!($($x)*); - } - }; -} - -macro_rules! assert_ne { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::assert_ne!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::assert_ne!($($x)*); - } - }; -} - -macro_rules! debug_assert { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::debug_assert!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::debug_assert!($($x)*); - } - }; -} - -macro_rules! debug_assert_eq { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::debug_assert_eq!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::debug_assert_eq!($($x)*); - } - }; -} - -macro_rules! debug_assert_ne { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::debug_assert_ne!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::debug_assert_ne!($($x)*); - } - }; -} - -macro_rules! todo { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::todo!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::todo!($($x)*); - } - }; -} - -macro_rules! unreachable { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } - }; -} - -macro_rules! panic { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::panic!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::panic!($($x)*); - } - }; -} - -macro_rules! trace { - ($s:literal $(, $x:expr)* $(,)?) => { - { - #[cfg(feature = "log")] - ::log::trace!($s $(, $x)*); - #[cfg(feature = "defmt")] - ::defmt::trace!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] - let _ = ($( & $x ),*); - } - }; -} - -macro_rules! debug { - ($s:literal $(, $x:expr)* $(,)?) => { - { - #[cfg(feature = "log")] - ::log::debug!($s $(, $x)*); - #[cfg(feature = "defmt")] - ::defmt::debug!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] - let _ = ($( & $x ),*); - } - }; -} - -macro_rules! info { - ($s:literal $(, $x:expr)* $(,)?) => { - { - #[cfg(feature = "log")] - ::log::info!($s $(, $x)*); - #[cfg(feature = "defmt")] - ::defmt::info!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] - let _ = ($( & $x ),*); - } - }; -} - -macro_rules! warn { - ($s:literal $(, $x:expr)* $(,)?) => { - { - #[cfg(feature = "log")] - ::log::warn!($s $(, $x)*); - #[cfg(feature = "defmt")] - ::defmt::warn!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] - let _ = ($( & $x ),*); - } - }; -} - -macro_rules! error { - ($s:literal $(, $x:expr)* $(,)?) => { - { - #[cfg(feature = "log")] - ::log::error!($s $(, $x)*); - #[cfg(feature = "defmt")] - ::defmt::error!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] - let _ = ($( & $x ),*); - } - }; -} - -#[cfg(feature = "defmt")] -macro_rules! unwrap { - ($($x:tt)*) => { - ::defmt::unwrap!($($x)*) - }; -} - -#[cfg(not(feature = "defmt"))] -macro_rules! unwrap { - ($arg:expr) => { - match $crate::fmt::Try::into_result($arg) { - ::core::result::Result::Ok(t) => t, - ::core::result::Result::Err(e) => { - ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); - } - } - }; - ($arg:expr, $($msg:expr),+ $(,)? ) => { - match $crate::fmt::Try::into_result($arg) { - ::core::result::Result::Ok(t) => t, - ::core::result::Result::Err(e) => { - ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); - } - } - } -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub struct NoneError; - -pub trait Try { - type Ok; - type Error; - fn into_result(self) -> Result; -} - -impl Try for Option { - type Ok = T; - type Error = NoneError; - - #[inline] - fn into_result(self) -> Result { - self.ok_or(NoneError) - } -} - -impl Try for Result { - type Ok = T; - type Error = E; - - #[inline] - fn into_result(self) -> Self { - self - } -} diff --git a/embassy-cortex-m/src/interrupt.rs b/embassy-cortex-m/src/interrupt.rs deleted file mode 100644 index e9fa43e87..000000000 --- a/embassy-cortex-m/src/interrupt.rs +++ /dev/null @@ -1,846 +0,0 @@ -//! Interrupt handling for cortex-m devices. -use core::mem; -use core::sync::atomic::{compiler_fence, Ordering}; - -use cortex_m::interrupt::InterruptNumber; -use cortex_m::peripheral::NVIC; - -/// Generate a standard `mod interrupt` for a HAL. -#[macro_export] -macro_rules! interrupt_mod { - ($($irqs:ident),* $(,)?) => { - #[cfg(feature = "rt")] - pub use cortex_m_rt::interrupt; - - /// Interrupt definitions. - pub mod interrupt { - pub use embassy_cortex_m::interrupt::{InterruptExt, Priority}; - pub use crate::pac::Interrupt::*; - pub use crate::pac::Interrupt; - - /// Type-level interrupt infrastructure. - /// - /// This module contains one *type* per interrupt. This is used for checking at compile time that - /// the interrupts are correctly bound to HAL drivers. - /// - /// As an end user, you shouldn't need to use this module directly. Use the [`crate::bind_interrupts!`] macro - /// to bind interrupts, and the [`crate::interrupt`] module to manually register interrupt handlers and manipulate - /// interrupts directly (pending/unpending, enabling/disabling, setting the priority, etc...) - pub mod typelevel { - use super::InterruptExt; - - mod sealed { - pub trait Interrupt {} - } - - /// Type-level interrupt. - /// - /// This trait is implemented for all typelevel interrupt types in this module. - pub trait Interrupt: sealed::Interrupt { - - /// Interrupt enum variant. - /// - /// This allows going from typelevel interrupts (one type per interrupt) to - /// non-typelevel interrupts (a single `Interrupt` enum type, with one variant per interrupt). - const IRQ: super::Interrupt; - - /// Enable the interrupt. - #[inline] - unsafe fn enable() { - Self::IRQ.enable() - } - - /// Disable the interrupt. - #[inline] - fn disable() { - Self::IRQ.disable() - } - - /// Check if interrupt is enabled. - #[inline] - fn is_enabled() -> bool { - Self::IRQ.is_enabled() - } - - /// Check if interrupt is pending. - #[inline] - fn is_pending() -> bool { - Self::IRQ.is_pending() - } - - /// Set interrupt pending. - #[inline] - fn pend() { - Self::IRQ.pend() - } - - /// Unset interrupt pending. - #[inline] - fn unpend() { - Self::IRQ.unpend() - } - - /// Get the priority of the interrupt. - #[inline] - fn get_priority() -> crate::interrupt::Priority { - Self::IRQ.get_priority() - } - - /// Set the interrupt priority. - #[inline] - fn set_priority(prio: crate::interrupt::Priority) { - Self::IRQ.set_priority(prio) - } - } - - $( - #[allow(non_camel_case_types)] - #[doc=stringify!($irqs)] - #[doc=" typelevel interrupt."] - pub enum $irqs {} - impl sealed::Interrupt for $irqs{} - impl Interrupt for $irqs { - const IRQ: super::Interrupt = super::Interrupt::$irqs; - } - )* - - /// Interrupt handler trait. - /// - /// Drivers that need to handle interrupts implement this trait. - /// The user must ensure `on_interrupt()` is called every time the interrupt fires. - /// Drivers must use use [`Binding`] to assert at compile time that the user has done so. - pub trait Handler { - /// Interrupt handler function. - /// - /// Must be called every time the `I` interrupt fires, synchronously from - /// the interrupt handler context. - /// - /// # Safety - /// - /// This function must ONLY be called from the interrupt handler for `I`. - unsafe fn on_interrupt(); - } - - /// Compile-time assertion that an interrupt has been bound to a handler. - /// - /// For the vast majority of cases, you should use the `bind_interrupts!` - /// macro instead of writing `unsafe impl`s of this trait. - /// - /// # Safety - /// - /// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()` - /// to be called every time the `I` interrupt fires. - /// - /// This allows drivers to check bindings at compile-time. - pub unsafe trait Binding> {} - } - } - }; -} - -/// Represents an interrupt type that can be configured by embassy to handle -/// interrupts. -pub unsafe trait InterruptExt: InterruptNumber + Copy { - /// Enable the interrupt. - #[inline] - unsafe fn enable(self) { - compiler_fence(Ordering::SeqCst); - NVIC::unmask(self) - } - - /// Disable the interrupt. - #[inline] - fn disable(self) { - NVIC::mask(self); - compiler_fence(Ordering::SeqCst); - } - - /// Check if interrupt is being handled. - #[inline] - #[cfg(not(armv6m))] - fn is_active(self) -> bool { - NVIC::is_active(self) - } - - /// Check if interrupt is enabled. - #[inline] - fn is_enabled(self) -> bool { - NVIC::is_enabled(self) - } - - /// Check if interrupt is pending. - #[inline] - fn is_pending(self) -> bool { - NVIC::is_pending(self) - } - - /// Set interrupt pending. - #[inline] - fn pend(self) { - NVIC::pend(self) - } - - /// Unset interrupt pending. - #[inline] - fn unpend(self) { - NVIC::unpend(self) - } - - /// Get the priority of the interrupt. - #[inline] - fn get_priority(self) -> Priority { - Priority::from(NVIC::get_priority(self)) - } - - /// Set the interrupt priority. - #[inline] - fn set_priority(self, prio: Priority) { - critical_section::with(|_| unsafe { - let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(()); - nvic.set_priority(self, prio.into()) - }) - } -} - -unsafe impl InterruptExt for T {} - -impl From for Priority { - fn from(priority: u8) -> Self { - unsafe { mem::transmute(priority & PRIO_MASK) } - } -} - -impl From for u8 { - fn from(p: Priority) -> Self { - p as u8 - } -} - -#[cfg(feature = "prio-bits-0")] -const PRIO_MASK: u8 = 0x00; -#[cfg(feature = "prio-bits-1")] -const PRIO_MASK: u8 = 0x80; -#[cfg(feature = "prio-bits-2")] -const PRIO_MASK: u8 = 0xc0; -#[cfg(feature = "prio-bits-3")] -const PRIO_MASK: u8 = 0xe0; -#[cfg(feature = "prio-bits-4")] -const PRIO_MASK: u8 = 0xf0; -#[cfg(feature = "prio-bits-5")] -const PRIO_MASK: u8 = 0xf8; -#[cfg(feature = "prio-bits-6")] -const PRIO_MASK: u8 = 0xfc; -#[cfg(feature = "prio-bits-7")] -const PRIO_MASK: u8 = 0xfe; -#[cfg(feature = "prio-bits-8")] -const PRIO_MASK: u8 = 0xff; - -/// The interrupt priority level. -/// -/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature. -#[cfg(feature = "prio-bits-0")] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(u8)] -#[allow(missing_docs)] -pub enum Priority { - P0 = 0x0, -} - -/// The interrupt priority level. -/// -/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature. -#[cfg(feature = "prio-bits-1")] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(u8)] -#[allow(missing_docs)] -pub enum Priority { - P0 = 0x0, - P1 = 0x80, -} - -/// The interrupt priority level. -/// -/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature. -#[cfg(feature = "prio-bits-2")] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(u8)] -#[allow(missing_docs)] -pub enum Priority { - P0 = 0x0, - P1 = 0x40, - P2 = 0x80, - P3 = 0xc0, -} - -/// The interrupt priority level. -/// -/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature. -#[cfg(feature = "prio-bits-3")] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(u8)] -#[allow(missing_docs)] -pub enum Priority { - P0 = 0x0, - P1 = 0x20, - P2 = 0x40, - P3 = 0x60, - P4 = 0x80, - P5 = 0xa0, - P6 = 0xc0, - P7 = 0xe0, -} - -/// The interrupt priority level. -/// -/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature. -#[cfg(feature = "prio-bits-4")] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(u8)] -#[allow(missing_docs)] -pub enum Priority { - P0 = 0x0, - P1 = 0x10, - P2 = 0x20, - P3 = 0x30, - P4 = 0x40, - P5 = 0x50, - P6 = 0x60, - P7 = 0x70, - P8 = 0x80, - P9 = 0x90, - P10 = 0xa0, - P11 = 0xb0, - P12 = 0xc0, - P13 = 0xd0, - P14 = 0xe0, - P15 = 0xf0, -} - -/// The interrupt priority level. -/// -/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature. -#[cfg(feature = "prio-bits-5")] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(u8)] -#[allow(missing_docs)] -pub enum Priority { - P0 = 0x0, - P1 = 0x8, - P2 = 0x10, - P3 = 0x18, - P4 = 0x20, - P5 = 0x28, - P6 = 0x30, - P7 = 0x38, - P8 = 0x40, - P9 = 0x48, - P10 = 0x50, - P11 = 0x58, - P12 = 0x60, - P13 = 0x68, - P14 = 0x70, - P15 = 0x78, - P16 = 0x80, - P17 = 0x88, - P18 = 0x90, - P19 = 0x98, - P20 = 0xa0, - P21 = 0xa8, - P22 = 0xb0, - P23 = 0xb8, - P24 = 0xc0, - P25 = 0xc8, - P26 = 0xd0, - P27 = 0xd8, - P28 = 0xe0, - P29 = 0xe8, - P30 = 0xf0, - P31 = 0xf8, -} - -/// The interrupt priority level. -/// -/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature. -#[cfg(feature = "prio-bits-6")] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(u8)] -#[allow(missing_docs)] -pub enum Priority { - P0 = 0x0, - P1 = 0x4, - P2 = 0x8, - P3 = 0xc, - P4 = 0x10, - P5 = 0x14, - P6 = 0x18, - P7 = 0x1c, - P8 = 0x20, - P9 = 0x24, - P10 = 0x28, - P11 = 0x2c, - P12 = 0x30, - P13 = 0x34, - P14 = 0x38, - P15 = 0x3c, - P16 = 0x40, - P17 = 0x44, - P18 = 0x48, - P19 = 0x4c, - P20 = 0x50, - P21 = 0x54, - P22 = 0x58, - P23 = 0x5c, - P24 = 0x60, - P25 = 0x64, - P26 = 0x68, - P27 = 0x6c, - P28 = 0x70, - P29 = 0x74, - P30 = 0x78, - P31 = 0x7c, - P32 = 0x80, - P33 = 0x84, - P34 = 0x88, - P35 = 0x8c, - P36 = 0x90, - P37 = 0x94, - P38 = 0x98, - P39 = 0x9c, - P40 = 0xa0, - P41 = 0xa4, - P42 = 0xa8, - P43 = 0xac, - P44 = 0xb0, - P45 = 0xb4, - P46 = 0xb8, - P47 = 0xbc, - P48 = 0xc0, - P49 = 0xc4, - P50 = 0xc8, - P51 = 0xcc, - P52 = 0xd0, - P53 = 0xd4, - P54 = 0xd8, - P55 = 0xdc, - P56 = 0xe0, - P57 = 0xe4, - P58 = 0xe8, - P59 = 0xec, - P60 = 0xf0, - P61 = 0xf4, - P62 = 0xf8, - P63 = 0xfc, -} - -/// The interrupt priority level. -/// -/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature. -#[cfg(feature = "prio-bits-7")] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(u8)] -#[allow(missing_docs)] -pub enum Priority { - P0 = 0x0, - P1 = 0x2, - P2 = 0x4, - P3 = 0x6, - P4 = 0x8, - P5 = 0xa, - P6 = 0xc, - P7 = 0xe, - P8 = 0x10, - P9 = 0x12, - P10 = 0x14, - P11 = 0x16, - P12 = 0x18, - P13 = 0x1a, - P14 = 0x1c, - P15 = 0x1e, - P16 = 0x20, - P17 = 0x22, - P18 = 0x24, - P19 = 0x26, - P20 = 0x28, - P21 = 0x2a, - P22 = 0x2c, - P23 = 0x2e, - P24 = 0x30, - P25 = 0x32, - P26 = 0x34, - P27 = 0x36, - P28 = 0x38, - P29 = 0x3a, - P30 = 0x3c, - P31 = 0x3e, - P32 = 0x40, - P33 = 0x42, - P34 = 0x44, - P35 = 0x46, - P36 = 0x48, - P37 = 0x4a, - P38 = 0x4c, - P39 = 0x4e, - P40 = 0x50, - P41 = 0x52, - P42 = 0x54, - P43 = 0x56, - P44 = 0x58, - P45 = 0x5a, - P46 = 0x5c, - P47 = 0x5e, - P48 = 0x60, - P49 = 0x62, - P50 = 0x64, - P51 = 0x66, - P52 = 0x68, - P53 = 0x6a, - P54 = 0x6c, - P55 = 0x6e, - P56 = 0x70, - P57 = 0x72, - P58 = 0x74, - P59 = 0x76, - P60 = 0x78, - P61 = 0x7a, - P62 = 0x7c, - P63 = 0x7e, - P64 = 0x80, - P65 = 0x82, - P66 = 0x84, - P67 = 0x86, - P68 = 0x88, - P69 = 0x8a, - P70 = 0x8c, - P71 = 0x8e, - P72 = 0x90, - P73 = 0x92, - P74 = 0x94, - P75 = 0x96, - P76 = 0x98, - P77 = 0x9a, - P78 = 0x9c, - P79 = 0x9e, - P80 = 0xa0, - P81 = 0xa2, - P82 = 0xa4, - P83 = 0xa6, - P84 = 0xa8, - P85 = 0xaa, - P86 = 0xac, - P87 = 0xae, - P88 = 0xb0, - P89 = 0xb2, - P90 = 0xb4, - P91 = 0xb6, - P92 = 0xb8, - P93 = 0xba, - P94 = 0xbc, - P95 = 0xbe, - P96 = 0xc0, - P97 = 0xc2, - P98 = 0xc4, - P99 = 0xc6, - P100 = 0xc8, - P101 = 0xca, - P102 = 0xcc, - P103 = 0xce, - P104 = 0xd0, - P105 = 0xd2, - P106 = 0xd4, - P107 = 0xd6, - P108 = 0xd8, - P109 = 0xda, - P110 = 0xdc, - P111 = 0xde, - P112 = 0xe0, - P113 = 0xe2, - P114 = 0xe4, - P115 = 0xe6, - P116 = 0xe8, - P117 = 0xea, - P118 = 0xec, - P119 = 0xee, - P120 = 0xf0, - P121 = 0xf2, - P122 = 0xf4, - P123 = 0xf6, - P124 = 0xf8, - P125 = 0xfa, - P126 = 0xfc, - P127 = 0xfe, -} - -/// The interrupt priority level. -/// -/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature. -#[cfg(feature = "prio-bits-8")] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(u8)] -#[allow(missing_docs)] -pub enum Priority { - P0 = 0x0, - P1 = 0x1, - P2 = 0x2, - P3 = 0x3, - P4 = 0x4, - P5 = 0x5, - P6 = 0x6, - P7 = 0x7, - P8 = 0x8, - P9 = 0x9, - P10 = 0xa, - P11 = 0xb, - P12 = 0xc, - P13 = 0xd, - P14 = 0xe, - P15 = 0xf, - P16 = 0x10, - P17 = 0x11, - P18 = 0x12, - P19 = 0x13, - P20 = 0x14, - P21 = 0x15, - P22 = 0x16, - P23 = 0x17, - P24 = 0x18, - P25 = 0x19, - P26 = 0x1a, - P27 = 0x1b, - P28 = 0x1c, - P29 = 0x1d, - P30 = 0x1e, - P31 = 0x1f, - P32 = 0x20, - P33 = 0x21, - P34 = 0x22, - P35 = 0x23, - P36 = 0x24, - P37 = 0x25, - P38 = 0x26, - P39 = 0x27, - P40 = 0x28, - P41 = 0x29, - P42 = 0x2a, - P43 = 0x2b, - P44 = 0x2c, - P45 = 0x2d, - P46 = 0x2e, - P47 = 0x2f, - P48 = 0x30, - P49 = 0x31, - P50 = 0x32, - P51 = 0x33, - P52 = 0x34, - P53 = 0x35, - P54 = 0x36, - P55 = 0x37, - P56 = 0x38, - P57 = 0x39, - P58 = 0x3a, - P59 = 0x3b, - P60 = 0x3c, - P61 = 0x3d, - P62 = 0x3e, - P63 = 0x3f, - P64 = 0x40, - P65 = 0x41, - P66 = 0x42, - P67 = 0x43, - P68 = 0x44, - P69 = 0x45, - P70 = 0x46, - P71 = 0x47, - P72 = 0x48, - P73 = 0x49, - P74 = 0x4a, - P75 = 0x4b, - P76 = 0x4c, - P77 = 0x4d, - P78 = 0x4e, - P79 = 0x4f, - P80 = 0x50, - P81 = 0x51, - P82 = 0x52, - P83 = 0x53, - P84 = 0x54, - P85 = 0x55, - P86 = 0x56, - P87 = 0x57, - P88 = 0x58, - P89 = 0x59, - P90 = 0x5a, - P91 = 0x5b, - P92 = 0x5c, - P93 = 0x5d, - P94 = 0x5e, - P95 = 0x5f, - P96 = 0x60, - P97 = 0x61, - P98 = 0x62, - P99 = 0x63, - P100 = 0x64, - P101 = 0x65, - P102 = 0x66, - P103 = 0x67, - P104 = 0x68, - P105 = 0x69, - P106 = 0x6a, - P107 = 0x6b, - P108 = 0x6c, - P109 = 0x6d, - P110 = 0x6e, - P111 = 0x6f, - P112 = 0x70, - P113 = 0x71, - P114 = 0x72, - P115 = 0x73, - P116 = 0x74, - P117 = 0x75, - P118 = 0x76, - P119 = 0x77, - P120 = 0x78, - P121 = 0x79, - P122 = 0x7a, - P123 = 0x7b, - P124 = 0x7c, - P125 = 0x7d, - P126 = 0x7e, - P127 = 0x7f, - P128 = 0x80, - P129 = 0x81, - P130 = 0x82, - P131 = 0x83, - P132 = 0x84, - P133 = 0x85, - P134 = 0x86, - P135 = 0x87, - P136 = 0x88, - P137 = 0x89, - P138 = 0x8a, - P139 = 0x8b, - P140 = 0x8c, - P141 = 0x8d, - P142 = 0x8e, - P143 = 0x8f, - P144 = 0x90, - P145 = 0x91, - P146 = 0x92, - P147 = 0x93, - P148 = 0x94, - P149 = 0x95, - P150 = 0x96, - P151 = 0x97, - P152 = 0x98, - P153 = 0x99, - P154 = 0x9a, - P155 = 0x9b, - P156 = 0x9c, - P157 = 0x9d, - P158 = 0x9e, - P159 = 0x9f, - P160 = 0xa0, - P161 = 0xa1, - P162 = 0xa2, - P163 = 0xa3, - P164 = 0xa4, - P165 = 0xa5, - P166 = 0xa6, - P167 = 0xa7, - P168 = 0xa8, - P169 = 0xa9, - P170 = 0xaa, - P171 = 0xab, - P172 = 0xac, - P173 = 0xad, - P174 = 0xae, - P175 = 0xaf, - P176 = 0xb0, - P177 = 0xb1, - P178 = 0xb2, - P179 = 0xb3, - P180 = 0xb4, - P181 = 0xb5, - P182 = 0xb6, - P183 = 0xb7, - P184 = 0xb8, - P185 = 0xb9, - P186 = 0xba, - P187 = 0xbb, - P188 = 0xbc, - P189 = 0xbd, - P190 = 0xbe, - P191 = 0xbf, - P192 = 0xc0, - P193 = 0xc1, - P194 = 0xc2, - P195 = 0xc3, - P196 = 0xc4, - P197 = 0xc5, - P198 = 0xc6, - P199 = 0xc7, - P200 = 0xc8, - P201 = 0xc9, - P202 = 0xca, - P203 = 0xcb, - P204 = 0xcc, - P205 = 0xcd, - P206 = 0xce, - P207 = 0xcf, - P208 = 0xd0, - P209 = 0xd1, - P210 = 0xd2, - P211 = 0xd3, - P212 = 0xd4, - P213 = 0xd5, - P214 = 0xd6, - P215 = 0xd7, - P216 = 0xd8, - P217 = 0xd9, - P218 = 0xda, - P219 = 0xdb, - P220 = 0xdc, - P221 = 0xdd, - P222 = 0xde, - P223 = 0xdf, - P224 = 0xe0, - P225 = 0xe1, - P226 = 0xe2, - P227 = 0xe3, - P228 = 0xe4, - P229 = 0xe5, - P230 = 0xe6, - P231 = 0xe7, - P232 = 0xe8, - P233 = 0xe9, - P234 = 0xea, - P235 = 0xeb, - P236 = 0xec, - P237 = 0xed, - P238 = 0xee, - P239 = 0xef, - P240 = 0xf0, - P241 = 0xf1, - P242 = 0xf2, - P243 = 0xf3, - P244 = 0xf4, - P245 = 0xf5, - P246 = 0xf6, - P247 = 0xf7, - P248 = 0xf8, - P249 = 0xf9, - P250 = 0xfa, - P251 = 0xfb, - P252 = 0xfc, - P253 = 0xfd, - P254 = 0xfe, - P255 = 0xff, -} diff --git a/embassy-cortex-m/src/lib.rs b/embassy-cortex-m/src/lib.rs deleted file mode 100644 index 7bc16d3ba..000000000 --- a/embassy-cortex-m/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! Embassy executor and interrupt handling specific to cortex-m devices. -#![no_std] -#![warn(missing_docs)] - -// This mod MUST go first, so that the others see its macros. -pub(crate) mod fmt; - -pub use embassy_executor as executor; -pub mod interrupt; -- cgit