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 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(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -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,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
|
||||||
}
|
}
|
||||||
|
@ -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…
Reference in New Issue
Block a user