From 6d3a652026d222bb0191c77406e1f4145a64c5f9 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 23 Jun 2022 12:59:34 +0200 Subject: [PATCH 1/2] Fix new warnings for embassy docs --- embassy/src/channel/pubsub/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy/src/channel/pubsub/mod.rs b/embassy/src/channel/pubsub/mod.rs index 9bfb845e0..11c889368 100644 --- a/embassy/src/channel/pubsub/mod.rs +++ b/embassy/src/channel/pubsub/mod.rs @@ -25,8 +25,8 @@ pub use subscriber::{DynSubscriber, Subscriber}; /// Any published message can be read by all subscribers. /// A publisher can choose how it sends its message. /// -/// - With [Publisher::publish] the publisher has to wait until there is space in the internal message queue. -/// - With [Publisher::publish_immediate] the publisher doesn't await and instead lets the oldest message +/// - With [Pub::publish()] the publisher has to wait until there is space in the internal message queue. +/// - With [Pub::publish_immediate()] the publisher doesn't await and instead lets the oldest message /// in the queue drop if necessary. This will cause any [Subscriber] that missed the message to receive /// an error to indicate that it has lagged. /// From ca59c1ff3570474dc819c2d759c69c3a186ca5bc Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 23 Jun 2022 12:59:18 +0200 Subject: [PATCH 2/2] 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 ++++++ embassy-nrf/src/buffered_uarte.rs | 2 +- embassy-nrf/src/gpio.rs | 2 +- embassy-nrf/src/lib.rs | 30 +++++++++++++++-- embassy-nrf/src/uarte.rs | 6 ++-- 8 files changed, 102 insertions(+), 10 deletions(-) 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(); diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 34f20efe7..4fc78b95d 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -3,7 +3,7 @@ //! WARNING!!! The functionality provided here is intended to be used only //! in situations where hardware flow control are available i.e. CTS and RTS. //! This is a problem that should be addressed at a later stage and can be -//! fully explained at https://github.com/embassy-rs/embassy/issues/536. +//! fully explained at . //! //! Note that discarding a future from a read or write operation may lead to losing //! data. For example, when using `futures_util::future::select` and completion occurs diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index e68b8874a..0ba20b0b1 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -429,7 +429,7 @@ mod eh02 { } } - /// Implement [`InputPin`] for [`Flex`]; + /// Implement [`embedded_hal_02::digital::v2::InputPin`] for [`Flex`]; /// /// If the pin is not in input mode the result is unspecified. impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Flex<'d, T> { diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 1f1ffc99d..3699ad0fa 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -1,3 +1,11 @@ +//! # Embassy nRF HAL +//! +//! HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. +//! +//! The Embassy nRF HAL targets the Nordic Semiconductor nRF family of hardware. The HAL implements both blocking and async APIs +//! for many peripherals. The benefit of using the async APIs is that the HAL takes care of waiting for peripherals to +//! complete operations in low power mod and handling interrupts, so that applications can focus on more important matters. +//! //! ## EasyDMA considerations //! //! On nRF chips, peripherals can use the so called EasyDMA feature to offload the task of interacting @@ -23,8 +31,8 @@ //! ``` //! //! Each peripheral struct which uses EasyDMA ([`Spim`](spim::Spim), [`Uarte`](uarte::Uarte), [`Twim`](twim::Twim)) has two variants of their mutating functions: -//! - Functions with the suffix (e.g. [`write_from_ram`](Spim::write_from_ram), [`transfer_from_ram`](Spim::transfer_from_ram)) will return an error if the passed slice does not reside in RAM. -//! - Functions without the suffix (e.g. [`write`](Spim::write), [`transfer`](Spim::transfer)) will check whether the data is in RAM and copy it into memory prior to transmission. +//! - Functions with the suffix (e.g. [`write_from_ram`](spim::Spim::write_from_ram), [`transfer_from_ram`](spim::Spim::transfer_from_ram)) will return an error if the passed slice does not reside in RAM. +//! - Functions without the suffix (e.g. [`write`](spim::Spim::write), [`transfer`](spim::Spim::transfer)) will check whether the data is in RAM and copy it into memory prior to transmission. //! //! Since copying incurs a overhead, you are given the option to choose from `_from_ram` variants which will //! fail and notify you, or the more convenient versions without the suffix which are potentially a little bit @@ -112,6 +120,7 @@ mod chip; pub use chip::EASY_DMA_SIZE; pub mod interrupt { + //! nRF interrupts for cortex-m devices. pub use cortex_m::interrupt::{CriticalSection, Mutex}; pub use embassy_cortex_m::interrupt::*; @@ -130,28 +139,44 @@ pub use embassy_hal_common::{unborrow, Unborrow}; pub use embassy_macros::cortex_m_interrupt as interrupt; pub mod config { + //! Configuration options used when initializing the HAL. + + /// High frequency clock source. pub enum HfclkSource { + /// Internal source Internal, + /// External source from xtal. ExternalXtal, } + /// Low frequency clock source pub enum LfclkSource { + /// Internal RC oscillator InternalRC, + /// Synthesized from the high frequency clock source. #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] Synthesized, + /// External source from xtal. ExternalXtal, + /// External source from xtal with low swing applied. #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] ExternalLowSwing, + /// External source from xtal with full swing applied. #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] ExternalFullSwing, } + /// Configuration for peripherals. Default configuration should work on any nRF chip. #[non_exhaustive] pub struct Config { + /// High frequency clock source. pub hfclk_source: HfclkSource, + /// Low frequency clock source. pub lfclk_source: LfclkSource, + /// GPIOTE interrupt priority. Should be lower priority than softdevice if used. #[cfg(feature = "gpiote")] pub gpiote_interrupt_priority: crate::interrupt::Priority, + /// Time driver interrupt priority. Should be lower priority than softdevice if used. #[cfg(feature = "_time-driver")] pub time_interrupt_priority: crate::interrupt::Priority, } @@ -173,6 +198,7 @@ pub mod config { } } +/// Initialize peripherals with the provided configuration. This should only be called once at startup. pub fn init(config: config::Config) -> Peripherals { // Do this first, so that it panics if user is calling `init` a second time // before doing anything important. diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index c129fb63a..f626c62a5 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -19,9 +19,9 @@ use core::task::Poll; use embassy_hal_common::drop::OnDrop; use embassy_hal_common::unborrow; -use futures::future::poll_fn; -// Re-export SVD variants to allow user to directly set values. -pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; +use futures::future::poll_fn; // Re-export SVD variants to allow user to directly set values. +pub use pac::uarte0::baudrate::BAUDRATE_A as Baudrate; +pub use pac::uarte0::config::PARITY_A as Parity; use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; use crate::gpio::sealed::Pin as _;