From ca59c1ff3570474dc819c2d759c69c3a186ca5bc Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 23 Jun 2022 12:59:18 +0200 Subject: Add more API docs for embassy-cortex-m and embassy-nrf --- embassy-cortex-m/src/executor.rs | 7 ++--- embassy-cortex-m/src/interrupt.rs | 54 ++++++++++++++++++++++++++++++++++++++ embassy-cortex-m/src/lib.rs | 1 + embassy-cortex-m/src/peripheral.rs | 10 +++++++ 4 files changed, 69 insertions(+), 3 deletions(-) (limited to 'embassy-cortex-m/src') diff --git a/embassy-cortex-m/src/executor.rs b/embassy-cortex-m/src/executor.rs index 34f3ec236..8c7f8cf9d 100644 --- a/embassy-cortex-m/src/executor.rs +++ b/embassy-cortex-m/src/executor.rs @@ -1,3 +1,4 @@ +//! Executor specific to cortex-m devices. use core::marker::PhantomData; pub use embassy::executor::Executor; @@ -60,18 +61,18 @@ impl InterruptExecutor { /// 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`] because the executor effectively runs in a + /// 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`] for this executor, use [`Spawner::for_current_executor`] from + /// 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: /// - /// - a [Forever](crate::util::Forever) (safe) + /// - a [Forever](embassy::util::Forever) (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 { diff --git a/embassy-cortex-m/src/interrupt.rs b/embassy-cortex-m/src/interrupt.rs index 72686b402..cd132076f 100644 --- a/embassy-cortex-m/src/interrupt.rs +++ b/embassy-cortex-m/src/interrupt.rs @@ -1,3 +1,4 @@ +//! Interrupt handling for cortex-m devices. use core::{mem, ptr}; use atomic_polyfill::{compiler_fence, AtomicPtr, Ordering}; @@ -29,8 +30,16 @@ 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: Unborrow { + /// 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. @@ -38,19 +47,55 @@ pub unsafe trait Interrupt: Unborrow { unsafe fn __handler(&self) -> &'static Handler; } +/// 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); } @@ -159,6 +204,7 @@ const PRIO_MASK: u8 = 0xfe; #[cfg(feature = "prio-bits-8")] const PRIO_MASK: u8 = 0xff; +/// The interrupt priority level. #[cfg(feature = "prio-bits-0")] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -167,6 +213,7 @@ pub enum Priority { P0 = 0x0, } +/// The interrupt priority level. #[cfg(feature = "prio-bits-1")] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -176,6 +223,7 @@ pub enum Priority { P1 = 0x80, } +/// The interrupt priority level. #[cfg(feature = "prio-bits-2")] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -187,6 +235,7 @@ pub enum Priority { P3 = 0xc0, } +/// The interrupt priority level. #[cfg(feature = "prio-bits-3")] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -202,6 +251,7 @@ pub enum Priority { P7 = 0xe0, } +/// The interrupt priority level. #[cfg(feature = "prio-bits-4")] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -225,6 +275,7 @@ pub enum Priority { P15 = 0xf0, } +/// The interrupt priority level. #[cfg(feature = "prio-bits-5")] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -264,6 +315,7 @@ pub enum Priority { P31 = 0xf8, } +/// The interrupt priority level. #[cfg(feature = "prio-bits-6")] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -335,6 +387,7 @@ pub enum Priority { P63 = 0xfc, } +/// The interrupt priority level. #[cfg(feature = "prio-bits-7")] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -470,6 +523,7 @@ pub enum Priority { P127 = 0xfe, } +/// The interrupt priority level. #[cfg(feature = "prio-bits-8")] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] diff --git a/embassy-cortex-m/src/lib.rs b/embassy-cortex-m/src/lib.rs index 143c56f39..680c2c8db 100644 --- a/embassy-cortex-m/src/lib.rs +++ b/embassy-cortex-m/src/lib.rs @@ -1,3 +1,4 @@ +//! Embassy executor and interrupt handling specific to cortex-m devices. #![no_std] // This mod MUST go first, so that the others see its macros. diff --git a/embassy-cortex-m/src/peripheral.rs b/embassy-cortex-m/src/peripheral.rs index 5ff690831..6a03bfb9f 100644 --- a/embassy-cortex-m/src/peripheral.rs +++ b/embassy-cortex-m/src/peripheral.rs @@ -1,3 +1,4 @@ +//! Peripheral interrupt handling specific to cortex-m devices. use core::marker::PhantomData; use core::mem::MaybeUninit; @@ -11,18 +12,25 @@ use crate::interrupt::{Interrupt, InterruptExt, Priority}; /// 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, _phantom: PhantomData<&'a mut S>, @@ -87,6 +95,8 @@ impl<'a, S: PeripheralState> PeripheralMutex<'a, S> { } } + /// 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(); -- cgit