Merge pull request #2310 from embassy-rs/stm32-docs

stm32/sai: docs, cleanup api.
This commit is contained in:
Dario Nieuwenhuis 2023-12-19 00:37:49 +01:00 committed by GitHub
commit 08e9a4d84a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 294 additions and 355 deletions

View File

@ -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.

View File

@ -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)),

View File

@ -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

View File

@ -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")]

View File

@ -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")]

View File

@ -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;

View File

@ -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;

View File

@ -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")]

View File

@ -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;

View File

@ -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)]

View File

@ -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;

View File

@ -1,3 +1,5 @@
//! High Resolution Timer (HRTIM)
mod traits; mod traits;
use core::marker::PhantomData; use core::marker::PhantomData;

View File

@ -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")]

View File

@ -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 _};

View File

@ -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);

View File

@ -1,3 +1,5 @@
//! Quad Serial Peripheral Interface (QSPI)
#![macro_use] #![macro_use]
pub mod enums; pub mod enums;

View File

@ -1,3 +1,4 @@
//! Random Number Generator (RNG)
#![macro_use] #![macro_use]
use core::future::poll_fn; use core::future::poll_fn;

View File

@ -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>>>,

View File

@ -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 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 {} 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(())
}
}

View File

@ -1,3 +1,4 @@
//! Secure Digital / MultiMedia Card (SDMMC)
#![macro_use] #![macro_use]
use core::default::Default; use core::default::Default;

View File

@ -1,3 +1,4 @@
//! Serial Peripheral Interface (SPI)
#![macro_use] #![macro_use]
use core::ptr; use core::ptr;

View File

@ -1,9 +1,9 @@
#![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;
} }
@ -11,8 +11,8 @@ macro_rules! pin_trait {
} }
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
} }

View File

@ -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]>() }

View File

@ -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;

View File

@ -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};

View File

@ -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};