diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 9093ad919..e3458e2de 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -354,7 +354,11 @@ unsafe fn uicr_write_masked(address: *mut u32, value: u32, mask: u32) -> WriteRe WriteResult::Written } -/// Initialize peripherals with the provided configuration. This should only be called once at startup. +/// Initialize the `embassy-nrf` 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. pub fn init(config: config::Config) -> Peripherals { // Do this first, so that it panics if user is calling `init` a second time // before doing anything important. diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index bb60d244f..058b8a0fc 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -672,14 +672,14 @@ fn main() { (("lpuart", "RTS"), quote!(crate::usart::RtsPin)), (("lpuart", "CK"), quote!(crate::usart::CkPin)), (("lpuart", "DE"), quote!(crate::usart::DePin)), - (("sai", "SCK_A"), quote!(crate::sai::SckAPin)), - (("sai", "SCK_B"), quote!(crate::sai::SckBPin)), - (("sai", "FS_A"), quote!(crate::sai::FsAPin)), - (("sai", "FS_B"), quote!(crate::sai::FsBPin)), - (("sai", "SD_A"), quote!(crate::sai::SdAPin)), - (("sai", "SD_B"), quote!(crate::sai::SdBPin)), - (("sai", "MCLK_A"), quote!(crate::sai::MclkAPin)), - (("sai", "MCLK_B"), quote!(crate::sai::MclkBPin)), + (("sai", "SCK_A"), quote!(crate::sai::SckPin)), + (("sai", "SCK_B"), quote!(crate::sai::SckPin)), + (("sai", "FS_A"), quote!(crate::sai::FsPin)), + (("sai", "FS_B"), quote!(crate::sai::FsPin)), + (("sai", "SD_A"), quote!(crate::sai::SdPin)), + (("sai", "SD_B"), quote!(crate::sai::SdPin)), + (("sai", "MCLK_A"), quote!(crate::sai::MclkPin)), + (("sai", "MCLK_B"), quote!(crate::sai::MclkPin)), (("sai", "WS"), quote!(crate::sai::WsPin)), (("spi", "SCK"), quote!(crate::spi::SckPin)), (("spi", "MOSI"), quote!(crate::spi::MosiPin)), @@ -995,8 +995,8 @@ fn main() { (("usart", "TX"), quote!(crate::usart::TxDma)), (("lpuart", "RX"), quote!(crate::usart::RxDma)), (("lpuart", "TX"), quote!(crate::usart::TxDma)), - (("sai", "A"), quote!(crate::sai::DmaA)), - (("sai", "B"), quote!(crate::sai::DmaB)), + (("sai", "A"), quote!(crate::sai::Dma)), + (("sai", "B"), quote!(crate::sai::Dma)), (("spi", "RX"), quote!(crate::spi::RxDma)), (("spi", "TX"), quote!(crate::spi::TxDma)), (("i2c", "RX"), quote!(crate::i2c::RxDma)), diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index ff523ca3b..e4dd35c34 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -1,4 +1,5 @@ -//! Analog to Digital (ADC) converter driver. +//! Analog to Digital Converter (ADC) + #![macro_use] #![allow(missing_docs)] // TODO diff --git a/embassy-stm32/src/can/mod.rs b/embassy-stm32/src/can/mod.rs index 425f9ac2e..915edb3a6 100644 --- a/embassy-stm32/src/can/mod.rs +++ b/embassy-stm32/src/can/mod.rs @@ -1,3 +1,4 @@ +//! Controller Area Network (CAN) #![macro_use] #[cfg_attr(can_bxcan, path = "bxcan.rs")] diff --git a/embassy-stm32/src/crc/mod.rs b/embassy-stm32/src/crc/mod.rs index 63f7ad9ba..29523b92d 100644 --- a/embassy-stm32/src/crc/mod.rs +++ b/embassy-stm32/src/crc/mod.rs @@ -1,3 +1,4 @@ +//! Cyclic Redundancy Check (CRC) #[cfg_attr(crc_v1, path = "v1.rs")] #[cfg_attr(crc_v2, path = "v2v3.rs")] #[cfg_attr(crc_v3, path = "v2v3.rs")] diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 9c670195d..31dedf06e 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -1,4 +1,4 @@ -//! Provide access to the STM32 digital-to-analog converter (DAC). +//! Digital to Analog Converter (DAC) #![macro_use] use core::marker::PhantomData; diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs index 139d8fd1b..4d02284b2 100644 --- a/embassy-stm32/src/dcmi.rs +++ b/embassy-stm32/src/dcmi.rs @@ -1,3 +1,4 @@ +//! Digital Camera Interface (DCMI) use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index dbf91eedc..448405507 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs @@ -1,3 +1,4 @@ +//! Ethernet (ETH) #![macro_use] #[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")] diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 371be913e..f83bae3ff 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -1,3 +1,4 @@ +//! External Interrupts (EXTI) use core::convert::Infallible; use core::future::Future; use core::marker::PhantomData; diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 6b6b4d41c..cbf5c25b2 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -1,3 +1,4 @@ +//! Flash memory (FLASH) use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; #[cfg(flash_f4)] diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs index 23ac82f63..873c8a70c 100644 --- a/embassy-stm32/src/fmc.rs +++ b/embassy-stm32/src/fmc.rs @@ -1,3 +1,4 @@ +//! Flexible Memory Controller (FMC) / Flexible Static Memory Controller (FSMC) use core::marker::PhantomData; use embassy_hal_internal::into_ref; diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index 17096d48c..6539326b4 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs @@ -1,3 +1,5 @@ +//! High Resolution Timer (HRTIM) + mod traits; use core::marker::PhantomData; diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 0af291e9c..9b0b35eca 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -1,3 +1,4 @@ +//! Inter-Integrated-Circuit (I2C) #![macro_use] #[cfg_attr(i2c_v1, path = "v1.rs")] diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index 372c86db3..1f85c0bc5 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs @@ -1,3 +1,4 @@ +//! Inter-IC Sound (I2S) use embassy_hal_internal::into_ref; use crate::gpio::sealed::{AFType, Pin as _}; diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 5d9b4e6a0..fd691a732 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -149,15 +149,33 @@ 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, } @@ -178,7 +196,11 @@ impl Default for Config { } } -/// Initialize embassy. +/// 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. pub fn init(config: Config) -> Peripherals { critical_section::with(|cs| { let p = Peripherals::take_with_cs(cs); diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index bac91f300..9ea0a726c 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -1,3 +1,5 @@ +//! Quad Serial Peripheral Interface (QSPI) + #![macro_use] pub mod enums; diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index b2196b0d5..6ee89a922 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs @@ -1,3 +1,4 @@ +//! Random Number Generator (RNG) #![macro_use] use core::future::poll_fn; diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index fa359cdae..11b252139 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -1,4 +1,4 @@ -//! RTC peripheral abstraction +//! Real Time Clock (RTC) mod datetime; #[cfg(feature = "low-power")] @@ -163,7 +163,7 @@ impl RtcTimeProvider { } } -/// RTC Abstraction +/// RTC driver. pub struct Rtc { #[cfg(feature = "low-power")] stop_time: Mutex>>, diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 3d7f65996..ef8802184 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -1,8 +1,11 @@ +//! Serial Audio Interface (SAI) #![macro_use] -use embassy_embedded_hal::SetConfig; +use core::marker::PhantomData; + use embassy_hal_internal::{into_ref, PeripheralRef}; +use self::sealed::WhichSubBlock; pub use crate::dma::word; use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; use crate::gpio::sealed::{AFType, Pin as _}; @@ -11,48 +14,32 @@ use crate::pac::sai::{vals, Sai as Regs}; use crate::rcc::RccPeripheral; use crate::{peripherals, Peripheral}; +/// SAI error #[derive(Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { + /// `write` called on a SAI in receive mode. NotATransmitter, + /// `read` called on a SAI in transmit mode. NotAReceiver, - OverrunError, + /// Overrun + Overrun, } impl From for Error { fn from(_: ringbuffer::OverrunError) -> Self { - Self::OverrunError + Self::Overrun } } +/// Master/slave mode. #[derive(Copy, Clone)] -pub enum SyncBlock { - None, - Sai1BlockA, - Sai1BlockB, - Sai2BlockA, - Sai2BlockB, -} - -#[derive(Copy, Clone)] -pub enum SyncIn { - None, - ChannelZero, - ChannelOne, -} - -#[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum Mode { Master, Slave, } -#[derive(Copy, Clone)] -pub enum TxRx { - Transmitter, - Receiver, -} - impl Mode { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] const fn mode(&self, tx_rx: TxRx) -> vals::Mode { @@ -69,7 +56,17 @@ impl Mode { } } +/// Direction: transmit or receive #[derive(Copy, Clone)] +#[allow(missing_docs)] +pub enum TxRx { + Transmitter, + Receiver, +} + +/// Data slot size. +#[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum SlotSize { DataSize, /// 16 bit data length on 16 bit wide channel @@ -80,7 +77,7 @@ pub enum SlotSize { impl SlotSize { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn slotsz(&self) -> vals::Slotsz { + const fn slotsz(&self) -> vals::Slotsz { match self { SlotSize::DataSize => vals::Slotsz::DATASIZE, SlotSize::Channel16 => vals::Slotsz::BIT16, @@ -89,7 +86,9 @@ impl SlotSize { } } +/// Data size. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum DataSize { Data8, Data10, @@ -101,7 +100,7 @@ pub enum DataSize { impl DataSize { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn ds(&self) -> vals::Ds { + const fn ds(&self) -> vals::Ds { match self { DataSize::Data8 => vals::Ds::BIT8, DataSize::Data10 => vals::Ds::BIT10, @@ -113,7 +112,9 @@ impl DataSize { } } +/// FIFO threshold level. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum FifoThreshold { Empty, Quarter, @@ -124,7 +125,7 @@ pub enum FifoThreshold { impl FifoThreshold { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn fth(&self) -> vals::Fth { + const fn fth(&self) -> vals::Fth { match self { FifoThreshold::Empty => vals::Fth::EMPTY, FifoThreshold::Quarter => vals::Fth::QUARTER1, @@ -135,38 +136,9 @@ impl FifoThreshold { } } +/// Output value on mute. #[derive(Copy, Clone)] -pub enum FifoLevel { - Empty, - FirstQuarter, - SecondQuarter, - ThirdQuarter, - FourthQuarter, - Full, -} - -#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] -impl From for FifoLevel { - fn from(flvl: vals::Flvl) -> Self { - match flvl { - vals::Flvl::EMPTY => FifoLevel::Empty, - vals::Flvl::QUARTER1 => FifoLevel::FirstQuarter, - vals::Flvl::QUARTER2 => FifoLevel::SecondQuarter, - vals::Flvl::QUARTER3 => FifoLevel::ThirdQuarter, - vals::Flvl::QUARTER4 => FifoLevel::FourthQuarter, - vals::Flvl::FULL => FifoLevel::Full, - _ => FifoLevel::Empty, - } - } -} - -#[derive(Copy, Clone)] -pub enum MuteDetection { - NoMute, - Mute, -} - -#[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum MuteValue { Zero, LastValue, @@ -174,7 +146,7 @@ pub enum MuteValue { impl MuteValue { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn muteval(&self) -> vals::Muteval { + const fn muteval(&self) -> vals::Muteval { match self { MuteValue::Zero => vals::Muteval::SENDZERO, MuteValue::LastValue => vals::Muteval::SENDLAST, @@ -182,13 +154,9 @@ impl MuteValue { } } +/// Protocol variant to use. #[derive(Copy, Clone)] -pub enum OverUnderStatus { - NoError, - OverUnderRunDetected, -} - -#[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum Protocol { Free, Spdif, @@ -197,7 +165,7 @@ pub enum Protocol { impl Protocol { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn prtcfg(&self) -> vals::Prtcfg { + const fn prtcfg(&self) -> vals::Prtcfg { match self { Protocol::Free => vals::Prtcfg::FREE, Protocol::Spdif => vals::Prtcfg::SPDIF, @@ -206,7 +174,9 @@ impl Protocol { } } +/// Sync input between SAI units/blocks. #[derive(Copy, Clone, PartialEq)] +#[allow(missing_docs)] pub enum SyncInput { /// Not synced to any other SAI unit. None, @@ -218,7 +188,7 @@ pub enum SyncInput { } impl SyncInput { - pub const fn syncen(&self) -> vals::Syncen { + const fn syncen(&self) -> vals::Syncen { match self { SyncInput::None => vals::Syncen::ASYNCHRONOUS, SyncInput::Internal => vals::Syncen::INTERNAL, @@ -228,8 +198,10 @@ impl SyncInput { } } +/// SAI instance to sync from. #[cfg(sai_v4)] #[derive(Copy, Clone, PartialEq)] +#[allow(missing_docs)] pub enum SyncInputInstance { #[cfg(peri_sai1)] Sai1 = 0, @@ -241,7 +213,9 @@ pub enum SyncInputInstance { Sai4 = 3, } +/// Channels (stereo or mono). #[derive(Copy, Clone, PartialEq)] +#[allow(missing_docs)] pub enum StereoMono { Stereo, Mono, @@ -249,7 +223,7 @@ pub enum StereoMono { impl StereoMono { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn mono(&self) -> vals::Mono { + const fn mono(&self) -> vals::Mono { match self { StereoMono::Stereo => vals::Mono::STEREO, StereoMono::Mono => vals::Mono::MONO, @@ -257,15 +231,18 @@ impl StereoMono { } } +/// Bit order #[derive(Copy, Clone)] pub enum BitOrder { + /// Least significant bit first. LsbFirst, + /// Most significant bit first. MsbFirst, } impl BitOrder { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn lsbfirst(&self) -> vals::Lsbfirst { + const fn lsbfirst(&self) -> vals::Lsbfirst { match self { BitOrder::LsbFirst => vals::Lsbfirst::LSBFIRST, BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST, @@ -273,6 +250,7 @@ impl BitOrder { } } +/// Frame sync offset. #[derive(Copy, Clone)] pub enum FrameSyncOffset { /// This is used in modes other than standard I2S phillips mode @@ -283,7 +261,7 @@ pub enum FrameSyncOffset { impl FrameSyncOffset { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn fsoff(&self) -> vals::Fsoff { + const fn fsoff(&self) -> vals::Fsoff { match self { FrameSyncOffset::OnFirstBit => vals::Fsoff::ONFIRST, FrameSyncOffset::BeforeFirstBit => vals::Fsoff::BEFOREFIRST, @@ -291,15 +269,18 @@ impl FrameSyncOffset { } } +/// Frame sync polarity #[derive(Copy, Clone)] pub enum FrameSyncPolarity { + /// Sync signal is active low. ActiveLow, + /// Sync signal is active high ActiveHigh, } impl FrameSyncPolarity { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn fspol(&self) -> vals::Fspol { + const fn fspol(&self) -> vals::Fspol { match self { FrameSyncPolarity::ActiveLow => vals::Fspol::FALLINGEDGE, FrameSyncPolarity::ActiveHigh => vals::Fspol::RISINGEDGE, @@ -307,7 +288,9 @@ impl FrameSyncPolarity { } } +/// Sync definition. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum FrameSyncDefinition { StartOfFrame, ChannelIdentification, @@ -315,7 +298,7 @@ pub enum FrameSyncDefinition { impl FrameSyncDefinition { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn fsdef(&self) -> bool { + const fn fsdef(&self) -> bool { match self { FrameSyncDefinition::StartOfFrame => false, FrameSyncDefinition::ChannelIdentification => true, @@ -323,7 +306,9 @@ impl FrameSyncDefinition { } } +/// Clock strobe. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum ClockStrobe { Falling, Rising, @@ -331,7 +316,7 @@ pub enum ClockStrobe { impl ClockStrobe { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn ckstr(&self) -> vals::Ckstr { + const fn ckstr(&self) -> vals::Ckstr { match self { ClockStrobe::Falling => vals::Ckstr::FALLINGEDGE, ClockStrobe::Rising => vals::Ckstr::RISINGEDGE, @@ -339,7 +324,9 @@ impl ClockStrobe { } } +/// Complements format for negative samples. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum ComplementFormat { OnesComplement, TwosComplement, @@ -347,7 +334,7 @@ pub enum ComplementFormat { impl ComplementFormat { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn cpl(&self) -> vals::Cpl { + const fn cpl(&self) -> vals::Cpl { match self { ComplementFormat::OnesComplement => vals::Cpl::ONESCOMPLEMENT, ComplementFormat::TwosComplement => vals::Cpl::TWOSCOMPLEMENT, @@ -355,7 +342,9 @@ impl ComplementFormat { } } +/// Companding setting. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum Companding { None, MuLaw, @@ -364,7 +353,7 @@ pub enum Companding { impl Companding { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn comp(&self) -> vals::Comp { + const fn comp(&self) -> vals::Comp { match self { Companding::None => vals::Comp::NOCOMPANDING, Companding::MuLaw => vals::Comp::MULAW, @@ -373,7 +362,9 @@ impl Companding { } } +/// Output drive #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum OutputDrive { OnStart, Immediately, @@ -381,7 +372,7 @@ pub enum OutputDrive { impl OutputDrive { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn outdriv(&self) -> vals::Outdriv { + const fn outdriv(&self) -> vals::Outdriv { match self { OutputDrive::OnStart => vals::Outdriv::ONSTART, OutputDrive::Immediately => vals::Outdriv::IMMEDIATELY, @@ -389,7 +380,9 @@ impl OutputDrive { } } +/// Master clock divider. #[derive(Copy, Clone, PartialEq)] +#[allow(missing_docs)] pub enum MasterClockDivider { MasterClockDisabled, Div1, @@ -412,7 +405,7 @@ pub enum MasterClockDivider { impl MasterClockDivider { #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] - pub const fn mckdiv(&self) -> u8 { + const fn mckdiv(&self) -> u8 { match self { MasterClockDivider::MasterClockDisabled => 0, MasterClockDivider::Div1 => 0, @@ -436,6 +429,7 @@ impl MasterClockDivider { } /// [`SAI`] configuration. +#[allow(missing_docs)] #[non_exhaustive] #[derive(Copy, Clone)] pub struct Config { @@ -459,7 +453,7 @@ pub struct Config { pub clock_strobe: ClockStrobe, pub output_drive: OutputDrive, pub master_clock_divider: MasterClockDivider, - pub is_high_impedenane_on_inactive_slot: bool, + pub is_high_impedance_on_inactive_slot: bool, pub fifo_threshold: FifoThreshold, pub companding: Companding, pub complement_format: ComplementFormat, @@ -490,7 +484,7 @@ impl Default for Config { master_clock_divider: MasterClockDivider::MasterClockDisabled, clock_strobe: ClockStrobe::Rising, output_drive: OutputDrive::Immediately, - is_high_impedenane_on_inactive_slot: false, + is_high_impedance_on_inactive_slot: false, fifo_threshold: FifoThreshold::ThreeQuarters, companding: Companding::None, complement_format: ComplementFormat::TwosComplement, @@ -501,23 +495,10 @@ impl Default for Config { } impl Config { - pub fn new_i2s() -> Self { + /// Create a new config with all default values. + pub fn new() -> Self { return Default::default(); } - - pub fn new_msb_first() -> Self { - Self { - bit_order: BitOrder::MsbFirst, - frame_sync_offset: FrameSyncOffset::OnFirstBit, - ..Default::default() - } - } -} - -#[derive(Copy, Clone)] -enum WhichSubBlock { - A = 0, - B = 1, } enum RingBuffer<'d, C: Channel, W: word::Word> { @@ -531,28 +512,6 @@ fn dr(w: crate::pac::sai::Sai, sub_block: WhichSubBlock) -> *mut ch.dr().as_ptr() as _ } -pub struct SubBlock<'d, T: Instance, C: Channel, W: word::Word> { - _peri: PeripheralRef<'d, T>, - sd: Option>, - fs: Option>, - sck: Option>, - mclk: Option>, - ring_buffer: RingBuffer<'d, C, W>, - sub_block: WhichSubBlock, -} - -pub struct SubBlockA {} -pub struct SubBlockB {} - -pub struct SubBlockAPeripheral<'d, T>(PeripheralRef<'d, T>); -pub struct SubBlockBPeripheral<'d, T>(PeripheralRef<'d, T>); - -pub struct Sai<'d, T: Instance> { - _peri: PeripheralRef<'d, T>, - sub_block_a_peri: Option>, - sub_block_b_peri: Option>, -} - // return the type for (sd, sck) fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AFType, AFType) { ( @@ -591,34 +550,6 @@ fn get_ring_buffer<'d, T: Instance, C: Channel, W: word::Word>( } } -impl<'d, T: Instance> Sai<'d, T> { - pub fn new(peri: impl Peripheral

+ 'd) -> Self { - T::enable_and_reset(); - - Self { - _peri: unsafe { peri.clone_unchecked().into_ref() }, - sub_block_a_peri: Some(SubBlockAPeripheral(unsafe { peri.clone_unchecked().into_ref() })), - sub_block_b_peri: Some(SubBlockBPeripheral(peri.into_ref())), - } - } - - pub fn take_sub_block_a(self: &mut Self) -> Option> { - if self.sub_block_a_peri.is_some() { - self.sub_block_a_peri.take() - } else { - None - } - } - - pub fn take_sub_block_b(self: &mut Self) -> Option> { - if self.sub_block_b_peri.is_some() { - self.sub_block_b_peri.take() - } else { - None - } - } -} - fn update_synchronous_config(config: &mut Config) { config.mode = Mode::Slave; config.sync_output = false; @@ -636,19 +567,58 @@ fn update_synchronous_config(config: &mut Config) { } } -impl SubBlockA { - pub fn new_asynchronous_with_mclk<'d, T: Instance, C: Channel, W: word::Word>( - peri: SubBlockAPeripheral<'d, T>, - sck: impl Peripheral

> + 'd, - sd: impl Peripheral

> + 'd, - fs: impl Peripheral

> + 'd, - mclk: impl Peripheral

> + 'd, +/// SAI subblock instance. +pub struct SubBlock<'d, T, S: SubBlockInstance> { + peri: PeripheralRef<'d, T>, + _phantom: PhantomData, +} + +/// Split the main SAIx peripheral into the two subblocks. +/// +/// You can then create a [`Sai`] driver for each each half. +pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral

+ 'd) -> (SubBlock<'d, T, A>, SubBlock<'d, T, B>) { + into_ref!(peri); + T::enable_and_reset(); + + ( + SubBlock { + peri: unsafe { peri.clone_unchecked() }, + _phantom: PhantomData, + }, + SubBlock { + peri, + _phantom: PhantomData, + }, + ) +} + +/// SAI sub-block driver. +pub struct Sai<'d, T: Instance, C: Channel, W: word::Word> { + _peri: PeripheralRef<'d, T>, + sd: Option>, + fs: Option>, + sck: Option>, + mclk: Option>, + ring_buffer: RingBuffer<'d, C, W>, + sub_block: WhichSubBlock, +} + +impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { + /// Create a new SAI driver in asynchronous mode with MCLK. + /// + /// You can obtain the [`SubBlock`] with [`split_subblocks`]. + pub fn new_asynchronous_with_mclk( + peri: SubBlock<'d, T, S>, + sck: impl Peripheral

> + 'd, + sd: impl Peripheral

> + 'd, + fs: impl Peripheral

> + 'd, + mclk: impl Peripheral

> + 'd, dma: impl Peripheral

+ 'd, dma_buf: &'d mut [W], mut config: Config, - ) -> SubBlock<'d, T, C, W> + ) -> Self where - C: Channel + DmaA, + C: Channel + Dma, { into_ref!(mclk); @@ -664,19 +634,22 @@ impl SubBlockA { Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config) } - pub fn new_asynchronous<'d, T: Instance, C: Channel, W: word::Word>( - peri: SubBlockAPeripheral<'d, T>, - sck: impl Peripheral

> + 'd, - sd: impl Peripheral

> + 'd, - fs: impl Peripheral

> + 'd, + /// Create a new SAI driver in asynchronous mode without MCLK. + /// + /// You can obtain the [`SubBlock`] with [`split_subblocks`]. + pub fn new_asynchronous( + peri: SubBlock<'d, T, S>, + sck: impl Peripheral

> + 'd, + sd: impl Peripheral

> + 'd, + fs: impl Peripheral

> + 'd, dma: impl Peripheral

+ 'd, dma_buf: &'d mut [W], config: Config, - ) -> SubBlock<'d, T, C, W> + ) -> Self where - C: Channel + DmaA, + C: Channel + Dma, { - let peri = peri.0; + let peri = peri.peri; into_ref!(peri, dma, sck, sd, fs); let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); @@ -688,10 +661,10 @@ impl SubBlockA { fs.set_as_af(fs.af_num(), ck_af_type); fs.set_speed(crate::gpio::Speed::VeryHigh); - let sub_block = WhichSubBlock::A; + let sub_block = S::WHICH; let request = dma.request(); - SubBlock::new_inner( + Self::new_inner( peri, sub_block, Some(sck.map_into()), @@ -703,19 +676,22 @@ impl SubBlockA { ) } - pub fn new_synchronous<'d, T: Instance, C: Channel, W: word::Word>( - peri: SubBlockAPeripheral<'d, T>, - sd: impl Peripheral

> + 'd, + /// Create a new SAI driver in synchronous mode. + /// + /// You can obtain the [`SubBlock`] with [`split_subblocks`]. + pub fn new_synchronous( + peri: SubBlock<'d, T, S>, + sd: impl Peripheral

> + 'd, dma: impl Peripheral

+ 'd, dma_buf: &'d mut [W], mut config: Config, - ) -> SubBlock<'d, T, C, W> + ) -> Self where - C: Channel + DmaA, + C: Channel + Dma, { update_synchronous_config(&mut config); - let peri = peri.0; + let peri = peri.peri; into_ref!(dma, peri, sd); let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx); @@ -723,10 +699,10 @@ impl SubBlockA { sd.set_as_af(sd.af_num(), sd_af_type); sd.set_speed(crate::gpio::Speed::VeryHigh); - let sub_block = WhichSubBlock::A; + let sub_block = S::WHICH; let request = dma.request(); - SubBlock::new_inner( + Self::new_inner( peri, sub_block, None, @@ -737,129 +713,6 @@ impl SubBlockA { config, ) } -} - -impl SubBlockB { - pub fn new_asynchronous_with_mclk<'d, T: Instance, C: Channel, W: word::Word>( - peri: SubBlockBPeripheral<'d, T>, - sck: impl Peripheral

> + 'd, - sd: impl Peripheral

> + 'd, - fs: impl Peripheral

> + 'd, - mclk: impl Peripheral

> + 'd, - dma: impl Peripheral

+ 'd, - dma_buf: &'d mut [W], - mut config: Config, - ) -> SubBlock<'d, T, C, W> - where - C: Channel + DmaB, - { - into_ref!(mclk); - - let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); - - mclk.set_as_af(mclk.af_num(), ck_af_type); - mclk.set_speed(crate::gpio::Speed::VeryHigh); - - if config.master_clock_divider == MasterClockDivider::MasterClockDisabled { - config.master_clock_divider = MasterClockDivider::Div1; - } - - Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config) - } - - pub fn new_asynchronous<'d, T: Instance, C: Channel, W: word::Word>( - peri: SubBlockBPeripheral<'d, T>, - sck: impl Peripheral

> + 'd, - sd: impl Peripheral

> + 'd, - fs: impl Peripheral

> + 'd, - dma: impl Peripheral

+ 'd, - dma_buf: &'d mut [W], - config: Config, - ) -> SubBlock<'d, T, C, W> - where - C: Channel + DmaB, - { - let peri = peri.0; - into_ref!(dma, peri, sck, sd, fs); - - let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); - - sd.set_as_af(sd.af_num(), sd_af_type); - sd.set_speed(crate::gpio::Speed::VeryHigh); - - sck.set_as_af(sck.af_num(), ck_af_type); - sck.set_speed(crate::gpio::Speed::VeryHigh); - fs.set_as_af(fs.af_num(), ck_af_type); - fs.set_speed(crate::gpio::Speed::VeryHigh); - - let sub_block = WhichSubBlock::B; - let request = dma.request(); - - SubBlock::new_inner( - peri, - sub_block, - Some(sck.map_into()), - None, - Some(sd.map_into()), - Some(fs.map_into()), - get_ring_buffer::(dma, dma_buf, request, sub_block, config.tx_rx), - config, - ) - } - - pub fn new_synchronous<'d, T: Instance, C: Channel, W: word::Word>( - peri: SubBlockBPeripheral<'d, T>, - sd: impl Peripheral

> + 'd, - dma: impl Peripheral

+ 'd, - dma_buf: &'d mut [W], - mut config: Config, - ) -> SubBlock<'d, T, C, W> - where - C: Channel + DmaB, - { - update_synchronous_config(&mut config); - let peri = peri.0; - into_ref!(dma, peri, sd); - - let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx); - - sd.set_as_af(sd.af_num(), sd_af_type); - sd.set_speed(crate::gpio::Speed::VeryHigh); - - let sub_block = WhichSubBlock::B; - let request = dma.request(); - - SubBlock::new_inner( - peri, - sub_block, - None, - None, - Some(sd.map_into()), - None, - get_ring_buffer::(dma, dma_buf, request, sub_block, config.tx_rx), - config, - ) - } -} - -impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { - pub fn start(self: &mut Self) { - match self.ring_buffer { - RingBuffer::Writable(ref mut rb) => { - rb.start(); - } - RingBuffer::Readable(ref mut rb) => { - rb.start(); - } - } - } - - fn is_transmitter(ring_buffer: &RingBuffer) -> bool { - match ring_buffer { - RingBuffer::Writable(_) => true, - _ => false, - } - } fn new_inner( peri: impl Peripheral

+ 'd, @@ -929,7 +782,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { w.set_cpl(config.complement_format.cpl()); w.set_muteval(config.mute_value.muteval()); w.set_mutecnt(config.mute_detection_counter.0 as u8); - w.set_tris(config.is_high_impedenane_on_inactive_slot); + w.set_tris(config.is_high_impedance_on_inactive_slot); }); ch.frcr().modify(|w| { @@ -965,10 +818,31 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { } } + /// Start the SAI driver. + pub fn start(&mut self) { + match self.ring_buffer { + RingBuffer::Writable(ref mut rb) => { + rb.start(); + } + RingBuffer::Readable(ref mut rb) => { + rb.start(); + } + } + } + + fn is_transmitter(ring_buffer: &RingBuffer) -> bool { + match ring_buffer { + RingBuffer::Writable(_) => true, + _ => false, + } + } + + /// Reset SAI operation. pub fn reset() { T::enable_and_reset(); } + /// Flush. pub fn flush(&mut self) { let ch = T::REGS.ch(self.sub_block as usize); ch.cr1().modify(|w| w.set_saien(false)); @@ -983,19 +857,18 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { ch.cr1().modify(|w| w.set_saien(true)); } + /// Enable or disable mute. pub fn set_mute(&mut self, value: bool) { let ch = T::REGS.ch(self.sub_block as usize); ch.cr2().modify(|w| w.set_mute(value)); } - #[allow(dead_code)] - /// Reconfigures it with the supplied config. - fn reconfigure(&mut self, _config: Config) {} - - pub fn get_current_config(&self) -> Config { - Config::default() - } - + /// Write data to the SAI ringbuffer. + /// + /// This appends the data to the buffer and returns immediately. The + /// data will be transmitted in the background. + /// + /// If there's no space in the buffer, this waits until there is. pub async fn write(&mut self, data: &[W]) -> Result<(), Error> { match &mut self.ring_buffer { RingBuffer::Writable(buffer) => { @@ -1006,6 +879,12 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { } } + /// Read data from the SAI ringbuffer. + /// + /// SAI is always receiving data in the background. This function pops already-received + /// data from the buffer. + /// + /// If there's less than `data.len()` data in the buffer, this waits until there is. pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> { match &mut self.ring_buffer { RingBuffer::Readable(buffer) => { @@ -1017,7 +896,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { } } -impl<'d, T: Instance, C: Channel, W: word::Word> Drop for SubBlock<'d, T, C, W> { +impl<'d, T: Instance, C: Channel, W: word::Word> Drop for Sai<'d, T, C, W> { fn drop(&mut self) { let ch = T::REGS.ch(self.sub_block as usize); ch.cr1().modify(|w| w.set_saien(false)); @@ -1034,22 +913,43 @@ pub(crate) mod sealed { pub trait Instance { const REGS: Regs; } + + #[derive(Copy, Clone)] + pub enum WhichSubBlock { + A = 0, + B = 1, + } + + pub trait SubBlock { + const WHICH: WhichSubBlock; + } } -pub trait Word: word::Word {} +/// Sub-block instance trait. +pub trait SubBlockInstance: sealed::SubBlock {} +/// Sub-block A. +pub enum A {} +impl sealed::SubBlock for A { + const WHICH: WhichSubBlock = WhichSubBlock::A; +} +impl SubBlockInstance for A {} + +/// Sub-block B. +pub enum B {} +impl sealed::SubBlock for B { + const WHICH: WhichSubBlock = WhichSubBlock::B; +} +impl SubBlockInstance for B {} + +/// SAI instance trait. pub trait Instance: Peripheral

+ sealed::Instance + RccPeripheral {} -pin_trait!(SckAPin, Instance); -pin_trait!(SckBPin, Instance); -pin_trait!(FsAPin, Instance); -pin_trait!(FsBPin, Instance); -pin_trait!(SdAPin, Instance); -pin_trait!(SdBPin, Instance); -pin_trait!(MclkAPin, Instance); -pin_trait!(MclkBPin, Instance); +pin_trait!(SckPin, Instance, SubBlockInstance); +pin_trait!(FsPin, Instance, SubBlockInstance); +pin_trait!(SdPin, Instance, SubBlockInstance); +pin_trait!(MclkPin, Instance, SubBlockInstance); -dma_trait!(DmaA, Instance); -dma_trait!(DmaB, Instance); +dma_trait!(Dma, Instance, SubBlockInstance); foreach_peripheral!( (sai, $inst:ident) => { @@ -1060,13 +960,3 @@ foreach_peripheral!( impl Instance for peripherals::$inst {} }; ); - -impl<'d, T: Instance> SetConfig for Sai<'d, T> { - type Config = Config; - type ConfigError = (); - fn set_config(&mut self, _config: &Self::Config) -> Result<(), ()> { - // self.reconfigure(*config); - - Ok(()) - } -} diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 27a12062c..6099b9f43 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -1,3 +1,4 @@ +//! Secure Digital / MultiMedia Card (SDMMC) #![macro_use] use core::default::Default; diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 92599c75e..5a1ad3e91 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -1,3 +1,4 @@ +//! Serial Peripheral Interface (SPI) #![macro_use] use core::ptr; diff --git a/embassy-stm32/src/traits.rs b/embassy-stm32/src/traits.rs index b4166e71a..13f695821 100644 --- a/embassy-stm32/src/traits.rs +++ b/embassy-stm32/src/traits.rs @@ -1,18 +1,18 @@ #![macro_use] macro_rules! pin_trait { - ($signal:ident, $instance:path) => { + ($signal:ident, $instance:path $(, $mode: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))] + 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; } }; } macro_rules! pin_trait_impl { - (crate::$mod:ident::$trait:ident, $instance:ident, $pin:ident, $af:expr) => { - impl crate::$mod::$trait for crate::peripherals::$pin { + (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $pin:ident, $af:expr) => { + impl crate::$mod::$trait for crate::peripherals::$pin { fn af_num(&self) -> u8 { $af } @@ -23,9 +23,9 @@ macro_rules! pin_trait_impl { // ==================== macro_rules! dma_trait { - ($signal:ident, $instance:path) => { + ($signal:ident, $instance:path$(, $mode:path)?) => { #[doc = concat!(stringify!($signal), " DMA request trait")] - pub trait $signal: crate::dma::Channel { + 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. @@ -37,8 +37,8 @@ macro_rules! dma_trait { #[allow(unused)] macro_rules! dma_trait_impl { // DMAMUX - (crate::$mod:ident::$trait:ident, $instance:ident, {dmamux: $dmamux:ident}, $request:expr) => { - impl crate::$mod::$trait for T + (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {dmamux: $dmamux:ident}, $request:expr) => { + impl crate::$mod::$trait for T where T: crate::dma::Channel + crate::dma::MuxChannel, { @@ -49,8 +49,8 @@ macro_rules! dma_trait_impl { }; // DMAMUX - (crate::$mod:ident::$trait:ident, $instance:ident, {dma: $dma:ident}, $request:expr) => { - impl crate::$mod::$trait for T + (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {dma: $dma:ident}, $request:expr) => { + impl crate::$mod::$trait for T where T: crate::dma::Channel, { @@ -61,8 +61,8 @@ macro_rules! dma_trait_impl { }; // DMA/GPDMA, without DMAMUX - (crate::$mod:ident::$trait:ident, $instance:ident, {channel: $channel:ident}, $request:expr) => { - impl crate::$mod::$trait for crate::peripherals::$channel { + (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {channel: $channel:ident}, $request:expr) => { + impl crate::$mod::$trait for crate::peripherals::$channel { fn request(&self) -> crate::dma::Request { $request } diff --git a/embassy-stm32/src/uid.rs b/embassy-stm32/src/uid.rs index 6dcfcb96e..aa13586f8 100644 --- a/embassy-stm32/src/uid.rs +++ b/embassy-stm32/src/uid.rs @@ -1,3 +1,5 @@ +//! Unique ID (UID) + /// Get this device's unique 96-bit ID. pub fn uid() -> &'static [u8; 12] { unsafe { &*crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index dfa1f3a6a..e2e3bd3eb 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1,3 +1,4 @@ +//! Universal Synchronous/Asynchronous Receiver Transmitter (USART, UART, LPUART) #![macro_use] use core::future::poll_fn; diff --git a/embassy-stm32/src/usb_otg/mod.rs b/embassy-stm32/src/usb_otg/mod.rs index be54a3d10..1abd031dd 100644 --- a/embassy-stm32/src/usb_otg/mod.rs +++ b/embassy-stm32/src/usb_otg/mod.rs @@ -1,3 +1,5 @@ +//! USB On The Go (OTG) + use crate::rcc::RccPeripheral; use crate::{interrupt, peripherals}; diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs index c7c2694e0..5751a9ff3 100644 --- a/embassy-stm32/src/wdg/mod.rs +++ b/embassy-stm32/src/wdg/mod.rs @@ -1,3 +1,4 @@ +//! Watchdog Timer (IWDG, WWDG) use core::marker::PhantomData; use embassy_hal_internal::{into_ref, Peripheral};