From c8c8b89104acb396476b72ff9192d7b14a46752d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 19 Dec 2023 18:03:20 +0100 Subject: [PATCH] stm32: doc everything else. --- embassy-stm32/src/dma/gpdma.rs | 18 ++++++ embassy-stm32/src/ipcc.rs | 8 +++ embassy-stm32/src/lib.rs | 1 + embassy-stm32/src/low_power.rs | 106 +++++++++++++++++-------------- embassy-stm32/src/opamp.rs | 9 +++ embassy-stm32/src/rng.rs | 1 + embassy-stm32/src/sdmmc/mod.rs | 2 + embassy-stm32/src/usb/mod.rs | 4 ++ embassy-stm32/src/usb/usb.rs | 7 ++ embassy-stm32/src/usb_otg/mod.rs | 2 + embassy-stm32/src/usb_otg/usb.rs | 13 +++- embassy-stm32/src/wdg/mod.rs | 4 ++ 12 files changed, 127 insertions(+), 48 deletions(-) diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index b061415eb..34b2426b9 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs @@ -16,6 +16,7 @@ use crate::interrupt::Priority; use crate::pac; use crate::pac::gpdma::vals; +/// GPDMA transfer options. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] @@ -113,10 +114,13 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::gpdma::Gpdma, channel_num: usize, in } } +/// DMA request type alias. (also known as DMA channel number in some chips) pub type Request = u8; +/// DMA channel. #[cfg(dmamux)] pub trait Channel: sealed::Channel + Peripheral

+ 'static + super::dmamux::MuxChannel {} +/// DMA channel. #[cfg(not(dmamux))] pub trait Channel: sealed::Channel + Peripheral

+ 'static {} @@ -131,12 +135,14 @@ pub(crate) mod sealed { } } +/// DMA transfer. #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Transfer<'a, C: Channel> { channel: PeripheralRef<'a, C>, } impl<'a, C: Channel> Transfer<'a, C> { + /// Create a new read DMA transfer (peripheral to memory). pub unsafe fn new_read( channel: impl Peripheral

+ 'a, request: Request, @@ -147,6 +153,7 @@ impl<'a, C: Channel> Transfer<'a, C> { Self::new_read_raw(channel, request, peri_addr, buf, options) } + /// Create a new read DMA transfer (peripheral to memory), using raw pointers. pub unsafe fn new_read_raw( channel: impl Peripheral

+ 'a, request: Request, @@ -172,6 +179,7 @@ impl<'a, C: Channel> Transfer<'a, C> { ) } + /// Create a new write DMA transfer (memory to peripheral). pub unsafe fn new_write( channel: impl Peripheral

+ 'a, request: Request, @@ -182,6 +190,7 @@ impl<'a, C: Channel> Transfer<'a, C> { Self::new_write_raw(channel, request, buf, peri_addr, options) } + /// Create a new write DMA transfer (memory to peripheral), using raw pointers. pub unsafe fn new_write_raw( channel: impl Peripheral

+ 'a, request: Request, @@ -207,6 +216,7 @@ impl<'a, C: Channel> Transfer<'a, C> { ) } + /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly. pub unsafe fn new_write_repeated( channel: impl Peripheral

+ 'a, request: Request, @@ -297,6 +307,9 @@ impl<'a, C: Channel> Transfer<'a, C> { this } + /// Request the transfer to stop. + /// + /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. pub fn request_stop(&mut self) { let ch = self.channel.regs().ch(self.channel.num()); ch.cr().modify(|w| { @@ -304,6 +317,10 @@ impl<'a, C: Channel> Transfer<'a, C> { }) } + /// Return whether this transfer is still running. + /// + /// If this returns `false`, it can be because either the transfer finished, or + /// it was requested to stop early with [`request_stop`](Self::request_stop). pub fn is_running(&mut self) -> bool { let ch = self.channel.regs().ch(self.channel.num()); let sr = ch.sr().read(); @@ -317,6 +334,7 @@ impl<'a, C: Channel> Transfer<'a, C> { ch.br1().read().bndt() } + /// Blocking wait until the transfer finishes. pub fn blocking_wait(mut self) { while self.is_running() {} diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index 4006dee19..663a7f59d 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs @@ -1,3 +1,5 @@ +//! Inter-Process Communication Controller (IPCC) + use core::future::poll_fn; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; @@ -41,6 +43,7 @@ impl interrupt::typelevel::Handler for Receive } } +/// TX interrupt handler. pub struct TransmitInterruptHandler {} impl interrupt::typelevel::Handler for TransmitInterruptHandler { @@ -72,6 +75,7 @@ impl interrupt::typelevel::Handler for Transmi } } +/// IPCC config. #[non_exhaustive] #[derive(Clone, Copy, Default)] pub struct Config { @@ -79,6 +83,8 @@ pub struct Config { // reserved for future use } +/// Channel. +#[allow(missing_docs)] #[derive(Debug, Clone, Copy)] #[repr(C)] pub enum IpccChannel { @@ -90,9 +96,11 @@ pub enum IpccChannel { Channel6 = 5, } +/// IPCC driver. pub struct Ipcc; impl Ipcc { + /// Enable IPCC. pub fn enable(_config: Config) { IPCC::enable_and_reset(); IPCC::set_cpu2(true); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 4952d26eb..207f7ed8f 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -1,5 +1,6 @@ #![cfg_attr(not(test), no_std)] #![allow(async_fn_in_trait)] +#![warn(missing_docs)] //! ## Feature flags #![doc = document_features::document_features!(feature_label = r#"{feature}"#)] diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 20d8f9045..a41c40eba 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -1,50 +1,53 @@ -/// The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating -/// to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which -/// can use knowledge of which peripherals are currently blocked upon to transparently and safely -/// enter such low-power modes (currently, only `STOP2`) when idle. -/// -/// The executor determines which peripherals are active by their RCC state; consequently, -/// low-power states can only be entered if all peripherals have been `drop`'d. There are a few -/// exceptions to this rule: -/// -/// * `GPIO` -/// * `RCC` -/// -/// Since entering and leaving low-power modes typically incurs a significant latency, the -/// low-power executor will only attempt to enter when the next timer event is at least -/// [`time_driver::MIN_STOP_PAUSE`] in the future. -/// -/// Currently there is no macro analogous to `embassy_executor::main` for this executor; -/// consequently one must define their entrypoint manually. Moveover, you must relinquish control -/// of the `RTC` peripheral to the executor. This will typically look like -/// -/// ```rust,no_run -/// use embassy_executor::Spawner; -/// use embassy_stm32::low_power::Executor; -/// use embassy_stm32::rtc::{Rtc, RtcConfig}; -/// use static_cell::make_static; -/// -/// #[cortex_m_rt::entry] -/// fn main() -> ! { -/// Executor::take().run(|spawner| { -/// unwrap!(spawner.spawn(async_main(spawner))); -/// }); -/// } -/// -/// #[embassy_executor::task] -/// async fn async_main(spawner: Spawner) { -/// // initialize the platform... -/// let mut config = embassy_stm32::Config::default(); -/// let p = embassy_stm32::init(config); -/// -/// // give the RTC to the executor... -/// let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); -/// let rtc = make_static!(rtc); -/// embassy_stm32::low_power::stop_with_rtc(rtc); -/// -/// // your application here... -/// } -/// ``` +//! Low-power support. +//! +//! The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating +//! to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which +//! can use knowledge of which peripherals are currently blocked upon to transparently and safely +//! enter such low-power modes (currently, only `STOP2`) when idle. +//! +//! The executor determines which peripherals are active by their RCC state; consequently, +//! low-power states can only be entered if all peripherals have been `drop`'d. There are a few +//! exceptions to this rule: +//! +//! * `GPIO` +//! * `RCC` +//! +//! Since entering and leaving low-power modes typically incurs a significant latency, the +//! low-power executor will only attempt to enter when the next timer event is at least +//! [`time_driver::MIN_STOP_PAUSE`] in the future. +//! +//! Currently there is no macro analogous to `embassy_executor::main` for this executor; +//! consequently one must define their entrypoint manually. Moveover, you must relinquish control +//! of the `RTC` peripheral to the executor. This will typically look like +//! +//! ```rust,no_run +//! use embassy_executor::Spawner; +//! use embassy_stm32::low_power::Executor; +//! use embassy_stm32::rtc::{Rtc, RtcConfig}; +//! use static_cell::make_static; +//! +//! #[cortex_m_rt::entry] +//! fn main() -> ! { +//! Executor::take().run(|spawner| { +//! unwrap!(spawner.spawn(async_main(spawner))); +//! }); +//! } +//! +//! #[embassy_executor::task] +//! async fn async_main(spawner: Spawner) { +//! // initialize the platform... +//! let mut config = embassy_stm32::Config::default(); +//! let p = embassy_stm32::init(config); +//! +//! // give the RTC to the executor... +//! let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); +//! let rtc = make_static!(rtc); +//! embassy_stm32::low_power::stop_with_rtc(rtc); +//! +//! // your application here... +//! } +//! ``` + use core::arch::asm; use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; @@ -64,6 +67,7 @@ static mut EXECUTOR: Option = None; foreach_interrupt! { (RTC, rtc, $block:ident, WKUP, $irq:ident) => { #[interrupt] + #[allow(non_snake_case)] unsafe fn $irq() { EXECUTOR.as_mut().unwrap().on_wakeup_irq(); } @@ -75,10 +79,15 @@ pub(crate) unsafe fn on_wakeup_irq() { EXECUTOR.as_mut().unwrap().on_wakeup_irq(); } +/// Configure STOP mode with RTC. pub fn stop_with_rtc(rtc: &'static Rtc) { unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) } +/// Get whether the core is ready to enter the given stop mode. +/// +/// This will return false if some peripheral driver is in use that +/// prevents entering the given stop mode. pub fn stop_ready(stop_mode: StopMode) -> bool { match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() { Some(StopMode::Stop2) => true, @@ -87,10 +96,13 @@ pub fn stop_ready(stop_mode: StopMode) -> bool { } } +/// Available stop modes. #[non_exhaustive] #[derive(PartialEq)] pub enum StopMode { + /// STOP 1 Stop1, + /// STOP 2 Stop2, } diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index e1eb031d1..df8a78bcc 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs @@ -1,9 +1,12 @@ +//! Operational Amplifier (OPAMP) #![macro_use] use embassy_hal_internal::{into_ref, PeripheralRef}; use crate::Peripheral; +/// Gain +#[allow(missing_docs)] #[derive(Clone, Copy)] pub enum OpAmpGain { Mul1, @@ -13,6 +16,8 @@ pub enum OpAmpGain { Mul16, } +/// Speed +#[allow(missing_docs)] #[derive(Clone, Copy)] pub enum OpAmpSpeed { Normal, @@ -180,6 +185,7 @@ impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> { } } +/// Opamp instance trait. pub trait Instance: sealed::Instance + 'static {} pub(crate) mod sealed { @@ -198,8 +204,11 @@ pub(crate) mod sealed { pub trait OutputPin {} } +/// Non-inverting pin trait. pub trait NonInvertingPin: sealed::NonInvertingPin {} +/// Inverting pin trait. pub trait InvertingPin: sealed::InvertingPin {} +/// Output pin trait. pub trait OutputPin: sealed::OutputPin {} macro_rules! impl_opamp_external_output { diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index 6ee89a922..ca641f352 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs @@ -80,6 +80,7 @@ impl<'d, T: Instance> Rng<'d, T> { let _ = self.next_u32(); } + /// Reset the RNG. #[cfg(not(rng_v1))] pub fn reset(&mut self) { T::regs().cr().write(|reg| { diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index ab142053a..10006baff 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -293,6 +293,7 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma = NoDma> { #[cfg(sdmmc_v1)] impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { + /// Create a new SDMMC driver, with 1 data lane. pub fn new_1bit( sdmmc: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, @@ -327,6 +328,7 @@ impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { ) } + /// Create a new SDMMC driver, with 4 data lanes. pub fn new_4bit( sdmmc: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs index d0b289462..4debd4e54 100644 --- a/embassy-stm32/src/usb/mod.rs +++ b/embassy-stm32/src/usb/mod.rs @@ -1,3 +1,5 @@ +//! Universal Serial Bus (USB) + use crate::interrupt; use crate::rcc::RccPeripheral; @@ -10,7 +12,9 @@ pub(crate) mod sealed { } } +/// USB instance trait. pub trait Instance: sealed::Instance + RccPeripheral + 'static { + /// Interrupt for this USB instance. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 295dc9198..a8aebfe1f 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -244,6 +244,7 @@ struct EndpointData { used_out: bool, } +/// USB driver. pub struct Driver<'d, T: Instance> { phantom: PhantomData<&'d mut T>, alloc: [EndpointData; EP_COUNT], @@ -251,6 +252,7 @@ pub struct Driver<'d, T: Instance> { } impl<'d, T: Instance> Driver<'d, T> { + /// Create a new USB driver. pub fn new( _usb: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, @@ -465,6 +467,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { } } +/// USB bus. pub struct Bus<'d, T: Instance> { phantom: PhantomData<&'d mut T>, ep_types: [EpType; EP_COUNT - 1], @@ -640,6 +643,7 @@ trait Dir { fn waker(i: usize) -> &'static AtomicWaker; } +/// Marker type for the "IN" direction. pub enum In {} impl Dir for In { fn dir() -> Direction { @@ -652,6 +656,7 @@ impl Dir for In { } } +/// Marker type for the "OUT" direction. pub enum Out {} impl Dir for Out { fn dir() -> Direction { @@ -664,6 +669,7 @@ impl Dir for Out { } } +/// USB endpoint. pub struct Endpoint<'d, T: Instance, D> { _phantom: PhantomData<(&'d mut T, D)>, info: EndpointInfo, @@ -813,6 +819,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { } } +/// USB control pipe. pub struct ControlPipe<'d, T: Instance> { _phantom: PhantomData<&'d mut T>, max_packet_size: u16, diff --git a/embassy-stm32/src/usb_otg/mod.rs b/embassy-stm32/src/usb_otg/mod.rs index 1abd031dd..0649e684b 100644 --- a/embassy-stm32/src/usb_otg/mod.rs +++ b/embassy-stm32/src/usb_otg/mod.rs @@ -20,7 +20,9 @@ pub(crate) mod sealed { } } +/// USB OTG instance. pub trait Instance: sealed::Instance + RccPeripheral { + /// Interrupt for this USB OTG instance. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs index ba77bfb16..190fb274f 100644 --- a/embassy-stm32/src/usb_otg/usb.rs +++ b/embassy-stm32/src/usb_otg/usb.rs @@ -204,6 +204,7 @@ pub enum PhyType { } impl PhyType { + /// Get whether this PHY is any of the internal types. pub fn internal(&self) -> bool { match self { PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true, @@ -211,6 +212,7 @@ impl PhyType { } } + /// Get whether this PHY is any of the high-speed types. pub fn high_speed(&self) -> bool { match self { PhyType::InternalFullSpeed => false, @@ -218,7 +220,7 @@ impl PhyType { } } - pub fn to_dspd(&self) -> vals::Dspd { + fn to_dspd(&self) -> vals::Dspd { match self { PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL, PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED, @@ -230,6 +232,7 @@ impl PhyType { /// Indicates that [State::ep_out_buffers] is empty. const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX; +/// USB OTG driver state. pub struct State { /// Holds received SETUP packets. Available if [State::ep0_setup_ready] is true. ep0_setup_data: UnsafeCell<[u8; 8]>, @@ -247,6 +250,7 @@ unsafe impl Send for State {} unsafe impl Sync for State {} impl State { + /// Create a new State. pub const fn new() -> Self { const NEW_AW: AtomicWaker = AtomicWaker::new(); const NEW_BUF: UnsafeCell<*mut u8> = UnsafeCell::new(0 as _); @@ -271,6 +275,7 @@ struct EndpointData { fifo_size_words: u16, } +/// USB driver config. #[non_exhaustive] #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct Config { @@ -297,6 +302,7 @@ impl Default for Config { } } +/// USB driver. pub struct Driver<'d, T: Instance> { config: Config, phantom: PhantomData<&'d mut T>, @@ -527,6 +533,7 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> { } } +/// USB bus. pub struct Bus<'d, T: Instance> { config: Config, phantom: PhantomData<&'d mut T>, @@ -1092,6 +1099,7 @@ trait Dir { fn dir() -> Direction; } +/// Marker type for the "IN" direction. pub enum In {} impl Dir for In { fn dir() -> Direction { @@ -1099,6 +1107,7 @@ impl Dir for In { } } +/// Marker type for the "OUT" direction. pub enum Out {} impl Dir for Out { fn dir() -> Direction { @@ -1106,6 +1115,7 @@ impl Dir for Out { } } +/// USB endpoint. pub struct Endpoint<'d, T: Instance, D> { _phantom: PhantomData<(&'d mut T, D)>, info: EndpointInfo, @@ -1299,6 +1309,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> { } } +/// USB control pipe. pub struct ControlPipe<'d, T: Instance> { _phantom: PhantomData<&'d mut T>, max_packet_size: u16, diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs index 5751a9ff3..dc701ef64 100644 --- a/embassy-stm32/src/wdg/mod.rs +++ b/embassy-stm32/src/wdg/mod.rs @@ -6,6 +6,7 @@ use stm32_metapac::iwdg::vals::{Key, Pr}; use crate::rcc::LSI_FREQ; +/// Independent watchdog (IWDG) driver. pub struct IndependentWatchdog<'d, T: Instance> { wdg: PhantomData<&'d mut T>, } @@ -64,10 +65,12 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> { IndependentWatchdog { wdg: PhantomData } } + /// Unleash (start) the watchdog. pub fn unleash(&mut self) { T::regs().kr().write(|w| w.set_key(Key::START)); } + /// Pet (reload, refresh) the watchdog. pub fn pet(&mut self) { T::regs().kr().write(|w| w.set_key(Key::RESET)); } @@ -79,6 +82,7 @@ mod sealed { } } +/// IWDG instance trait. pub trait Instance: sealed::Instance {} foreach_peripheral!(