From 80c9d04bbd83367340a4f3a1e991df825a0b6029 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 17 Dec 2023 22:09:14 +0100 Subject: [PATCH] stm32: add some docs. --- embassy-nrf/src/gpio.rs | 25 ++++---- embassy-stm32/src/adc/mod.rs | 6 ++ embassy-stm32/src/adc/resolution.rs | 7 +++ embassy-stm32/src/adc/v4.rs | 11 ++++ embassy-stm32/src/can/fdcan.rs | 15 +---- embassy-stm32/src/crc/v2v3.rs | 13 ++++ embassy-stm32/src/dac/mod.rs | 21 ++++--- embassy-stm32/src/dac/tsel.rs | 2 + embassy-stm32/src/dcmi.rs | 24 +++++++- embassy-stm32/src/dma/bdma.rs | 62 ++++++++++++++++--- embassy-stm32/src/dma/dma.rs | 79 ++++++++++++++++++++++-- embassy-stm32/src/dma/dmamux.rs | 4 ++ embassy-stm32/src/dma/mod.rs | 7 +++ embassy-stm32/src/dma/word.rs | 10 +++ embassy-stm32/src/eth/generic_smi.rs | 1 + embassy-stm32/src/eth/mod.rs | 25 +++++++- embassy-stm32/src/eth/v2/mod.rs | 3 + embassy-stm32/src/exti.rs | 50 ++++++++++++--- embassy-stm32/src/flash/asynch.rs | 2 +- embassy-stm32/src/flash/common.rs | 33 +++++++++- embassy-stm32/src/flash/f0.rs | 4 +- embassy-stm32/src/flash/f3.rs | 4 +- embassy-stm32/src/flash/f7.rs | 4 +- embassy-stm32/src/flash/g.rs | 4 +- embassy-stm32/src/flash/h7.rs | 4 +- embassy-stm32/src/flash/l.rs | 4 +- embassy-stm32/src/flash/mod.rs | 76 +++++++++++++++++------ embassy-stm32/src/flash/other.rs | 4 +- embassy-stm32/src/gpio.rs | 81 ++++++++++++++++++++++--- embassy-stm32/src/i2c/mod.rs | 14 ++++- embassy-stm32/src/qspi/enums.rs | 41 ++++++++++--- embassy-stm32/src/qspi/mod.rs | 4 +- embassy-stm32/src/sai/mod.rs | 4 +- embassy-stm32/src/traits.rs | 6 ++ embassy-stm32/src/usart/ringbuffered.rs | 2 +- examples/stm32f4/src/bin/flash.rs | 6 +- examples/stm32f4/src/bin/flash_async.rs | 6 +- 37 files changed, 544 insertions(+), 124 deletions(-) diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 85977a80..a47fb835 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -50,19 +50,19 @@ impl<'d, T: Pin> Input<'d, T> { Self { pin } } - /// Test if current pin level is high. + /// Get whether the pin input level is high. #[inline] pub fn is_high(&mut self) -> bool { self.pin.is_high() } - /// Test if current pin level is low. + /// Get whether the pin input level is low. #[inline] pub fn is_low(&mut self) -> bool { self.pin.is_low() } - /// Returns current pin level + /// Get the pin input level. #[inline] pub fn get_level(&mut self) -> Level { self.pin.get_level() @@ -158,19 +158,19 @@ impl<'d, T: Pin> Output<'d, T> { self.pin.set_level(level) } - /// Is the output pin set as high? + /// Get whether the output level is set to high. #[inline] pub fn is_set_high(&mut self) -> bool { self.pin.is_set_high() } - /// Is the output pin set as low? + /// Get whether the output level is set to low. #[inline] pub fn is_set_low(&mut self) -> bool { self.pin.is_set_low() } - /// What level output is set to + /// Get the current output level. #[inline] pub fn get_output_level(&mut self) -> Level { self.pin.get_output_level() @@ -275,13 +275,13 @@ impl<'d, T: Pin> Flex<'d, T> { self.pin.conf().reset(); } - /// Test if current pin level is high. + /// Get whether the pin input level is high. #[inline] pub fn is_high(&mut self) -> bool { !self.is_low() } - /// Test if current pin level is low. + /// Get whether the pin input level is low. #[inline] pub fn is_low(&mut self) -> bool { self.ref_is_low() @@ -292,7 +292,7 @@ impl<'d, T: Pin> Flex<'d, T> { self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0 } - /// Returns current pin level + /// Get the pin input level. #[inline] pub fn get_level(&mut self) -> Level { self.is_high().into() @@ -319,25 +319,24 @@ impl<'d, T: Pin> Flex<'d, T> { } } - /// Is the output pin set as high? + /// Get whether the output level is set to high. #[inline] pub fn is_set_high(&mut self) -> bool { !self.is_set_low() } - /// Is the output pin set as low? + /// Get whether the output level is set to low. #[inline] pub fn is_set_low(&mut self) -> bool { self.ref_is_set_low() } - /// Is the output pin set as low? #[inline] pub(crate) fn ref_is_set_low(&self) -> bool { self.pin.block().out.read().bits() & (1 << self.pin.pin()) == 0 } - /// What level output is set to + /// Get the current output level. #[inline] pub fn get_output_level(&mut self) -> Level { self.is_set_high().into() diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index dbe53c80..2e470662 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -1,3 +1,4 @@ +//! Analog to Digital (ADC) converter driver. #![macro_use] #[cfg(not(adc_f3_v2))] @@ -24,6 +25,7 @@ pub use sample_time::SampleTime; use crate::peripherals; +/// Analog to Digital driver. pub struct Adc<'d, T: Instance> { #[allow(unused)] adc: crate::PeripheralRef<'d, T>, @@ -75,12 +77,16 @@ pub(crate) mod sealed { } } +/// ADC instance. #[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))] pub trait Instance: sealed::Instance + crate::Peripheral

{} +/// ADC instance. #[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))] pub trait Instance: sealed::Instance + crate::Peripheral

+ crate::rcc::RccPeripheral {} +/// ADC pin. pub trait AdcPin: sealed::AdcPin {} +/// ADC internal channel. pub trait InternalChannel: sealed::InternalChannel {} foreach_adc!( diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs index 383980b5..64c25a77 100644 --- a/embassy-stm32/src/adc/resolution.rs +++ b/embassy-stm32/src/adc/resolution.rs @@ -1,3 +1,5 @@ +/// ADC resolution +#[allow(missing_docs)] #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -8,6 +10,8 @@ pub enum Resolution { SixBit, } +/// ADC resolution +#[allow(missing_docs)] #[cfg(adc_v4)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -49,6 +53,9 @@ impl From for crate::pac::adc::vals::Res { } impl Resolution { + /// Get the maximum reading value for this resolution. + /// + /// This is `2**n - 1`. pub fn to_max_count(&self) -> u32 { match self { #[cfg(adc_v4)] diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index d74617cb..048e7318 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -32,6 +32,7 @@ const TEMP_CHANNEL: u8 = 18; const VBAT_CHANNEL: u8 = 17; // NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs +/// Internal voltage reference channel. pub struct VrefInt; impl InternalChannel for VrefInt {} impl super::sealed::InternalChannel for VrefInt { @@ -40,6 +41,7 @@ impl super::sealed::InternalChannel for VrefInt { } } +/// Internal temperature channel. pub struct Temperature; impl InternalChannel for Temperature {} impl super::sealed::InternalChannel for Temperature { @@ -48,6 +50,7 @@ impl super::sealed::InternalChannel for Temperature { } } +/// Internal battery voltage channel. pub struct Vbat; impl InternalChannel for Vbat {} impl super::sealed::InternalChannel for Vbat { @@ -125,6 +128,7 @@ impl Prescaler { } impl<'d, T: Instance> Adc<'d, T> { + /// Create a new ADC driver. pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { embassy_hal_internal::into_ref!(adc); T::enable_and_reset(); @@ -212,6 +216,7 @@ impl<'d, T: Instance> Adc<'d, T> { }); } + /// Enable reading the voltage reference internal channel. pub fn enable_vrefint(&self) -> VrefInt { T::common_regs().ccr().modify(|reg| { reg.set_vrefen(true); @@ -220,6 +225,7 @@ impl<'d, T: Instance> Adc<'d, T> { VrefInt {} } + /// Enable reading the temperature internal channel. pub fn enable_temperature(&self) -> Temperature { T::common_regs().ccr().modify(|reg| { reg.set_vsenseen(true); @@ -228,6 +234,7 @@ impl<'d, T: Instance> Adc<'d, T> { Temperature {} } + /// Enable reading the vbat internal channel. pub fn enable_vbat(&self) -> Vbat { T::common_regs().ccr().modify(|reg| { reg.set_vbaten(true); @@ -236,10 +243,12 @@ impl<'d, T: Instance> Adc<'d, T> { Vbat {} } + /// Set the ADC sample time. pub fn set_sample_time(&mut self, sample_time: SampleTime) { self.sample_time = sample_time; } + /// Set the ADC resolution. pub fn set_resolution(&mut self, resolution: Resolution) { T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); } @@ -263,6 +272,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().dr().read().0 as u16 } + /// Read an ADC pin. pub fn read

(&mut self, pin: &mut P) -> u16 where P: AdcPin, @@ -273,6 +283,7 @@ impl<'d, T: Instance> Adc<'d, T> { self.read_channel(pin.channel()) } + /// Read an ADC internal channel. pub fn read_internal(&mut self, channel: &mut impl InternalChannel) -> u16 { self.read_channel(channel.channel()) } diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index f77788db..0cc2559c 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -1,6 +1,3 @@ -pub use bxcan; -use embassy_hal_internal::PeripheralRef; - use crate::peripherals; pub(crate) mod sealed { @@ -25,27 +22,19 @@ pub(crate) mod sealed { } pub trait Instance { - const REGISTERS: *mut bxcan::RegisterBlock; - fn regs() -> &'static crate::pac::can::Fdcan; fn state() -> &'static State; } } +/// Interruptable FDCAN instance. pub trait InterruptableInstance {} +/// FDCAN instance. pub trait Instance: sealed::Instance + InterruptableInstance + 'static {} -pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); - -unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> { - const REGISTERS: *mut bxcan::RegisterBlock = T::REGISTERS; -} - foreach_peripheral!( (can, $inst:ident) => { impl sealed::Instance for peripherals::$inst { - const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _; - fn regs() -> &'static crate::pac::can::Fdcan { &crate::pac::$inst } diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs index b36f6018..0c4ae55c 100644 --- a/embassy-stm32/src/crc/v2v3.rs +++ b/embassy-stm32/src/crc/v2v3.rs @@ -6,15 +6,19 @@ use crate::peripherals::CRC; use crate::rcc::sealed::RccPeripheral; use crate::Peripheral; +/// CRC driver. pub struct Crc<'d> { _peripheral: PeripheralRef<'d, CRC>, _config: Config, } +/// CRC configuration errlr pub enum ConfigError { + /// The selected polynomial is invalid. InvalidPolynomial, } +/// CRC configuration pub struct Config { reverse_in: InputReverseConfig, reverse_out: bool, @@ -25,14 +29,20 @@ pub struct Config { crc_poly: u32, } +/// Input reverse configuration. pub enum InputReverseConfig { + /// Don't reverse anything None, + /// Reverse bytes Byte, + /// Reverse 16-bit halfwords. Halfword, + /// Reverse 32-bit words. Word, } impl Config { + /// Create a new CRC config. pub fn new( reverse_in: InputReverseConfig, reverse_out: bool, @@ -57,7 +67,9 @@ impl Config { } } +/// Polynomial size #[cfg(crc_v3)] +#[allow(missing_docs)] pub enum PolySize { Width7, Width8, @@ -81,6 +93,7 @@ impl<'d> Crc<'d> { instance } + /// Reset the CRC engine. pub fn reset(&mut self) { PAC_CRC.cr().modify(|w| w.set_reset(true)); } diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 500eac4c..9c670195 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -62,11 +62,11 @@ impl Mode { /// /// 12-bit values outside the permitted range are silently truncated. pub enum Value { - // 8 bit value + /// 8 bit value Bit8(u8), - // 12 bit value stored in a u16, left-aligned + /// 12 bit value stored in a u16, left-aligned Bit12Left(u16), - // 12 bit value stored in a u16, right-aligned + /// 12 bit value stored in a u16, right-aligned Bit12Right(u16), } @@ -76,11 +76,11 @@ pub enum Value { /// /// 12-bit values outside the permitted range are silently truncated. pub enum DualValue { - // 8 bit value + /// 8 bit value Bit8(u8, u8), - // 12 bit value stored in a u16, left-aligned + /// 12 bit value stored in a u16, left-aligned Bit12Left(u16, u16), - // 12 bit value stored in a u16, right-aligned + /// 12 bit value stored in a u16, right-aligned Bit12Right(u16, u16), } @@ -88,11 +88,11 @@ pub enum DualValue { #[cfg_attr(feature = "defmt", derive(defmt::Format))] /// Array variant of [`Value`]. pub enum ValueArray<'a> { - // 8 bit values + /// 8 bit values Bit8(&'a [u8]), - // 12 bit value stored in a u16, left-aligned + /// 12 bit value stored in a u16, left-aligned Bit12Left(&'a [u16]), - // 12 bit values stored in a u16, right-aligned + /// 12 bit values stored in a u16, right-aligned Bit12Right(&'a [u16]), } @@ -106,7 +106,9 @@ pub struct DacChannel<'d, T: Instance, const N: u8, DMA = NoDma> { dma: PeripheralRef<'d, DMA>, } +/// DAC channel 1 type alias. pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>; +/// DAC channel 2 type alias. pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, 2, DMA>; impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { @@ -492,6 +494,7 @@ pub(crate) mod sealed { } } +/// DAC instance. pub trait Instance: sealed::Instance + RccPeripheral + 'static {} dma_trait!(DacDma1, Instance); dma_trait!(DacDma2, Instance); diff --git a/embassy-stm32/src/dac/tsel.rs b/embassy-stm32/src/dac/tsel.rs index f38dd8fd..22d8d3df 100644 --- a/embassy-stm32/src/dac/tsel.rs +++ b/embassy-stm32/src/dac/tsel.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + /// Trigger selection for STM32F0. #[cfg(stm32f0)] #[derive(Debug, Copy, Clone, Eq, PartialEq)] diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs index b1223079..139d8fd1 100644 --- a/embassy-stm32/src/dcmi.rs +++ b/embassy-stm32/src/dcmi.rs @@ -36,6 +36,7 @@ impl interrupt::typelevel::Handler for InterruptHandl } /// The level on the VSync pin when the data is not valid on the parallel interface. +#[allow(missing_docs)] #[derive(Clone, Copy, PartialEq)] pub enum VSyncDataInvalidLevel { Low, @@ -43,6 +44,7 @@ pub enum VSyncDataInvalidLevel { } /// The level on the VSync pin when the data is not valid on the parallel interface. +#[allow(missing_docs)] #[derive(Clone, Copy, PartialEq)] pub enum HSyncDataInvalidLevel { Low, @@ -50,14 +52,16 @@ pub enum HSyncDataInvalidLevel { } #[derive(Clone, Copy, PartialEq)] +#[allow(missing_docs)] pub enum PixelClockPolarity { RisingEdge, FallingEdge, } -pub struct State { +struct State { waker: AtomicWaker, } + impl State { const fn new() -> State { State { @@ -68,18 +72,25 @@ impl State { static STATE: State = State::new(); +/// DCMI error. #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub enum Error { + /// Overrun error: the hardware generated data faster than we could read it. Overrun, + /// Internal peripheral error. PeripheralError, } +/// DCMI configuration. #[non_exhaustive] pub struct Config { + /// VSYNC level. pub vsync_level: VSyncDataInvalidLevel, + /// HSYNC level. pub hsync_level: HSyncDataInvalidLevel, + /// PIXCLK polarity. pub pixclk_polarity: PixelClockPolarity, } @@ -105,6 +116,7 @@ macro_rules! config_pins { }; } +/// DCMI driver. pub struct Dcmi<'d, T: Instance, Dma: FrameDma> { inner: PeripheralRef<'d, T>, dma: PeripheralRef<'d, Dma>, @@ -115,6 +127,7 @@ where T: Instance, Dma: FrameDma, { + /// Create a new DCMI driver with 8 data bits. pub fn new_8bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, @@ -139,6 +152,7 @@ where Self::new_inner(peri, dma, config, false, 0b00) } + /// Create a new DCMI driver with 10 data bits. pub fn new_10bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, @@ -165,6 +179,7 @@ where Self::new_inner(peri, dma, config, false, 0b01) } + /// Create a new DCMI driver with 12 data bits. pub fn new_12bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, @@ -193,6 +208,7 @@ where Self::new_inner(peri, dma, config, false, 0b10) } + /// Create a new DCMI driver with 14 data bits. pub fn new_14bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, @@ -223,6 +239,7 @@ where Self::new_inner(peri, dma, config, false, 0b11) } + /// Create a new DCMI driver with 8 data bits, with embedded synchronization. pub fn new_es_8bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, @@ -245,6 +262,7 @@ where Self::new_inner(peri, dma, config, true, 0b00) } + /// Create a new DCMI driver with 10 data bits, with embedded synchronization. pub fn new_es_10bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, @@ -269,6 +287,7 @@ where Self::new_inner(peri, dma, config, true, 0b01) } + /// Create a new DCMI driver with 12 data bits, with embedded synchronization. pub fn new_es_12bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, @@ -295,6 +314,7 @@ where Self::new_inner(peri, dma, config, true, 0b10) } + /// Create a new DCMI driver with 14 data bits, with embedded synchronization. pub fn new_es_14bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, @@ -538,7 +558,9 @@ mod sealed { } } +/// DCMI instance. pub trait Instance: sealed::Instance + 'static { + /// Interrupt for this instance. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index a7422f66..5102330c 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -1,4 +1,4 @@ -#![macro_use] +//! Basic Direct Memory Acccess (BDMA) use core::future::Future; use core::pin::Pin; @@ -17,6 +17,7 @@ use crate::interrupt::Priority; use crate::pac; use crate::pac::bdma::{regs, vals}; +/// BDMA transfer options. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] @@ -140,13 +141,17 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index STATE.ch_wakers[index].wake(); } +/// DMA request type alias. #[cfg(any(bdma_v2, dmamux))] pub type Request = u8; +/// DMA request type alias. #[cfg(not(any(bdma_v2, dmamux)))] pub type Request = (); +/// 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 {} @@ -161,12 +166,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, @@ -177,6 +184,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, @@ -202,6 +210,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, @@ -212,6 +221,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, @@ -237,6 +247,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, @@ -321,6 +332,9 @@ impl<'a, C: Channel> Transfer<'a, C> { }); } + /// 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()); @@ -331,6 +345,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 en = ch.cr().read().en(); @@ -339,13 +357,15 @@ impl<'a, C: Channel> Transfer<'a, C> { en && (circular || !tcif) } - /// Gets the total remaining transfers for the channel - /// Note: this will be zero for transfers that completed without cancellation. + /// Get the total remaining transfers for the channel. + /// + /// This will be zero for transfers that completed instead of being canceled with [`request_stop`](Self::request_stop). pub fn get_remaining_transfers(&self) -> u16 { let ch = self.channel.regs().ch(self.channel.num()); ch.ndtr().read().ndt() } + /// Blocking wait until the transfer finishes. pub fn blocking_wait(mut self) { while self.is_running() {} self.request_stop(); @@ -411,6 +431,7 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { } } +/// Ringbuffer for reading data using DMA circular mode. pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { cr: regs::Cr, channel: PeripheralRef<'a, C>, @@ -418,7 +439,8 @@ pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { } impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { - pub unsafe fn new_read( + /// Create a new ring buffer. + pub unsafe fn new( channel: impl Peripheral

+ 'a, _request: Request, peri_addr: *mut W, @@ -473,11 +495,15 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { this } + /// Start the ring buffer operation. + /// + /// You must call this after creating it for it to work. pub fn start(&mut self) { let ch = self.channel.regs().ch(self.channel.num()); ch.cr().write_value(self.cr) } + /// Clear all data in the ring buffer. pub fn clear(&mut self) { self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); } @@ -509,10 +535,11 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { } /// The capacity of the ringbuffer. - pub const fn cap(&self) -> usize { + pub const fn capacity(&self) -> usize { self.ringbuf.cap() } + /// Set a waker to be woken when at least one byte is received. pub fn set_waker(&mut self, waker: &Waker) { DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); } @@ -526,6 +553,9 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { }); } + /// Request DMA 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()); @@ -539,6 +569,10 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { }); } + /// Return whether DMA 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()); ch.cr().read().en() @@ -555,6 +589,7 @@ impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> { } } +/// Ringbuffer for writing data using DMA circular mode. pub struct WritableRingBuffer<'a, C: Channel, W: Word> { cr: regs::Cr, channel: PeripheralRef<'a, C>, @@ -562,7 +597,8 @@ pub struct WritableRingBuffer<'a, C: Channel, W: Word> { } impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { - pub unsafe fn new_write( + /// Create a new ring buffer. + pub unsafe fn new( channel: impl Peripheral

+ 'a, _request: Request, peri_addr: *mut W, @@ -617,11 +653,15 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { this } + /// Start the ring buffer operation. + /// + /// You must call this after creating it for it to work. pub fn start(&mut self) { let ch = self.channel.regs().ch(self.channel.num()); ch.cr().write_value(self.cr) } + /// Clear all data in the ring buffer. pub fn clear(&mut self) { self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); } @@ -640,10 +680,11 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { } /// The capacity of the ringbuffer. - pub const fn cap(&self) -> usize { + pub const fn capacity(&self) -> usize { self.ringbuf.cap() } + /// Set a waker to be woken when at least one byte is sent. pub fn set_waker(&mut self, waker: &Waker) { DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); } @@ -657,6 +698,9 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { }); } + /// Request DMA 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()); @@ -670,6 +714,10 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { }); } + /// Return whether DMA 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()); ch.cr().read().en() diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index cce0407c..64e492c1 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -16,6 +16,7 @@ use crate::interrupt::Priority; use crate::pac::dma::{regs, vals}; use crate::{interrupt, pac}; +/// DMA transfer options. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] @@ -69,6 +70,7 @@ impl From

for vals::Dir { } } +/// DMA transfer burst setting. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Burst { @@ -93,6 +95,7 @@ impl From for vals::Burst { } } +/// DMA flow control setting. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum FlowControl { @@ -111,6 +114,7 @@ impl From for vals::Pfctrl { } } +/// DMA FIFO threshold. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum FifoThreshold { @@ -208,13 +212,17 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: usize, index: STATE.ch_wakers[index].wake(); } +/// DMA request type alias. (also known as DMA channel number in some chips) #[cfg(any(dma_v2, dmamux))] pub type Request = u8; +/// DMA request type alias. (also known as DMA channel number in some chips) #[cfg(not(any(dma_v2, dmamux)))] pub type Request = (); +/// 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 {} @@ -229,12 +237,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, @@ -245,6 +255,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, @@ -270,6 +281,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, @@ -280,6 +292,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, @@ -305,6 +318,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, @@ -407,6 +421,9 @@ impl<'a, C: Channel> Transfer<'a, C> { }); } + /// 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().st(self.channel.num()); @@ -417,6 +434,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().st(self.channel.num()); ch.cr().read().en() @@ -429,6 +450,7 @@ impl<'a, C: Channel> Transfer<'a, C> { ch.ndtr().read().ndt() } + /// Blocking wait until the transfer finishes. pub fn blocking_wait(mut self) { while self.is_running() {} @@ -465,12 +487,14 @@ impl<'a, C: Channel> Future for Transfer<'a, C> { // ================================== +/// Double-buffered DMA transfer. pub struct DoubleBuffered<'a, C: Channel, W: Word> { channel: PeripheralRef<'a, C>, _phantom: PhantomData, } impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { + /// Create a new read DMA transfer (peripheral to memory). pub unsafe fn new_read( channel: impl Peripheral

+ 'a, _request: Request, @@ -554,25 +578,36 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { }); } + /// Set the first buffer address. + /// + /// You may call this while DMA is transferring the other buffer. pub unsafe fn set_buffer0(&mut self, buffer: *mut W) { let ch = self.channel.regs().st(self.channel.num()); ch.m0ar().write_value(buffer as _); } + /// Set the second buffer address. + /// + /// You may call this while DMA is transferring the other buffer. pub unsafe fn set_buffer1(&mut self, buffer: *mut W) { let ch = self.channel.regs().st(self.channel.num()); ch.m1ar().write_value(buffer as _); } + /// Returh whether buffer0 is accessible (i.e. whether DMA is transferring buffer1 now) pub fn is_buffer0_accessible(&mut self) -> bool { let ch = self.channel.regs().st(self.channel.num()); ch.cr().read().ct() == vals::Ct::MEMORY1 } + /// Set a waker to be woken when one of the buffers is being transferred. pub fn set_waker(&mut self, waker: &Waker) { STATE.ch_wakers[self.channel.index()].register(waker); } + /// 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().st(self.channel.num()); @@ -583,6 +618,10 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { }); } + /// 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().st(self.channel.num()); ch.cr().read().en() @@ -629,6 +668,7 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { } } +/// Ringbuffer for receiving data using DMA circular mode. pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { cr: regs::Cr, channel: PeripheralRef<'a, C>, @@ -636,7 +676,8 @@ pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { } impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { - pub unsafe fn new_read( + /// Create a new ring buffer. + pub unsafe fn new( channel: impl Peripheral

+ 'a, _request: Request, peri_addr: *mut W, @@ -706,11 +747,15 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { this } + /// Start the ring buffer operation. + /// + /// You must call this after creating it for it to work. pub fn start(&mut self) { let ch = self.channel.regs().st(self.channel.num()); ch.cr().write_value(self.cr); } + /// Clear all data in the ring buffer. pub fn clear(&mut self) { self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); } @@ -741,11 +786,12 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { .await } - // The capacity of the ringbuffer - pub const fn cap(&self) -> usize { + /// The capacity of the ringbuffer + pub const fn capacity(&self) -> usize { self.ringbuf.cap() } + /// Set a waker to be woken when at least one byte is received. pub fn set_waker(&mut self, waker: &Waker) { DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); } @@ -763,6 +809,9 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { }); } + /// Request DMA 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().st(self.channel.num()); @@ -774,6 +823,10 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { }); } + /// Return whether DMA 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().st(self.channel.num()); ch.cr().read().en() @@ -790,6 +843,7 @@ impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> { } } +/// Ringbuffer for writing data using DMA circular mode. pub struct WritableRingBuffer<'a, C: Channel, W: Word> { cr: regs::Cr, channel: PeripheralRef<'a, C>, @@ -797,7 +851,8 @@ pub struct WritableRingBuffer<'a, C: Channel, W: Word> { } impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { - pub unsafe fn new_write( + /// Create a new ring buffer. + pub unsafe fn new( channel: impl Peripheral

+ 'a, _request: Request, peri_addr: *mut W, @@ -867,11 +922,15 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { this } + /// Start the ring buffer operation. + /// + /// You must call this after creating it for it to work. pub fn start(&mut self) { let ch = self.channel.regs().st(self.channel.num()); ch.cr().write_value(self.cr); } + /// Clear all data in the ring buffer. pub fn clear(&mut self) { self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); } @@ -889,11 +948,12 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { .await } - // The capacity of the ringbuffer - pub const fn cap(&self) -> usize { + /// The capacity of the ringbuffer + pub const fn capacity(&self) -> usize { self.ringbuf.cap() } + /// Set a waker to be woken when at least one byte is received. pub fn set_waker(&mut self, waker: &Waker) { DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); } @@ -911,6 +971,9 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { }); } + /// Request DMA 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().st(self.channel.num()); @@ -922,6 +985,10 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { }); } + /// Return whether DMA 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().st(self.channel.num()); ch.cr().read().en() diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs index 20601dc8..9cd49472 100644 --- a/embassy-stm32/src/dma/dmamux.rs +++ b/embassy-stm32/src/dma/dmamux.rs @@ -22,11 +22,15 @@ pub(crate) mod dmamux_sealed { } } +/// DMAMUX1 instance. pub struct DMAMUX1; +/// DMAMUX2 instance. #[cfg(stm32h7)] pub struct DMAMUX2; +/// DMAMUX channel trait. pub trait MuxChannel: dmamux_sealed::MuxChannel { + /// DMAMUX instance this channel is on. type Mux; } diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 29fced8f..fb40a4b5 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -39,6 +39,13 @@ enum Dir { PeripheralToMemory, } +/// "No DMA" placeholder. +/// +/// You may pass this in place of a real DMA channel when creating a driver +/// to indicate it should not use DMA. +/// +/// This often causes async functionality to not be available on the instance, +/// leaving only blocking functionality. pub struct NoDma; impl_peripheral!(NoDma); diff --git a/embassy-stm32/src/dma/word.rs b/embassy-stm32/src/dma/word.rs index aef6e970..a72c4b7d 100644 --- a/embassy-stm32/src/dma/word.rs +++ b/embassy-stm32/src/dma/word.rs @@ -1,3 +1,6 @@ +//! DMA word sizes. + +#[allow(missing_docs)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum WordSize { @@ -7,6 +10,7 @@ pub enum WordSize { } impl WordSize { + /// Amount of bytes of this word size. pub fn bytes(&self) -> usize { match self { Self::OneByte => 1, @@ -20,8 +24,13 @@ mod sealed { pub trait Word {} } +/// DMA word trait. +/// +/// This is implemented for u8, u16, u32, etc. pub trait Word: sealed::Word + Default + Copy + 'static { + /// Word size fn size() -> WordSize; + /// Amount of bits of this word size. fn bits() -> usize; } @@ -40,6 +49,7 @@ macro_rules! impl_word { ($T:ident, $uX:ident, $bits:literal, $size:ident) => { #[repr(transparent)] #[derive(Copy, Clone, Default)] + #[doc = concat!(stringify!($T), " word size")] pub struct $T(pub $uX); impl_word!(_, $T, $bits, $size); }; diff --git a/embassy-stm32/src/eth/generic_smi.rs b/embassy-stm32/src/eth/generic_smi.rs index 1e1094a1..9c26e90f 100644 --- a/embassy-stm32/src/eth/generic_smi.rs +++ b/embassy-stm32/src/eth/generic_smi.rs @@ -102,6 +102,7 @@ unsafe impl PHY for GenericSMI { /// Public functions for the PHY impl GenericSMI { + /// Set the SMI polling interval. #[cfg(feature = "time")] pub fn set_poll_interval(&mut self, poll_interval: Duration) { self.poll_interval = poll_interval diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index 556aadd7..dbf91eed 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs @@ -22,6 +22,14 @@ const RX_BUFFER_SIZE: usize = 1536; #[derive(Copy, Clone)] pub(crate) struct Packet([u8; N]); +/// Ethernet packet queue. +/// +/// This struct owns the memory used for reading and writing packets. +/// +/// `TX` is the number of packets in the transmit queue, `RX` in the receive +/// queue. A bigger queue allows the hardware to receive more packets while the +/// CPU is busy doing other things, which may increase performance (especially for RX) +/// at the cost of more RAM usage. pub struct PacketQueue { tx_desc: [TDes; TX], rx_desc: [RDes; RX], @@ -30,6 +38,7 @@ pub struct PacketQueue { } impl PacketQueue { + /// Create a new packet queue. pub const fn new() -> Self { const NEW_TDES: TDes = TDes::new(); const NEW_RDES: RDes = RDes::new(); @@ -41,7 +50,18 @@ impl PacketQueue { } } - // Allow to initialize a Self without requiring it to go on the stack + /// Initialize a packet queue in-place. + /// + /// This can be helpful to avoid accidentally stack-allocating the packet queue in the stack. The + /// Rust compiler can sometimes be a bit dumb when working with large owned values: if you call `new()` + /// and then store the returned PacketQueue in its final place (like a `static`), the compiler might + /// place it temporarily on the stack then move it. Since this struct is quite big, it may result + /// in a stack overflow. + /// + /// With this function, you can create an uninitialized `static` with type `MaybeUninit>` + /// and initialize it in-place, guaranteeing no stack usage. + /// + /// After calling this function, calling `assume_init` on the MaybeUninit is guaranteed safe. pub fn init(this: &mut MaybeUninit) { unsafe { this.as_mut_ptr().write_bytes(0u8, 1); @@ -93,6 +113,7 @@ impl<'d, T: Instance, P: PHY> embassy_net_driver::Driver for Ethernet<'d, T, P> } } +/// `embassy-net` RX token. pub struct RxToken<'a, 'd> { rx: &'a mut RDesRing<'d>, } @@ -110,6 +131,7 @@ impl<'a, 'd> embassy_net_driver::RxToken for RxToken<'a, 'd> { } } +/// `embassy-net` TX token. pub struct TxToken<'a, 'd> { tx: &'a mut TDesRing<'d>, } @@ -159,6 +181,7 @@ pub(crate) mod sealed { } } +/// Ethernet instance. pub trait Instance: sealed::Instance + Send + 'static {} impl sealed::Instance for crate::peripherals::ETH { diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index c77155fe..59745cba 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -34,6 +34,7 @@ impl interrupt::typelevel::Handler for InterruptHandl } } +/// Ethernet driver. pub struct Ethernet<'d, T: Instance, P: PHY> { _peri: PeripheralRef<'d, T>, pub(crate) tx: TDesRing<'d>, @@ -56,6 +57,7 @@ macro_rules! config_pins { } impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { + /// Create a new Ethernet driver. pub fn new( queue: &'d mut PacketQueue, peri: impl Peripheral

+ 'd, @@ -237,6 +239,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { } } +/// Ethernet SMI driver. pub struct EthernetStationManagement { peri: PhantomData, clock_range: u8, diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index e77ac30f..371be913 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -39,7 +39,7 @@ fn exticr_regs() -> pac::afio::Afio { pac::AFIO } -pub unsafe fn on_irq() { +unsafe fn on_irq() { #[cfg(feature = "low-power")] crate::low_power::on_wakeup_irq(); @@ -85,7 +85,13 @@ impl Iterator for BitIter { } } -/// EXTI input driver +/// EXTI input driver. +/// +/// This driver augments a GPIO `Input` with EXTI functionality. EXTI is not +/// built into `Input` itself because it needs to take ownership of the corresponding +/// EXTI channel, which is a limited resource. +/// +/// Pins PA5, PB5, PC5... all use EXTI channel 5, so you can't use EXTI on, say, PA5 and PC5 at the same time. pub struct ExtiInput<'d, T: GpioPin> { pin: Input<'d, T>, } @@ -93,23 +99,30 @@ pub struct ExtiInput<'d, T: GpioPin> { impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {} impl<'d, T: GpioPin> ExtiInput<'d, T> { + /// Create an EXTI input. pub fn new(pin: Input<'d, T>, _ch: impl Peripheral

+ 'd) -> Self { Self { pin } } + /// Get whether the pin is high. pub fn is_high(&mut self) -> bool { self.pin.is_high() } + /// Get whether the pin is low. pub fn is_low(&mut self) -> bool { self.pin.is_low() } + /// Get the pin level. pub fn get_level(&mut self) -> Level { self.pin.get_level() } - pub async fn wait_for_high<'a>(&'a mut self) { + /// Asynchronously wait until the pin is high. + /// + /// This returns immediately if the pin is already high. + pub async fn wait_for_high(&mut self) { let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false); if self.is_high() { return; @@ -117,7 +130,10 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> { fut.await } - pub async fn wait_for_low<'a>(&'a mut self) { + /// Asynchronously wait until the pin is low. + /// + /// This returns immediately if the pin is already low. + pub async fn wait_for_low(&mut self) { let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true); if self.is_low() { return; @@ -125,15 +141,22 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> { fut.await } - pub async fn wait_for_rising_edge<'a>(&'a mut self) { + /// Asynchronously wait until the pin sees a rising edge. + /// + /// If the pin is already high, it will wait for it to go low then back high. + pub async fn wait_for_rising_edge(&mut self) { ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false).await } - pub async fn wait_for_falling_edge<'a>(&'a mut self) { + /// Asynchronously wait until the pin sees a falling edge. + /// + /// If the pin is already low, it will wait for it to go high then back low. + pub async fn wait_for_falling_edge(&mut self) { ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true).await } - pub async fn wait_for_any_edge<'a>(&'a mut self) { + /// Asynchronously wait until the pin sees any edge (either rising or falling). + pub async fn wait_for_any_edge(&mut self) { ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true).await } } @@ -284,6 +307,7 @@ macro_rules! foreach_exti_irq { macro_rules! impl_irq { ($e:ident) => { + #[allow(non_snake_case)] #[cfg(feature = "rt")] #[interrupt] unsafe fn $e() { @@ -298,8 +322,16 @@ pub(crate) mod sealed { pub trait Channel {} } +/// EXTI channel trait. pub trait Channel: sealed::Channel + Sized { + /// Get the EXTI channel number. fn number(&self) -> usize; + + /// Type-erase (degrade) this channel into an `AnyChannel`. + /// + /// This converts EXTI channel singletons (`EXTI0`, `EXTI1`, ...), which + /// are all different types, into the same type. It is useful for + /// creating arrays of channels, or avoiding generics. fn degrade(self) -> AnyChannel { AnyChannel { number: self.number() as u8, @@ -307,9 +339,13 @@ pub trait Channel: sealed::Channel + Sized { } } +/// Type-erased (degraded) EXTI channel. +/// +/// This represents ownership over any EXTI channel, known at runtime. pub struct AnyChannel { number: u8, } + impl_peripheral!(AnyChannel); impl sealed::Channel for AnyChannel {} impl Channel for AnyChannel { diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs index eae40c7e..e3c6d4d6 100644 --- a/embassy-stm32/src/flash/asynch.rs +++ b/embassy-stm32/src/flash/asynch.rs @@ -59,7 +59,7 @@ impl embedded_storage_async::nor_flash::ReadNorFlash for Flash<'_, Async> { const READ_SIZE: usize = super::READ_SIZE; async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.read(offset, bytes) + self.blocking_read(offset, bytes) } fn capacity(&self) -> usize { diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 8acad1c7..f8561edb 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -12,12 +12,14 @@ use super::{ use crate::peripherals::FLASH; use crate::Peripheral; +/// Internal flash memory driver. pub struct Flash<'d, MODE = Async> { pub(crate) inner: PeripheralRef<'d, FLASH>, pub(crate) _mode: PhantomData, } impl<'d> Flash<'d, Blocking> { + /// Create a new flash driver, usable in blocking mode. pub fn new_blocking(p: impl Peripheral

+ 'd) -> Self { into_ref!(p); @@ -29,15 +31,26 @@ impl<'d> Flash<'d, Blocking> { } impl<'d, MODE> Flash<'d, MODE> { + /// Split this flash driver into one instance per flash memory region. + /// + /// See module-level documentation for details on how memory regions work. pub fn into_blocking_regions(self) -> FlashLayout<'d, Blocking> { assert!(family::is_default_layout()); FlashLayout::new(self.inner) } - pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { + /// Blocking read. + /// + /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. + /// For example, to read address `0x0800_1234` you have to use offset `0x1234`. + pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { blocking_read(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) } + /// Blocking write. + /// + /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. + /// For example, to write address `0x0800_1234` you have to use offset `0x1234`. pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { unsafe { blocking_write( @@ -50,6 +63,10 @@ impl<'d, MODE> Flash<'d, MODE> { } } + /// Blocking erase. + /// + /// NOTE: `from` and `to` are offsets from the flash start, NOT an absolute address. + /// For example, to erase address `0x0801_0000` you have to use offset `0x1_0000`. pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { unsafe { blocking_erase(FLASH_BASE as u32, from, to, erase_sector_unlocked) } } @@ -206,7 +223,7 @@ impl embedded_storage::nor_flash::ReadNorFlash for Flash<'_, MODE> { const READ_SIZE: usize = READ_SIZE; fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.read(offset, bytes) + self.blocking_read(offset, bytes) } fn capacity(&self) -> usize { @@ -230,16 +247,28 @@ impl embedded_storage::nor_flash::NorFlash for Flash<'_, MODE> { foreach_flash_region! { ($type_name:ident, $write_size:literal, $erase_size:literal) => { impl crate::_generated::flash_regions::$type_name<'_, MODE> { + /// Blocking read. + /// + /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. + /// For example, to read address `0x0800_1234` you have to use offset `0x1234`. pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { blocking_read(self.0.base, self.0.size, offset, bytes) } } impl crate::_generated::flash_regions::$type_name<'_, Blocking> { + /// Blocking write. + /// + /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. + /// For example, to write address `0x0800_1234` you have to use offset `0x1234`. pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { unsafe { blocking_write(self.0.base, self.0.size, offset, bytes, write_chunk_with_critical_section) } } + /// Blocking erase. + /// + /// NOTE: `from` and `to` are offsets from the flash start, NOT an absolute address. + /// For example, to erase address `0x0801_0000` you have to use offset `0x1_0000`. pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { unsafe { blocking_erase(self.0.base, from, to, erase_sector_with_critical_section) } } diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs index 80d2a816..c0a8d702 100644 --- a/embassy-stm32/src/flash/f0.rs +++ b/embassy-stm32/src/flash/f0.rs @@ -6,11 +6,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub const fn is_default_layout() -> bool { +pub(crate) const fn is_default_layout() -> bool { true } -pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs index 27d5281a..817ccef4 100644 --- a/embassy-stm32/src/flash/f3.rs +++ b/embassy-stm32/src/flash/f3.rs @@ -6,11 +6,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub const fn is_default_layout() -> bool { +pub(crate) const fn is_default_layout() -> bool { true } -pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index 017393e8..6b3e66ac 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -6,11 +6,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub const fn is_default_layout() -> bool { +pub(crate) const fn is_default_layout() -> bool { true } -pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs index 08145e9c..d97b4a93 100644 --- a/embassy-stm32/src/flash/g.rs +++ b/embassy-stm32/src/flash/g.rs @@ -8,11 +8,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub const fn is_default_layout() -> bool { +pub(crate) const fn is_default_layout() -> bool { true } -pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index 555f8d15..65d163d2 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -6,7 +6,7 @@ use super::{FlashRegion, FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub const fn is_default_layout() -> bool { +pub(crate) const fn is_default_layout() -> bool { true } @@ -14,7 +14,7 @@ const fn is_dual_bank() -> bool { FLASH_REGIONS.len() >= 2 } -pub fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub(crate) fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index e0159a3f..0b332dc6 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -5,11 +5,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub const fn is_default_layout() -> bool { +pub(crate) const fn is_default_layout() -> bool { true } -pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 3e8f2830..6b6b4d41 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -14,50 +14,84 @@ pub use crate::_generated::flash_regions::*; pub use crate::_generated::MAX_ERASE_SIZE; pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; +/// Get whether the default flash layout is being used. +/// +/// In some chips, dual-bank is not default. This will then return `false` +/// when dual-bank is enabled. +pub fn is_default_layout() -> bool { + family::is_default_layout() +} + +/// Get all flash regions. +pub fn get_flash_regions() -> &'static [&'static FlashRegion] { + family::get_flash_regions() +} + +/// Read size (always 1) pub const READ_SIZE: usize = 1; -pub struct Blocking; -pub struct Async; +/// Blocking flash mode typestate. +pub enum Blocking {} +/// Async flash mode typestate. +pub enum Async {} +/// Flash memory region #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct FlashRegion { + /// Bank number. pub bank: FlashBank, + /// Absolute base address. pub base: u32, + /// Size in bytes. pub size: u32, + /// Erase size (sector size). pub erase_size: u32, + /// Minimum write size. pub write_size: u32, + /// Erase value (usually `0xFF`, but is `0x00` in some chips) pub erase_value: u8, pub(crate) _ensure_internal: (), } -#[derive(Debug, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct FlashSector { - pub bank: FlashBank, - pub index_in_bank: u8, - pub start: u32, - pub size: u32, -} - -#[derive(Clone, Copy, Debug, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum FlashBank { - Bank1 = 0, - Bank2 = 1, - Otp, -} - impl FlashRegion { + /// Absolute end address. pub const fn end(&self) -> u32 { self.base + self.size } + /// Number of sectors in the region. pub const fn sectors(&self) -> u8 { (self.size / self.erase_size) as u8 } } +/// Flash sector. +#[derive(Debug, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct FlashSector { + /// Bank number. + pub bank: FlashBank, + /// Sector number within the bank. + pub index_in_bank: u8, + /// Absolute start address. + pub start: u32, + /// Size in bytes. + pub size: u32, +} + +/// Flash bank. +#[derive(Clone, Copy, Debug, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum FlashBank { + /// Bank 1 + Bank1 = 0, + /// Bank 2 + Bank2 = 1, + /// OTP region + Otp, +} + #[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")] #[cfg_attr(flash_f0, path = "f0.rs")] #[cfg_attr(flash_f3, path = "f3.rs")] @@ -78,6 +112,10 @@ mod family; #[allow(unused_imports)] pub use family::*; +/// Flash error +/// +/// See STM32 Reference Manual for your chip for details. +#[allow(missing_docs)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs index a7e8d1d5..20f84a72 100644 --- a/embassy-stm32/src/flash/other.rs +++ b/embassy-stm32/src/flash/other.rs @@ -2,11 +2,11 @@ use super::{Error, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; -pub const fn is_default_layout() -> bool { +pub(crate) const fn is_default_layout() -> bool { true } -pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index bb3cf2bc..083b3237 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -29,6 +29,11 @@ impl<'d, T: Pin> Flex<'d, T> { Self { pin } } + /// Type-erase (degrade) this pin into an `AnyPin`. + /// + /// This converts pin singletons (`PA5`, `PB6`, ...), which + /// are all different types, into the same type. It is useful for + /// creating arrays of pins, or avoiding generics. #[inline] pub fn degrade(self) -> Flex<'d, AnyPin> { // Safety: We are about to drop the other copy of this pin, so @@ -141,11 +146,13 @@ impl<'d, T: Pin> Flex<'d, T> { }); } + /// Get whether the pin input level is high. #[inline] pub fn is_high(&mut self) -> bool { !self.ref_is_low() } + /// Get whether the pin input level is low. #[inline] pub fn is_low(&mut self) -> bool { self.ref_is_low() @@ -157,17 +164,19 @@ impl<'d, T: Pin> Flex<'d, T> { state == vals::Idr::LOW } + /// Get the current pin input level. #[inline] pub fn get_level(&mut self) -> Level { self.is_high().into() } + /// Get whether the output level is set to high. #[inline] pub fn is_set_high(&mut self) -> bool { !self.ref_is_set_low() } - /// Is the output pin set as low? + /// Get whether the output level is set to low. #[inline] pub fn is_set_low(&mut self) -> bool { self.ref_is_set_low() @@ -179,12 +188,13 @@ impl<'d, T: Pin> Flex<'d, T> { state == vals::Odr::LOW } - /// What level output is set to + /// Get the current output level. #[inline] pub fn get_output_level(&mut self) -> Level { self.is_set_high().into() } + /// Set the output as high. #[inline] pub fn set_high(&mut self) { self.pin.set_high(); @@ -196,6 +206,7 @@ impl<'d, T: Pin> Flex<'d, T> { self.pin.set_low(); } + /// Set the output level. #[inline] pub fn set_level(&mut self, level: Level) { match level { @@ -204,7 +215,7 @@ impl<'d, T: Pin> Flex<'d, T> { } } - /// Toggle pin output + /// Toggle the output level. #[inline] pub fn toggle(&mut self) { if self.is_set_low() { @@ -242,8 +253,11 @@ impl<'d, T: Pin> Drop for Flex<'d, T> { #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Pull { + /// No pull None, + /// Pull up Up, + /// Pull down Down, } @@ -261,6 +275,9 @@ impl From for vals::Pupdr { } /// Speed settings +/// +/// These vary dpeending on the chip, ceck the reference manual or datasheet for details. +#[allow(missing_docs)] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Speed { @@ -305,6 +322,7 @@ pub struct Input<'d, T: Pin> { } impl<'d, T: Pin> Input<'d, T> { + /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration. #[inline] pub fn new(pin: impl Peripheral

+ 'd, pull: Pull) -> Self { let mut pin = Flex::new(pin); @@ -312,6 +330,11 @@ impl<'d, T: Pin> Input<'d, T> { Self { pin } } + /// Type-erase (degrade) this pin into an `AnyPin`. + /// + /// This converts pin singletons (`PA5`, `PB6`, ...), which + /// are all different types, into the same type. It is useful for + /// creating arrays of pins, or avoiding generics. #[inline] pub fn degrade(self) -> Input<'d, AnyPin> { Input { @@ -319,16 +342,19 @@ impl<'d, T: Pin> Input<'d, T> { } } + /// Get whether the pin input level is high. #[inline] pub fn is_high(&mut self) -> bool { self.pin.is_high() } + /// Get whether the pin input level is low. #[inline] pub fn is_low(&mut self) -> bool { self.pin.is_low() } + /// Get the current pin input level. #[inline] pub fn get_level(&mut self) -> Level { self.pin.get_level() @@ -339,7 +365,9 @@ impl<'d, T: Pin> Input<'d, T> { #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Level { + /// Low Low, + /// High High, } @@ -371,6 +399,7 @@ pub struct Output<'d, T: Pin> { } impl<'d, T: Pin> Output<'d, T> { + /// Create GPIO output driver for a [Pin] with the provided [Level] and [Speed] configuration. #[inline] pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level, speed: Speed) -> Self { let mut pin = Flex::new(pin); @@ -382,6 +411,11 @@ impl<'d, T: Pin> Output<'d, T> { Self { pin } } + /// Type-erase (degrade) this pin into an `AnyPin`. + /// + /// This converts pin singletons (`PA5`, `PB6`, ...), which + /// are all different types, into the same type. It is useful for + /// creating arrays of pins, or avoiding generics. #[inline] pub fn degrade(self) -> Output<'d, AnyPin> { Output { @@ -442,6 +476,7 @@ pub struct OutputOpenDrain<'d, T: Pin> { } impl<'d, T: Pin> OutputOpenDrain<'d, T> { + /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level] and [Speed], [Pull] configuration. #[inline] pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self { let mut pin = Flex::new(pin); @@ -455,6 +490,11 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { Self { pin } } + /// Type-erase (degrade) this pin into an `AnyPin`. + /// + /// This converts pin singletons (`PA5`, `PB6`, ...), which + /// are all different types, into the same type. It is useful for + /// creating arrays of pins, or avoiding generics. #[inline] pub fn degrade(self) -> Output<'d, AnyPin> { Output { @@ -462,17 +502,19 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { } } + /// Get whether the pin input level is high. #[inline] pub fn is_high(&mut self) -> bool { !self.pin.is_low() } + /// Get whether the pin input level is low. #[inline] pub fn is_low(&mut self) -> bool { self.pin.is_low() } - /// Returns current pin level + /// Get the current pin input level. #[inline] pub fn get_level(&mut self) -> Level { self.pin.get_level() @@ -496,19 +538,19 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { self.pin.set_level(level); } - /// Is the output pin set as high? + /// Get whether the output level is set to high. #[inline] pub fn is_set_high(&mut self) -> bool { self.pin.is_set_high() } - /// Is the output pin set as low? + /// Get whether the output level is set to low. #[inline] pub fn is_set_low(&mut self) -> bool { self.pin.is_set_low() } - /// What level output is set to + /// Get the current output level. #[inline] pub fn get_output_level(&mut self) -> Level { self.pin.get_output_level() @@ -521,8 +563,11 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { } } +/// GPIO output type pub enum OutputType { + /// Drive the pin both high or low. PushPull, + /// Drive the pin low, or don't drive it at all if the output level is high. OpenDrain, } @@ -535,6 +580,7 @@ impl From for sealed::AFType { } } +#[allow(missing_docs)] pub(crate) mod sealed { use super::*; @@ -542,8 +588,11 @@ pub(crate) mod sealed { #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum AFType { + /// Input Input, + /// Output, drive the pin both high or low. OutputPushPull, + /// Output, drive the pin low, or don't drive it at all if the output level is high. OutputOpenDrain, } @@ -686,7 +735,11 @@ pub(crate) mod sealed { } } +/// GPIO pin trait. pub trait Pin: Peripheral

+ Into + sealed::Pin + Sized + 'static { + /// EXTI channel assigned to this pin. + /// + /// For example, PC4 uses EXTI4. #[cfg(feature = "exti")] type ExtiChannel: crate::exti::Channel; @@ -702,7 +755,11 @@ pub trait Pin: Peripheral

+ Into + sealed::Pin + Sized + 'stat self._port() } - /// Convert from concrete pin type PX_XX to type erased `AnyPin`. + /// Type-erase (degrade) this pin into an `AnyPin`. + /// + /// This converts pin singletons (`PA5`, `PB6`, ...), which + /// are all different types, into the same type. It is useful for + /// creating arrays of pins, or avoiding generics. #[inline] fn degrade(self) -> AnyPin { AnyPin { @@ -711,12 +768,15 @@ pub trait Pin: Peripheral

+ Into + sealed::Pin + Sized + 'stat } } -// Type-erased GPIO pin +/// Type-erased GPIO pin pub struct AnyPin { pin_port: u8, } impl AnyPin { + /// Unsafely create an `AnyPin` from a pin+port number. + /// + /// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc... #[inline] pub unsafe fn steal(pin_port: u8) -> Self { Self { pin_port } @@ -727,6 +787,8 @@ impl AnyPin { self.pin_port / 16 } + /// Get the GPIO register block for this pin. + #[cfg(feature = "unstable-pac")] #[inline] pub fn block(&self) -> gpio::Gpio { pac::GPIO(self._port() as _) @@ -1072,6 +1134,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { } } +/// Low-level GPIO manipulation. #[cfg(feature = "unstable-pac")] pub mod low_level { pub use super::sealed::*; diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index d2a50cf7..a8dc8e0e 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -13,15 +13,23 @@ use embassy_sync::waitqueue::AtomicWaker; use crate::peripherals; +/// I2C error. #[derive(Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { + /// Bus error Bus, + /// Arbitration lost Arbitration, + /// ACK not received (either to the address or to a data byte) Nack, + /// Timeout Timeout, + /// CRC error Crc, + /// Overrun error Overrun, + /// Zero-length transfers are not allowed. ZeroLengthTransfer, } @@ -47,8 +55,11 @@ pub(crate) mod sealed { } } +/// I2C peripheral instance pub trait Instance: sealed::Instance + 'static { + /// Event interrupt for this instance type EventInterrupt: interrupt::typelevel::Interrupt; + /// Error interrupt for this instance type ErrorInterrupt: interrupt::typelevel::Interrupt; } @@ -57,7 +68,7 @@ pin_trait!(SdaPin, Instance); dma_trait!(RxDma, Instance); dma_trait!(TxDma, Instance); -/// Interrupt handler. +/// Event interrupt handler. pub struct EventInterruptHandler { _phantom: PhantomData, } @@ -68,6 +79,7 @@ impl interrupt::typelevel::Handler for EventInte } } +/// Error interrupt handler. pub struct ErrorInterruptHandler { _phantom: PhantomData, } diff --git a/embassy-stm32/src/qspi/enums.rs b/embassy-stm32/src/qspi/enums.rs index 0412d991..e9e7fd48 100644 --- a/embassy-stm32/src/qspi/enums.rs +++ b/embassy-stm32/src/qspi/enums.rs @@ -18,12 +18,17 @@ impl Into for QspiMode { } } +/// QSPI lane width #[allow(dead_code)] #[derive(Copy, Clone)] pub enum QspiWidth { + /// None NONE, + /// Single lane SING, + /// Dual lanes DUAL, + /// Quad lanes QUAD, } @@ -38,10 +43,13 @@ impl Into for QspiWidth { } } +/// Flash bank selection #[allow(dead_code)] #[derive(Copy, Clone)] pub enum FlashSelection { + /// Bank 1 Flash1, + /// Bank 2 Flash2, } @@ -54,6 +62,8 @@ impl Into for FlashSelection { } } +/// QSPI memory size. +#[allow(missing_docs)] #[derive(Copy, Clone)] pub enum MemorySize { _1KiB, @@ -113,11 +123,16 @@ impl Into for MemorySize { } } +/// QSPI Address size #[derive(Copy, Clone)] pub enum AddressSize { + /// 8-bit address _8Bit, + /// 16-bit address _16Bit, + /// 24-bit address _24bit, + /// 32-bit address _32bit, } @@ -132,8 +147,10 @@ impl Into for AddressSize { } } +/// Time the Chip Select line stays high. +#[allow(missing_docs)] #[derive(Copy, Clone)] -pub enum ChipSelectHightTime { +pub enum ChipSelectHighTime { _1Cycle, _2Cycle, _3Cycle, @@ -144,21 +161,23 @@ pub enum ChipSelectHightTime { _8Cycle, } -impl Into for ChipSelectHightTime { +impl Into for ChipSelectHighTime { fn into(self) -> u8 { match self { - ChipSelectHightTime::_1Cycle => 0, - ChipSelectHightTime::_2Cycle => 1, - ChipSelectHightTime::_3Cycle => 2, - ChipSelectHightTime::_4Cycle => 3, - ChipSelectHightTime::_5Cycle => 4, - ChipSelectHightTime::_6Cycle => 5, - ChipSelectHightTime::_7Cycle => 6, - ChipSelectHightTime::_8Cycle => 7, + ChipSelectHighTime::_1Cycle => 0, + ChipSelectHighTime::_2Cycle => 1, + ChipSelectHighTime::_3Cycle => 2, + ChipSelectHighTime::_4Cycle => 3, + ChipSelectHighTime::_5Cycle => 4, + ChipSelectHighTime::_6Cycle => 5, + ChipSelectHighTime::_7Cycle => 6, + ChipSelectHighTime::_8Cycle => 7, } } } +/// FIFO threshold. +#[allow(missing_docs)] #[derive(Copy, Clone)] pub enum FIFOThresholdLevel { _1Bytes, @@ -234,6 +253,8 @@ impl Into for FIFOThresholdLevel { } } +/// Dummy cycle count +#[allow(missing_docs)] #[derive(Copy, Clone)] pub enum DummyCycles { _0, diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 1153455c..bac91f30 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -54,7 +54,7 @@ pub struct Config { /// Number of bytes to trigger FIFO threshold flag. pub fifo_threshold: FIFOThresholdLevel, /// Minimum number of cycles that chip select must be high between issued commands - pub cs_high_time: ChipSelectHightTime, + pub cs_high_time: ChipSelectHighTime, } impl Default for Config { @@ -64,7 +64,7 @@ impl Default for Config { address_size: AddressSize::_24bit, prescaler: 128, fifo_threshold: FIFOThresholdLevel::_17Bytes, - cs_high_time: ChipSelectHightTime::_5Cycle, + cs_high_time: ChipSelectHighTime::_5Cycle, } } } diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index a16d38af..3d7f6599 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -583,10 +583,10 @@ fn get_ring_buffer<'d, T: Instance, C: Channel, W: word::Word>( }; match tx_rx { TxRx::Transmitter => RingBuffer::Writable(unsafe { - WritableRingBuffer::new_write(dma, request, dr(T::REGS, sub_block), dma_buf, opts) + WritableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts) }), TxRx::Receiver => RingBuffer::Readable(unsafe { - ReadableRingBuffer::new_read(dma, request, dr(T::REGS, sub_block), dma_buf, opts) + ReadableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts) }), } } diff --git a/embassy-stm32/src/traits.rs b/embassy-stm32/src/traits.rs index ffce7bd4..b4166e71 100644 --- a/embassy-stm32/src/traits.rs +++ b/embassy-stm32/src/traits.rs @@ -2,7 +2,9 @@ macro_rules! pin_trait { ($signal:ident, $instance:path) => { + #[doc = concat!(stringify!($signal), " pin trait")] pub trait $signal: crate::gpio::Pin { + #[doc = concat!("Get the AF number needed to use this pin as", stringify!($signal))] fn af_num(&self) -> u8; } }; @@ -22,7 +24,11 @@ macro_rules! pin_trait_impl { macro_rules! dma_trait { ($signal:ident, $instance:path) => { + #[doc = concat!(stringify!($signal), " DMA request trait")] pub trait $signal: crate::dma::Channel { + #[doc = concat!("Get the DMA request number needed to use this channel as", stringify!($signal))] + /// Note: in some chips, ST calls this the "channel", and calls channels "streams". + /// `embassy-stm32` always uses the "channel" and "request number" names. fn request(&self) -> crate::dma::Request; } }; diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index b8d17e4e..f8ada392 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -39,7 +39,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> UartRx<'d, T, RxDma> { let rx_dma = unsafe { self.rx_dma.clone_unchecked() }; let _peri = unsafe { self._peri.clone_unchecked() }; - let ring_buf = unsafe { ReadableRingBuffer::new_read(rx_dma, request, rdr(T::regs()), dma_buf, opts) }; + let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(T::regs()), dma_buf, opts) }; // Don't disable the clock mem::forget(self); diff --git a/examples/stm32f4/src/bin/flash.rs b/examples/stm32f4/src/bin/flash.rs index 93c54e94..56a35dde 100644 --- a/examples/stm32f4/src/bin/flash.rs +++ b/examples/stm32f4/src/bin/flash.rs @@ -31,7 +31,7 @@ fn test_flash(f: &mut Flash<'_, Blocking>, offset: u32, size: u32) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(offset, &mut buf)); + unwrap!(f.blocking_read(offset, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Erasing..."); @@ -39,7 +39,7 @@ fn test_flash(f: &mut Flash<'_, Blocking>, offset: u32, size: u32) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(offset, &mut buf)); + unwrap!(f.blocking_read(offset, &mut buf)); info!("Read after erase: {=[u8]:x}", buf); info!("Writing..."); @@ -53,7 +53,7 @@ fn test_flash(f: &mut Flash<'_, Blocking>, offset: u32, size: u32) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(offset, &mut buf)); + unwrap!(f.blocking_read(offset, &mut buf)); info!("Read: {=[u8]:x}", buf); assert_eq!( &buf[..], diff --git a/examples/stm32f4/src/bin/flash_async.rs b/examples/stm32f4/src/bin/flash_async.rs index f0a65a72..1624d842 100644 --- a/examples/stm32f4/src/bin/flash_async.rs +++ b/examples/stm32f4/src/bin/flash_async.rs @@ -48,7 +48,7 @@ async fn test_flash<'a>(f: &mut Flash<'a>, offset: u32, size: u32) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(offset, &mut buf)); + unwrap!(f.blocking_read(offset, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Erasing..."); @@ -56,7 +56,7 @@ async fn test_flash<'a>(f: &mut Flash<'a>, offset: u32, size: u32) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(offset, &mut buf)); + unwrap!(f.blocking_read(offset, &mut buf)); info!("Read after erase: {=[u8]:x}", buf); info!("Writing..."); @@ -73,7 +73,7 @@ async fn test_flash<'a>(f: &mut Flash<'a>, offset: u32, size: u32) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(offset, &mut buf)); + unwrap!(f.blocking_read(offset, &mut buf)); info!("Read: {=[u8]:x}", buf); assert_eq!( &buf[..],