Merge pull request #2310 from embassy-rs/stm32-docs
stm32/sai: docs, cleanup api.
This commit is contained in:
		
						commit
						08e9a4d84a
					
				| @ -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.
 | ||||
|  | ||||
| @ -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<A>)), | ||||
|         (("sai", "SCK_B"), quote!(crate::sai::SckPin<B>)), | ||||
|         (("sai", "FS_A"), quote!(crate::sai::FsPin<A>)), | ||||
|         (("sai", "FS_B"), quote!(crate::sai::FsPin<B>)), | ||||
|         (("sai", "SD_A"), quote!(crate::sai::SdPin<A>)), | ||||
|         (("sai", "SD_B"), quote!(crate::sai::SdPin<B>)), | ||||
|         (("sai", "MCLK_A"), quote!(crate::sai::MclkPin<A>)), | ||||
|         (("sai", "MCLK_B"), quote!(crate::sai::MclkPin<B>)), | ||||
|         (("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<A>)), | ||||
|         (("sai", "B"), quote!(crate::sai::Dma<B>)), | ||||
|         (("spi", "RX"), quote!(crate::spi::RxDma)), | ||||
|         (("spi", "TX"), quote!(crate::spi::TxDma)), | ||||
|         (("i2c", "RX"), quote!(crate::i2c::RxDma)), | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| //! Analog to Digital (ADC) converter driver.
 | ||||
| //! Analog to Digital Converter (ADC)
 | ||||
| 
 | ||||
| #![macro_use] | ||||
| #![allow(missing_docs)] // TODO
 | ||||
| 
 | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| //! Controller Area Network (CAN)
 | ||||
| #![macro_use] | ||||
| 
 | ||||
| #[cfg_attr(can_bxcan, path = "bxcan.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")] | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| //! Digital Camera Interface (DCMI)
 | ||||
| use core::future::poll_fn; | ||||
| use core::marker::PhantomData; | ||||
| use core::task::Poll; | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| //! Ethernet (ETH)
 | ||||
| #![macro_use] | ||||
| 
 | ||||
| #[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")] | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| //! External Interrupts (EXTI)
 | ||||
| use core::convert::Infallible; | ||||
| use core::future::Future; | ||||
| use core::marker::PhantomData; | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| //! Flash memory (FLASH)
 | ||||
| use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; | ||||
| 
 | ||||
| #[cfg(flash_f4)] | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| //! Flexible Memory Controller (FMC) / Flexible Static Memory Controller (FSMC)
 | ||||
| use core::marker::PhantomData; | ||||
| 
 | ||||
| use embassy_hal_internal::into_ref; | ||||
|  | ||||
| @ -1,3 +1,5 @@ | ||||
| //! High Resolution Timer (HRTIM)
 | ||||
| 
 | ||||
| mod traits; | ||||
| 
 | ||||
| use core::marker::PhantomData; | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| //! Inter-Integrated-Circuit (I2C)
 | ||||
| #![macro_use] | ||||
| 
 | ||||
| #[cfg_attr(i2c_v1, path = "v1.rs")] | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| //! Inter-IC Sound (I2S)
 | ||||
| use embassy_hal_internal::into_ref; | ||||
| 
 | ||||
| use crate::gpio::sealed::{AFType, Pin as _}; | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -1,3 +1,5 @@ | ||||
| //! Quad Serial Peripheral Interface (QSPI)
 | ||||
| 
 | ||||
| #![macro_use] | ||||
| 
 | ||||
| pub mod enums; | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| //! Random Number Generator (RNG)
 | ||||
| #![macro_use] | ||||
| 
 | ||||
| use core::future::poll_fn; | ||||
|  | ||||
| @ -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<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>, | ||||
|  | ||||
| @ -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<ringbuffer::OverrunError> 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<vals::Flvl> 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: word::Word>(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<PeripheralRef<'d, AnyPin>>, | ||||
|     fs: Option<PeripheralRef<'d, AnyPin>>, | ||||
|     sck: Option<PeripheralRef<'d, AnyPin>>, | ||||
|     mclk: Option<PeripheralRef<'d, AnyPin>>, | ||||
|     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<SubBlockAPeripheral<'d, T>>, | ||||
|     sub_block_b_peri: Option<SubBlockBPeripheral<'d, T>>, | ||||
| } | ||||
| 
 | ||||
| // 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<P = T> + '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<SubBlockAPeripheral<'d, T>> { | ||||
|         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<SubBlockBPeripheral<'d, T>> { | ||||
|         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<P = impl SckAPin<T>> + 'd, | ||||
|         sd: impl Peripheral<P = impl SdAPin<T>> + 'd, | ||||
|         fs: impl Peripheral<P = impl FsAPin<T>> + 'd, | ||||
|         mclk: impl Peripheral<P = impl MclkAPin<T>> + 'd, | ||||
| /// SAI subblock instance.
 | ||||
| pub struct SubBlock<'d, T, S: SubBlockInstance> { | ||||
|     peri: PeripheralRef<'d, T>, | ||||
|     _phantom: PhantomData<S>, | ||||
| } | ||||
| 
 | ||||
| /// 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<P = T> + '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<PeripheralRef<'d, AnyPin>>, | ||||
|     fs: Option<PeripheralRef<'d, AnyPin>>, | ||||
|     sck: Option<PeripheralRef<'d, AnyPin>>, | ||||
|     mclk: Option<PeripheralRef<'d, AnyPin>>, | ||||
|     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<S: SubBlockInstance>( | ||||
|         peri: SubBlock<'d, T, S>, | ||||
|         sck: impl Peripheral<P = impl SckPin<T, S>> + 'd, | ||||
|         sd: impl Peripheral<P = impl SdPin<T, S>> + 'd, | ||||
|         fs: impl Peripheral<P = impl FsPin<T, S>> + 'd, | ||||
|         mclk: impl Peripheral<P = impl MclkPin<T, S>> + 'd, | ||||
|         dma: impl Peripheral<P = C> + 'd, | ||||
|         dma_buf: &'d mut [W], | ||||
|         mut config: Config, | ||||
|     ) -> SubBlock<'d, T, C, W> | ||||
|     ) -> Self | ||||
|     where | ||||
|         C: Channel + DmaA<T>, | ||||
|         C: Channel + Dma<T, S>, | ||||
|     { | ||||
|         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<P = impl SckAPin<T>> + 'd, | ||||
|         sd: impl Peripheral<P = impl SdAPin<T>> + 'd, | ||||
|         fs: impl Peripheral<P = impl FsAPin<T>> + 'd, | ||||
|     /// Create a new SAI driver in asynchronous mode without MCLK.
 | ||||
|     ///
 | ||||
|     /// You can obtain the [`SubBlock`] with [`split_subblocks`].
 | ||||
|     pub fn new_asynchronous<S: SubBlockInstance>( | ||||
|         peri: SubBlock<'d, T, S>, | ||||
|         sck: impl Peripheral<P = impl SckPin<T, S>> + 'd, | ||||
|         sd: impl Peripheral<P = impl SdPin<T, S>> + 'd, | ||||
|         fs: impl Peripheral<P = impl FsPin<T, S>> + 'd, | ||||
|         dma: impl Peripheral<P = C> + 'd, | ||||
|         dma_buf: &'d mut [W], | ||||
|         config: Config, | ||||
|     ) -> SubBlock<'d, T, C, W> | ||||
|     ) -> Self | ||||
|     where | ||||
|         C: Channel + DmaA<T>, | ||||
|         C: Channel + Dma<T, S>, | ||||
|     { | ||||
|         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<P = impl SdAPin<T>> + 'd, | ||||
|     /// Create a new SAI driver in synchronous mode.
 | ||||
|     ///
 | ||||
|     /// You can obtain the [`SubBlock`] with [`split_subblocks`].
 | ||||
|     pub fn new_synchronous<S: SubBlockInstance>( | ||||
|         peri: SubBlock<'d, T, S>, | ||||
|         sd: impl Peripheral<P = impl SdPin<T, S>> + 'd, | ||||
|         dma: impl Peripheral<P = C> + 'd, | ||||
|         dma_buf: &'d mut [W], | ||||
|         mut config: Config, | ||||
|     ) -> SubBlock<'d, T, C, W> | ||||
|     ) -> Self | ||||
|     where | ||||
|         C: Channel + DmaA<T>, | ||||
|         C: Channel + Dma<T, S>, | ||||
|     { | ||||
|         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<P = impl SckBPin<T>> + 'd, | ||||
|         sd: impl Peripheral<P = impl SdBPin<T>> + 'd, | ||||
|         fs: impl Peripheral<P = impl FsBPin<T>> + 'd, | ||||
|         mclk: impl Peripheral<P = impl MclkBPin<T>> + 'd, | ||||
|         dma: impl Peripheral<P = C> + 'd, | ||||
|         dma_buf: &'d mut [W], | ||||
|         mut config: Config, | ||||
|     ) -> SubBlock<'d, T, C, W> | ||||
|     where | ||||
|         C: Channel + DmaB<T>, | ||||
|     { | ||||
|         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<P = impl SckBPin<T>> + 'd, | ||||
|         sd: impl Peripheral<P = impl SdBPin<T>> + 'd, | ||||
|         fs: impl Peripheral<P = impl FsBPin<T>> + 'd, | ||||
|         dma: impl Peripheral<P = C> + 'd, | ||||
|         dma_buf: &'d mut [W], | ||||
|         config: Config, | ||||
|     ) -> SubBlock<'d, T, C, W> | ||||
|     where | ||||
|         C: Channel + DmaB<T>, | ||||
|     { | ||||
|         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::<T, C, W>(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<P = impl SdBPin<T>> + 'd, | ||||
|         dma: impl Peripheral<P = C> + 'd, | ||||
|         dma_buf: &'d mut [W], | ||||
|         mut config: Config, | ||||
|     ) -> SubBlock<'d, T, C, W> | ||||
|     where | ||||
|         C: Channel + DmaB<T>, | ||||
|     { | ||||
|         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::<T, C, W>(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<C, W>) -> bool { | ||||
|         match ring_buffer { | ||||
|             RingBuffer::Writable(_) => true, | ||||
|             _ => false, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn new_inner( | ||||
|         peri: impl Peripheral<P = T> + '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<C, W>) -> 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 Word: word::Word {} | ||||
|     pub trait SubBlock { | ||||
|         const WHICH: WhichSubBlock; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// 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<P = Self> + 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(()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| //! Secure Digital / MultiMedia Card (SDMMC)
 | ||||
| #![macro_use] | ||||
| 
 | ||||
| use core::default::Default; | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| //! Serial Peripheral Interface (SPI)
 | ||||
| #![macro_use] | ||||
| 
 | ||||
| use core::ptr; | ||||
|  | ||||
| @ -1,9 +1,9 @@ | ||||
| #![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<T: $instance>: crate::gpio::Pin { | ||||
|         pub trait $signal<T: $instance $(, M: $mode)?>: crate::gpio::Pin { | ||||
|             #[doc = concat!("Get the AF number needed to use this pin as ", stringify!($signal))] | ||||
|             fn af_num(&self) -> u8; | ||||
|         } | ||||
| @ -11,8 +11,8 @@ macro_rules! pin_trait { | ||||
| } | ||||
| 
 | ||||
| macro_rules! pin_trait_impl { | ||||
|     (crate::$mod:ident::$trait:ident, $instance:ident, $pin:ident, $af:expr) => { | ||||
|         impl crate::$mod::$trait<crate::peripherals::$instance> for crate::peripherals::$pin { | ||||
|     (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $pin:ident, $af:expr) => { | ||||
|         impl crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> 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<T: $instance>: crate::dma::Channel { | ||||
|         pub trait $signal<T: $instance $(, M: $mode)?>: 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<T> crate::$mod::$trait<crate::peripherals::$instance> for T | ||||
|     (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {dmamux: $dmamux:ident}, $request:expr) => { | ||||
|         impl<T> crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for T | ||||
|         where | ||||
|             T: crate::dma::Channel + crate::dma::MuxChannel<Mux = crate::dma::$dmamux>, | ||||
|         { | ||||
| @ -49,8 +49,8 @@ macro_rules! dma_trait_impl { | ||||
|     }; | ||||
| 
 | ||||
|     // DMAMUX
 | ||||
|     (crate::$mod:ident::$trait:ident, $instance:ident, {dma: $dma:ident}, $request:expr) => { | ||||
|         impl<T> crate::$mod::$trait<crate::peripherals::$instance> for T | ||||
|     (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {dma: $dma:ident}, $request:expr) => { | ||||
|         impl<T> crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> 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<crate::peripherals::$instance> for crate::peripherals::$channel { | ||||
|     (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {channel: $channel:ident}, $request:expr) => { | ||||
|         impl crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for crate::peripherals::$channel { | ||||
|             fn request(&self) -> crate::dma::Request { | ||||
|                 $request | ||||
|             } | ||||
|  | ||||
| @ -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]>() } | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| //! Universal Synchronous/Asynchronous Receiver Transmitter (USART, UART, LPUART)
 | ||||
| #![macro_use] | ||||
| 
 | ||||
| use core::future::poll_fn; | ||||
|  | ||||
| @ -1,3 +1,5 @@ | ||||
| //! USB On The Go (OTG)
 | ||||
| 
 | ||||
| use crate::rcc::RccPeripheral; | ||||
| use crate::{interrupt, peripherals}; | ||||
| 
 | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| //! Watchdog Timer (IWDG, WWDG)
 | ||||
| use core::marker::PhantomData; | ||||
| 
 | ||||
| use embassy_hal_internal::{into_ref, Peripheral}; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user