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!(