2022-06-23 12:59:18 +02:00
//! Peripheral interrupt handling specific to cortex-m devices.
2021-07-29 14:08:32 +02:00
use core ::mem ::MaybeUninit ;
2022-06-12 22:15:44 +02:00
2021-07-29 07:19:57 +02:00
use cortex_m ::peripheral ::scb ::VectActive ;
2021-07-27 09:28:52 +02:00
use cortex_m ::peripheral ::{ NVIC , SCB } ;
2022-07-23 14:00:19 +02:00
use embassy_hal_common ::{ into_ref , Peripheral , PeripheralRef } ;
2022-06-11 05:08:57 +02:00
use crate ::interrupt ::{ Interrupt , InterruptExt , Priority } ;
2021-03-01 00:44:38 +01:00
2021-07-24 04:53:57 +02:00
/// 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,
2021-07-28 13:31:31 +02:00
/// and `&mut T` is only `Send` where `T: Send`.
2021-07-29 07:11:26 +02:00
pub trait PeripheralState : Send {
2022-06-23 12:59:18 +02:00
/// The interrupt that is used for this peripheral.
2021-07-05 09:42:43 +02:00
type Interrupt : Interrupt ;
2022-06-23 12:59:18 +02:00
/// 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.
2021-07-05 09:42:43 +02:00
fn on_interrupt ( & mut self ) ;
}
2022-06-23 12:59:18 +02:00
/// A type for storing the state of a peripheral that can be stored in a static.
2021-07-29 14:08:32 +02:00
pub struct StateStorage < S > ( MaybeUninit < S > ) ;
2021-02-28 22:03:45 +01:00
2021-07-29 14:08:32 +02:00
impl < S > StateStorage < S > {
2022-06-23 12:59:18 +02:00
/// Create a new instance for storing peripheral state.
2021-08-02 19:50:07 +02:00
pub const fn new ( ) -> Self {
2021-07-29 14:08:32 +02:00
Self ( MaybeUninit ::uninit ( ) )
}
}
2021-02-28 22:03:45 +01:00
2022-06-23 12:59:18 +02:00
/// 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.
2021-07-29 14:08:32 +02:00
pub struct PeripheralMutex < ' a , S : PeripheralState > {
state : * mut S ,
2022-07-23 14:00:19 +02:00
irq : PeripheralRef < ' a , S ::Interrupt > ,
2021-01-03 01:40:40 +01:00
}
2021-07-27 09:28:52 +02:00
/// Whether `irq` can be preempted by the current interrupt.
pub ( crate ) fn can_be_preempted ( irq : & impl Interrupt ) -> bool {
match SCB ::vect_active ( ) {
2021-07-29 07:19:57 +02:00
// Thread mode can't preempt anything.
2021-07-27 09:28:52 +02:00
VectActive ::ThreadMode = > false ,
2021-07-29 07:19:57 +02:00
// 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 ,
2021-07-27 09:28:52 +02:00
VectActive ::Interrupt { irqn } = > {
#[ derive(Clone, Copy) ]
struct NrWrap ( u16 ) ;
unsafe impl cortex_m ::interrupt ::InterruptNumber for NrWrap {
fn number ( self ) -> u16 {
self . 0
}
}
2021-07-28 13:31:31 +02:00
NVIC ::get_priority ( NrWrap ( irqn . into ( ) ) ) < irq . get_priority ( ) . into ( )
2021-07-27 09:28:52 +02:00
}
}
}
2021-07-29 14:08:32 +02:00
impl < ' a , S : PeripheralState > PeripheralMutex < ' a , S > {
2021-08-02 20:13:41 +02:00
/// Create a new `PeripheralMutex` wrapping `irq`, with `init` initializing the initial state.
2021-07-29 07:11:26 +02:00
///
2021-07-29 14:08:32 +02:00
/// Registers `on_interrupt` as the `irq`'s handler, and enables it.
2022-07-23 01:29:35 +02:00
pub fn new (
2022-07-23 14:00:19 +02:00
irq : impl Peripheral < P = S ::Interrupt > + ' a ,
2022-07-23 01:29:35 +02:00
storage : & ' a mut StateStorage < S > ,
init : impl FnOnce ( ) -> S ,
) -> Self {
2022-07-23 14:00:19 +02:00
into_ref! ( irq ) ;
2022-07-23 01:29:35 +02:00
if can_be_preempted ( & * irq ) {
2022-06-12 22:15:44 +02:00
panic! (
" `PeripheralMutex` cannot be created in an interrupt with higher priority than the interrupt it wraps "
) ;
2021-07-27 09:28:52 +02:00
}
2021-07-29 14:08:32 +02:00
let state_ptr = storage . 0. as_mut_ptr ( ) ;
2021-03-18 02:01:29 +01:00
2021-07-29 14:08:32 +02:00
// Safety: The pointer is valid and not used by anyone else
// because we have the `&mut StateStorage`.
2022-06-09 21:28:13 +02:00
unsafe { state_ptr . write ( init ( ) ) } ;
2021-03-18 02:29:03 +01:00
2021-07-29 14:08:32 +02:00
irq . disable ( ) ;
2022-06-09 21:28:13 +02:00
irq . set_handler ( | p | unsafe {
2021-07-27 09:28:52 +02:00
// 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.
2022-02-16 03:54:39 +01:00
let state = & mut * ( p as * mut S ) ;
2021-07-27 09:28:52 +02:00
state . on_interrupt ( ) ;
2021-02-26 02:04:48 +01:00
} ) ;
2021-07-29 14:08:32 +02:00
irq . set_handler_context ( state_ptr as * mut ( ) ) ;
irq . enable ( ) ;
2021-02-28 22:03:45 +01:00
2022-07-23 01:29:35 +02:00
Self { irq , state : state_ptr }
2021-02-28 22:03:45 +01:00
}
2022-06-23 12:59:18 +02:00
/// Access the peripheral state ensuring interrupts are disabled so that the state can be
/// safely accessed.
2021-07-29 14:08:32 +02:00
pub fn with < R > ( & mut self , f : impl FnOnce ( & mut S ) -> R ) -> R {
self . irq . disable ( ) ;
2021-01-05 01:57:05 +01:00
// Safety: it's OK to get a &mut to the state, since the irq is disabled.
2021-07-29 14:08:32 +02:00
let state = unsafe { & mut * self . state } ;
2021-07-27 09:28:52 +02:00
let r = f ( state ) ;
2021-01-03 01:40:40 +01:00
2021-07-29 14:08:32 +02:00
self . irq . enable ( ) ;
2021-01-03 01:40:40 +01:00
r
}
2021-07-27 09:28:52 +02:00
/// 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.
2022-06-11 05:08:57 +02:00
pub fn priority ( & self ) -> Priority {
2021-07-27 09:28:52 +02:00
self . irq . get_priority ( )
}
2021-01-03 01:40:40 +01:00
}
2021-07-29 14:08:32 +02:00
impl < ' a , S : PeripheralState > Drop for PeripheralMutex < ' a , S > {
2021-01-03 01:40:40 +01:00
fn drop ( & mut self ) {
2021-03-18 02:01:29 +01:00
self . irq . disable ( ) ;
self . irq . remove_handler ( ) ;
2021-07-29 14:08:32 +02:00
// 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 ( ) }
2021-01-03 01:40:40 +01:00
}
}