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 |     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 { | pub fn init(config: config::Config) -> Peripherals { | ||||||
|     // Do this first, so that it panics if user is calling `init` a second time
 |     // Do this first, so that it panics if user is calling `init` a second time
 | ||||||
|     // before doing anything important.
 |     // before doing anything important.
 | ||||||
|  | |||||||
| @ -672,14 +672,14 @@ fn main() { | |||||||
|         (("lpuart", "RTS"), quote!(crate::usart::RtsPin)), |         (("lpuart", "RTS"), quote!(crate::usart::RtsPin)), | ||||||
|         (("lpuart", "CK"), quote!(crate::usart::CkPin)), |         (("lpuart", "CK"), quote!(crate::usart::CkPin)), | ||||||
|         (("lpuart", "DE"), quote!(crate::usart::DePin)), |         (("lpuart", "DE"), quote!(crate::usart::DePin)), | ||||||
|         (("sai", "SCK_A"), quote!(crate::sai::SckAPin)), |         (("sai", "SCK_A"), quote!(crate::sai::SckPin<A>)), | ||||||
|         (("sai", "SCK_B"), quote!(crate::sai::SckBPin)), |         (("sai", "SCK_B"), quote!(crate::sai::SckPin<B>)), | ||||||
|         (("sai", "FS_A"), quote!(crate::sai::FsAPin)), |         (("sai", "FS_A"), quote!(crate::sai::FsPin<A>)), | ||||||
|         (("sai", "FS_B"), quote!(crate::sai::FsBPin)), |         (("sai", "FS_B"), quote!(crate::sai::FsPin<B>)), | ||||||
|         (("sai", "SD_A"), quote!(crate::sai::SdAPin)), |         (("sai", "SD_A"), quote!(crate::sai::SdPin<A>)), | ||||||
|         (("sai", "SD_B"), quote!(crate::sai::SdBPin)), |         (("sai", "SD_B"), quote!(crate::sai::SdPin<B>)), | ||||||
|         (("sai", "MCLK_A"), quote!(crate::sai::MclkAPin)), |         (("sai", "MCLK_A"), quote!(crate::sai::MclkPin<A>)), | ||||||
|         (("sai", "MCLK_B"), quote!(crate::sai::MclkBPin)), |         (("sai", "MCLK_B"), quote!(crate::sai::MclkPin<B>)), | ||||||
|         (("sai", "WS"), quote!(crate::sai::WsPin)), |         (("sai", "WS"), quote!(crate::sai::WsPin)), | ||||||
|         (("spi", "SCK"), quote!(crate::spi::SckPin)), |         (("spi", "SCK"), quote!(crate::spi::SckPin)), | ||||||
|         (("spi", "MOSI"), quote!(crate::spi::MosiPin)), |         (("spi", "MOSI"), quote!(crate::spi::MosiPin)), | ||||||
| @ -995,8 +995,8 @@ fn main() { | |||||||
|         (("usart", "TX"), quote!(crate::usart::TxDma)), |         (("usart", "TX"), quote!(crate::usart::TxDma)), | ||||||
|         (("lpuart", "RX"), quote!(crate::usart::RxDma)), |         (("lpuart", "RX"), quote!(crate::usart::RxDma)), | ||||||
|         (("lpuart", "TX"), quote!(crate::usart::TxDma)), |         (("lpuart", "TX"), quote!(crate::usart::TxDma)), | ||||||
|         (("sai", "A"), quote!(crate::sai::DmaA)), |         (("sai", "A"), quote!(crate::sai::Dma<A>)), | ||||||
|         (("sai", "B"), quote!(crate::sai::DmaB)), |         (("sai", "B"), quote!(crate::sai::Dma<B>)), | ||||||
|         (("spi", "RX"), quote!(crate::spi::RxDma)), |         (("spi", "RX"), quote!(crate::spi::RxDma)), | ||||||
|         (("spi", "TX"), quote!(crate::spi::TxDma)), |         (("spi", "TX"), quote!(crate::spi::TxDma)), | ||||||
|         (("i2c", "RX"), quote!(crate::i2c::RxDma)), |         (("i2c", "RX"), quote!(crate::i2c::RxDma)), | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| //! Analog to Digital (ADC) converter driver.
 | //! Analog to Digital Converter (ADC)
 | ||||||
|  | 
 | ||||||
| #![macro_use] | #![macro_use] | ||||||
| #![allow(missing_docs)] // TODO
 | #![allow(missing_docs)] // TODO
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | //! Controller Area Network (CAN)
 | ||||||
| #![macro_use] | #![macro_use] | ||||||
| 
 | 
 | ||||||
| #[cfg_attr(can_bxcan, path = "bxcan.rs")] | #[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_v1, path = "v1.rs")] | ||||||
| #[cfg_attr(crc_v2, path = "v2v3.rs")] | #[cfg_attr(crc_v2, path = "v2v3.rs")] | ||||||
| #[cfg_attr(crc_v3, 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] | #![macro_use] | ||||||
| 
 | 
 | ||||||
| use core::marker::PhantomData; | use core::marker::PhantomData; | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | //! Digital Camera Interface (DCMI)
 | ||||||
| use core::future::poll_fn; | use core::future::poll_fn; | ||||||
| use core::marker::PhantomData; | use core::marker::PhantomData; | ||||||
| use core::task::Poll; | use core::task::Poll; | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | //! Ethernet (ETH)
 | ||||||
| #![macro_use] | #![macro_use] | ||||||
| 
 | 
 | ||||||
| #[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")] | #[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::convert::Infallible; | ||||||
| use core::future::Future; | use core::future::Future; | ||||||
| use core::marker::PhantomData; | use core::marker::PhantomData; | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | //! Flash memory (FLASH)
 | ||||||
| use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; | use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; | ||||||
| 
 | 
 | ||||||
| #[cfg(flash_f4)] | #[cfg(flash_f4)] | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | //! Flexible Memory Controller (FMC) / Flexible Static Memory Controller (FSMC)
 | ||||||
| use core::marker::PhantomData; | use core::marker::PhantomData; | ||||||
| 
 | 
 | ||||||
| use embassy_hal_internal::into_ref; | use embassy_hal_internal::into_ref; | ||||||
|  | |||||||
| @ -1,3 +1,5 @@ | |||||||
|  | //! High Resolution Timer (HRTIM)
 | ||||||
|  | 
 | ||||||
| mod traits; | mod traits; | ||||||
| 
 | 
 | ||||||
| use core::marker::PhantomData; | use core::marker::PhantomData; | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | //! Inter-Integrated-Circuit (I2C)
 | ||||||
| #![macro_use] | #![macro_use] | ||||||
| 
 | 
 | ||||||
| #[cfg_attr(i2c_v1, path = "v1.rs")] | #[cfg_attr(i2c_v1, path = "v1.rs")] | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | //! Inter-IC Sound (I2S)
 | ||||||
| use embassy_hal_internal::into_ref; | use embassy_hal_internal::into_ref; | ||||||
| 
 | 
 | ||||||
| use crate::gpio::sealed::{AFType, Pin as _}; | use crate::gpio::sealed::{AFType, Pin as _}; | ||||||
|  | |||||||
| @ -149,15 +149,33 @@ use crate::interrupt::Priority; | |||||||
| pub use crate::pac::NVIC_PRIO_BITS; | pub use crate::pac::NVIC_PRIO_BITS; | ||||||
| use crate::rcc::sealed::RccPeripheral; | use crate::rcc::sealed::RccPeripheral; | ||||||
| 
 | 
 | ||||||
|  | /// `embassy-stm32` global configuration.
 | ||||||
| #[non_exhaustive] | #[non_exhaustive] | ||||||
| pub struct Config { | pub struct Config { | ||||||
|  |     /// RCC config.
 | ||||||
|     pub rcc: rcc::Config, |     pub rcc: rcc::Config, | ||||||
|  | 
 | ||||||
|  |     /// Enable debug during sleep.
 | ||||||
|  |     ///
 | ||||||
|  |     /// May incrase power consumption. Defaults to true.
 | ||||||
|     #[cfg(dbgmcu)] |     #[cfg(dbgmcu)] | ||||||
|     pub enable_debug_during_sleep: bool, |     pub enable_debug_during_sleep: bool, | ||||||
|  | 
 | ||||||
|  |     /// BDMA interrupt priority.
 | ||||||
|  |     ///
 | ||||||
|  |     /// Defaults to P0 (highest).
 | ||||||
|     #[cfg(bdma)] |     #[cfg(bdma)] | ||||||
|     pub bdma_interrupt_priority: Priority, |     pub bdma_interrupt_priority: Priority, | ||||||
|  | 
 | ||||||
|  |     /// DMA interrupt priority.
 | ||||||
|  |     ///
 | ||||||
|  |     /// Defaults to P0 (highest).
 | ||||||
|     #[cfg(dma)] |     #[cfg(dma)] | ||||||
|     pub dma_interrupt_priority: Priority, |     pub dma_interrupt_priority: Priority, | ||||||
|  | 
 | ||||||
|  |     /// GPDMA interrupt priority.
 | ||||||
|  |     ///
 | ||||||
|  |     /// Defaults to P0 (highest).
 | ||||||
|     #[cfg(gpdma)] |     #[cfg(gpdma)] | ||||||
|     pub gpdma_interrupt_priority: Priority, |     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 { | pub fn init(config: Config) -> Peripherals { | ||||||
|     critical_section::with(|cs| { |     critical_section::with(|cs| { | ||||||
|         let p = Peripherals::take_with_cs(cs); |         let p = Peripherals::take_with_cs(cs); | ||||||
|  | |||||||
| @ -1,3 +1,5 @@ | |||||||
|  | //! Quad Serial Peripheral Interface (QSPI)
 | ||||||
|  | 
 | ||||||
| #![macro_use] | #![macro_use] | ||||||
| 
 | 
 | ||||||
| pub mod enums; | pub mod enums; | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | //! Random Number Generator (RNG)
 | ||||||
| #![macro_use] | #![macro_use] | ||||||
| 
 | 
 | ||||||
| use core::future::poll_fn; | use core::future::poll_fn; | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| //! RTC peripheral abstraction
 | //! Real Time Clock (RTC)
 | ||||||
| mod datetime; | mod datetime; | ||||||
| 
 | 
 | ||||||
| #[cfg(feature = "low-power")] | #[cfg(feature = "low-power")] | ||||||
| @ -163,7 +163,7 @@ impl RtcTimeProvider { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// RTC Abstraction
 | /// RTC driver.
 | ||||||
| pub struct Rtc { | pub struct Rtc { | ||||||
|     #[cfg(feature = "low-power")] |     #[cfg(feature = "low-power")] | ||||||
|     stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>, |     stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>, | ||||||
|  | |||||||
| @ -1,8 +1,11 @@ | |||||||
|  | //! Serial Audio Interface (SAI)
 | ||||||
| #![macro_use] | #![macro_use] | ||||||
| 
 | 
 | ||||||
| use embassy_embedded_hal::SetConfig; | use core::marker::PhantomData; | ||||||
|  | 
 | ||||||
| use embassy_hal_internal::{into_ref, PeripheralRef}; | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||||||
| 
 | 
 | ||||||
|  | use self::sealed::WhichSubBlock; | ||||||
| pub use crate::dma::word; | pub use crate::dma::word; | ||||||
| use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; | use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; | ||||||
| use crate::gpio::sealed::{AFType, Pin as _}; | 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::rcc::RccPeripheral; | ||||||
| use crate::{peripherals, Peripheral}; | use crate::{peripherals, Peripheral}; | ||||||
| 
 | 
 | ||||||
|  | /// SAI error
 | ||||||
| #[derive(Debug, PartialEq, Eq)] | #[derive(Debug, PartialEq, Eq)] | ||||||
| #[cfg_attr(feature = "defmt", derive(defmt::Format))] | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||||||
| pub enum Error { | pub enum Error { | ||||||
|  |     /// `write` called on a SAI in receive mode.
 | ||||||
|     NotATransmitter, |     NotATransmitter, | ||||||
|  |     /// `read` called on a SAI in transmit mode.
 | ||||||
|     NotAReceiver, |     NotAReceiver, | ||||||
|     OverrunError, |     /// Overrun
 | ||||||
|  |     Overrun, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl From<ringbuffer::OverrunError> for Error { | impl From<ringbuffer::OverrunError> for Error { | ||||||
|     fn from(_: ringbuffer::OverrunError) -> Self { |     fn from(_: ringbuffer::OverrunError) -> Self { | ||||||
|         Self::OverrunError |         Self::Overrun | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Master/slave mode.
 | ||||||
| #[derive(Copy, Clone)] | #[derive(Copy, Clone)] | ||||||
| pub enum SyncBlock { | #[allow(missing_docs)] | ||||||
|     None, |  | ||||||
|     Sai1BlockA, |  | ||||||
|     Sai1BlockB, |  | ||||||
|     Sai2BlockA, |  | ||||||
|     Sai2BlockB, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Copy, Clone)] |  | ||||||
| pub enum SyncIn { |  | ||||||
|     None, |  | ||||||
|     ChannelZero, |  | ||||||
|     ChannelOne, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Copy, Clone)] |  | ||||||
| pub enum Mode { | pub enum Mode { | ||||||
|     Master, |     Master, | ||||||
|     Slave, |     Slave, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Copy, Clone)] |  | ||||||
| pub enum TxRx { |  | ||||||
|     Transmitter, |  | ||||||
|     Receiver, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Mode { | impl Mode { | ||||||
|     #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |     #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | ||||||
|     const fn mode(&self, tx_rx: TxRx) -> vals::Mode { |     const fn mode(&self, tx_rx: TxRx) -> vals::Mode { | ||||||
| @ -69,7 +56,17 @@ impl Mode { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Direction: transmit or receive
 | ||||||
| #[derive(Copy, Clone)] | #[derive(Copy, Clone)] | ||||||
|  | #[allow(missing_docs)] | ||||||
|  | pub enum TxRx { | ||||||
|  |     Transmitter, | ||||||
|  |     Receiver, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Data slot size.
 | ||||||
|  | #[derive(Copy, Clone)] | ||||||
|  | #[allow(missing_docs)] | ||||||
| pub enum SlotSize { | pub enum SlotSize { | ||||||
|     DataSize, |     DataSize, | ||||||
|     /// 16 bit data length on 16 bit wide channel
 |     /// 16 bit data length on 16 bit wide channel
 | ||||||
| @ -80,7 +77,7 @@ pub enum SlotSize { | |||||||
| 
 | 
 | ||||||
| impl SlotSize { | impl SlotSize { | ||||||
|     #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |     #[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 { |         match self { | ||||||
|             SlotSize::DataSize => vals::Slotsz::DATASIZE, |             SlotSize::DataSize => vals::Slotsz::DATASIZE, | ||||||
|             SlotSize::Channel16 => vals::Slotsz::BIT16, |             SlotSize::Channel16 => vals::Slotsz::BIT16, | ||||||
| @ -89,7 +86,9 @@ impl SlotSize { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Data size.
 | ||||||
| #[derive(Copy, Clone)] | #[derive(Copy, Clone)] | ||||||
|  | #[allow(missing_docs)] | ||||||
| pub enum DataSize { | pub enum DataSize { | ||||||
|     Data8, |     Data8, | ||||||
|     Data10, |     Data10, | ||||||
| @ -101,7 +100,7 @@ pub enum DataSize { | |||||||
| 
 | 
 | ||||||
| impl DataSize { | impl DataSize { | ||||||
|     #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |     #[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 { |         match self { | ||||||
|             DataSize::Data8 => vals::Ds::BIT8, |             DataSize::Data8 => vals::Ds::BIT8, | ||||||
|             DataSize::Data10 => vals::Ds::BIT10, |             DataSize::Data10 => vals::Ds::BIT10, | ||||||
| @ -113,7 +112,9 @@ impl DataSize { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// FIFO threshold level.
 | ||||||
| #[derive(Copy, Clone)] | #[derive(Copy, Clone)] | ||||||
|  | #[allow(missing_docs)] | ||||||
| pub enum FifoThreshold { | pub enum FifoThreshold { | ||||||
|     Empty, |     Empty, | ||||||
|     Quarter, |     Quarter, | ||||||
| @ -124,7 +125,7 @@ pub enum FifoThreshold { | |||||||
| 
 | 
 | ||||||
| impl FifoThreshold { | impl FifoThreshold { | ||||||
|     #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |     #[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 { |         match self { | ||||||
|             FifoThreshold::Empty => vals::Fth::EMPTY, |             FifoThreshold::Empty => vals::Fth::EMPTY, | ||||||
|             FifoThreshold::Quarter => vals::Fth::QUARTER1, |             FifoThreshold::Quarter => vals::Fth::QUARTER1, | ||||||
| @ -135,38 +136,9 @@ impl FifoThreshold { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Output value on mute.
 | ||||||
| #[derive(Copy, Clone)] | #[derive(Copy, Clone)] | ||||||
| pub enum FifoLevel { | #[allow(missing_docs)] | ||||||
|     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)] |  | ||||||
| pub enum MuteValue { | pub enum MuteValue { | ||||||
|     Zero, |     Zero, | ||||||
|     LastValue, |     LastValue, | ||||||
| @ -174,7 +146,7 @@ pub enum MuteValue { | |||||||
| 
 | 
 | ||||||
| impl MuteValue { | impl MuteValue { | ||||||
|     #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |     #[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 { |         match self { | ||||||
|             MuteValue::Zero => vals::Muteval::SENDZERO, |             MuteValue::Zero => vals::Muteval::SENDZERO, | ||||||
|             MuteValue::LastValue => vals::Muteval::SENDLAST, |             MuteValue::LastValue => vals::Muteval::SENDLAST, | ||||||
| @ -182,13 +154,9 @@ impl MuteValue { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Protocol variant to use.
 | ||||||
| #[derive(Copy, Clone)] | #[derive(Copy, Clone)] | ||||||
| pub enum OverUnderStatus { | #[allow(missing_docs)] | ||||||
|     NoError, |  | ||||||
|     OverUnderRunDetected, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Copy, Clone)] |  | ||||||
| pub enum Protocol { | pub enum Protocol { | ||||||
|     Free, |     Free, | ||||||
|     Spdif, |     Spdif, | ||||||
| @ -197,7 +165,7 @@ pub enum Protocol { | |||||||
| 
 | 
 | ||||||
| impl Protocol { | impl Protocol { | ||||||
|     #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |     #[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 { |         match self { | ||||||
|             Protocol::Free => vals::Prtcfg::FREE, |             Protocol::Free => vals::Prtcfg::FREE, | ||||||
|             Protocol::Spdif => vals::Prtcfg::SPDIF, |             Protocol::Spdif => vals::Prtcfg::SPDIF, | ||||||
| @ -206,7 +174,9 @@ impl Protocol { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Sync input between SAI units/blocks.
 | ||||||
| #[derive(Copy, Clone, PartialEq)] | #[derive(Copy, Clone, PartialEq)] | ||||||
|  | #[allow(missing_docs)] | ||||||
| pub enum SyncInput { | pub enum SyncInput { | ||||||
|     /// Not synced to any other SAI unit.
 |     /// Not synced to any other SAI unit.
 | ||||||
|     None, |     None, | ||||||
| @ -218,7 +188,7 @@ pub enum SyncInput { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl SyncInput { | impl SyncInput { | ||||||
|     pub const fn syncen(&self) -> vals::Syncen { |     const fn syncen(&self) -> vals::Syncen { | ||||||
|         match self { |         match self { | ||||||
|             SyncInput::None => vals::Syncen::ASYNCHRONOUS, |             SyncInput::None => vals::Syncen::ASYNCHRONOUS, | ||||||
|             SyncInput::Internal => vals::Syncen::INTERNAL, |             SyncInput::Internal => vals::Syncen::INTERNAL, | ||||||
| @ -228,8 +198,10 @@ impl SyncInput { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// SAI instance to sync from.
 | ||||||
| #[cfg(sai_v4)] | #[cfg(sai_v4)] | ||||||
| #[derive(Copy, Clone, PartialEq)] | #[derive(Copy, Clone, PartialEq)] | ||||||
|  | #[allow(missing_docs)] | ||||||
| pub enum SyncInputInstance { | pub enum SyncInputInstance { | ||||||
|     #[cfg(peri_sai1)] |     #[cfg(peri_sai1)] | ||||||
|     Sai1 = 0, |     Sai1 = 0, | ||||||
| @ -241,7 +213,9 @@ pub enum SyncInputInstance { | |||||||
|     Sai4 = 3, |     Sai4 = 3, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Channels (stereo or mono).
 | ||||||
| #[derive(Copy, Clone, PartialEq)] | #[derive(Copy, Clone, PartialEq)] | ||||||
|  | #[allow(missing_docs)] | ||||||
| pub enum StereoMono { | pub enum StereoMono { | ||||||
|     Stereo, |     Stereo, | ||||||
|     Mono, |     Mono, | ||||||
| @ -249,7 +223,7 @@ pub enum StereoMono { | |||||||
| 
 | 
 | ||||||
| impl StereoMono { | impl StereoMono { | ||||||
|     #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |     #[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 { |         match self { | ||||||
|             StereoMono::Stereo => vals::Mono::STEREO, |             StereoMono::Stereo => vals::Mono::STEREO, | ||||||
|             StereoMono::Mono => vals::Mono::MONO, |             StereoMono::Mono => vals::Mono::MONO, | ||||||
| @ -257,15 +231,18 @@ impl StereoMono { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Bit order
 | ||||||
| #[derive(Copy, Clone)] | #[derive(Copy, Clone)] | ||||||
| pub enum BitOrder { | pub enum BitOrder { | ||||||
|  |     /// Least significant bit first.
 | ||||||
|     LsbFirst, |     LsbFirst, | ||||||
|  |     /// Most significant bit first.
 | ||||||
|     MsbFirst, |     MsbFirst, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl BitOrder { | impl BitOrder { | ||||||
|     #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |     #[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 { |         match self { | ||||||
|             BitOrder::LsbFirst => vals::Lsbfirst::LSBFIRST, |             BitOrder::LsbFirst => vals::Lsbfirst::LSBFIRST, | ||||||
|             BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST, |             BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST, | ||||||
| @ -273,6 +250,7 @@ impl BitOrder { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Frame sync offset.
 | ||||||
| #[derive(Copy, Clone)] | #[derive(Copy, Clone)] | ||||||
| pub enum FrameSyncOffset { | pub enum FrameSyncOffset { | ||||||
|     /// This is used in modes other than standard I2S phillips mode
 |     /// This is used in modes other than standard I2S phillips mode
 | ||||||
| @ -283,7 +261,7 @@ pub enum FrameSyncOffset { | |||||||
| 
 | 
 | ||||||
| impl FrameSyncOffset { | impl FrameSyncOffset { | ||||||
|     #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |     #[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 { |         match self { | ||||||
|             FrameSyncOffset::OnFirstBit => vals::Fsoff::ONFIRST, |             FrameSyncOffset::OnFirstBit => vals::Fsoff::ONFIRST, | ||||||
|             FrameSyncOffset::BeforeFirstBit => vals::Fsoff::BEFOREFIRST, |             FrameSyncOffset::BeforeFirstBit => vals::Fsoff::BEFOREFIRST, | ||||||
| @ -291,15 +269,18 @@ impl FrameSyncOffset { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Frame sync polarity
 | ||||||
| #[derive(Copy, Clone)] | #[derive(Copy, Clone)] | ||||||
| pub enum FrameSyncPolarity { | pub enum FrameSyncPolarity { | ||||||
|  |     /// Sync signal is active low.
 | ||||||
|     ActiveLow, |     ActiveLow, | ||||||
|  |     /// Sync signal is active high
 | ||||||
|     ActiveHigh, |     ActiveHigh, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl FrameSyncPolarity { | impl FrameSyncPolarity { | ||||||
|     #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |     #[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 { |         match self { | ||||||
|             FrameSyncPolarity::ActiveLow => vals::Fspol::FALLINGEDGE, |             FrameSyncPolarity::ActiveLow => vals::Fspol::FALLINGEDGE, | ||||||
|             FrameSyncPolarity::ActiveHigh => vals::Fspol::RISINGEDGE, |             FrameSyncPolarity::ActiveHigh => vals::Fspol::RISINGEDGE, | ||||||
| @ -307,7 +288,9 @@ impl FrameSyncPolarity { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Sync definition.
 | ||||||
| #[derive(Copy, Clone)] | #[derive(Copy, Clone)] | ||||||
|  | #[allow(missing_docs)] | ||||||
| pub enum FrameSyncDefinition { | pub enum FrameSyncDefinition { | ||||||
|     StartOfFrame, |     StartOfFrame, | ||||||
|     ChannelIdentification, |     ChannelIdentification, | ||||||
| @ -315,7 +298,7 @@ pub enum FrameSyncDefinition { | |||||||
| 
 | 
 | ||||||
| impl FrameSyncDefinition { | impl FrameSyncDefinition { | ||||||
|     #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |     #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | ||||||
|     pub const fn fsdef(&self) -> bool { |     const fn fsdef(&self) -> bool { | ||||||
|         match self { |         match self { | ||||||
|             FrameSyncDefinition::StartOfFrame => false, |             FrameSyncDefinition::StartOfFrame => false, | ||||||
|             FrameSyncDefinition::ChannelIdentification => true, |             FrameSyncDefinition::ChannelIdentification => true, | ||||||
| @ -323,7 +306,9 @@ impl FrameSyncDefinition { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Clock strobe.
 | ||||||
| #[derive(Copy, Clone)] | #[derive(Copy, Clone)] | ||||||
|  | #[allow(missing_docs)] | ||||||
| pub enum ClockStrobe { | pub enum ClockStrobe { | ||||||
|     Falling, |     Falling, | ||||||
|     Rising, |     Rising, | ||||||
| @ -331,7 +316,7 @@ pub enum ClockStrobe { | |||||||
| 
 | 
 | ||||||
| impl ClockStrobe { | impl ClockStrobe { | ||||||
|     #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |     #[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 { |         match self { | ||||||
|             ClockStrobe::Falling => vals::Ckstr::FALLINGEDGE, |             ClockStrobe::Falling => vals::Ckstr::FALLINGEDGE, | ||||||
|             ClockStrobe::Rising => vals::Ckstr::RISINGEDGE, |             ClockStrobe::Rising => vals::Ckstr::RISINGEDGE, | ||||||
| @ -339,7 +324,9 @@ impl ClockStrobe { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Complements format for negative samples.
 | ||||||
| #[derive(Copy, Clone)] | #[derive(Copy, Clone)] | ||||||
|  | #[allow(missing_docs)] | ||||||
| pub enum ComplementFormat { | pub enum ComplementFormat { | ||||||
|     OnesComplement, |     OnesComplement, | ||||||
|     TwosComplement, |     TwosComplement, | ||||||
| @ -347,7 +334,7 @@ pub enum ComplementFormat { | |||||||
| 
 | 
 | ||||||
| impl ComplementFormat { | impl ComplementFormat { | ||||||
|     #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |     #[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 { |         match self { | ||||||
|             ComplementFormat::OnesComplement => vals::Cpl::ONESCOMPLEMENT, |             ComplementFormat::OnesComplement => vals::Cpl::ONESCOMPLEMENT, | ||||||
|             ComplementFormat::TwosComplement => vals::Cpl::TWOSCOMPLEMENT, |             ComplementFormat::TwosComplement => vals::Cpl::TWOSCOMPLEMENT, | ||||||
| @ -355,7 +342,9 @@ impl ComplementFormat { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Companding setting.
 | ||||||
| #[derive(Copy, Clone)] | #[derive(Copy, Clone)] | ||||||
|  | #[allow(missing_docs)] | ||||||
| pub enum Companding { | pub enum Companding { | ||||||
|     None, |     None, | ||||||
|     MuLaw, |     MuLaw, | ||||||
| @ -364,7 +353,7 @@ pub enum Companding { | |||||||
| 
 | 
 | ||||||
| impl Companding { | impl Companding { | ||||||
|     #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |     #[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 { |         match self { | ||||||
|             Companding::None => vals::Comp::NOCOMPANDING, |             Companding::None => vals::Comp::NOCOMPANDING, | ||||||
|             Companding::MuLaw => vals::Comp::MULAW, |             Companding::MuLaw => vals::Comp::MULAW, | ||||||
| @ -373,7 +362,9 @@ impl Companding { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Output drive
 | ||||||
| #[derive(Copy, Clone)] | #[derive(Copy, Clone)] | ||||||
|  | #[allow(missing_docs)] | ||||||
| pub enum OutputDrive { | pub enum OutputDrive { | ||||||
|     OnStart, |     OnStart, | ||||||
|     Immediately, |     Immediately, | ||||||
| @ -381,7 +372,7 @@ pub enum OutputDrive { | |||||||
| 
 | 
 | ||||||
| impl OutputDrive { | impl OutputDrive { | ||||||
|     #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |     #[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 { |         match self { | ||||||
|             OutputDrive::OnStart => vals::Outdriv::ONSTART, |             OutputDrive::OnStart => vals::Outdriv::ONSTART, | ||||||
|             OutputDrive::Immediately => vals::Outdriv::IMMEDIATELY, |             OutputDrive::Immediately => vals::Outdriv::IMMEDIATELY, | ||||||
| @ -389,7 +380,9 @@ impl OutputDrive { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Master clock divider.
 | ||||||
| #[derive(Copy, Clone, PartialEq)] | #[derive(Copy, Clone, PartialEq)] | ||||||
|  | #[allow(missing_docs)] | ||||||
| pub enum MasterClockDivider { | pub enum MasterClockDivider { | ||||||
|     MasterClockDisabled, |     MasterClockDisabled, | ||||||
|     Div1, |     Div1, | ||||||
| @ -412,7 +405,7 @@ pub enum MasterClockDivider { | |||||||
| 
 | 
 | ||||||
| impl MasterClockDivider { | impl MasterClockDivider { | ||||||
|     #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |     #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | ||||||
|     pub const fn mckdiv(&self) -> u8 { |     const fn mckdiv(&self) -> u8 { | ||||||
|         match self { |         match self { | ||||||
|             MasterClockDivider::MasterClockDisabled => 0, |             MasterClockDivider::MasterClockDisabled => 0, | ||||||
|             MasterClockDivider::Div1 => 0, |             MasterClockDivider::Div1 => 0, | ||||||
| @ -436,6 +429,7 @@ impl MasterClockDivider { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// [`SAI`] configuration.
 | /// [`SAI`] configuration.
 | ||||||
|  | #[allow(missing_docs)] | ||||||
| #[non_exhaustive] | #[non_exhaustive] | ||||||
| #[derive(Copy, Clone)] | #[derive(Copy, Clone)] | ||||||
| pub struct Config { | pub struct Config { | ||||||
| @ -459,7 +453,7 @@ pub struct Config { | |||||||
|     pub clock_strobe: ClockStrobe, |     pub clock_strobe: ClockStrobe, | ||||||
|     pub output_drive: OutputDrive, |     pub output_drive: OutputDrive, | ||||||
|     pub master_clock_divider: MasterClockDivider, |     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 fifo_threshold: FifoThreshold, | ||||||
|     pub companding: Companding, |     pub companding: Companding, | ||||||
|     pub complement_format: ComplementFormat, |     pub complement_format: ComplementFormat, | ||||||
| @ -490,7 +484,7 @@ impl Default for Config { | |||||||
|             master_clock_divider: MasterClockDivider::MasterClockDisabled, |             master_clock_divider: MasterClockDivider::MasterClockDisabled, | ||||||
|             clock_strobe: ClockStrobe::Rising, |             clock_strobe: ClockStrobe::Rising, | ||||||
|             output_drive: OutputDrive::Immediately, |             output_drive: OutputDrive::Immediately, | ||||||
|             is_high_impedenane_on_inactive_slot: false, |             is_high_impedance_on_inactive_slot: false, | ||||||
|             fifo_threshold: FifoThreshold::ThreeQuarters, |             fifo_threshold: FifoThreshold::ThreeQuarters, | ||||||
|             companding: Companding::None, |             companding: Companding::None, | ||||||
|             complement_format: ComplementFormat::TwosComplement, |             complement_format: ComplementFormat::TwosComplement, | ||||||
| @ -501,23 +495,10 @@ impl Default for Config { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Config { | impl Config { | ||||||
|     pub fn new_i2s() -> Self { |     /// Create a new config with all default values.
 | ||||||
|  |     pub fn new() -> Self { | ||||||
|         return Default::default(); |         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> { | 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 _ |     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)
 | // return the type for (sd, sck)
 | ||||||
| fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AFType, AFType) { | 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) { | fn update_synchronous_config(config: &mut Config) { | ||||||
|     config.mode = Mode::Slave; |     config.mode = Mode::Slave; | ||||||
|     config.sync_output = false; |     config.sync_output = false; | ||||||
| @ -636,19 +567,58 @@ fn update_synchronous_config(config: &mut Config) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl SubBlockA { | /// SAI subblock instance.
 | ||||||
|     pub fn new_asynchronous_with_mclk<'d, T: Instance, C: Channel, W: word::Word>( | pub struct SubBlock<'d, T, S: SubBlockInstance> { | ||||||
|         peri: SubBlockAPeripheral<'d, T>, |     peri: PeripheralRef<'d, T>, | ||||||
|         sck: impl Peripheral<P = impl SckAPin<T>> + 'd, |     _phantom: PhantomData<S>, | ||||||
|         sd: impl Peripheral<P = impl SdAPin<T>> + 'd, | } | ||||||
|         fs: impl Peripheral<P = impl FsAPin<T>> + 'd, | 
 | ||||||
|         mclk: impl Peripheral<P = impl MclkAPin<T>> + 'd, | /// 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: impl Peripheral<P = C> + 'd, | ||||||
|         dma_buf: &'d mut [W], |         dma_buf: &'d mut [W], | ||||||
|         mut config: Config, |         mut config: Config, | ||||||
|     ) -> SubBlock<'d, T, C, W> |     ) -> Self | ||||||
|     where |     where | ||||||
|         C: Channel + DmaA<T>, |         C: Channel + Dma<T, S>, | ||||||
|     { |     { | ||||||
|         into_ref!(mclk); |         into_ref!(mclk); | ||||||
| 
 | 
 | ||||||
| @ -664,19 +634,22 @@ impl SubBlockA { | |||||||
|         Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config) |         Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn new_asynchronous<'d, T: Instance, C: Channel, W: word::Word>( |     /// Create a new SAI driver in asynchronous mode without MCLK.
 | ||||||
|         peri: SubBlockAPeripheral<'d, T>, |     ///
 | ||||||
|         sck: impl Peripheral<P = impl SckAPin<T>> + 'd, |     /// You can obtain the [`SubBlock`] with [`split_subblocks`].
 | ||||||
|         sd: impl Peripheral<P = impl SdAPin<T>> + 'd, |     pub fn new_asynchronous<S: SubBlockInstance>( | ||||||
|         fs: impl Peripheral<P = impl FsAPin<T>> + 'd, |         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: impl Peripheral<P = C> + 'd, | ||||||
|         dma_buf: &'d mut [W], |         dma_buf: &'d mut [W], | ||||||
|         config: Config, |         config: Config, | ||||||
|     ) -> SubBlock<'d, T, C, W> |     ) -> Self | ||||||
|     where |     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); |         into_ref!(peri, dma, sck, sd, fs); | ||||||
| 
 | 
 | ||||||
|         let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); |         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_as_af(fs.af_num(), ck_af_type); | ||||||
|         fs.set_speed(crate::gpio::Speed::VeryHigh); |         fs.set_speed(crate::gpio::Speed::VeryHigh); | ||||||
| 
 | 
 | ||||||
|         let sub_block = WhichSubBlock::A; |         let sub_block = S::WHICH; | ||||||
|         let request = dma.request(); |         let request = dma.request(); | ||||||
| 
 | 
 | ||||||
|         SubBlock::new_inner( |         Self::new_inner( | ||||||
|             peri, |             peri, | ||||||
|             sub_block, |             sub_block, | ||||||
|             Some(sck.map_into()), |             Some(sck.map_into()), | ||||||
| @ -703,19 +676,22 @@ impl SubBlockA { | |||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn new_synchronous<'d, T: Instance, C: Channel, W: word::Word>( |     /// Create a new SAI driver in synchronous mode.
 | ||||||
|         peri: SubBlockAPeripheral<'d, T>, |     ///
 | ||||||
|         sd: impl Peripheral<P = impl SdAPin<T>> + 'd, |     /// 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: impl Peripheral<P = C> + 'd, | ||||||
|         dma_buf: &'d mut [W], |         dma_buf: &'d mut [W], | ||||||
|         mut config: Config, |         mut config: Config, | ||||||
|     ) -> SubBlock<'d, T, C, W> |     ) -> Self | ||||||
|     where |     where | ||||||
|         C: Channel + DmaA<T>, |         C: Channel + Dma<T, S>, | ||||||
|     { |     { | ||||||
|         update_synchronous_config(&mut config); |         update_synchronous_config(&mut config); | ||||||
| 
 | 
 | ||||||
|         let peri = peri.0; |         let peri = peri.peri; | ||||||
|         into_ref!(dma, peri, sd); |         into_ref!(dma, peri, sd); | ||||||
| 
 | 
 | ||||||
|         let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx); |         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_as_af(sd.af_num(), sd_af_type); | ||||||
|         sd.set_speed(crate::gpio::Speed::VeryHigh); |         sd.set_speed(crate::gpio::Speed::VeryHigh); | ||||||
| 
 | 
 | ||||||
|         let sub_block = WhichSubBlock::A; |         let sub_block = S::WHICH; | ||||||
|         let request = dma.request(); |         let request = dma.request(); | ||||||
| 
 | 
 | ||||||
|         SubBlock::new_inner( |         Self::new_inner( | ||||||
|             peri, |             peri, | ||||||
|             sub_block, |             sub_block, | ||||||
|             None, |             None, | ||||||
| @ -737,129 +713,6 @@ impl SubBlockA { | |||||||
|             config, |             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( |     fn new_inner( | ||||||
|         peri: impl Peripheral<P = T> + 'd, |         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_cpl(config.complement_format.cpl()); | ||||||
|                 w.set_muteval(config.mute_value.muteval()); |                 w.set_muteval(config.mute_value.muteval()); | ||||||
|                 w.set_mutecnt(config.mute_detection_counter.0 as u8); |                 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| { |             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() { |     pub fn reset() { | ||||||
|         T::enable_and_reset(); |         T::enable_and_reset(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// Flush.
 | ||||||
|     pub fn flush(&mut self) { |     pub fn flush(&mut self) { | ||||||
|         let ch = T::REGS.ch(self.sub_block as usize); |         let ch = T::REGS.ch(self.sub_block as usize); | ||||||
|         ch.cr1().modify(|w| w.set_saien(false)); |         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)); |         ch.cr1().modify(|w| w.set_saien(true)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// Enable or disable mute.
 | ||||||
|     pub fn set_mute(&mut self, value: bool) { |     pub fn set_mute(&mut self, value: bool) { | ||||||
|         let ch = T::REGS.ch(self.sub_block as usize); |         let ch = T::REGS.ch(self.sub_block as usize); | ||||||
|         ch.cr2().modify(|w| w.set_mute(value)); |         ch.cr2().modify(|w| w.set_mute(value)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #[allow(dead_code)] |     /// Write data to the SAI ringbuffer.
 | ||||||
|     /// Reconfigures it with the supplied config.
 |     ///
 | ||||||
|     fn reconfigure(&mut self, _config: Config) {} |     /// This appends the data to the buffer and returns immediately. The
 | ||||||
| 
 |     /// data will be transmitted in the background.
 | ||||||
|     pub fn get_current_config(&self) -> Config { |     ///
 | ||||||
|         Config::default() |     /// If there's no space in the buffer, this waits until there is.
 | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub async fn write(&mut self, data: &[W]) -> Result<(), Error> { |     pub async fn write(&mut self, data: &[W]) -> Result<(), Error> { | ||||||
|         match &mut self.ring_buffer { |         match &mut self.ring_buffer { | ||||||
|             RingBuffer::Writable(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> { |     pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> { | ||||||
|         match &mut self.ring_buffer { |         match &mut self.ring_buffer { | ||||||
|             RingBuffer::Readable(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) { |     fn drop(&mut self) { | ||||||
|         let ch = T::REGS.ch(self.sub_block as usize); |         let ch = T::REGS.ch(self.sub_block as usize); | ||||||
|         ch.cr1().modify(|w| w.set_saien(false)); |         ch.cr1().modify(|w| w.set_saien(false)); | ||||||
| @ -1034,22 +913,43 @@ pub(crate) mod sealed { | |||||||
|     pub trait Instance { |     pub trait Instance { | ||||||
|         const REGS: Regs; |         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<P = Self> + sealed::Instance + RccPeripheral {} | pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} | ||||||
| pin_trait!(SckAPin, Instance); | pin_trait!(SckPin, Instance, SubBlockInstance); | ||||||
| pin_trait!(SckBPin, Instance); | pin_trait!(FsPin, Instance, SubBlockInstance); | ||||||
| pin_trait!(FsAPin, Instance); | pin_trait!(SdPin, Instance, SubBlockInstance); | ||||||
| pin_trait!(FsBPin, Instance); | pin_trait!(MclkPin, Instance, SubBlockInstance); | ||||||
| pin_trait!(SdAPin, Instance); |  | ||||||
| pin_trait!(SdBPin, Instance); |  | ||||||
| pin_trait!(MclkAPin, Instance); |  | ||||||
| pin_trait!(MclkBPin, Instance); |  | ||||||
| 
 | 
 | ||||||
| dma_trait!(DmaA, Instance); | dma_trait!(Dma, Instance, SubBlockInstance); | ||||||
| dma_trait!(DmaB, Instance); |  | ||||||
| 
 | 
 | ||||||
| foreach_peripheral!( | foreach_peripheral!( | ||||||
|     (sai, $inst:ident) => { |     (sai, $inst:ident) => { | ||||||
| @ -1060,13 +960,3 @@ foreach_peripheral!( | |||||||
|         impl Instance for peripherals::$inst {} |         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] | #![macro_use] | ||||||
| 
 | 
 | ||||||
| use core::default::Default; | use core::default::Default; | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | //! Serial Peripheral Interface (SPI)
 | ||||||
| #![macro_use] | #![macro_use] | ||||||
| 
 | 
 | ||||||
| use core::ptr; | use core::ptr; | ||||||
|  | |||||||
| @ -1,18 +1,18 @@ | |||||||
| #![macro_use] | #![macro_use] | ||||||
| 
 | 
 | ||||||
| macro_rules! pin_trait { | macro_rules! pin_trait { | ||||||
|     ($signal:ident, $instance:path) => { |     ($signal:ident, $instance:path $(, $mode:path)?) => { | ||||||
|         #[doc = concat!(stringify!($signal), " pin trait")] |         #[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))] |             #[doc = concat!("Get the AF number needed to use this pin as ", stringify!($signal))] | ||||||
|             fn af_num(&self) -> u8; |             fn af_num(&self) -> u8; | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| macro_rules! pin_trait_impl { | macro_rules! pin_trait_impl { | ||||||
|     (crate::$mod:ident::$trait:ident, $instance:ident, $pin:ident, $af:expr) => { |     (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $pin:ident, $af:expr) => { | ||||||
|         impl crate::$mod::$trait<crate::peripherals::$instance> for crate::peripherals::$pin { |         impl crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for crate::peripherals::$pin { | ||||||
|             fn af_num(&self) -> u8 { |             fn af_num(&self) -> u8 { | ||||||
|                 $af |                 $af | ||||||
|             } |             } | ||||||
| @ -23,9 +23,9 @@ macro_rules! pin_trait_impl { | |||||||
| // ====================
 | // ====================
 | ||||||
| 
 | 
 | ||||||
| macro_rules! dma_trait { | macro_rules! dma_trait { | ||||||
|     ($signal:ident, $instance:path) => { |     ($signal:ident, $instance:path$(, $mode:path)?) => { | ||||||
|         #[doc = concat!(stringify!($signal), " DMA request trait")] |         #[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))] |             #[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".
 |             /// Note: in some chips, ST calls this the "channel", and calls channels "streams".
 | ||||||
|             /// `embassy-stm32` always uses the "channel" and "request number" names.
 |             /// `embassy-stm32` always uses the "channel" and "request number" names.
 | ||||||
| @ -37,8 +37,8 @@ macro_rules! dma_trait { | |||||||
| #[allow(unused)] | #[allow(unused)] | ||||||
| macro_rules! dma_trait_impl { | macro_rules! dma_trait_impl { | ||||||
|     // DMAMUX
 |     // DMAMUX
 | ||||||
|     (crate::$mod:ident::$trait:ident, $instance:ident, {dmamux: $dmamux:ident}, $request:expr) => { |     (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {dmamux: $dmamux:ident}, $request:expr) => { | ||||||
|         impl<T> crate::$mod::$trait<crate::peripherals::$instance> for T |         impl<T> crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for T | ||||||
|         where |         where | ||||||
|             T: crate::dma::Channel + crate::dma::MuxChannel<Mux = crate::dma::$dmamux>, |             T: crate::dma::Channel + crate::dma::MuxChannel<Mux = crate::dma::$dmamux>, | ||||||
|         { |         { | ||||||
| @ -49,8 +49,8 @@ macro_rules! dma_trait_impl { | |||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     // DMAMUX
 |     // DMAMUX
 | ||||||
|     (crate::$mod:ident::$trait:ident, $instance:ident, {dma: $dma:ident}, $request:expr) => { |     (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {dma: $dma:ident}, $request:expr) => { | ||||||
|         impl<T> crate::$mod::$trait<crate::peripherals::$instance> for T |         impl<T> crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for T | ||||||
|         where |         where | ||||||
|             T: crate::dma::Channel, |             T: crate::dma::Channel, | ||||||
|         { |         { | ||||||
| @ -61,8 +61,8 @@ macro_rules! dma_trait_impl { | |||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     // DMA/GPDMA, without DMAMUX
 |     // DMA/GPDMA, without DMAMUX
 | ||||||
|     (crate::$mod:ident::$trait:ident, $instance:ident, {channel: $channel:ident}, $request:expr) => { |     (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {channel: $channel:ident}, $request:expr) => { | ||||||
|         impl crate::$mod::$trait<crate::peripherals::$instance> for crate::peripherals::$channel { |         impl crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for crate::peripherals::$channel { | ||||||
|             fn request(&self) -> crate::dma::Request { |             fn request(&self) -> crate::dma::Request { | ||||||
|                 $request |                 $request | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -1,3 +1,5 @@ | |||||||
|  | //! Unique ID (UID)
 | ||||||
|  | 
 | ||||||
| /// Get this device's unique 96-bit ID.
 | /// Get this device's unique 96-bit ID.
 | ||||||
| pub fn uid() -> &'static [u8; 12] { | pub fn uid() -> &'static [u8; 12] { | ||||||
|     unsafe { &*crate::pac::UID.uid(0).as_ptr().cast::<[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] | #![macro_use] | ||||||
| 
 | 
 | ||||||
| use core::future::poll_fn; | use core::future::poll_fn; | ||||||
|  | |||||||
| @ -1,3 +1,5 @@ | |||||||
|  | //! USB On The Go (OTG)
 | ||||||
|  | 
 | ||||||
| use crate::rcc::RccPeripheral; | use crate::rcc::RccPeripheral; | ||||||
| use crate::{interrupt, peripherals}; | use crate::{interrupt, peripherals}; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | //! Watchdog Timer (IWDG, WWDG)
 | ||||||
| use core::marker::PhantomData; | use core::marker::PhantomData; | ||||||
| 
 | 
 | ||||||
| use embassy_hal_internal::{into_ref, Peripheral}; | use embassy_hal_internal::{into_ref, Peripheral}; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user