From 1ea87ec6e752dca60e13731863e11d0e0f5c0492 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 19 Dec 2023 16:18:24 +0100 Subject: [PATCH] stm32: document hrtim, qspi, sdmmc, spi. --- embassy-stm32/src/hrtim/mod.rs | 59 +++++++++++++++++++++---------- embassy-stm32/src/hrtim/traits.rs | 6 +--- embassy-stm32/src/lib.rs | 24 +------------ embassy-stm32/src/qspi/enums.rs | 2 ++ embassy-stm32/src/qspi/mod.rs | 11 ++++++ embassy-stm32/src/sdmmc/mod.rs | 39 ++++++++++++++------ embassy-stm32/src/spi/mod.rs | 46 +++++++++++++++++++++++- embassy-stm32/src/time.rs | 3 ++ 8 files changed, 132 insertions(+), 58 deletions(-) diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index 6539326b..1e6626a5 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs @@ -15,38 +15,42 @@ use crate::rcc::get_freqs; use crate::time::Hertz; use crate::Peripheral; -pub enum Source { - Master, - ChA, - ChB, - ChC, - ChD, - ChE, - #[cfg(hrtim_v2)] - ChF, -} - +/// HRTIM burst controller instance. pub struct BurstController { phantom: PhantomData, } + +/// HRTIM master instance. pub struct Master { phantom: PhantomData, } + +/// HRTIM channel A instance. pub struct ChA { phantom: PhantomData, } + +/// HRTIM channel B instance. pub struct ChB { phantom: PhantomData, } + +/// HRTIM channel C instance. pub struct ChC { phantom: PhantomData, } + +/// HRTIM channel D instance. pub struct ChD { phantom: PhantomData, } + +/// HRTIM channel E instance. pub struct ChE { phantom: PhantomData, } + +/// HRTIM channel F instance. #[cfg(hrtim_v2)] pub struct ChF { phantom: PhantomData, @@ -60,13 +64,16 @@ mod sealed { } } +/// Advanced channel instance trait. pub trait AdvancedChannel: sealed::AdvancedChannel {} +/// HRTIM PWM pin. pub struct PwmPin<'d, Perip, Channel> { _pin: PeripheralRef<'d, AnyPin>, phantom: PhantomData<(Perip, Channel)>, } +/// HRTIM complementary PWM pin. pub struct ComplementaryPwmPin<'d, Perip, Channel> { _pin: PeripheralRef<'d, AnyPin>, phantom: PhantomData<(Perip, Channel)>, @@ -75,6 +82,7 @@ pub struct ComplementaryPwmPin<'d, Perip, Channel> { macro_rules! advanced_channel_impl { ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { impl<'d, Perip: Instance> PwmPin<'d, Perip, $channel> { + #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); critical_section::with(|_| { @@ -91,6 +99,7 @@ macro_rules! advanced_channel_impl { } impl<'d, Perip: Instance> ComplementaryPwmPin<'d, Perip, $channel> { + #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); critical_section::with(|_| { @@ -126,18 +135,29 @@ advanced_channel_impl!(new_chf, ChF, 5, ChannelFPin, ChannelFComplementaryPin); /// Struct used to divide a high resolution timer into multiple channels pub struct AdvancedPwm<'d, T: Instance> { _inner: PeripheralRef<'d, T>, + /// Master instance. pub master: Master, + /// Burst controller. pub burst_controller: BurstController, + /// Channel A. pub ch_a: ChA, + /// Channel B. pub ch_b: ChB, + /// Channel C. pub ch_c: ChC, + /// Channel D. pub ch_d: ChD, + /// Channel E. pub ch_e: ChE, + /// Channel F. #[cfg(hrtim_v2)] pub ch_f: ChF, } impl<'d, T: Instance> AdvancedPwm<'d, T> { + /// Create a new HRTIM driver. + /// + /// This splits the HRTIM into its constituent parts, which you can then use individually. pub fn new( tim: impl Peripheral

+ 'd, _cha: Option>>, @@ -200,13 +220,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> { } } -impl BurstController { - pub fn set_source(&mut self, _source: Source) { - todo!("burst mode control registers not implemented") - } -} - -/// Represents a fixed-frequency bridge converter +/// Fixed-frequency bridge converter driver. /// /// Our implementation of the bridge converter uses a single channel and three compare registers, /// allowing implementation of a synchronous buck or boost converter in continuous or discontinuous @@ -225,6 +239,7 @@ pub struct BridgeConverter> { } impl> BridgeConverter { + /// Create a new HRTIM bridge converter driver. pub fn new(_channel: C, frequency: Hertz) -> Self { use crate::pac::hrtim::vals::{Activeeffect, Inactiveeffect}; @@ -281,14 +296,17 @@ impl> BridgeConverter { } } + /// Start HRTIM. pub fn start(&mut self) { T::regs().mcr().modify(|w| w.set_tcen(C::raw(), true)); } + /// Stop HRTIM. pub fn stop(&mut self) { T::regs().mcr().modify(|w| w.set_tcen(C::raw(), false)); } + /// Enable burst mode. pub fn enable_burst_mode(&mut self) { T::regs().tim(C::raw()).outr().modify(|w| { // Enable Burst Mode @@ -301,6 +319,7 @@ impl> BridgeConverter { }) } + /// Disable burst mode. pub fn disable_burst_mode(&mut self) { T::regs().tim(C::raw()).outr().modify(|w| { // Disable Burst Mode @@ -357,7 +376,7 @@ impl> BridgeConverter { } } -/// Represents a variable-frequency resonant converter +/// Variable-frequency resonant converter driver. /// /// This implementation of a resonsant converter is appropriate for a half or full bridge, /// but does not include secondary rectification, which is appropriate for applications @@ -370,6 +389,7 @@ pub struct ResonantConverter> { } impl> ResonantConverter { + /// Create a new variable-frequency resonant converter driver. pub fn new(_channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self { T::set_channel_frequency(C::raw(), min_frequency); @@ -408,6 +428,7 @@ impl> ResonantConverter { T::set_channel_dead_time(C::raw(), value); } + /// Set the timer period. pub fn set_period(&mut self, period: u16) { assert!(period < self.max_period); assert!(period > self.min_period); diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs index 34a363a1..cfd31c47 100644 --- a/embassy-stm32/src/hrtim/traits.rs +++ b/embassy-stm32/src/hrtim/traits.rs @@ -125,7 +125,6 @@ pub(crate) mod sealed { } /// Set the dead time as a proportion of max_duty - fn set_channel_dead_time(channel: usize, dead_time: u16) { let regs = Self::regs(); @@ -148,13 +147,10 @@ pub(crate) mod sealed { w.set_dtr(dt_val as u16); }); } - - // fn enable_outputs(enable: bool); - // - // fn enable_channel(&mut self, channel: usize, enable: bool); } } +/// HRTIM instance trait. pub trait Instance: sealed::Instance + 'static {} foreach_interrupt! { diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index fd691a73..5d9b4e6a 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -149,33 +149,15 @@ use crate::interrupt::Priority; pub use crate::pac::NVIC_PRIO_BITS; use crate::rcc::sealed::RccPeripheral; -/// `embassy-stm32` global configuration. #[non_exhaustive] pub struct Config { - /// RCC config. pub rcc: rcc::Config, - - /// Enable debug during sleep. - /// - /// May incrase power consumption. Defaults to true. #[cfg(dbgmcu)] pub enable_debug_during_sleep: bool, - - /// BDMA interrupt priority. - /// - /// Defaults to P0 (highest). #[cfg(bdma)] pub bdma_interrupt_priority: Priority, - - /// DMA interrupt priority. - /// - /// Defaults to P0 (highest). #[cfg(dma)] pub dma_interrupt_priority: Priority, - - /// GPDMA interrupt priority. - /// - /// Defaults to P0 (highest). #[cfg(gpdma)] pub gpdma_interrupt_priority: Priority, } @@ -196,11 +178,7 @@ impl Default for Config { } } -/// Initialize the `embassy-stm32` HAL with the provided configuration. -/// -/// This returns the peripheral singletons that can be used for creating drivers. -/// -/// This should only be called once at startup, otherwise it panics. +/// Initialize embassy. pub fn init(config: Config) -> Peripherals { critical_section::with(|cs| { let p = Peripherals::take_with_cs(cs); diff --git a/embassy-stm32/src/qspi/enums.rs b/embassy-stm32/src/qspi/enums.rs index e9e7fd48..ecade9b1 100644 --- a/embassy-stm32/src/qspi/enums.rs +++ b/embassy-stm32/src/qspi/enums.rs @@ -1,3 +1,5 @@ +//! Enums used in QSPI configuration. + #[allow(dead_code)] #[derive(Copy, Clone)] pub(crate) enum QspiMode { diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 9ea0a726..8a709a89 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -14,6 +14,7 @@ use crate::pac::quadspi::Quadspi as Regs; use crate::rcc::RccPeripheral; use crate::{peripherals, Peripheral}; +/// QSPI transfer configuration. pub struct TransferConfig { /// Instraction width (IMODE) pub iwidth: QspiWidth, @@ -45,6 +46,7 @@ impl Default for TransferConfig { } } +/// QSPI driver configuration. pub struct Config { /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen. /// If you need other value the whose predefined use `Other` variant. @@ -71,6 +73,7 @@ impl Default for Config { } } +/// QSPI driver. #[allow(dead_code)] pub struct Qspi<'d, T: Instance, Dma> { _peri: PeripheralRef<'d, T>, @@ -85,6 +88,7 @@ pub struct Qspi<'d, T: Instance, Dma> { } impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { + /// Create a new QSPI driver for bank 1. pub fn new_bk1( peri: impl Peripheral

+ 'd, d0: impl Peripheral

> + 'd, @@ -125,6 +129,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { ) } + /// Create a new QSPI driver for bank 2. pub fn new_bk2( peri: impl Peripheral

+ 'd, d0: impl Peripheral

> + 'd, @@ -223,6 +228,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { } } + /// Do a QSPI command. pub fn command(&mut self, transaction: TransferConfig) { #[cfg(not(stm32h7))] T::REGS.cr().modify(|v| v.set_dmaen(false)); @@ -232,6 +238,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { T::REGS.fcr().modify(|v| v.set_ctcf(true)); } + /// Blocking read data. pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { #[cfg(not(stm32h7))] T::REGS.cr().modify(|v| v.set_dmaen(false)); @@ -256,6 +263,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { T::REGS.fcr().modify(|v| v.set_ctcf(true)); } + /// Blocking write data. pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { // STM32H7 does not have dmaen #[cfg(not(stm32h7))] @@ -278,6 +286,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { T::REGS.fcr().modify(|v| v.set_ctcf(true)); } + /// Blocking read data, using DMA. pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) where Dma: QuadDma, @@ -310,6 +319,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { transfer.blocking_wait(); } + /// Blocking write data, using DMA. pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) where Dma: QuadDma, @@ -379,6 +389,7 @@ pub(crate) mod sealed { } } +/// QSPI instance trait. pub trait Instance: Peripheral

+ sealed::Instance + RccPeripheral {} pin_trait!(SckPin, Instance); diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 6099b9f4..ab142053 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -54,6 +54,7 @@ const SD_INIT_FREQ: Hertz = Hertz(400_000); /// The signalling scheme used on the SDMMC bus #[non_exhaustive] +#[allow(missing_docs)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Signalling { @@ -70,6 +71,9 @@ impl Default for Signalling { } } +/// Aligned data block for SDMMC transfers. +/// +/// This is a 512-byte array, aligned to 4 bytes to satisfy DMA requirements. #[repr(align(4))] #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -94,17 +98,23 @@ impl DerefMut for DataBlock { #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { + /// Timeout reported by the hardware Timeout, + /// Timeout reported by the software driver. SoftwareTimeout, + /// Unsupported card version. UnsupportedCardVersion, + /// Unsupported card type. UnsupportedCardType, + /// CRC error. Crc, - DataCrcFail, - RxOverFlow, + /// No card inserted. NoCard, + /// Bad clock supplied to the SDMMC peripheral. BadClock, + /// Signaling switch failed. SignalingSwitchFailed, - PeripheralBusy, + /// ST bit error. #[cfg(sdmmc_v1)] StBitErr, } @@ -363,6 +373,7 @@ impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { #[cfg(sdmmc_v2)] impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { + /// Create a new SDMMC driver, with 1 data lane. pub fn new_1bit( sdmmc: impl Peripheral

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

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, @@ -497,7 +509,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { } /// Data transfer is in progress - #[inline(always)] + #[inline] fn data_active() -> bool { let regs = T::regs(); @@ -509,7 +521,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { } /// Coammand transfer is in progress - #[inline(always)] + #[inline] fn cmd_active() -> bool { let regs = T::regs(); @@ -521,7 +533,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { } /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) - #[inline(always)] + #[inline] fn wait_idle() { while Self::data_active() || Self::cmd_active() {} } @@ -837,7 +849,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { } /// Clear flags in interrupt clear register - #[inline(always)] + #[inline] fn clear_interrupt_flags() { let regs = T::regs(); regs.icr().write(|w| { @@ -1152,7 +1164,8 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { Ok(()) } - #[inline(always)] + /// Read a data block. + #[inline] pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { let card_capacity = self.card()?.card_type; @@ -1204,6 +1217,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { res } + /// Write a data block. pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { let card = self.card.as_mut().ok_or(Error::NoCard)?; @@ -1283,7 +1297,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { /// /// Returns Error::NoCard if [`init_card`](#method.init_card) /// has not previously succeeded - #[inline(always)] + #[inline] pub fn card(&self) -> Result<&Card, Error> { self.card.as_ref().ok_or(Error::NoCard) } @@ -1419,7 +1433,9 @@ pub(crate) mod sealed { pub trait Pins {} } +/// SDMMC instance trait. pub trait Instance: sealed::Instance + RccPeripheral + 'static {} + pin_trait!(CkPin, Instance); pin_trait!(CmdPin, Instance); pin_trait!(D0Pin, Instance); @@ -1434,7 +1450,10 @@ pin_trait!(D7Pin, Instance); #[cfg(sdmmc_v1)] dma_trait!(SdmmcDma, Instance); -// SDMMCv2 uses internal DMA +/// DMA instance trait. +/// +/// This is only implemented for `NoDma`, since SDMMCv2 has DMA built-in, instead of +/// using ST's system-wide DMA peripheral. #[cfg(sdmmc_v2)] pub trait SdmmcDma {} #[cfg(sdmmc_v2)] diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 5a1ad3e9..674a5d31 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -16,27 +16,38 @@ use crate::rcc::RccPeripheral; use crate::time::Hertz; use crate::{peripherals, Peripheral}; +/// SPI error. #[derive(Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { + /// Invalid framing. Framing, + /// CRC error (only if hardware CRC checking is enabled). Crc, + /// Mode fault ModeFault, + /// Overrun. Overrun, } -// TODO move upwards in the tree +/// SPI bit order #[derive(Copy, Clone)] pub enum BitOrder { + /// Least significant bit first. LsbFirst, + /// Most significant bit first. MsbFirst, } +/// SPI configuration. #[non_exhaustive] #[derive(Copy, Clone)] pub struct Config { + /// SPI mode. pub mode: Mode, + /// Bit order. pub bit_order: BitOrder, + /// Clock frequency. pub frequency: Hertz, } @@ -73,6 +84,7 @@ impl Config { } } +/// SPI driver. pub struct Spi<'d, T: Instance, Tx, Rx> { _peri: PeripheralRef<'d, T>, sck: Option>, @@ -84,6 +96,7 @@ pub struct Spi<'d, T: Instance, Tx, Rx> { } impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { + /// Create a new SPI driver. pub fn new( peri: impl Peripheral

+ 'd, sck: impl Peripheral

> + 'd, @@ -118,6 +131,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { ) } + /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI). pub fn new_rxonly( peri: impl Peripheral

+ 'd, sck: impl Peripheral

> + 'd, @@ -143,6 +157,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { ) } + /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO). pub fn new_txonly( peri: impl Peripheral

+ 'd, sck: impl Peripheral

> + 'd, @@ -168,6 +183,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { ) } + /// Create a new SPI driver, in TX-only mode, without SCK pin. + /// + /// This can be useful for bit-banging non-SPI protocols. pub fn new_txonly_nosck( peri: impl Peripheral

+ 'd, mosi: impl Peripheral

> + 'd, @@ -355,6 +373,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { Ok(()) } + /// Get current SPI configuration. pub fn get_current_config(&self) -> Config { #[cfg(any(spi_v1, spi_f1, spi_v2))] let cfg = T::REGS.cr1().read(); @@ -444,6 +463,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { self.current_word_size = word_size; } + /// SPI write, using DMA. pub async fn write(&mut self, data: &[W]) -> Result<(), Error> where Tx: TxDma, @@ -477,6 +497,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { Ok(()) } + /// SPI read, using DMA. pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> where Tx: TxDma, @@ -580,6 +601,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { Ok(()) } + /// Bidirectional transfer, using DMA. + /// + /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`. + /// + /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored. + /// If `write` is shorter it is padded with zero bytes. pub async fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> where Tx: TxDma, @@ -588,6 +615,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { self.transfer_inner(read, write).await } + /// In-place bidirectional transfer, using DMA. + /// + /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time. pub async fn transfer_in_place(&mut self, data: &mut [W]) -> Result<(), Error> where Tx: TxDma, @@ -596,6 +626,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { self.transfer_inner(data, data).await } + /// Blocking write. pub fn blocking_write(&mut self, words: &[W]) -> Result<(), Error> { T::REGS.cr1().modify(|w| w.set_spe(true)); flush_rx_fifo(T::REGS); @@ -606,6 +637,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { Ok(()) } + /// Blocking read. pub fn blocking_read(&mut self, words: &mut [W]) -> Result<(), Error> { T::REGS.cr1().modify(|w| w.set_spe(true)); flush_rx_fifo(T::REGS); @@ -616,6 +648,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { Ok(()) } + /// Blocking in-place bidirectional transfer. + /// + /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time. pub fn blocking_transfer_in_place(&mut self, words: &mut [W]) -> Result<(), Error> { T::REGS.cr1().modify(|w| w.set_spe(true)); flush_rx_fifo(T::REGS); @@ -626,6 +661,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { Ok(()) } + /// Blocking bidirectional transfer. + /// + /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`. + /// + /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored. + /// If `write` is shorter it is padded with zero bytes. pub fn blocking_transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { T::REGS.cr1().modify(|w| w.set_spe(true)); flush_rx_fifo(T::REGS); @@ -946,6 +987,7 @@ pub(crate) mod sealed { } } +/// Word sizes usable for SPI. pub trait Word: word::Word + sealed::Word {} macro_rules! impl_word { @@ -1025,7 +1067,9 @@ mod word_impl { impl_word!(u32, 32 - 1); } +/// SPI instance trait. pub trait Instance: Peripheral

+ sealed::Instance + RccPeripheral {} + pin_trait!(SckPin, Instance); pin_trait!(MosiPin, Instance); pin_trait!(MisoPin, Instance); diff --git a/embassy-stm32/src/time.rs b/embassy-stm32/src/time.rs index a0bc3394..17690aef 100644 --- a/embassy-stm32/src/time.rs +++ b/embassy-stm32/src/time.rs @@ -8,14 +8,17 @@ use core::ops::{Div, Mul}; pub struct Hertz(pub u32); impl Hertz { + /// Create a `Hertz` from the given hertz. pub const fn hz(hertz: u32) -> Self { Self(hertz) } + /// Create a `Hertz` from the given kilohertz. pub const fn khz(kilohertz: u32) -> Self { Self(kilohertz * 1_000) } + /// Create a `Hertz` from the given megahertz. pub const fn mhz(megahertz: u32) -> Self { Self(megahertz * 1_000_000) }