diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index bb60d244..058b8a0f 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -672,14 +672,14 @@ fn main() { (("lpuart", "RTS"), quote!(crate::usart::RtsPin)), (("lpuart", "CK"), quote!(crate::usart::CkPin)), (("lpuart", "DE"), quote!(crate::usart::DePin)), - (("sai", "SCK_A"), quote!(crate::sai::SckAPin)), - (("sai", "SCK_B"), quote!(crate::sai::SckBPin)), - (("sai", "FS_A"), quote!(crate::sai::FsAPin)), - (("sai", "FS_B"), quote!(crate::sai::FsBPin)), - (("sai", "SD_A"), quote!(crate::sai::SdAPin)), - (("sai", "SD_B"), quote!(crate::sai::SdBPin)), - (("sai", "MCLK_A"), quote!(crate::sai::MclkAPin)), - (("sai", "MCLK_B"), quote!(crate::sai::MclkBPin)), + (("sai", "SCK_A"), quote!(crate::sai::SckPin)), + (("sai", "SCK_B"), quote!(crate::sai::SckPin)), + (("sai", "FS_A"), quote!(crate::sai::FsPin)), + (("sai", "FS_B"), quote!(crate::sai::FsPin)), + (("sai", "SD_A"), quote!(crate::sai::SdPin)), + (("sai", "SD_B"), quote!(crate::sai::SdPin)), + (("sai", "MCLK_A"), quote!(crate::sai::MclkPin)), + (("sai", "MCLK_B"), quote!(crate::sai::MclkPin)), (("sai", "WS"), quote!(crate::sai::WsPin)), (("spi", "SCK"), quote!(crate::spi::SckPin)), (("spi", "MOSI"), quote!(crate::spi::MosiPin)), @@ -995,8 +995,8 @@ fn main() { (("usart", "TX"), quote!(crate::usart::TxDma)), (("lpuart", "RX"), quote!(crate::usart::RxDma)), (("lpuart", "TX"), quote!(crate::usart::TxDma)), - (("sai", "A"), quote!(crate::sai::DmaA)), - (("sai", "B"), quote!(crate::sai::DmaB)), + (("sai", "A"), quote!(crate::sai::Dma)), + (("sai", "B"), quote!(crate::sai::Dma)), (("spi", "RX"), quote!(crate::spi::RxDma)), (("spi", "TX"), quote!(crate::spi::TxDma)), (("i2c", "RX"), quote!(crate::i2c::RxDma)), diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 96acd9e4..e0349752 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -1,7 +1,10 @@ #![macro_use] +use core::marker::PhantomData; + use embassy_hal_internal::{into_ref, PeripheralRef}; +use self::sealed::WhichSubBlock; pub use crate::dma::word; use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; use crate::gpio::sealed::{AFType, Pin as _}; @@ -500,23 +503,10 @@ impl Default for Config { } impl Config { - pub fn new_i2s() -> Self { + /// Create a new config with all default values. + pub fn new() -> Self { return Default::default(); } - - pub fn new_msb_first() -> Self { - Self { - bit_order: BitOrder::MsbFirst, - frame_sync_offset: FrameSyncOffset::OnFirstBit, - ..Default::default() - } - } -} - -#[derive(Copy, Clone)] -enum WhichSubBlock { - A = 0, - B = 1, } enum RingBuffer<'d, C: Channel, W: word::Word> { @@ -530,28 +520,6 @@ fn dr(w: crate::pac::sai::Sai, sub_block: WhichSubBlock) -> *mut ch.dr().as_ptr() as _ } -pub struct SubBlock<'d, T: Instance, C: Channel, W: word::Word> { - _peri: PeripheralRef<'d, T>, - sd: Option>, - fs: Option>, - sck: Option>, - mclk: Option>, - ring_buffer: RingBuffer<'d, C, W>, - sub_block: WhichSubBlock, -} - -pub struct SubBlockA {} -pub struct SubBlockB {} - -pub struct SubBlockAPeripheral<'d, T>(PeripheralRef<'d, T>); -pub struct SubBlockBPeripheral<'d, T>(PeripheralRef<'d, T>); - -pub struct Sai<'d, T: Instance> { - _peri: PeripheralRef<'d, T>, - sub_block_a_peri: Option>, - sub_block_b_peri: Option>, -} - // return the type for (sd, sck) fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AFType, AFType) { ( @@ -590,34 +558,6 @@ fn get_ring_buffer<'d, T: Instance, C: Channel, W: word::Word>( } } -impl<'d, T: Instance> Sai<'d, T> { - pub fn new(peri: impl Peripheral

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

> + 'd, - sd: impl Peripheral

> + 'd, - fs: impl Peripheral

> + 'd, - mclk: impl Peripheral

> + 'd, +pub struct SubBlock<'d, T, S: SubBlockInstance> { + peri: PeripheralRef<'d, T>, + _phantom: PhantomData, +} + +pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral

+ 'd) -> (SubBlock<'d, T, A>, SubBlock<'d, T, B>) { + into_ref!(peri); + T::enable_and_reset(); + + ( + SubBlock { + peri: unsafe { peri.clone_unchecked() }, + _phantom: PhantomData, + }, + SubBlock { + peri, + _phantom: PhantomData, + }, + ) +} + +/// SAI sub-block driver +pub struct Sai<'d, T: Instance, C: Channel, W: word::Word> { + _peri: PeripheralRef<'d, T>, + sd: Option>, + fs: Option>, + sck: Option>, + mclk: Option>, + ring_buffer: RingBuffer<'d, C, W>, + sub_block: WhichSubBlock, +} + +impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { + pub fn new_asynchronous_with_mclk( + peri: SubBlock<'d, T, S>, + sck: impl Peripheral

> + 'd, + sd: impl Peripheral

> + 'd, + fs: impl Peripheral

> + 'd, + mclk: impl Peripheral

> + 'd, dma: impl Peripheral

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

> + 'd, - sd: impl Peripheral

> + 'd, - fs: impl Peripheral

> + 'd, + pub fn new_asynchronous( + peri: SubBlock<'d, T, S>, + sck: impl Peripheral

> + 'd, + sd: impl Peripheral

> + 'd, + fs: impl Peripheral

> + 'd, dma: impl Peripheral

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

> + 'd, + pub fn new_synchronous( + peri: SubBlock<'d, T, S>, + sd: impl Peripheral

> + 'd, dma: impl Peripheral

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

> + 'd, - sd: impl Peripheral

> + 'd, - fs: impl Peripheral

> + 'd, - mclk: impl Peripheral

> + 'd, - dma: impl Peripheral

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

> + 'd, - sd: impl Peripheral

> + 'd, - fs: impl Peripheral

> + 'd, - dma: impl Peripheral

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

> + 'd, - dma: impl Peripheral

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

+ 'd, @@ -964,6 +813,24 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { } } + pub fn start(&mut self) { + match self.ring_buffer { + RingBuffer::Writable(ref mut rb) => { + rb.start(); + } + RingBuffer::Readable(ref mut rb) => { + rb.start(); + } + } + } + + fn is_transmitter(ring_buffer: &RingBuffer) -> bool { + match ring_buffer { + RingBuffer::Writable(_) => true, + _ => false, + } + } + pub fn reset() { T::enable_and_reset(); } @@ -1008,7 +875,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { } } -impl<'d, T: Instance, C: Channel, W: word::Word> Drop for SubBlock<'d, T, C, W> { +impl<'d, T: Instance, C: Channel, W: word::Word> Drop for Sai<'d, T, C, W> { fn drop(&mut self) { let ch = T::REGS.ch(self.sub_block as usize); ch.cr1().modify(|w| w.set_saien(false)); @@ -1025,22 +892,40 @@ pub(crate) mod sealed { pub trait Instance { const REGS: Regs; } + + #[derive(Copy, Clone)] + pub enum WhichSubBlock { + A = 0, + B = 1, + } + + pub trait SubBlock { + const WHICH: WhichSubBlock; + } } pub trait Word: word::Word {} -pub trait Instance: Peripheral

+ sealed::Instance + RccPeripheral {} -pin_trait!(SckAPin, Instance); -pin_trait!(SckBPin, Instance); -pin_trait!(FsAPin, Instance); -pin_trait!(FsBPin, Instance); -pin_trait!(SdAPin, Instance); -pin_trait!(SdBPin, Instance); -pin_trait!(MclkAPin, Instance); -pin_trait!(MclkBPin, Instance); +pub trait SubBlockInstance: sealed::SubBlock {} -dma_trait!(DmaA, Instance); -dma_trait!(DmaB, Instance); +pub enum A {} +impl sealed::SubBlock for A { + const WHICH: WhichSubBlock = WhichSubBlock::A; +} +impl SubBlockInstance for A {} +pub enum B {} +impl sealed::SubBlock for B { + const WHICH: WhichSubBlock = WhichSubBlock::B; +} +impl SubBlockInstance for B {} + +pub trait Instance: Peripheral

+ sealed::Instance + RccPeripheral {} +pin_trait!(SckPin, Instance, SubBlockInstance); +pin_trait!(FsPin, Instance, SubBlockInstance); +pin_trait!(SdPin, Instance, SubBlockInstance); +pin_trait!(MclkPin, Instance, SubBlockInstance); + +dma_trait!(Dma, Instance, SubBlockInstance); foreach_peripheral!( (sai, $inst:ident) => { diff --git a/embassy-stm32/src/traits.rs b/embassy-stm32/src/traits.rs index b4166e71..13f69582 100644 --- a/embassy-stm32/src/traits.rs +++ b/embassy-stm32/src/traits.rs @@ -1,18 +1,18 @@ #![macro_use] macro_rules! pin_trait { - ($signal:ident, $instance:path) => { + ($signal:ident, $instance:path $(, $mode:path)?) => { #[doc = concat!(stringify!($signal), " pin trait")] - pub trait $signal: crate::gpio::Pin { - #[doc = concat!("Get the AF number needed to use this pin as", stringify!($signal))] + pub trait $signal: crate::gpio::Pin { + #[doc = concat!("Get the AF number needed to use this pin as ", stringify!($signal))] fn af_num(&self) -> u8; } }; } macro_rules! pin_trait_impl { - (crate::$mod:ident::$trait:ident, $instance:ident, $pin:ident, $af:expr) => { - impl crate::$mod::$trait for crate::peripherals::$pin { + (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $pin:ident, $af:expr) => { + impl crate::$mod::$trait for crate::peripherals::$pin { fn af_num(&self) -> u8 { $af } @@ -23,9 +23,9 @@ macro_rules! pin_trait_impl { // ==================== macro_rules! dma_trait { - ($signal:ident, $instance:path) => { + ($signal:ident, $instance:path$(, $mode:path)?) => { #[doc = concat!(stringify!($signal), " DMA request trait")] - pub trait $signal: crate::dma::Channel { + pub trait $signal: crate::dma::Channel { #[doc = concat!("Get the DMA request number needed to use this channel as", stringify!($signal))] /// Note: in some chips, ST calls this the "channel", and calls channels "streams". /// `embassy-stm32` always uses the "channel" and "request number" names. @@ -37,8 +37,8 @@ macro_rules! dma_trait { #[allow(unused)] macro_rules! dma_trait_impl { // DMAMUX - (crate::$mod:ident::$trait:ident, $instance:ident, {dmamux: $dmamux:ident}, $request:expr) => { - impl crate::$mod::$trait for T + (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {dmamux: $dmamux:ident}, $request:expr) => { + impl crate::$mod::$trait for T where T: crate::dma::Channel + crate::dma::MuxChannel, { @@ -49,8 +49,8 @@ macro_rules! dma_trait_impl { }; // DMAMUX - (crate::$mod:ident::$trait:ident, $instance:ident, {dma: $dma:ident}, $request:expr) => { - impl crate::$mod::$trait for T + (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {dma: $dma:ident}, $request:expr) => { + impl crate::$mod::$trait for T where T: crate::dma::Channel, { @@ -61,8 +61,8 @@ macro_rules! dma_trait_impl { }; // DMA/GPDMA, without DMAMUX - (crate::$mod:ident::$trait:ident, $instance:ident, {channel: $channel:ident}, $request:expr) => { - impl crate::$mod::$trait for crate::peripherals::$channel { + (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {channel: $channel:ident}, $request:expr) => { + impl crate::$mod::$trait for crate::peripherals::$channel { fn request(&self) -> crate::dma::Request { $request }