diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 6ee8d983a..98054d720 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -10,15 +10,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - ESP32-S3: Added SDMMC signals (#2556) -- `dma::{Channel, ChannelRx, ChannelTx}::set_priority` for GDMA devices (#2403) +- Added `set_priority` to the `DmaChannel` trait on GDMA devices (#2403, #2526) +- Added `into_async` and `into_blocking` functions for `ParlIoTxOnly`, `ParlIoRxOnly` (#2526) +- ESP32-C6, H2, S3: Added `split` function to the `DmaChannel` trait. (#2526) ### Changed +- DMA channel objects now implement `Peripheral` (#2526) +- DMA channel objects are no longer wrapped in `Channel`. The `Channel` drivers are now managed by DMA enabled peripheral drivers. (#2526) +- The `Dpi` driver and `DpiTransfer` now have a `Mode` type parameter. The driver's asyncness is determined by the asyncness of the `Lcd` used to create it. (#2526) + ### Fixed ### Removed - The `configure` and `configure_for_async` DMA channel functions has been removed (#2403) +- The DMA channel objects no longer have `tx` and `rx` fields. (#2526) ## [0.22.0] - 2024-11-20 diff --git a/esp-hal/MIGRATING-0.22.md b/esp-hal/MIGRATING-0.22.md index 2de39aaa9..7cb68ead4 100644 --- a/esp-hal/MIGRATING-0.22.md +++ b/esp-hal/MIGRATING-0.22.md @@ -15,3 +15,14 @@ -.with_dma(dma_channel.configure(false, DmaPriority::Priority0)); +.with_dma(dma_channel); ``` + +```diff ++dma_channel.set_priority(DmaPriority::Priority1); + let mut spi = Spi::new_with_config( + peripherals.SPI2, + Config::default(), + ) + // other setup +-.with_dma(dma_channel.configure(false, DmaPriority::Priority1)); ++.with_dma(dma_channel); +``` diff --git a/esp-hal/src/aes/mod.rs b/esp-hal/src/aes/mod.rs index 5112ebbd2..f2a32f245 100644 --- a/esp-hal/src/aes/mod.rs +++ b/esp-hal/src/aes/mod.rs @@ -242,15 +242,18 @@ pub mod dma { ChannelTx, DescriptorChain, DmaChannelConvert, + DmaChannelFor, DmaDescriptor, - DmaEligible, DmaPeripheral, DmaTransferRxTx, ReadBuffer, Rx, + RxChannelFor, Tx, + TxChannelFor, WriteBuffer, }, + peripheral::Peripheral, peripherals::AES, Blocking, }; @@ -278,7 +281,7 @@ pub mod dma { /// The underlying [`Aes`](super::Aes) driver pub aes: super::Aes<'d>, - channel: Channel<'d, Blocking, ::Dma>, + channel: Channel<'d, Blocking, DmaChannelFor>, rx_chain: DescriptorChain, tx_chain: DescriptorChain, } @@ -287,16 +290,18 @@ pub mod dma { /// Enable DMA for the current instance of the AES driver pub fn with_dma( self, - channel: Channel<'d, Blocking, CH>, + channel: impl Peripheral

+ 'd, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], ) -> AesDma<'d> where - CH: DmaChannelConvert<::Dma>, + CH: DmaChannelConvert>, { + let channel = Channel::new(channel.map(|ch| ch.degrade())); + channel.runtime_ensure_compatible(&self.aes); AesDma { aes: self, - channel: channel.degrade(), + channel, rx_chain: DescriptorChain::new(rx_descriptors), tx_chain: DescriptorChain::new(tx_descriptors), } @@ -326,7 +331,7 @@ pub mod dma { } impl<'d> DmaSupportTx for AesDma<'d> { - type TX = ChannelTx<'d, Blocking, ::Dma>; + type TX = ChannelTx<'d, Blocking, TxChannelFor>; fn tx(&mut self) -> &mut Self::TX { &mut self.channel.tx @@ -338,7 +343,7 @@ pub mod dma { } impl<'d> DmaSupportRx for AesDma<'d> { - type RX = ChannelRx<'d, Blocking, ::Dma>; + type RX = ChannelRx<'d, Blocking, RxChannelFor>; fn rx(&mut self) -> &mut Self::RX { &mut self.channel.rx diff --git a/esp-hal/src/dma/gdma.rs b/esp-hal/src/dma/gdma.rs index c9ff270a6..c271cc17f 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -16,105 +16,58 @@ use crate::{ dma::*, - peripheral::PeripheralRef, + peripheral::{Peripheral, PeripheralRef}, peripherals::Interrupt, - system::{Peripheral, PeripheralClockControl}, - Blocking, + system::{self, PeripheralClockControl}, }; -#[doc(hidden)] -pub trait GdmaChannel { - fn number(&self) -> u8; +/// An arbitrary GDMA channel +pub struct AnyGdmaChannel(u8); - fn async_handler_out(&self) -> Option { - match self.number() { - 0 => DmaChannel0::handler_out(), - #[cfg(not(esp32c2))] - 1 => DmaChannel1::handler_out(), - #[cfg(not(esp32c2))] - 2 => DmaChannel2::handler_out(), - #[cfg(esp32s3)] - 3 => DmaChannel3::handler_out(), - #[cfg(esp32s3)] - 4 => DmaChannel4::handler_out(), - _ => unreachable!(), - } - } +impl Peripheral for AnyGdmaChannel { + type P = Self; - fn peripheral_interrupt_out(&self) -> Option { - match self.number() { - 0 => DmaChannel0::isr_out(), - #[cfg(not(esp32c2))] - 1 => DmaChannel1::isr_out(), - #[cfg(not(esp32c2))] - 2 => DmaChannel2::isr_out(), - #[cfg(esp32s3)] - 3 => DmaChannel3::isr_out(), - #[cfg(esp32s3)] - 4 => DmaChannel4::isr_out(), - _ => unreachable!(), - } - } - - fn async_handler_in(&self) -> Option { - match self.number() { - 0 => DmaChannel0::handler_in(), - #[cfg(not(esp32c2))] - 1 => DmaChannel1::handler_in(), - #[cfg(not(esp32c2))] - 2 => DmaChannel2::handler_in(), - #[cfg(esp32s3)] - 3 => DmaChannel3::handler_in(), - #[cfg(esp32s3)] - 4 => DmaChannel4::handler_in(), - _ => unreachable!(), - } - } - - fn peripheral_interrupt_in(&self) -> Option { - match self.number() { - 0 => DmaChannel0::isr_in(), - #[cfg(not(esp32c2))] - 1 => DmaChannel1::isr_in(), - #[cfg(not(esp32c2))] - 2 => DmaChannel2::isr_in(), - #[cfg(esp32s3)] - 3 => DmaChannel3::isr_in(), - #[cfg(esp32s3)] - 4 => DmaChannel4::isr_in(), - _ => unreachable!(), - } + unsafe fn clone_unchecked(&self) -> Self::P { + Self(self.0) } } -/// An arbitrary GDMA channel -#[non_exhaustive] -pub struct AnyGdmaChannel(u8); - impl crate::private::Sealed for AnyGdmaChannel {} impl DmaChannel for AnyGdmaChannel { - type Rx = ChannelRxImpl; - type Tx = ChannelTxImpl; -} + type Rx = AnyGdmaRxChannel; + type Tx = AnyGdmaTxChannel; -#[non_exhaustive] -#[doc(hidden)] -pub struct SpecificGdmaChannel {} - -impl GdmaChannel for AnyGdmaChannel { - fn number(&self) -> u8 { - self.0 + fn set_priority(&self, priority: DmaPriority) { + AnyGdmaRxChannel(self.0).set_priority(priority); + AnyGdmaTxChannel(self.0).set_priority(priority); } -} -impl GdmaChannel for SpecificGdmaChannel { - fn number(&self) -> u8 { - N + + unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) { + (AnyGdmaRxChannel(self.0), AnyGdmaTxChannel(self.0)) } } -#[non_exhaustive] -#[doc(hidden)] -pub struct ChannelTxImpl(C); +/// An arbitrary GDMA RX channel +pub struct AnyGdmaRxChannel(u8); + +impl Peripheral for AnyGdmaRxChannel { + type P = Self; + + unsafe fn clone_unchecked(&self) -> Self::P { + Self(self.0) + } +} + +/// An arbitrary GDMA TX channel +pub struct AnyGdmaTxChannel(u8); + +impl Peripheral for AnyGdmaTxChannel { + type P = Self; + + unsafe fn clone_unchecked(&self) -> Self::P { + Self(self.0) + } +} use embassy_sync::waitqueue::AtomicWaker; @@ -129,40 +82,37 @@ cfg_if::cfg_if! { } } -impl crate::private::Sealed for ChannelTxImpl {} +impl crate::private::Sealed for AnyGdmaTxChannel {} +impl DmaTxChannel for AnyGdmaTxChannel {} -impl ChannelTxImpl { +impl AnyGdmaTxChannel { #[inline(always)] fn ch(&self) -> &crate::peripherals::dma::ch::CH { let dma = unsafe { &*crate::peripherals::DMA::PTR }; - dma.ch(self.0.number() as usize) + dma.ch(self.0 as usize) } #[cfg(any(esp32c2, esp32c3))] #[inline(always)] fn int(&self) -> &crate::peripherals::dma::int_ch::INT_CH { let dma = unsafe { &*crate::peripherals::DMA::PTR }; - dma.int_ch(self.0.number() as usize) + dma.int_ch(self.0 as usize) } #[inline(always)] #[cfg(any(esp32c6, esp32h2))] fn int(&self) -> &crate::peripherals::dma::out_int_ch::OUT_INT_CH { let dma = unsafe { &*crate::peripherals::DMA::PTR }; - dma.out_int_ch(self.0.number() as usize) + dma.out_int_ch(self.0 as usize) } #[cfg(esp32s3)] #[inline(always)] fn int(&self) -> &crate::peripherals::dma::ch::out_int::OUT_INT { let dma = unsafe { &*crate::peripherals::DMA::PTR }; - dma.ch(self.0.number() as usize).out_int() - } - - fn degrade(self) -> ChannelTxImpl { - ChannelTxImpl(AnyGdmaChannel(self.0.number())) + dma.ch(self.0 as usize).out_int() } } -impl RegisterAccess for ChannelTxImpl { +impl RegisterAccess for AnyGdmaTxChannel { fn reset(&self) { let conf0 = self.ch().out_conf0(); conf0.modify(|_, w| w.out_rst().set_bit()); @@ -231,7 +181,7 @@ impl RegisterAccess for ChannelTxImpl { } } -impl TxRegisterAccess for ChannelTxImpl { +impl TxRegisterAccess for AnyGdmaTxChannel { fn set_auto_write_back(&self, enable: bool) { self.ch() .out_conf0() @@ -247,15 +197,37 @@ impl TxRegisterAccess for ChannelTxImpl { } fn async_handler(&self) -> Option { - self.0.async_handler_out() + match self.0 { + 0 => DmaChannel0::handler_out(), + #[cfg(not(esp32c2))] + 1 => DmaChannel1::handler_out(), + #[cfg(not(esp32c2))] + 2 => DmaChannel2::handler_out(), + #[cfg(esp32s3)] + 3 => DmaChannel3::handler_out(), + #[cfg(esp32s3)] + 4 => DmaChannel4::handler_out(), + _ => unreachable!(), + } } fn peripheral_interrupt(&self) -> Option { - self.0.peripheral_interrupt_out() + match self.0 { + 0 => DmaChannel0::isr_out(), + #[cfg(not(esp32c2))] + 1 => DmaChannel1::isr_out(), + #[cfg(not(esp32c2))] + 2 => DmaChannel2::isr_out(), + #[cfg(esp32s3)] + 3 => DmaChannel3::isr_out(), + #[cfg(esp32s3)] + 4 => DmaChannel4::isr_out(), + _ => unreachable!(), + } } } -impl InterruptAccess for ChannelTxImpl { +impl InterruptAccess for AnyGdmaTxChannel { fn enable_listen(&self, interrupts: EnumSet, enable: bool) { self.int().ena().modify(|_, w| { for interrupt in interrupts { @@ -325,13 +297,13 @@ impl InterruptAccess for ChannelTxImpl { } fn waker(&self) -> &'static AtomicWaker { - &TX_WAKERS[self.0.number() as usize] + &TX_WAKERS[self.0 as usize] } fn is_async(&self) -> bool { cfg_if::cfg_if! { if #[cfg(any(esp32c2, esp32c3))] { - TX_IS_ASYNC[self.0.number() as usize].load(portable_atomic::Ordering::Acquire) + TX_IS_ASYNC[self.0 as usize].load(portable_atomic::Ordering::Acquire) } else { true } @@ -341,52 +313,45 @@ impl InterruptAccess for ChannelTxImpl { fn set_async(&self, _is_async: bool) { cfg_if::cfg_if! { if #[cfg(any(esp32c2, esp32c3))] { - TX_IS_ASYNC[self.0.number() as usize].store(_is_async, portable_atomic::Ordering::Release); + TX_IS_ASYNC[self.0 as usize].store(_is_async, portable_atomic::Ordering::Release); } } } } -#[non_exhaustive] -#[doc(hidden)] -pub struct ChannelRxImpl(C); +impl crate::private::Sealed for AnyGdmaRxChannel {} +impl DmaRxChannel for AnyGdmaRxChannel {} -impl crate::private::Sealed for ChannelRxImpl {} - -impl ChannelRxImpl { +impl AnyGdmaRxChannel { #[inline(always)] fn ch(&self) -> &crate::peripherals::dma::ch::CH { let dma = unsafe { &*crate::peripherals::DMA::PTR }; - dma.ch(self.0.number() as usize) + dma.ch(self.0 as usize) } #[cfg(any(esp32c2, esp32c3))] #[inline(always)] fn int(&self) -> &crate::peripherals::dma::int_ch::INT_CH { let dma = unsafe { &*crate::peripherals::DMA::PTR }; - dma.int_ch(self.0.number() as usize) + dma.int_ch(self.0 as usize) } #[inline(always)] #[cfg(any(esp32c6, esp32h2))] fn int(&self) -> &crate::peripherals::dma::in_int_ch::IN_INT_CH { let dma = unsafe { &*crate::peripherals::DMA::PTR }; - dma.in_int_ch(self.0.number() as usize) + dma.in_int_ch(self.0 as usize) } #[cfg(esp32s3)] #[inline(always)] fn int(&self) -> &crate::peripherals::dma::ch::in_int::IN_INT { let dma = unsafe { &*crate::peripherals::DMA::PTR }; - dma.ch(self.0.number() as usize).in_int() - } - - fn degrade(self) -> ChannelRxImpl { - ChannelRxImpl(AnyGdmaChannel(self.0.number())) + dma.ch(self.0 as usize).in_int() } } -impl RegisterAccess for ChannelRxImpl { +impl RegisterAccess for AnyGdmaRxChannel { fn reset(&self) { let conf0 = self.ch().in_conf0(); conf0.modify(|_, w| w.in_rst().set_bit()); @@ -453,7 +418,7 @@ impl RegisterAccess for ChannelRxImpl { } } -impl RxRegisterAccess for ChannelRxImpl { +impl RxRegisterAccess for AnyGdmaRxChannel { fn set_mem2mem_mode(&self, value: bool) { self.ch() .in_conf0() @@ -461,15 +426,37 @@ impl RxRegisterAccess for ChannelRxImpl { } fn async_handler(&self) -> Option { - self.0.async_handler_in() + match self.0 { + 0 => DmaChannel0::handler_in(), + #[cfg(not(esp32c2))] + 1 => DmaChannel1::handler_in(), + #[cfg(not(esp32c2))] + 2 => DmaChannel2::handler_in(), + #[cfg(esp32s3)] + 3 => DmaChannel3::handler_in(), + #[cfg(esp32s3)] + 4 => DmaChannel4::handler_in(), + _ => unreachable!(), + } } fn peripheral_interrupt(&self) -> Option { - self.0.peripheral_interrupt_in() + match self.0 { + 0 => DmaChannel0::isr_in(), + #[cfg(not(esp32c2))] + 1 => DmaChannel1::isr_in(), + #[cfg(not(esp32c2))] + 2 => DmaChannel2::isr_in(), + #[cfg(esp32s3)] + 3 => DmaChannel3::isr_in(), + #[cfg(esp32s3)] + 4 => DmaChannel4::isr_in(), + _ => unreachable!(), + } } } -impl InterruptAccess for ChannelRxImpl { +impl InterruptAccess for AnyGdmaRxChannel { fn enable_listen(&self, interrupts: EnumSet, enable: bool) { self.int().ena().modify(|_, w| { for interrupt in interrupts { @@ -547,13 +534,13 @@ impl InterruptAccess for ChannelRxImpl { } fn waker(&self) -> &'static AtomicWaker { - &RX_WAKERS[self.0.number() as usize] + &RX_WAKERS[self.0 as usize] } fn is_async(&self) -> bool { cfg_if::cfg_if! { if #[cfg(any(esp32c2, esp32c3))] { - RX_IS_ASYNC[self.0.number() as usize].load(portable_atomic::Ordering::Acquire) + RX_IS_ASYNC[self.0 as usize].load(portable_atomic::Ordering::Acquire) } else { true } @@ -563,7 +550,7 @@ impl InterruptAccess for ChannelRxImpl { fn set_async(&self, _is_async: bool) { cfg_if::cfg_if! { if #[cfg(any(esp32c2, esp32c3))] { - RX_IS_ASYNC[self.0.number() as usize].store(_is_async, portable_atomic::Ordering::Release); + RX_IS_ASYNC[self.0 as usize].store(_is_async, portable_atomic::Ordering::Release); } } } @@ -583,7 +570,26 @@ macro_rules! impl_channel { #[non_exhaustive] pub struct [] {} - impl crate::private::Sealed for [] {} + impl $crate::private::Sealed for [] {} + + impl Peripheral for [] { + type P = Self; + + unsafe fn clone_unchecked(&self) -> Self::P { + Self::steal() + } + } + + impl [] { + /// Unsafely constructs a new DMA channel. + /// + /// # Safety + /// + /// The caller must ensure that only a single instance is used. + pub unsafe fn steal() -> Self { + Self {} + } + } impl [] { fn handler_in() -> Option { @@ -604,44 +610,43 @@ macro_rules! impl_channel { } impl DmaChannel for [] { - type Rx = ChannelRxImpl>; - type Tx = ChannelTxImpl>; + type Rx = AnyGdmaRxChannel; + type Tx = AnyGdmaTxChannel; + + fn set_priority(&self, priority: DmaPriority) { + AnyGdmaChannel($num).set_priority(priority); + } + + unsafe fn split_internal(self, _: $crate::private::Internal) -> (Self::Rx, Self::Tx) { + (AnyGdmaRxChannel($num), AnyGdmaTxChannel($num)) + } } impl DmaChannelConvert for [] { - fn degrade_rx(rx: Self::Rx) -> ChannelRxImpl { - rx.degrade() + fn degrade(self) -> AnyGdmaChannel { + AnyGdmaChannel($num) } - fn degrade_tx(tx: Self::Tx) -> ChannelTxImpl { - tx.degrade() + } + + impl DmaChannelConvert for [] { + fn degrade(self) -> AnyGdmaRxChannel { + AnyGdmaRxChannel($num) + } + } + + impl DmaChannelConvert for [] { + fn degrade(self) -> AnyGdmaTxChannel { + AnyGdmaTxChannel($num) } } impl DmaChannelExt for [] { fn rx_interrupts() -> impl InterruptAccess { - ChannelRxImpl(SpecificGdmaChannel::<$num> {}) + AnyGdmaRxChannel($num) } fn tx_interrupts() -> impl InterruptAccess { - ChannelTxImpl(SpecificGdmaChannel::<$num> {}) - } - } - - impl [] { - /// Unsafely constructs a new DMA channel. - /// - /// # Safety - /// - /// The caller must ensure that only a single instance is used. - pub unsafe fn steal<'a>() -> Channel<'a, Blocking, Self> { - let mut this = Channel { - tx: ChannelTx::new(ChannelTxImpl(SpecificGdmaChannel::<$num> {})), - rx: ChannelRx::new(ChannelRxImpl(SpecificGdmaChannel::<$num> {})), - }; - - this.set_priority(DmaPriority::Priority0); - - this + AnyGdmaTxChannel($num) } } } @@ -737,30 +742,28 @@ crate::impl_dma_eligible! { pub struct Dma<'d> { _inner: PeripheralRef<'d, crate::peripherals::DMA>, /// Channel 0 - pub channel0: Channel<'d, Blocking, DmaChannel0>, + pub channel0: DmaChannel0, /// Channel 1 #[cfg(not(esp32c2))] - pub channel1: Channel<'d, Blocking, DmaChannel1>, + pub channel1: DmaChannel1, /// Channel 2 #[cfg(not(esp32c2))] - pub channel2: Channel<'d, Blocking, DmaChannel2>, + pub channel2: DmaChannel2, /// Channel 3 #[cfg(esp32s3)] - pub channel3: Channel<'d, Blocking, DmaChannel3>, + pub channel3: DmaChannel3, /// Channel 4 #[cfg(esp32s3)] - pub channel4: Channel<'d, Blocking, DmaChannel4>, + pub channel4: DmaChannel4, } impl<'d> Dma<'d> { /// Create a DMA instance. - pub fn new( - dma: impl crate::peripheral::Peripheral

+ 'd, - ) -> Dma<'d> { + pub fn new(dma: impl Peripheral

+ 'd) -> Dma<'d> { crate::into_ref!(dma); - if PeripheralClockControl::enable(Peripheral::Gdma) { - PeripheralClockControl::reset(Peripheral::Gdma); + if PeripheralClockControl::enable(system::Peripheral::Gdma) { + PeripheralClockControl::reset(system::Peripheral::Gdma); } dma.misc_conf().modify(|_, w| w.ahbm_rst_inter().set_bit()); dma.misc_conf() diff --git a/esp-hal/src/dma/m2m.rs b/esp-hal/src/dma/m2m.rs index 0b2009950..495d63788 100644 --- a/esp-hal/src/dma/m2m.rs +++ b/esp-hal/src/dma/m2m.rs @@ -4,6 +4,7 @@ use crate::{ dma::{ dma_private::{DmaSupport, DmaSupportRx}, AnyGdmaChannel, + AnyGdmaRxChannel, Channel, ChannelRx, DescriptorChain, @@ -18,6 +19,7 @@ use crate::{ Tx, WriteBuffer, }, + peripheral::Peripheral, Async, Blocking, Mode, @@ -40,16 +42,14 @@ where impl<'d> Mem2Mem<'d, Blocking> { /// Create a new Mem2Mem instance. - pub fn new( - channel: Channel<'d, DM, CH>, + pub fn new( + channel: impl Peripheral

+ 'd, peripheral: impl DmaEligible, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], ) -> Result where CH: DmaChannelConvert, - DM: Mode, - Channel<'d, Blocking, CH>: From>, { unsafe { Self::new_unsafe( @@ -63,8 +63,8 @@ impl<'d> Mem2Mem<'d, Blocking> { } /// Create a new Mem2Mem instance with specific chunk size. - pub fn new_with_chunk_size( - channel: Channel<'d, DM, CH>, + pub fn new_with_chunk_size( + channel: impl Peripheral

+ 'd, peripheral: impl DmaEligible, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], @@ -72,8 +72,6 @@ impl<'d> Mem2Mem<'d, Blocking> { ) -> Result where CH: DmaChannelConvert, - DM: Mode, - Channel<'d, Blocking, CH>: From>, { unsafe { Self::new_unsafe( @@ -92,8 +90,8 @@ impl<'d> Mem2Mem<'d, Blocking> { /// /// You must ensure that your not using DMA for the same peripheral and /// that your the only one using the DmaPeripheral. - pub unsafe fn new_unsafe( - channel: Channel<'d, DM, CH>, + pub unsafe fn new_unsafe( + channel: impl Peripheral

+ 'd, peripheral: DmaPeripheral, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], @@ -101,8 +99,6 @@ impl<'d> Mem2Mem<'d, Blocking> { ) -> Result where CH: DmaChannelConvert, - DM: Mode, - Channel<'d, Blocking, CH>: From>, { if !(1..=4092).contains(&chunk_size) { return Err(DmaError::InvalidChunkSize); @@ -111,7 +107,7 @@ impl<'d> Mem2Mem<'d, Blocking> { return Err(DmaError::OutOfDescriptors); } Ok(Mem2Mem { - channel: Channel::::from(channel).degrade(), + channel: Channel::new(channel.map(|ch| ch.degrade())), peripheral, rx_chain: DescriptorChain::new_with_chunk_size(rx_descriptors, chunk_size), tx_chain: DescriptorChain::new_with_chunk_size(tx_descriptors, chunk_size), @@ -194,7 +190,7 @@ impl<'d, M> DmaSupportRx for Mem2Mem<'d, M> where M: Mode, { - type RX = ChannelRx<'d, M, AnyGdmaChannel>; + type RX = ChannelRx<'d, M, AnyGdmaRxChannel>; fn rx(&mut self) -> &mut Self::RX { &mut self.channel.rx diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index f31325bb3..b73ffb99a 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -67,6 +67,7 @@ pub use self::m2m::*; pub use self::pdma::*; use crate::{ interrupt::InterruptHandler, + peripheral::{Peripheral, PeripheralRef}, peripherals::Interrupt, soc::is_slice_in_dram, Async, @@ -943,6 +944,13 @@ pub trait DmaEligible { fn dma_peripheral(&self) -> DmaPeripheral; } +/// Helper type to get the DMA (Rx and Tx) channel for a peripheral. +pub type DmaChannelFor = ::Dma; +/// Helper type to get the DMA Rx channel for a peripheral. +pub type RxChannelFor = as DmaChannel>::Rx; +/// Helper type to get the DMA Tx channel for a peripheral. +pub type TxChannelFor = as DmaChannel>::Tx; + #[doc(hidden)] #[macro_export] macro_rules! impl_dma_eligible { @@ -1585,13 +1593,46 @@ impl RxCircularState { } } +#[doc(hidden)] +pub trait DmaRxChannel: + RxRegisterAccess + InterruptAccess + Peripheral

+{ +} + +#[doc(hidden)] +pub trait DmaTxChannel: + TxRegisterAccess + InterruptAccess + Peripheral

+{ +} + /// A description of a DMA Channel. -pub trait DmaChannel: crate::private::Sealed + Sized { +pub trait DmaChannel: Peripheral

{ /// A description of the RX half of a DMA Channel. - type Rx: RxRegisterAccess + InterruptAccess; + type Rx: DmaRxChannel; /// A description of the TX half of a DMA Channel. - type Tx: TxRegisterAccess + InterruptAccess; + type Tx: DmaTxChannel; + + /// Sets the priority of the DMA channel. + #[cfg(gdma)] + fn set_priority(&self, priority: DmaPriority); + + /// Splits the DMA channel into its RX and TX halves. + #[cfg(any(esp32c6, esp32h2, esp32s3))] // TODO relax this to allow splitting on all chips + fn split(self) -> (Self::Rx, Self::Tx) { + // This function is exposed safely on chips that have separate IN and OUT + // interrupt handlers. + // TODO: this includes the P4 as well. + unsafe { self.split_internal(crate::private::Internal) } + } + + /// Splits the DMA channel into its RX and TX halves. + /// + /// # Safety + /// + /// This function must only be used if the separate halves are used by the + /// same peripheral. + unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx); } #[doc(hidden)] @@ -1606,18 +1647,13 @@ pub trait DmaChannelExt: DmaChannel { note = "Not all channels are useable with all peripherals" )] #[doc(hidden)] -pub trait DmaChannelConvert: DmaChannel { - fn degrade_rx(rx: Self::Rx) -> DEG::Rx; - fn degrade_tx(tx: Self::Tx) -> DEG::Tx; +pub trait DmaChannelConvert: DmaChannel { + fn degrade(self) -> DEG; } impl DmaChannelConvert for DEG { - fn degrade_rx(rx: Self::Rx) -> DEG::Rx { - rx - } - - fn degrade_tx(tx: Self::Tx) -> DEG::Tx { - tx + fn degrade(self) -> DEG { + self } } @@ -1683,17 +1719,20 @@ pub trait Rx: crate::private::Sealed { #[doc(hidden)] pub struct ChannelRx<'a, M, CH> where - CH: DmaChannel, + M: Mode, + CH: DmaRxChannel, { - pub(crate) rx_impl: CH::Rx, - pub(crate) _phantom: PhantomData<(&'a (), CH, M)>, + pub(crate) rx_impl: PeripheralRef<'a, CH>, + pub(crate) _phantom: PhantomData, } impl<'a, CH> ChannelRx<'a, Blocking, CH> where - CH: DmaChannel, + CH: DmaRxChannel, { - fn new(rx_impl: CH::Rx) -> Self { + /// Creates a new RX channel half. + pub fn new(rx_impl: impl Peripheral

+ 'a) -> Self { + crate::into_ref!(rx_impl); #[cfg(gdma)] // clear the mem2mem mode to avoid failed DMA if this // channel was previously used for a mem2mem transfer. @@ -1724,10 +1763,7 @@ where } } - fn set_interrupt_handler(&mut self, handler: InterruptHandler) - where - CH: DmaChannel, - { + fn set_interrupt_handler(&mut self, handler: InterruptHandler) { self.unlisten_in(EnumSet::all()); self.clear_in(EnumSet::all()); @@ -1743,7 +1779,7 @@ where impl<'a, CH> ChannelRx<'a, Async, CH> where - CH: DmaChannel, + CH: DmaRxChannel, { /// Converts an async channel into a blocking channel. pub(crate) fn into_blocking(self) -> ChannelRx<'a, Blocking, CH> { @@ -1761,20 +1797,8 @@ where impl<'a, M, CH> ChannelRx<'a, M, CH> where M: Mode, - CH: DmaChannel, + CH: DmaRxChannel, { - /// Return a less specific (degraded) version of this channel. - #[doc(hidden)] - pub fn degrade(self) -> ChannelRx<'a, M, DEG> - where - CH: DmaChannelConvert, - { - ChannelRx { - rx_impl: CH::degrade_rx(self.rx_impl), - _phantom: PhantomData, - } - } - /// Configure the channel. #[cfg(gdma)] pub fn set_priority(&mut self, priority: DmaPriority) { @@ -1806,14 +1830,14 @@ where impl crate::private::Sealed for ChannelRx<'_, M, CH> where M: Mode, - CH: DmaChannel, + CH: DmaRxChannel, { } impl Rx for ChannelRx<'_, M, CH> where M: Mode, - CH: DmaChannel, + CH: DmaRxChannel, { // TODO: used by I2S, which should be rewritten to use the Preparation-based // API. @@ -1978,24 +2002,26 @@ pub trait Tx: crate::private::Sealed { #[doc(hidden)] pub struct ChannelTx<'a, M, CH> where - CH: DmaChannel, + M: Mode, + CH: DmaTxChannel, { - pub(crate) tx_impl: CH::Tx, - pub(crate) _phantom: PhantomData<(&'a (), CH, M)>, + pub(crate) tx_impl: PeripheralRef<'a, CH>, + pub(crate) _phantom: PhantomData, } impl<'a, CH> ChannelTx<'a, Blocking, CH> where - CH: DmaChannel, + CH: DmaTxChannel, { - fn new(tx_impl: CH::Tx) -> Self { + /// Creates a new TX channel half. + pub fn new(tx_impl: impl Peripheral

+ 'a) -> Self { + crate::into_ref!(tx_impl); if let Some(interrupt) = tx_impl.peripheral_interrupt() { for cpu in Cpu::all() { crate::interrupt::disable(cpu, interrupt); } } tx_impl.set_async(false); - Self { tx_impl, _phantom: PhantomData, @@ -2014,10 +2040,7 @@ where } } - fn set_interrupt_handler(&mut self, handler: InterruptHandler) - where - CH: DmaChannel, - { + fn set_interrupt_handler(&mut self, handler: InterruptHandler) { self.unlisten_out(EnumSet::all()); self.clear_out(EnumSet::all()); @@ -2033,7 +2056,7 @@ where impl<'a, CH> ChannelTx<'a, Async, CH> where - CH: DmaChannel, + CH: DmaTxChannel, { /// Converts an async channel into a blocking channel. pub(crate) fn into_blocking(self) -> ChannelTx<'a, Blocking, CH> { @@ -2051,20 +2074,8 @@ where impl<'a, M, CH> ChannelTx<'a, M, CH> where M: Mode, - CH: DmaChannel, + CH: DmaTxChannel, { - /// Return a less specific (degraded) version of this channel. - #[doc(hidden)] - pub fn degrade(self) -> ChannelTx<'a, M, DEG> - where - CH: DmaChannelConvert, - { - ChannelTx { - tx_impl: CH::degrade_tx(self.tx_impl), - _phantom: PhantomData, - } - } - /// Configure the channel priority. #[cfg(gdma)] pub fn set_priority(&mut self, priority: DmaPriority) { @@ -2101,14 +2112,14 @@ where impl crate::private::Sealed for ChannelTx<'_, M, CH> where M: Mode, - CH: DmaChannel, + CH: DmaTxChannel, { } impl Tx for ChannelTx<'_, M, CH> where M: Mode, - CH: DmaChannel, + CH: DmaTxChannel, { // TODO: used by I2S, which should be rewritten to use the Preparation-based // API. @@ -2309,28 +2320,38 @@ pub trait InterruptAccess: crate::private::Sealed { } /// DMA Channel +#[non_exhaustive] pub struct Channel<'d, M, CH> where M: Mode, CH: DmaChannel, { /// RX half of the channel - pub rx: ChannelRx<'d, M, CH>, + pub rx: ChannelRx<'d, M, CH::Rx>, /// TX half of the channel - pub tx: ChannelTx<'d, M, CH>, + pub tx: ChannelTx<'d, M, CH::Tx>, } impl<'d, CH> Channel<'d, Blocking, CH> where CH: DmaChannel, { + pub(crate) fn new(channel: impl Peripheral

) -> Self { + let (rx, tx) = unsafe { + channel + .clone_unchecked() + .split_internal(crate::private::Internal) + }; + Self { + rx: ChannelRx::new(rx), + tx: ChannelTx::new(tx), + } + } + /// Sets the interrupt handler for RX and TX interrupts. /// /// Interrupts are not enabled at the peripheral level here. - pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) - where - CH: DmaChannel, - { + pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) { self.rx.set_interrupt_handler(handler); self.tx.set_interrupt_handler(handler); } @@ -2418,25 +2439,6 @@ impl<'d, CH: DmaChannel> From> for Channel<'d, Blocking, } } -impl<'d, M, CH> Channel<'d, M, CH> -where - M: Mode, - CH: DmaChannel, -{ - /// Return a less specific (degraded) version of this channel (both rx and - /// tx). - #[doc(hidden)] - pub fn degrade(self) -> Channel<'d, M, DEG> - where - CH: DmaChannelConvert, - { - Channel { - rx: self.rx.degrade(), - tx: self.tx.degrade(), - } - } -} - pub(crate) mod dma_private { use super::*; diff --git a/esp-hal/src/dma/pdma.rs b/esp-hal/src/dma/pdma.rs index 4b0ca3cb8..0847eea7b 100644 --- a/esp-hal/src/dma/pdma.rs +++ b/esp-hal/src/dma/pdma.rs @@ -16,10 +16,9 @@ use portable_atomic::{AtomicBool, Ordering}; use crate::{ dma::*, - peripheral::PeripheralRef, + peripheral::{Peripheral, PeripheralRef}, peripherals::Interrupt, - system::{Peripheral, PeripheralClockControl}, - Blocking, + system::{self, PeripheralClockControl}, }; type SpiRegisterBlock = crate::peripherals::spi2::RegisterBlock; @@ -40,17 +39,33 @@ pub trait PdmaChannel: crate::private::Sealed { fn tx_async_flag(&self) -> &'static AtomicBool; } -#[doc(hidden)] -pub struct SpiDmaRxChannelImpl(C); +/// The RX half of an arbitrary SPI DMA channel. +pub struct AnySpiDmaRxChannel(AnySpiDmaChannel); -impl crate::private::Sealed for SpiDmaRxChannelImpl {} +impl crate::private::Sealed for AnySpiDmaRxChannel {} +impl DmaRxChannel for AnySpiDmaRxChannel {} +impl Peripheral for AnySpiDmaRxChannel { + type P = Self; -#[doc(hidden)] -pub struct SpiDmaTxChannelImpl(C); + unsafe fn clone_unchecked(&self) -> Self::P { + Self(self.0.clone_unchecked()) + } +} -impl crate::private::Sealed for SpiDmaTxChannelImpl {} +/// The TX half of an arbitrary SPI DMA channel. +pub struct AnySpiDmaTxChannel(AnySpiDmaChannel); -impl> RegisterAccess for SpiDmaTxChannelImpl { +impl crate::private::Sealed for AnySpiDmaTxChannel {} +impl DmaTxChannel for AnySpiDmaTxChannel {} +impl Peripheral for AnySpiDmaTxChannel { + type P = Self; + + unsafe fn clone_unchecked(&self) -> Self::P { + Self(self.0.clone_unchecked()) + } +} + +impl RegisterAccess for AnySpiDmaTxChannel { fn reset(&self) { let spi = self.0.register_block(); spi.dma_conf().modify(|_, w| w.out_rst().set_bit()); @@ -107,7 +122,7 @@ impl> RegisterAccess for SpiDma } } -impl> TxRegisterAccess for SpiDmaTxChannelImpl { +impl TxRegisterAccess for AnySpiDmaTxChannel { fn set_auto_write_back(&self, enable: bool) { // there is no `auto_wrback` for SPI assert!(!enable); @@ -127,9 +142,7 @@ impl> TxRegisterAccess for SpiD } } -impl> InterruptAccess - for SpiDmaTxChannelImpl -{ +impl InterruptAccess for AnySpiDmaTxChannel { fn enable_listen(&self, interrupts: EnumSet, enable: bool) { let reg_block = self.0.register_block(); reg_block.dma_int_ena().modify(|_, w| { @@ -215,7 +228,7 @@ impl> InterruptAccess> RegisterAccess for SpiDmaRxChannelImpl { +impl RegisterAccess for AnySpiDmaRxChannel { fn reset(&self) { let spi = self.0.register_block(); spi.dma_conf().modify(|_, w| w.in_rst().set_bit()); @@ -267,7 +280,7 @@ impl> RegisterAccess for SpiDma } } -impl> RxRegisterAccess for SpiDmaRxChannelImpl { +impl RxRegisterAccess for AnySpiDmaRxChannel { fn peripheral_interrupt(&self) -> Option { Some(self.0.peripheral_interrupt()) } @@ -277,9 +290,7 @@ impl> RxRegisterAccess for SpiD } } -impl> InterruptAccess - for SpiDmaRxChannelImpl -{ +impl InterruptAccess for AnySpiDmaRxChannel { fn enable_listen(&self, interrupts: EnumSet, enable: bool) { let reg_block = self.0.register_block(); reg_block.dma_int_ena().modify(|_, w| { @@ -385,17 +396,42 @@ macro_rules! ImplSpiChannel { #[non_exhaustive] pub struct [] {} + impl $crate::private::Sealed for [] {} + + impl Peripheral for [] { + type P = Self; + + unsafe fn clone_unchecked(&self) -> Self::P { + Self::steal() + } + } + + impl [] { + /// Unsafely constructs a new DMA channel. + /// + /// # Safety + /// + /// The caller must ensure that only a single instance is used. + pub unsafe fn steal() -> Self { + Self {} + } + } + impl DmaChannel for [] { - type Rx = SpiDmaRxChannelImpl; - type Tx = SpiDmaTxChannelImpl; + type Rx = AnySpiDmaRxChannel; + type Tx = AnySpiDmaTxChannel; + + unsafe fn split_internal(self, _: $crate::private::Internal) -> (Self::Rx, Self::Tx) { + (AnySpiDmaRxChannel(Self {}.into()), AnySpiDmaTxChannel(Self {}.into())) + } } impl DmaChannelExt for [] { fn rx_interrupts() -> impl InterruptAccess { - SpiDmaRxChannelImpl(Self {}) + AnySpiDmaRxChannel(Self {}.into()) } fn tx_interrupts() -> impl InterruptAccess { - SpiDmaTxChannelImpl(Self {}) + AnySpiDmaTxChannel(Self {}.into()) } } @@ -403,7 +439,7 @@ macro_rules! ImplSpiChannel { type RegisterBlock = SpiRegisterBlock; fn register_block(&self) -> &SpiRegisterBlock { - unsafe { &*crate::peripherals::[]::PTR } + unsafe { &*$crate::peripherals::[]::PTR } } fn tx_waker(&self) -> &'static AtomicWaker { static WAKER: AtomicWaker = AtomicWaker::new(); @@ -436,44 +472,53 @@ macro_rules! ImplSpiChannel { } impl DmaChannelConvert for [] { - fn degrade_rx(rx: SpiDmaRxChannelImpl) -> SpiDmaRxChannelImpl { - SpiDmaRxChannelImpl(rx.0.into()) - } - fn degrade_tx(tx: SpiDmaTxChannelImpl) -> SpiDmaTxChannelImpl { - SpiDmaTxChannelImpl(tx.0.into()) + fn degrade(self) -> AnySpiDmaChannel { + self.into() } } - impl $crate::private::Sealed for [] {} + impl DmaChannelConvert for [] { + fn degrade(self) -> AnySpiDmaRxChannel { + AnySpiDmaRxChannel(Self {}.into()) + } + } - impl [] { - /// Unsafely constructs a new DMA channel. - /// - /// # Safety - /// - /// The caller must ensure that only a single instance is used. - pub unsafe fn steal<'a>() -> Channel<'a, Blocking, Self> { - Channel { - tx: ChannelTx::new(SpiDmaTxChannelImpl([] {})), - rx: ChannelRx::new(SpiDmaRxChannelImpl([] {})), - } + impl DmaChannelConvert for [] { + fn degrade(self) -> AnySpiDmaTxChannel { + AnySpiDmaTxChannel(Self {}.into()) } } } }; } -#[doc(hidden)] -pub struct I2sDmaRxChannelImpl(C); +/// The RX half of an arbitrary I2S DMA channel. +pub struct AnyI2sDmaRxChannel(AnyI2sDmaChannel); -impl crate::private::Sealed for I2sDmaRxChannelImpl {} +impl crate::private::Sealed for AnyI2sDmaRxChannel {} +impl DmaRxChannel for AnyI2sDmaRxChannel {} +impl Peripheral for AnyI2sDmaRxChannel { + type P = Self; -#[doc(hidden)] -pub struct I2sDmaTxChannelImpl(C); + unsafe fn clone_unchecked(&self) -> Self::P { + Self(self.0.clone_unchecked()) + } +} -impl crate::private::Sealed for I2sDmaTxChannelImpl {} +/// The TX half of an arbitrary I2S DMA channel. +pub struct AnyI2sDmaTxChannel(AnyI2sDmaChannel); -impl> RegisterAccess for I2sDmaTxChannelImpl { +impl crate::private::Sealed for AnyI2sDmaTxChannel {} +impl DmaTxChannel for AnyI2sDmaTxChannel {} +impl Peripheral for AnyI2sDmaTxChannel { + type P = Self; + + unsafe fn clone_unchecked(&self) -> Self::P { + Self(self.0.clone_unchecked()) + } +} + +impl RegisterAccess for AnyI2sDmaTxChannel { fn reset(&self) { let reg_block = self.0.register_block(); reg_block.lc_conf().modify(|_, w| w.out_rst().set_bit()); @@ -538,7 +583,7 @@ impl> RegisterAccess for I2sDma } } -impl> TxRegisterAccess for I2sDmaTxChannelImpl { +impl TxRegisterAccess for AnyI2sDmaTxChannel { fn set_auto_write_back(&self, enable: bool) { let reg_block = self.0.register_block(); reg_block @@ -564,9 +609,7 @@ impl> TxRegisterAccess for I2sD } } -impl> InterruptAccess - for I2sDmaTxChannelImpl -{ +impl InterruptAccess for AnyI2sDmaTxChannel { fn enable_listen(&self, interrupts: EnumSet, enable: bool) { let reg_block = self.0.register_block(); reg_block.int_ena().modify(|_, w| { @@ -652,7 +695,7 @@ impl> InterruptAccess> RegisterAccess for I2sDmaRxChannelImpl { +impl RegisterAccess for AnyI2sDmaRxChannel { fn reset(&self) { let reg_block = self.0.register_block(); reg_block.lc_conf().modify(|_, w| w.in_rst().set_bit()); @@ -710,7 +753,7 @@ impl> RegisterAccess for I2sDma } } -impl> RxRegisterAccess for I2sDmaRxChannelImpl { +impl RxRegisterAccess for AnyI2sDmaRxChannel { fn peripheral_interrupt(&self) -> Option { Some(self.0.peripheral_interrupt()) } @@ -720,9 +763,7 @@ impl> RxRegisterAccess for I2sD } } -impl> InterruptAccess - for I2sDmaRxChannelImpl -{ +impl InterruptAccess for AnyI2sDmaRxChannel { fn enable_listen(&self, interrupts: EnumSet, enable: bool) { let reg_block = self.0.register_block(); reg_block.int_ena().modify(|_, w| { @@ -824,17 +865,40 @@ macro_rules! ImplI2sChannel { impl $crate::private::Sealed for [] {} + impl Peripheral for [] { + type P = Self; + + unsafe fn clone_unchecked(&self) -> Self::P { + Self::steal() + } + } + + impl [] { + /// Unsafely constructs a new DMA channel. + /// + /// # Safety + /// + /// The caller must ensure that only a single instance is used. + pub unsafe fn steal() -> Self { + Self {} + } + } + impl DmaChannel for [] { - type Rx = I2sDmaRxChannelImpl; - type Tx = I2sDmaTxChannelImpl; + type Rx = AnyI2sDmaRxChannel; + type Tx = AnyI2sDmaTxChannel; + + unsafe fn split_internal(self, _: $crate::private::Internal) -> (Self::Rx, Self::Tx) { + (AnyI2sDmaRxChannel(Self {}.into()), AnyI2sDmaTxChannel(Self {}.into())) + } } impl DmaChannelExt for [] { fn rx_interrupts() -> impl InterruptAccess { - I2sDmaRxChannelImpl(Self {}) + AnyI2sDmaRxChannel(Self {}.into()) } fn tx_interrupts() -> impl InterruptAccess { - I2sDmaTxChannelImpl(Self {}) + AnyI2sDmaTxChannel(Self {}.into()) } } @@ -874,25 +938,20 @@ macro_rules! ImplI2sChannel { } impl DmaChannelConvert for [] { - fn degrade_rx(rx: I2sDmaRxChannelImpl) -> I2sDmaRxChannelImpl { - I2sDmaRxChannelImpl(rx.0.into()) - } - fn degrade_tx(tx: I2sDmaTxChannelImpl) -> I2sDmaTxChannelImpl { - I2sDmaTxChannelImpl(tx.0.into()) + fn degrade(self) -> AnyI2sDmaChannel { + self.into() } } - impl [] { - /// Unsafely constructs a new DMA channel. - /// - /// # Safety - /// - /// The caller must ensure that only a single instance is used. - pub unsafe fn steal<'a>() -> Channel<'a, Blocking, Self> { - Channel { - tx: ChannelTx::new(I2sDmaTxChannelImpl([] {})), - rx: ChannelRx::new(I2sDmaRxChannelImpl([] {})), - } + impl DmaChannelConvert for [] { + fn degrade(self) -> AnyI2sDmaRxChannel { + AnyI2sDmaRxChannel(Self {}.into()) + } + } + + impl DmaChannelConvert for [] { + fn degrade(self) -> AnyI2sDmaTxChannel { + AnyI2sDmaTxChannel(Self {}.into()) } } } @@ -921,23 +980,21 @@ crate::impl_dma_eligible!([I2s1DmaChannel] I2S1 => I2s1); pub struct Dma<'d> { _inner: PeripheralRef<'d, crate::peripherals::DMA>, /// DMA channel for SPI2 - pub spi2channel: Channel<'d, Blocking, Spi2DmaChannel>, + pub spi2channel: Spi2DmaChannel, /// DMA channel for SPI3 - pub spi3channel: Channel<'d, Blocking, Spi3DmaChannel>, + pub spi3channel: Spi3DmaChannel, /// DMA channel for I2S0 - pub i2s0channel: Channel<'d, Blocking, I2s0DmaChannel>, + pub i2s0channel: I2s0DmaChannel, /// DMA channel for I2S1 #[cfg(i2s1)] - pub i2s1channel: Channel<'d, Blocking, I2s1DmaChannel>, + pub i2s1channel: I2s1DmaChannel, } impl<'d> Dma<'d> { /// Create a DMA instance. - pub fn new( - dma: impl crate::peripheral::Peripheral

+ 'd, - ) -> Dma<'d> { - if PeripheralClockControl::enable(Peripheral::Dma) { - PeripheralClockControl::reset(Peripheral::Dma); + pub fn new(dma: impl Peripheral

+ 'd) -> Dma<'d> { + if PeripheralClockControl::enable(system::Peripheral::Dma) { + PeripheralClockControl::reset(system::Peripheral::Dma); } #[cfg(esp32)] @@ -983,31 +1040,31 @@ where } } -/// A marker for SPI-compatible type-erased DMA channels. -pub struct AnySpiDmaChannel; - -impl crate::private::Sealed for AnySpiDmaChannel {} - -impl DmaChannel for AnySpiDmaChannel { - type Rx = SpiDmaRxChannelImpl; - type Tx = SpiDmaTxChannelImpl; -} - -crate::any_enum! { - #[doc(hidden)] - pub enum AnySpiDmaChannelInner { +crate::any_peripheral! { + /// An SPI-compatible type-erased DMA channel. + pub peripheral AnySpiDmaChannel { Spi2(Spi2DmaChannel), Spi3(Spi3DmaChannel), } } -impl crate::private::Sealed for AnySpiDmaChannelInner {} +impl DmaChannel for AnySpiDmaChannel { + type Rx = AnySpiDmaRxChannel; + type Tx = AnySpiDmaTxChannel; -impl PdmaChannel for AnySpiDmaChannelInner { + unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) { + ( + AnySpiDmaRxChannel(unsafe { self.clone_unchecked() }), + AnySpiDmaTxChannel(unsafe { self.clone_unchecked() }), + ) + } +} + +impl PdmaChannel for AnySpiDmaChannel { type RegisterBlock = SpiRegisterBlock; delegate::delegate! { - to match self { + to match &self.0 { AnySpiDmaChannelInner::Spi2(channel) => channel, AnySpiDmaChannelInner::Spi3(channel) => channel, } { @@ -1023,32 +1080,32 @@ impl PdmaChannel for AnySpiDmaChannelInner { } } -/// A marker for I2S-compatible type-erased DMA channels. -pub struct AnyI2sDmaChannel; - -impl crate::private::Sealed for AnyI2sDmaChannel {} - -impl DmaChannel for AnyI2sDmaChannel { - type Rx = I2sDmaRxChannelImpl; - type Tx = I2sDmaTxChannelImpl; -} - -crate::any_enum! { - #[doc(hidden)] - pub enum AnyI2sDmaChannelInner { +crate::any_peripheral! { + /// An I2S-compatible type-erased DMA channel. + pub peripheral AnyI2sDmaChannel { I2s0(I2s0DmaChannel), #[cfg(i2s1)] I2s1(I2s1DmaChannel), } } -impl crate::private::Sealed for AnyI2sDmaChannelInner {} +impl DmaChannel for AnyI2sDmaChannel { + type Rx = AnyI2sDmaRxChannel; + type Tx = AnyI2sDmaTxChannel; -impl PdmaChannel for AnyI2sDmaChannelInner { + unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) { + ( + AnyI2sDmaRxChannel(unsafe { self.clone_unchecked() }), + AnyI2sDmaTxChannel(unsafe { self.clone_unchecked() }), + ) + } +} + +impl PdmaChannel for AnyI2sDmaChannel { type RegisterBlock = I2sRegisterBlock; delegate::delegate! { - to match self { + to match &self.0 { AnyI2sDmaChannelInner::I2s0(channel) => channel, #[cfg(i2s1)] AnyI2sDmaChannelInner::I2s1(channel) => channel, diff --git a/esp-hal/src/i2s/master.rs b/esp-hal/src/i2s/master.rs index eef8e5aec..cdaaaee27 100644 --- a/esp-hal/src/i2s/master.rs +++ b/esp-hal/src/i2s/master.rs @@ -82,6 +82,7 @@ use crate::{ ChannelTx, DescriptorChain, DmaChannelConvert, + DmaChannelFor, DmaDescriptor, DmaEligible, DmaError, @@ -91,7 +92,9 @@ use crate::{ DmaTransferTxCircular, ReadBuffer, Rx, + RxChannelFor, Tx, + TxChannelFor, WriteBuffer, }, gpio::interconnect::PeripheralOutput, @@ -258,24 +261,21 @@ where pub i2s_tx: TxCreator<'d, M, T>, } -impl<'d, DmaMode, T> I2s<'d, DmaMode, T> +impl<'d, T> I2s<'d, Blocking, T> where T: RegisterAccess, - DmaMode: Mode, { #[allow(clippy::too_many_arguments)] - fn new_internal( + fn new_internal( i2s: PeripheralRef<'d, T>, standard: Standard, data_format: DataFormat, sample_rate: impl Into, - channel: Channel<'d, DmaMode, CH>, + channel: PeripheralRef<'d, DmaChannelFor>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], - ) -> Self - where - CH: DmaChannelConvert, - { + ) -> Self { + let channel = Channel::new(channel); channel.runtime_ensure_compatible(&i2s); // on ESP32-C3 / ESP32-S3 and later RX and TX are independent and // could be configured totally independently but for now handle all @@ -291,7 +291,6 @@ where i2s.set_master(); i2s.update(); - let channel = channel.degrade(); Self { i2s_rx: RxCreator { i2s: unsafe { i2s.clone_unchecked() }, @@ -368,19 +367,17 @@ impl<'d> I2s<'d, Blocking> { /// Construct a new I2S peripheral driver instance for the first I2S /// peripheral #[allow(clippy::too_many_arguments)] - pub fn new( + pub fn new( i2s: impl Peripheral

+ 'd, standard: Standard, data_format: DataFormat, sample_rate: impl Into, - channel: Channel<'d, DM, CH>, + channel: impl Peripheral

+ 'd, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], ) -> Self where - CH: DmaChannelConvert<::Dma>, - DM: Mode, - Channel<'d, Blocking, CH>: From>, + CH: DmaChannelConvert>, { Self::new_typed( i2s.map_into(), @@ -401,19 +398,17 @@ where /// Construct a new I2S peripheral driver instance for the first I2S /// peripheral #[allow(clippy::too_many_arguments)] - pub fn new_typed( + pub fn new_typed( i2s: impl Peripheral

+ 'd, standard: Standard, data_format: DataFormat, sample_rate: impl Into, - channel: Channel<'d, DM, CH>, + channel: impl Peripheral

+ 'd, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], ) -> Self where - CH: DmaChannelConvert, - DM: Mode, - Channel<'d, Blocking, CH>: From>, + CH: DmaChannelConvert>, { crate::into_ref!(i2s); Self::new_internal( @@ -421,7 +416,7 @@ where standard, data_format, sample_rate, - channel.into(), + channel.map(|ch| ch.degrade()).into_ref(), rx_descriptors, tx_descriptors, ) @@ -465,9 +460,10 @@ where pub struct I2sTx<'d, DmaMode, T = AnyI2s> where T: RegisterAccess, + DmaMode: Mode, { i2s: PeripheralRef<'d, T>, - tx_channel: ChannelTx<'d, DmaMode, T::Dma>, + tx_channel: ChannelTx<'d, DmaMode, TxChannelFor>, tx_chain: DescriptorChain, _guard: PeripheralGuard, } @@ -501,7 +497,7 @@ where T: RegisterAccess, DmaMode: Mode, { - type TX = ChannelTx<'d, DmaMode, T::Dma>; + type TX = ChannelTx<'d, DmaMode, TxChannelFor>; fn tx(&mut self) -> &mut Self::TX { &mut self.tx_channel @@ -600,7 +596,7 @@ where DmaMode: Mode, { i2s: PeripheralRef<'d, T>, - rx_channel: ChannelRx<'d, DmaMode, T::Dma>, + rx_channel: ChannelRx<'d, DmaMode, RxChannelFor>, rx_chain: DescriptorChain, _guard: PeripheralGuard, } @@ -634,7 +630,7 @@ where T: RegisterAccess, DmaMode: Mode, { - type RX = ChannelRx<'d, DmaMode, T::Dma>; + type RX = ChannelRx<'d, DmaMode, RxChannelFor>; fn rx(&mut self) -> &mut Self::RX { &mut self.rx_channel @@ -743,16 +739,7 @@ mod private { use enumset::EnumSet; use fugit::HertzU32; - use super::{ - DataFormat, - I2sInterrupt, - I2sRx, - I2sTx, - PeripheralGuard, - RegisterAccess, - Standard, - I2S_LL_MCLK_DIVIDER_MAX, - }; + use super::*; #[cfg(not(i2s1))] use crate::peripherals::i2s0::RegisterBlock; // on ESP32-S3 I2S1 doesn't support all features - use that to avoid using those features @@ -779,7 +766,7 @@ mod private { M: Mode, { pub i2s: PeripheralRef<'d, T>, - pub tx_channel: ChannelTx<'d, M, T::Dma>, + pub tx_channel: ChannelTx<'d, M, TxChannelFor>, pub descriptors: &'static mut [DmaDescriptor], pub(crate) guard: PeripheralGuard, } @@ -839,7 +826,7 @@ mod private { M: Mode, { pub i2s: PeripheralRef<'d, T>, - pub rx_channel: ChannelRx<'d, M, T::Dma>, + pub rx_channel: ChannelRx<'d, M, RxChannelFor>, pub descriptors: &'static mut [DmaDescriptor], pub(crate) guard: PeripheralGuard, } diff --git a/esp-hal/src/i2s/parallel.rs b/esp-hal/src/i2s/parallel.rs index 10f3a42e6..e46f49bc8 100644 --- a/esp-hal/src/i2s/parallel.rs +++ b/esp-hal/src/i2s/parallel.rs @@ -47,11 +47,13 @@ use crate::{ Channel, ChannelTx, DmaChannelConvert, + DmaChannelFor, DmaEligible, DmaError, DmaPeripheral, DmaTxBuffer, Tx, + TxChannelFor, }, gpio::{ interconnect::{OutputConnection, PeripheralOutput}, @@ -177,7 +179,7 @@ where I: Instance, { instance: PeripheralRef<'d, I>, - tx_channel: ChannelTx<'d, DM, I::Dma>, + tx_channel: ChannelTx<'d, DM, TxChannelFor>, _guard: PeripheralGuard, } @@ -185,13 +187,13 @@ impl<'d> I2sParallel<'d, Blocking> { /// Create a new I2S Parallel Interface pub fn new( i2s: impl Peripheral

+ 'd, - channel: Channel<'d, Blocking, CH>, + channel: impl Peripheral

+ 'd, frequency: impl Into, pins: impl TxPins<'d>, clock_pin: impl Peripheral

+ 'd, ) -> Self where - CH: DmaChannelConvert<::Dma>, + CH: DmaChannelConvert>, { Self::new_typed(i2s.map_into(), channel, frequency, pins, clock_pin) } @@ -204,19 +206,19 @@ where /// Create a new I2S Parallel Interface pub fn new_typed( i2s: impl Peripheral

+ 'd, - channel: Channel<'d, Blocking, CH>, + channel: impl Peripheral

+ 'd, frequency: impl Into, mut pins: impl TxPins<'d>, clock_pin: impl Peripheral

+ 'd, ) -> Self where - CH: DmaChannelConvert, + CH: DmaChannelConvert>, { crate::into_ref!(i2s); crate::into_mapped_ref!(clock_pin); + let channel = Channel::new(channel.map(|ch| ch.degrade())); channel.runtime_ensure_compatible(&i2s); - let channel = channel.degrade(); let guard = PeripheralGuard::new(i2s.peripheral()); diff --git a/esp-hal/src/lcd_cam/cam.rs b/esp-hal/src/lcd_cam/cam.rs index 423799f65..7748259d4 100644 --- a/esp-hal/src/lcd_cam/cam.rs +++ b/esp-hal/src/lcd_cam/cam.rs @@ -44,7 +44,7 @@ //! let lcd_cam = LcdCam::new(peripherals.LCD_CAM); //! let mut camera = Camera::new( //! lcd_cam.cam, -//! channel.rx, +//! channel, //! data_pins, //! 20u32.MHz(), //! ) @@ -67,7 +67,7 @@ use fugit::HertzU32; use crate::{ clock::Clocks, - dma::{ChannelRx, DmaChannelConvert, DmaEligible, DmaError, DmaPeripheral, DmaRxBuffer, Rx}, + dma::{ChannelRx, DmaChannelConvert, DmaError, DmaPeripheral, DmaRxBuffer, Rx, RxChannelFor}, gpio::{ interconnect::{PeripheralInput, PeripheralOutput}, InputSignal, @@ -123,7 +123,7 @@ pub struct Cam<'d> { /// Represents the camera interface with DMA support. pub struct Camera<'d> { lcd_cam: PeripheralRef<'d, LCD_CAM>, - rx_channel: ChannelRx<'d, Blocking, ::Dma>, + rx_channel: ChannelRx<'d, Blocking, RxChannelFor>, _guard: GenericPeripheralGuard<{ system::Peripheral::LcdCam as u8 }>, } @@ -131,14 +131,15 @@ impl<'d> Camera<'d> { /// Creates a new `Camera` instance with DMA support. pub fn new( cam: Cam<'d>, - channel: ChannelRx<'d, Blocking, CH>, + channel: impl Peripheral

+ 'd, _pins: P, frequency: HertzU32, ) -> Self where - CH: DmaChannelConvert<::Dma>, + CH: DmaChannelConvert>, P: RxPins, { + let rx_channel = ChannelRx::new(channel.map(|ch| ch.degrade())); let lcd_cam = cam.lcd_cam; let clocks = Clocks::get(); @@ -184,7 +185,7 @@ impl<'d> Camera<'d> { Self { lcd_cam, - rx_channel: channel.degrade(), + rx_channel, _guard: cam._guard, } } diff --git a/esp-hal/src/lcd_cam/lcd/dpi.rs b/esp-hal/src/lcd_cam/lcd/dpi.rs index e4b870869..77b30012b 100644 --- a/esp-hal/src/lcd_cam/lcd/dpi.rs +++ b/esp-hal/src/lcd_cam/lcd/dpi.rs @@ -61,7 +61,7 @@ //! config.de_idle_level = Level::Low; //! config.disable_black_region = false; //! -//! let mut dpi = Dpi::new(lcd_cam.lcd, channel.tx, 1.MHz(), config) +//! let mut dpi = Dpi::new(lcd_cam.lcd, channel, 1.MHz(), config) //! .with_vsync(peripherals.GPIO3) //! .with_hsync(peripherals.GPIO46) //! .with_de(peripherals.GPIO17) @@ -97,6 +97,7 @@ //! ``` use core::{ + marker::PhantomData, mem::ManuallyDrop, ops::{Deref, DerefMut}, }; @@ -105,7 +106,7 @@ use fugit::HertzU32; use crate::{ clock::Clocks, - dma::{ChannelTx, DmaChannelConvert, DmaEligible, DmaError, DmaPeripheral, DmaTxBuffer, Tx}, + dma::{ChannelTx, DmaChannelConvert, DmaError, DmaPeripheral, DmaTxBuffer, Tx, TxChannelFor}, gpio::{interconnect::PeripheralOutput, Level, OutputSignal}, lcd_cam::{ calculate_clkm, @@ -120,22 +121,27 @@ use crate::{ }; /// Represents the RGB LCD interface. -pub struct Dpi<'d> { +pub struct Dpi<'d, DM: Mode> { lcd_cam: PeripheralRef<'d, LCD_CAM>, - tx_channel: ChannelTx<'d, Blocking, ::Dma>, + tx_channel: ChannelTx<'d, Blocking, TxChannelFor>, + _mode: PhantomData, } -impl<'d> Dpi<'d> { +impl<'d, DM> Dpi<'d, DM> +where + DM: Mode, +{ /// Create a new instance of the RGB/DPI driver. - pub fn new( + pub fn new( lcd: Lcd<'d, DM>, - channel: ChannelTx<'d, Blocking, CH>, + channel: impl Peripheral

+ 'd, frequency: HertzU32, config: Config, ) -> Self where - CH: DmaChannelConvert<::Dma>, + CH: DmaChannelConvert>, { + let tx_channel = ChannelTx::new(channel.map(|ch| ch.degrade())); let lcd_cam = lcd.lcd_cam; let clocks = Clocks::get(); @@ -270,7 +276,8 @@ impl<'d> Dpi<'d> { Self { lcd_cam, - tx_channel: channel.degrade(), + tx_channel, + _mode: PhantomData, } } @@ -522,7 +529,7 @@ impl<'d> Dpi<'d> { mut self, next_frame_en: bool, mut buf: TX, - ) -> Result, (DmaError, Self, TX)> { + ) -> Result, (DmaError, Self, TX)> { let result = unsafe { self.tx_channel .prepare_transfer(DmaPeripheral::LcdCam, &mut buf) @@ -561,12 +568,12 @@ impl<'d> Dpi<'d> { /// Represents an ongoing (or potentially finished) transfer using the RGB LCD /// interface -pub struct DpiTransfer<'d, BUF: DmaTxBuffer> { - dpi: ManuallyDrop>, +pub struct DpiTransfer<'d, BUF: DmaTxBuffer, DM: Mode> { + dpi: ManuallyDrop>, buffer_view: ManuallyDrop, } -impl<'d, BUF: DmaTxBuffer> DpiTransfer<'d, BUF> { +impl<'d, BUF: DmaTxBuffer, DM: Mode> DpiTransfer<'d, BUF, DM> { /// Returns true when [Self::wait] will not block. pub fn is_done(&self) -> bool { self.dpi @@ -578,7 +585,7 @@ impl<'d, BUF: DmaTxBuffer> DpiTransfer<'d, BUF> { } /// Stops this transfer on the spot and returns the peripheral and buffer. - pub fn stop(mut self) -> (Dpi<'d>, BUF) { + pub fn stop(mut self) -> (Dpi<'d, DM>, BUF) { self.stop_peripherals(); let (dpi, view) = self.release(); (dpi, BUF::from_view(view)) @@ -588,7 +595,7 @@ impl<'d, BUF: DmaTxBuffer> DpiTransfer<'d, BUF> { /// /// Note: If you specified `next_frame_en` as true in [Dpi::send], you're /// just waiting for a DMA error when you call this. - pub fn wait(mut self) -> (Result<(), DmaError>, Dpi<'d>, BUF) { + pub fn wait(mut self) -> (Result<(), DmaError>, Dpi<'d, DM>, BUF) { while !self.is_done() { core::hint::spin_loop(); } @@ -611,7 +618,7 @@ impl<'d, BUF: DmaTxBuffer> DpiTransfer<'d, BUF> { (result, dpi, BUF::from_view(view)) } - fn release(mut self) -> (Dpi<'d>, BUF::View) { + fn release(mut self) -> (Dpi<'d, DM>, BUF::View) { // SAFETY: Since forget is called on self, we know that self.dpi and // self.buffer_view won't be touched again. let result = unsafe { @@ -635,7 +642,7 @@ impl<'d, BUF: DmaTxBuffer> DpiTransfer<'d, BUF> { } } -impl<'d, BUF: DmaTxBuffer> Deref for DpiTransfer<'d, BUF> { +impl<'d, BUF: DmaTxBuffer, DM: Mode> Deref for DpiTransfer<'d, BUF, DM> { type Target = BUF::View; fn deref(&self) -> &Self::Target { @@ -643,13 +650,13 @@ impl<'d, BUF: DmaTxBuffer> Deref for DpiTransfer<'d, BUF> { } } -impl<'d, BUF: DmaTxBuffer> DerefMut for DpiTransfer<'d, BUF> { +impl<'d, BUF: DmaTxBuffer, DM: Mode> DerefMut for DpiTransfer<'d, BUF, DM> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.buffer_view } } -impl<'d, BUF: DmaTxBuffer> Drop for DpiTransfer<'d, BUF> { +impl<'d, BUF: DmaTxBuffer, DM: Mode> Drop for DpiTransfer<'d, BUF, DM> { fn drop(&mut self) { self.stop_peripherals(); diff --git a/esp-hal/src/lcd_cam/lcd/i8080.rs b/esp-hal/src/lcd_cam/lcd/i8080.rs index 5dab70ce9..12d9e5856 100644 --- a/esp-hal/src/lcd_cam/lcd/i8080.rs +++ b/esp-hal/src/lcd_cam/lcd/i8080.rs @@ -38,7 +38,7 @@ //! //! let mut i8080 = I8080::new( //! lcd_cam.lcd, -//! channel.tx, +//! channel, //! tx_pins, //! 20.MHz(), //! Config::default(), @@ -62,7 +62,7 @@ use fugit::HertzU32; use crate::{ clock::Clocks, - dma::{ChannelTx, DmaChannelConvert, DmaEligible, DmaError, DmaPeripheral, DmaTxBuffer, Tx}, + dma::{ChannelTx, DmaChannelConvert, DmaError, DmaPeripheral, DmaTxBuffer, Tx, TxChannelFor}, gpio::{ interconnect::{OutputConnection, PeripheralOutput}, OutputSignal, @@ -85,7 +85,7 @@ use crate::{ /// Represents the I8080 LCD interface. pub struct I8080<'d, DM: Mode> { lcd_cam: PeripheralRef<'d, LCD_CAM>, - tx_channel: ChannelTx<'d, Blocking, ::Dma>, + tx_channel: ChannelTx<'d, Blocking, TxChannelFor>, _mode: PhantomData, } @@ -96,15 +96,16 @@ where /// Creates a new instance of the I8080 LCD interface. pub fn new( lcd: Lcd<'d, DM>, - channel: ChannelTx<'d, Blocking, CH>, + channel: impl Peripheral

+ 'd, mut pins: P, frequency: HertzU32, config: Config, ) -> Self where - CH: DmaChannelConvert<::Dma>, + CH: DmaChannelConvert>, P: TxPins, { + let tx_channel = ChannelTx::new(channel.map(|ch| ch.degrade())); let lcd_cam = lcd.lcd_cam; let clocks = Clocks::get(); @@ -207,7 +208,7 @@ where Self { lcd_cam, - tx_channel: channel.degrade(), + tx_channel, _mode: PhantomData, } } diff --git a/esp-hal/src/parl_io.rs b/esp-hal/src/parl_io.rs index e2badab61..d356f8ffa 100644 --- a/esp-hal/src/parl_io.rs +++ b/esp-hal/src/parl_io.rs @@ -36,15 +36,17 @@ use crate::{ ChannelTx, DescriptorChain, DmaChannelConvert, + DmaChannelFor, DmaDescriptor, - DmaEligible, DmaError, DmaPeripheral, DmaTransferRx, DmaTransferTx, ReadBuffer, Rx, + RxChannelFor, Tx, + TxChannelFor, WriteBuffer, }, gpio::{ @@ -53,7 +55,7 @@ use crate::{ }, interrupt::InterruptHandler, peripheral::{self, Peripheral}, - peripherals::{self, Interrupt, PARL_IO}, + peripherals::{Interrupt, PARL_IO}, system::{self, GenericPeripheralGuard}, Async, Blocking, @@ -809,7 +811,7 @@ pub struct ParlIoTx<'d, DM> where DM: Mode, { - tx_channel: ChannelTx<'d, DM, ::Dma>, + tx_channel: ChannelTx<'d, DM, TxChannelFor>, tx_chain: DescriptorChain, _guard: GenericPeripheralGuard<{ crate::system::Peripheral::ParlIo as u8 }>, } @@ -890,7 +892,7 @@ pub struct ParlIoRx<'d, DM> where DM: Mode, { - rx_channel: ChannelRx<'d, DM, ::Dma>, + rx_channel: ChannelRx<'d, DM, RxChannelFor>, rx_chain: DescriptorChain, _guard: GenericPeripheralGuard<{ crate::system::Peripheral::ParlIo as u8 }>, } @@ -1003,31 +1005,29 @@ where impl<'d> ParlIoFullDuplex<'d, Blocking> { /// Create a new instance of [ParlIoFullDuplex] - pub fn new( - _parl_io: impl Peripheral

+ 'd, - dma_channel: Channel<'d, DM, CH>, + pub fn new( + _parl_io: impl Peripheral

+ 'd, + dma_channel: impl Peripheral

+ 'd, tx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor], frequency: HertzU32, ) -> Result where - DM: Mode, - CH: DmaChannelConvert<::Dma>, - Channel<'d, Blocking, CH>: From>, + CH: DmaChannelConvert>, { let tx_guard = GenericPeripheralGuard::new(); let rx_guard = GenericPeripheralGuard::new(); - let dma_channel = Channel::::from(dma_channel); + let dma_channel = Channel::new(dma_channel.map(|ch| ch.degrade())); internal_init(frequency)?; Ok(Self { tx: TxCreatorFullDuplex { - tx_channel: dma_channel.tx.degrade(), + tx_channel: dma_channel.tx, descriptors: tx_descriptors, _guard: tx_guard, }, rx: RxCreatorFullDuplex { - rx_channel: dma_channel.rx.degrade(), + rx_channel: dma_channel.rx, descriptors: rx_descriptors, _guard: rx_guard, }, @@ -1036,6 +1036,17 @@ impl<'d> ParlIoFullDuplex<'d, Blocking> { /// Convert to an async version. pub fn into_async(self) -> ParlIoFullDuplex<'d, Async> { + for core in crate::Cpu::other() { + #[cfg(esp32c6)] + { + crate::interrupt::disable(core, Interrupt::PARL_IO); + } + #[cfg(esp32h2)] + { + crate::interrupt::disable(core, Interrupt::PARL_IO_RX); + crate::interrupt::disable(core, Interrupt::PARL_IO_TX); + } + } ParlIoFullDuplex { tx: TxCreatorFullDuplex { tx_channel: self.tx.tx_channel.into_async(), @@ -1115,35 +1126,52 @@ where pub tx: TxCreator<'d, DM>, } -impl<'d, DM> ParlIoTxOnly<'d, DM> -where - DM: Mode, -{ - /// Create a new [ParlIoTxOnly] - // TODO: only take a TX DMA channel? +impl<'d> ParlIoTxOnly<'d, Blocking> { + /// Creates a new [ParlIoTxOnly] pub fn new( - _parl_io: impl Peripheral

+ 'd, - dma_channel: Channel<'d, DM, CH>, + _parl_io: impl Peripheral

+ 'd, + dma_channel: impl Peripheral

+ 'd, descriptors: &'static mut [DmaDescriptor], frequency: HertzU32, ) -> Result where - CH: DmaChannelConvert<::Dma>, + CH: DmaChannelConvert>, { let guard = GenericPeripheralGuard::new(); + let tx_channel = ChannelTx::new(dma_channel.map(|ch| ch.degrade())); internal_init(frequency)?; Ok(Self { tx: TxCreator { - tx_channel: dma_channel.tx.degrade(), + tx_channel, descriptors, _guard: guard, }, }) } -} -impl ParlIoTxOnly<'_, Blocking> { + /// Converts to Async mode. + pub fn into_async(self) -> ParlIoTxOnly<'d, Async> { + for core in crate::Cpu::other() { + #[cfg(esp32c6)] + { + crate::interrupt::disable(core, Interrupt::PARL_IO); + } + #[cfg(esp32h2)] + { + crate::interrupt::disable(core, Interrupt::PARL_IO_RX); + crate::interrupt::disable(core, Interrupt::PARL_IO_TX); + } + } + ParlIoTxOnly { + tx: TxCreator { + tx_channel: self.tx.tx_channel.into_async(), + descriptors: self.tx.descriptors, + _guard: self.tx._guard, + }, + } + } + /// Sets the interrupt handler, enables it with /// [crate::interrupt::Priority::min()] /// @@ -1173,6 +1201,19 @@ impl ParlIoTxOnly<'_, Blocking> { } } +impl<'d> ParlIoTxOnly<'d, Async> { + /// Convert to a blocking version. + pub fn into_blocking(self) -> ParlIoTxOnly<'d, Blocking> { + ParlIoTxOnly { + tx: TxCreator { + tx_channel: self.tx.tx_channel.into_blocking(), + descriptors: self.tx.descriptors, + _guard: self.tx._guard, + }, + } + } +} + impl crate::private::Sealed for ParlIoTxOnly<'_, Blocking> {} impl InterruptConfigurable for ParlIoTxOnly<'_, Blocking> { @@ -1191,35 +1232,53 @@ where pub rx: RxCreator<'d, DM>, } -impl<'d, DM> ParlIoRxOnly<'d, DM> -where - DM: Mode, -{ +impl<'d> ParlIoRxOnly<'d, Blocking> { /// Create a new [ParlIoRxOnly] instance - // TODO: only take a RX DMA channel? pub fn new( - _parl_io: impl Peripheral

+ 'd, - dma_channel: Channel<'d, DM, CH>, + _parl_io: impl Peripheral

+ 'd, + dma_channel: impl Peripheral

+ 'd, descriptors: &'static mut [DmaDescriptor], frequency: HertzU32, ) -> Result where - CH: DmaChannelConvert<::Dma>, + CH: DmaChannelConvert>, { let guard = GenericPeripheralGuard::new(); + let rx_channel = ChannelRx::new(dma_channel.map(|ch| ch.degrade())); internal_init(frequency)?; Ok(Self { rx: RxCreator { - rx_channel: dma_channel.rx.degrade(), + rx_channel, descriptors, _guard: guard, }, }) } -} -impl ParlIoRxOnly<'_, Blocking> { + /// Converts to Async mode. + pub fn into_async(self) -> ParlIoRxOnly<'d, Async> { + for core in crate::Cpu::other() { + #[cfg(esp32c6)] + { + crate::interrupt::disable(core, Interrupt::PARL_IO); + } + #[cfg(esp32h2)] + { + crate::interrupt::disable(core, Interrupt::PARL_IO_RX); + crate::interrupt::disable(core, Interrupt::PARL_IO_TX); + } + } + + ParlIoRxOnly { + rx: RxCreator { + rx_channel: self.rx.rx_channel.into_async(), + descriptors: self.rx.descriptors, + _guard: self.rx._guard, + }, + } + } + /// Sets the interrupt handler, enables it with /// [crate::interrupt::Priority::min()] /// @@ -1249,6 +1308,19 @@ impl ParlIoRxOnly<'_, Blocking> { } } +impl<'d> ParlIoRxOnly<'d, Async> { + /// Convert to a blocking version. + pub fn into_blocking(self) -> ParlIoRxOnly<'d, Blocking> { + ParlIoRxOnly { + rx: RxCreator { + rx_channel: self.rx.rx_channel.into_blocking(), + descriptors: self.rx.descriptors, + _guard: self.rx._guard, + }, + } + } +} + impl crate::private::Sealed for ParlIoRxOnly<'_, Blocking> {} impl InterruptConfigurable for ParlIoRxOnly<'_, Blocking> { @@ -1361,7 +1433,7 @@ impl<'d, DM> DmaSupportTx for ParlIoTx<'d, DM> where DM: Mode, { - type TX = ChannelTx<'d, DM, ::Dma>; + type TX = ChannelTx<'d, DM, TxChannelFor>; fn tx(&mut self) -> &mut Self::TX { &mut self.tx_channel @@ -1403,7 +1475,7 @@ where } fn start_receive_bytes_dma( - rx_channel: &mut ChannelRx<'d, DM, ::Dma>, + rx_channel: &mut ChannelRx<'d, DM, RxChannelFor>, rx_chain: &mut DescriptorChain, ptr: *mut u8, len: usize, @@ -1457,7 +1529,7 @@ impl<'d, DM> DmaSupportRx for ParlIoRx<'d, DM> where DM: Mode, { - type RX = ChannelRx<'d, DM, ::Dma>; + type RX = ChannelRx<'d, DM, RxChannelFor>; fn rx(&mut self) -> &mut Self::RX { &mut self.rx_channel @@ -1473,7 +1545,7 @@ pub struct TxCreator<'d, DM> where DM: Mode, { - tx_channel: ChannelTx<'d, DM, ::Dma>, + tx_channel: ChannelTx<'d, DM, TxChannelFor>, descriptors: &'static mut [DmaDescriptor], _guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>, } @@ -1483,7 +1555,7 @@ pub struct RxCreator<'d, DM> where DM: Mode, { - rx_channel: ChannelRx<'d, DM, ::Dma>, + rx_channel: ChannelRx<'d, DM, RxChannelFor>, descriptors: &'static mut [DmaDescriptor], _guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>, } @@ -1493,7 +1565,7 @@ pub struct TxCreatorFullDuplex<'d, DM> where DM: Mode, { - tx_channel: ChannelTx<'d, DM, ::Dma>, + tx_channel: ChannelTx<'d, DM, TxChannelFor>, descriptors: &'static mut [DmaDescriptor], _guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>, } @@ -1503,7 +1575,7 @@ pub struct RxCreatorFullDuplex<'d, DM> where DM: Mode, { - rx_channel: ChannelRx<'d, DM, ::Dma>, + rx_channel: ChannelRx<'d, DM, RxChannelFor>, descriptors: &'static mut [DmaDescriptor], _guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>, } @@ -1529,6 +1601,25 @@ pub mod asynch { impl TxDoneFuture { pub fn new() -> Self { Instance::listen_tx_done(); + let mut parl_io = unsafe { crate::peripherals::PARL_IO::steal() }; + + #[cfg(esp32c6)] + { + parl_io.bind_parl_io_interrupt(interrupt_handler.handler()); + unwrap!(crate::interrupt::enable( + Interrupt::PARL_IO, + interrupt_handler.priority() + )); + } + #[cfg(esp32h2)] + { + parl_io.bind_parl_io_tx_interrupt(interrupt_handler.handler()); + unwrap!(crate::interrupt::enable( + Interrupt::PARL_IO_TX, + interrupt_handler.priority() + )); + } + Self {} } } @@ -1540,20 +1631,6 @@ pub mod asynch { self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>, ) -> Poll { - let mut parl_io = unsafe { crate::peripherals::PARL_IO::steal() }; - - #[cfg(esp32c6)] - { - parl_io.bind_parl_io_interrupt(interrupt_handler.handler()); - crate::interrupt::enable(Interrupt::PARL_IO, interrupt_handler.priority()).unwrap(); - } - #[cfg(esp32h2)] - { - parl_io.bind_parl_io_tx_interrupt(interrupt_handler.handler()); - crate::interrupt::enable(Interrupt::PARL_IO_TX, interrupt_handler.priority()) - .unwrap(); - } - TX_WAKER.register(cx.waker()); if Instance::is_listening_tx_done() { Poll::Pending diff --git a/esp-hal/src/peripheral.rs b/esp-hal/src/peripheral.rs index c2c10a417..622470d85 100644 --- a/esp-hal/src/peripheral.rs +++ b/esp-hal/src/peripheral.rs @@ -63,6 +63,18 @@ impl<'a, T> PeripheralRef<'a, T> { PeripheralRef::new(unsafe { self.inner.clone_unchecked() }) } + /// Transform the inner peripheral. + /// + /// This converts from `PeripheralRef<'a, T>` to `PeripheralRef<'a, U>`, + /// using a user-provided impl to convert from `T` to `U`. + #[inline] + pub fn map(self, transform: impl FnOnce(T) -> U) -> PeripheralRef<'a, U> { + PeripheralRef { + inner: transform(self.inner), + _lifetime: PhantomData, + } + } + /// Map the inner peripheral using `Into`. /// /// This converts from `PeripheralRef<'a, T>` to `PeripheralRef<'a, U>`, @@ -75,10 +87,7 @@ impl<'a, T> PeripheralRef<'a, T> { where T: Into, { - PeripheralRef { - inner: self.inner.into(), - _lifetime: PhantomData, - } + self.map(Into::into) } } @@ -179,7 +188,19 @@ pub trait Peripheral: Sized + crate::private::Sealed { Self::P: Into, U: Peripheral

, { - unsafe { self.clone_unchecked().into() } + self.map(Into::into) + } + + /// Map the peripheral using `Into`. + /// + /// This converts from `Peripheral

` to `Peripheral

`, + /// using an `Into` impl to convert from `T` to `U`. + #[inline] + fn map(self, transform: impl FnOnce(Self::P) -> U) -> U + where + U: Peripheral

, + { + transform(unsafe { self.clone_unchecked() }) } } diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index 5986b73aa..5c4dc8e10 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -78,7 +78,7 @@ use procmacros::ram; use super::{DmaError, Error, SpiBitOrder, SpiDataMode, SpiMode}; use crate::{ clock::Clocks, - dma::{Channel, DmaChannelConvert, DmaEligible, DmaRxBuffer, DmaTxBuffer, Rx, Tx}, + dma::{DmaChannelConvert, DmaChannelFor, DmaEligible, DmaRxBuffer, DmaTxBuffer, Rx, Tx}, gpio::{interconnect::PeripheralOutput, InputSignal, NoPin, OutputSignal}, interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, @@ -465,26 +465,6 @@ pub struct Spi<'d, M, T = AnySpi> { guard: PeripheralGuard, } -impl<'d, M, T> Spi<'d, M, T> -where - M: Mode, - T: Instance, -{ - /// Configures the SPI instance to use DMA with the specified channel. - /// - /// This method prepares the SPI instance for DMA transfers using SPI - /// and returns an instance of `SpiDma` that supports DMA - /// operations. - pub fn with_dma(self, channel: Channel<'d, DM, CH>) -> SpiDma<'d, M, T> - where - CH: DmaChannelConvert, - DM: Mode, - Channel<'d, M, CH>: From>, - { - SpiDma::new(self.spi, channel.into()) - } -} - impl Spi<'_, M, T> where T: Instance, @@ -549,6 +529,23 @@ impl<'d> Spi<'d, Blocking> { } } +impl<'d, T> Spi<'d, Blocking, T> +where + T: Instance, +{ + /// Configures the SPI instance to use DMA with the specified channel. + /// + /// This method prepares the SPI instance for DMA transfers using SPI + /// and returns an instance of `SpiDma` that supports DMA + /// operations. + pub fn with_dma(self, channel: impl Peripheral

+ 'd) -> SpiDma<'d, Blocking, T> + where + CH: DmaChannelConvert>, + { + SpiDma::new(self.spi, channel.map(|ch| ch.degrade()).into_ref()) + } +} + impl<'d> Spi<'d, Async> { /// Converts the SPI instance into blocking mode. pub fn into_blocking(self) -> Spi<'d, Blocking> { @@ -859,6 +856,7 @@ mod dma { dma::{ asynch::{DmaRxFuture, DmaTxFuture}, Channel, + DmaChannelFor, DmaRxBuf, DmaRxBuffer, DmaTxBuf, @@ -885,7 +883,7 @@ mod dma { M: Mode, { pub(crate) spi: PeripheralRef<'d, T>, - pub(crate) channel: Channel<'d, M, T::Dma>, + pub(crate) channel: Channel<'d, M, DmaChannelFor>, tx_transfer_in_progress: bool, rx_transfer_in_progress: bool, #[cfg(all(esp32, spi_address_workaround))] @@ -993,15 +991,15 @@ mod dma { } } - impl<'d, M, T> SpiDma<'d, M, T> + impl<'d, T> SpiDma<'d, Blocking, T> where T: Instance, - M: Mode, { - pub(super) fn new(spi: PeripheralRef<'d, T>, channel: Channel<'d, M, CH>) -> Self - where - CH: DmaChannelConvert, - { + pub(super) fn new( + spi: PeripheralRef<'d, T>, + channel: PeripheralRef<'d, DmaChannelFor>, + ) -> Self { + let channel = Channel::new(channel); channel.runtime_ensure_compatible(&spi); #[cfg(all(esp32, spi_address_workaround))] let address_buffer = { @@ -1027,7 +1025,7 @@ mod dma { Self { spi, - channel: channel.degrade(), + channel, #[cfg(all(esp32, spi_address_workaround))] address_buffer, tx_transfer_in_progress: false, @@ -1035,7 +1033,13 @@ mod dma { guard, } } + } + impl<'d, M, T> SpiDma<'d, M, T> + where + M: Mode, + T: Instance, + { fn driver(&self) -> &'static Info { self.spi.info() } diff --git a/esp-hal/src/spi/slave.rs b/esp-hal/src/spi/slave.rs index 89f1c6a32..cf48c07fe 100644 --- a/esp-hal/src/spi/slave.rs +++ b/esp-hal/src/spi/slave.rs @@ -177,39 +177,44 @@ pub mod dma { ChannelRx, ChannelTx, DescriptorChain, + DmaChannelFor, DmaDescriptor, DmaTransferRx, DmaTransferRxTx, DmaTransferTx, ReadBuffer, Rx, + RxChannelFor, Tx, + TxChannelFor, WriteBuffer, }, Mode, }; - impl<'d, M, T> Spi<'d, M, T> + impl<'d, T> Spi<'d, Blocking, T> where T: InstanceDma, - M: Mode, { - /// Configures the SPI3 peripheral with the provided DMA channel and + /// Configures the SPI peripheral with the provided DMA channel and /// descriptors. #[cfg_attr(esp32, doc = "\n\n**Note**: ESP32 only supports Mode 1 and 3.")] - pub fn with_dma( + pub fn with_dma( self, - channel: Channel<'d, DM, CH>, + channel: impl Peripheral

+ 'd, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], - ) -> SpiDma<'d, M, T> + ) -> SpiDma<'d, Blocking, T> where - CH: DmaChannelConvert, - DM: Mode, - Channel<'d, M, CH>: From>, + CH: DmaChannelConvert>, { self.spi.info().set_data_mode(self.data_mode, true); - SpiDma::new(self.spi, channel.into(), rx_descriptors, tx_descriptors) + SpiDma::new( + self.spi, + channel.map(|ch| ch.degrade()).into_ref(), + rx_descriptors, + tx_descriptors, + ) } } @@ -220,7 +225,7 @@ pub mod dma { M: Mode, { pub(crate) spi: PeripheralRef<'d, T>, - pub(crate) channel: Channel<'d, M, T::Dma>, + pub(crate) channel: Channel<'d, M, DmaChannelFor>, rx_chain: DescriptorChain, tx_chain: DescriptorChain, _guard: PeripheralGuard, @@ -260,7 +265,7 @@ pub mod dma { T: InstanceDma, DmaMode: Mode, { - type TX = ChannelTx<'d, DmaMode, T::Dma>; + type TX = ChannelTx<'d, DmaMode, TxChannelFor>; fn tx(&mut self) -> &mut Self::TX { &mut self.channel.tx @@ -276,7 +281,7 @@ pub mod dma { T: InstanceDma, DmaMode: Mode, { - type RX = ChannelRx<'d, DmaMode, T::Dma>; + type RX = ChannelRx<'d, DmaMode, RxChannelFor>; fn rx(&mut self) -> &mut Self::RX { &mut self.channel.rx @@ -287,32 +292,35 @@ pub mod dma { } } - impl<'d, DmaMode, T> SpiDma<'d, DmaMode, T> + impl<'d, T> SpiDma<'d, Blocking, T> where T: InstanceDma, - DmaMode: Mode, { - fn new( + fn new( spi: PeripheralRef<'d, T>, - channel: Channel<'d, DmaMode, CH>, + channel: PeripheralRef<'d, DmaChannelFor>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], - ) -> Self - where - CH: DmaChannelConvert, - { + ) -> Self { + let channel = Channel::new(channel); channel.runtime_ensure_compatible(&spi); let guard = PeripheralGuard::new(spi.info().peripheral); Self { spi, - channel: channel.degrade(), + channel, rx_chain: DescriptorChain::new(rx_descriptors), tx_chain: DescriptorChain::new(tx_descriptors), _guard: guard, } } + } + impl<'d, M, T> SpiDma<'d, M, T> + where + M: Mode, + T: InstanceDma, + { fn driver(&self) -> DmaDriver { DmaDriver { info: self.spi.info(), diff --git a/examples/src/bin/embassy_parl_io_rx.rs b/examples/src/bin/embassy_parl_io_rx.rs index 3e57728eb..5117252fa 100644 --- a/examples/src/bin/embassy_parl_io_rx.rs +++ b/examples/src/bin/embassy_parl_io_rx.rs @@ -43,13 +43,9 @@ async fn main(_spawner: Spawner) { ); let mut rx_clk_pin = NoPin; - let parl_io = ParlIoRxOnly::new( - peripherals.PARL_IO, - dma.channel0.into_async(), - rx_descriptors, - 1.MHz(), - ) - .unwrap(); + let parl_io = ParlIoRxOnly::new(peripherals.PARL_IO, dma.channel0, rx_descriptors, 1.MHz()) + .unwrap() + .into_async(); let mut parl_io_rx = parl_io .rx diff --git a/examples/src/bin/embassy_parl_io_tx.rs b/examples/src/bin/embassy_parl_io_tx.rs index ff99b2dc7..ca5c3a2aa 100644 --- a/examples/src/bin/embassy_parl_io_tx.rs +++ b/examples/src/bin/embassy_parl_io_tx.rs @@ -54,13 +54,9 @@ async fn main(_spawner: Spawner) { let mut pin_conf = TxPinConfigWithValidPin::new(tx_pins, peripherals.GPIO5); - let parl_io = ParlIoTxOnly::new( - peripherals.PARL_IO, - dma.channel0.into_async(), - tx_descriptors, - 1.MHz(), - ) - .unwrap(); + let parl_io = ParlIoTxOnly::new(peripherals.PARL_IO, dma.channel0, tx_descriptors, 1.MHz()) + .unwrap() + .into_async(); let mut clock_pin = ClkOutPin::new(peripherals.GPIO8); diff --git a/examples/src/bin/lcd_dpi.rs b/examples/src/bin/lcd_dpi.rs index aef980fe9..c70bf4436 100644 --- a/examples/src/bin/lcd_dpi.rs +++ b/examples/src/bin/lcd_dpi.rs @@ -71,7 +71,7 @@ fn main() -> ! { .with_scl(peripherals.GPIO48); let dma = Dma::new(peripherals.DMA); - let channel = dma.channel2; + let tx_channel = dma.channel2; let lcd_cam = LcdCam::new(peripherals.LCD_CAM); let mut expander = Tca9554::new(i2c); @@ -166,7 +166,7 @@ fn main() -> ! { config.de_idle_level = Level::Low; config.disable_black_region = false; - let mut dpi = Dpi::new(lcd_cam.lcd, channel.tx, 16.MHz(), config) + let mut dpi = Dpi::new(lcd_cam.lcd, tx_channel, 16.MHz(), config) .with_vsync(vsync_pin) .with_hsync(peripherals.GPIO46) .with_de(peripherals.GPIO17) diff --git a/hil-test/tests/dma_mem2mem.rs b/hil-test/tests/dma_mem2mem.rs index 6a8af0328..20ac1cfe8 100644 --- a/hil-test/tests/dma_mem2mem.rs +++ b/hil-test/tests/dma_mem2mem.rs @@ -6,11 +6,10 @@ #![no_main] use esp_hal::{ - dma::{AnyGdmaChannel, Channel, Dma, DmaError, Mem2Mem}, + dma::{AnyGdmaChannel, Dma, DmaChannelConvert, DmaError, Mem2Mem}, dma_buffers, dma_buffers_chunk_size, dma_descriptors, - Blocking, }; use hil_test as _; @@ -25,7 +24,7 @@ cfg_if::cfg_if! { } struct Context { - channel: Channel<'static, Blocking, AnyGdmaChannel>, + channel: AnyGdmaChannel, dma_peripheral: DmaPeripheralType, } diff --git a/hil-test/tests/embassy_interrupt_spi_dma.rs b/hil-test/tests/embassy_interrupt_spi_dma.rs index 37bed2fde..caf7b1b40 100644 --- a/hil-test/tests/embassy_interrupt_spi_dma.rs +++ b/hil-test/tests/embassy_interrupt_spi_dma.rs @@ -122,7 +122,7 @@ mod test { let mut spi = Spi::new_with_config( peripherals.SPI2, Config { - frequency: 100.kHz(), + frequency: 10000.kHz(), mode: SpiMode::Mode0, ..Config::default() }, @@ -137,7 +137,7 @@ mod test { let other_peripheral = Spi::new_with_config( peripherals.SPI3, Config { - frequency: 100.kHz(), + frequency: 10000.kHz(), mode: SpiMode::Mode0, ..Config::default() }, @@ -205,7 +205,7 @@ mod test { #[timeout(3)] async fn dma_does_not_lock_up_on_core_1() { use embassy_time::Timer; - use esp_hal::{dma::Channel, peripherals::SPI2, Blocking}; + use esp_hal::peripherals::SPI2; use portable_atomic::{AtomicU32, Ordering}; cfg_if::cfg_if! { @@ -221,7 +221,7 @@ mod test { pub struct SpiPeripherals { pub spi: SPI2, - pub dma_channel: Channel<'static, Blocking, DmaChannel>, + pub dma_channel: DmaChannel, } #[embassy_executor::task] diff --git a/hil-test/tests/i2s.rs b/hil-test/tests/i2s.rs index a7e88e883..e51915810 100644 --- a/hil-test/tests/i2s.rs +++ b/hil-test/tests/i2s.rs @@ -12,14 +12,13 @@ use esp_hal::{ delay::Delay, - dma::{Channel, Dma}, + dma::Dma, dma_buffers, gpio::{AnyPin, NoPin, Pin}, i2s::master::{DataFormat, I2s, I2sTx, Standard}, peripherals::I2S0, prelude::*, Async, - Blocking, }; use hil_test as _; @@ -105,7 +104,7 @@ mod tests { struct Context { dout: AnyPin, - dma_channel: Channel<'static, Blocking, DmaChannel0>, + dma_channel: DmaChannel0, i2s: I2S0, } diff --git a/hil-test/tests/lcd_cam.rs b/hil-test/tests/lcd_cam.rs index 3283aad38..1dcae2c78 100644 --- a/hil-test/tests/lcd_cam.rs +++ b/hil-test/tests/lcd_cam.rs @@ -6,7 +6,7 @@ #![no_main] use esp_hal::{ - dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf}, + dma::{Dma, DmaRxBuf, DmaTxBuf}, dma_buffers, gpio::Level, lcd_cam::{ @@ -58,7 +58,9 @@ mod tests { let dma = Dma::new(peripherals.DMA); let lcd_cam = LcdCam::new(peripherals.LCD_CAM); - let channel = dma.channel2; + // TODO: use split channels once supported + let tx_channel = dma.channel2; + let rx_channel = dma.channel3; let (vsync_in, vsync_out) = peripherals.GPIO6.split(); let (hsync_in, hsync_out) = peripherals.GPIO7.split(); @@ -101,7 +103,7 @@ mod tests { config.de_idle_level = Level::Low; config.disable_black_region = false; - let dpi = Dpi::new(lcd_cam.lcd, channel.tx, 500u32.kHz(), config) + let dpi = Dpi::new(lcd_cam.lcd, tx_channel, 500u32.kHz(), config) .with_vsync(vsync_out) .with_hsync(hsync_out) .with_de(de_out) @@ -117,7 +119,7 @@ mod tests { let camera = Camera::new( lcd_cam.cam, - channel.rx, + rx_channel, RxEightBits::new(d0_in, d1_in, d2_in, d3_in, d4_in, d5_in, d6_in, d7_in), 1u32.MHz(), ) diff --git a/hil-test/tests/lcd_cam_i8080.rs b/hil-test/tests/lcd_cam_i8080.rs index 8f35c649a..da5ad4df1 100644 --- a/hil-test/tests/lcd_cam_i8080.rs +++ b/hil-test/tests/lcd_cam_i8080.rs @@ -78,7 +78,7 @@ mod tests { let i8080 = I8080::new( ctx.lcd_cam.lcd, - ctx.dma.channel0.tx, + ctx.dma.channel0, pins, 20.MHz(), Config::default(), @@ -141,7 +141,7 @@ mod tests { let mut i8080 = I8080::new( ctx.lcd_cam.lcd, - ctx.dma.channel0.tx, + ctx.dma.channel0, pins, 20.MHz(), Config::default(), @@ -258,15 +258,9 @@ mod tests { unit3_signal, ); - let mut i8080 = I8080::new( - ctx.lcd_cam.lcd, - channel.tx, - pins, - 20.MHz(), - Config::default(), - ) - .with_cs(cs_signal) - .with_ctrl_pins(NoPin, NoPin); + let mut i8080 = I8080::new(ctx.lcd_cam.lcd, channel, pins, 20.MHz(), Config::default()) + .with_cs(cs_signal) + .with_ctrl_pins(NoPin, NoPin); // This is to make the test values look more intuitive. i8080.set_bit_order(BitOrder::Inverted); diff --git a/hil-test/tests/lcd_cam_i8080_async.rs b/hil-test/tests/lcd_cam_i8080_async.rs index 705447038..b2da394fb 100644 --- a/hil-test/tests/lcd_cam_i8080_async.rs +++ b/hil-test/tests/lcd_cam_i8080_async.rs @@ -54,7 +54,7 @@ mod tests { let i8080 = I8080::new( ctx.lcd_cam.lcd, - ctx.dma.channel0.tx, + ctx.dma.channel0, pins, 20.MHz(), Config::default(), diff --git a/hil-test/tests/parl_io_tx.rs b/hil-test/tests/parl_io_tx.rs index e9cc12aa0..54fbe1f27 100644 --- a/hil-test/tests/parl_io_tx.rs +++ b/hil-test/tests/parl_io_tx.rs @@ -7,7 +7,7 @@ #[cfg(esp32c6)] use esp_hal::parl_io::{TxPinConfigWithValidPin, TxSixteenBits}; use esp_hal::{ - dma::{Channel, Dma, DmaChannel0}, + dma::{Dma, DmaChannel0}, gpio::{ interconnect::{InputSignal, OutputSignal}, NoPin, @@ -27,13 +27,12 @@ use esp_hal::{ }, peripherals::PARL_IO, prelude::*, - Blocking, }; use hil_test as _; struct Context { parl_io: PARL_IO, - dma_channel: Channel<'static, Blocking, DmaChannel0>, + dma_channel: DmaChannel0, clock: OutputSignal, valid: OutputSignal, clock_loopback: InputSignal, diff --git a/hil-test/tests/parl_io_tx_async.rs b/hil-test/tests/parl_io_tx_async.rs index 09c4d6899..ab7b20200 100644 --- a/hil-test/tests/parl_io_tx_async.rs +++ b/hil-test/tests/parl_io_tx_async.rs @@ -9,7 +9,7 @@ #[cfg(esp32c6)] use esp_hal::parl_io::{TxPinConfigWithValidPin, TxSixteenBits}; use esp_hal::{ - dma::{Channel, Dma, DmaChannel0}, + dma::{Dma, DmaChannel0}, gpio::{ interconnect::{InputSignal, OutputSignal}, NoPin, @@ -29,13 +29,12 @@ use esp_hal::{ }, peripherals::PARL_IO, prelude::*, - Async, }; use hil_test as _; struct Context { parl_io: PARL_IO, - dma_channel: Channel<'static, Async, DmaChannel0>, + dma_channel: DmaChannel0, clock: OutputSignal, valid: OutputSignal, clock_loopback: InputSignal, @@ -61,7 +60,7 @@ mod tests { let pcnt = Pcnt::new(peripherals.PCNT); let pcnt_unit = pcnt.unit0; let dma = Dma::new(peripherals.DMA); - let dma_channel = dma.channel0.into_async(); + let dma_channel = dma.channel0; let parl_io = peripherals.PARL_IO; @@ -91,8 +90,9 @@ mod tests { let mut pins = TxPinConfigIncludingValidPin::new(pins); let mut clock_pin = ClkOutPin::new(ctx.clock); - let pio = - ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz()).unwrap(); + let pio = ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz()) + .unwrap() + .into_async(); let mut pio = pio .tx @@ -152,8 +152,9 @@ mod tests { let mut clock_pin = ClkOutPin::new(ctx.clock); - let pio = - ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz()).unwrap(); + let pio = ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz()) + .unwrap() + .into_async(); let mut pio = pio .tx @@ -166,7 +167,8 @@ mod tests { ) .unwrap(); - // use a PCNT unit to count the negitive clock edges only when valid is high + // use a PCNT unit to count the negitive clock edges only when + // valid is high let clock_unit = ctx.pcnt_unit; clock_unit.channel0.set_edge_signal(ctx.clock_loopback); clock_unit.channel0.set_ctrl_signal(ctx.valid_loopback); diff --git a/hil-test/tests/qspi.rs b/hil-test/tests/qspi.rs index 4c5a1e6a2..8960f767d 100644 --- a/hil-test/tests/qspi.rs +++ b/hil-test/tests/qspi.rs @@ -8,7 +8,7 @@ #[cfg(pcnt)] use esp_hal::pcnt::{channel::EdgeMode, unit::Unit, Pcnt}; use esp_hal::{ - dma::{Channel, Dma, DmaRxBuf, DmaTxBuf}, + dma::{Dma, DmaRxBuf, DmaTxBuf}, dma_buffers, gpio::{AnyPin, Input, Level, Output, Pull}, prelude::*, @@ -43,7 +43,7 @@ struct Context { spi: Spi<'static, Blocking>, #[cfg(pcnt)] pcnt: esp_hal::peripherals::PCNT, - dma_channel: Channel<'static, Blocking, DmaChannel0>, + dma_channel: DmaChannel0, gpios: [AnyPin; 3], } diff --git a/hil-test/tests/spi_full_duplex.rs b/hil-test/tests/spi_full_duplex.rs index a32a267e5..35a9209ac 100644 --- a/hil-test/tests/spi_full_duplex.rs +++ b/hil-test/tests/spi_full_duplex.rs @@ -12,7 +12,7 @@ use embedded_hal::spi::SpiBus; #[cfg(pcnt)] use embedded_hal_async::spi::SpiBus as SpiBusAsync; use esp_hal::{ - dma::{Channel, Dma, DmaDescriptor, DmaRxBuf, DmaTxBuf}, + dma::{Dma, DmaDescriptor, DmaRxBuf, DmaTxBuf}, dma_buffers, gpio::{Level, NoPin}, peripheral::Peripheral, @@ -37,7 +37,7 @@ cfg_if::cfg_if! { struct Context { spi: Spi<'static, Blocking>, - dma_channel: Channel<'static, Blocking, DmaChannel>, + dma_channel: DmaChannel, // Reuse the really large buffer so we don't run out of DRAM with many tests rx_buffer: &'static mut [u8], rx_descriptors: &'static mut [DmaDescriptor], @@ -424,9 +424,9 @@ mod tests { let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); let mut spi = ctx .spi - .into_async() .with_dma(ctx.dma_channel) - .with_buffers(dma_rx_buf, dma_tx_buf); + .with_buffers(dma_rx_buf, dma_tx_buf) + .into_async(); ctx.pcnt_unit.channel0.set_edge_signal(ctx.pcnt_source); ctx.pcnt_unit diff --git a/hil-test/tests/spi_slave.rs b/hil-test/tests/spi_slave.rs index 3485587ae..299a592a2 100644 --- a/hil-test/tests/spi_slave.rs +++ b/hil-test/tests/spi_slave.rs @@ -9,7 +9,7 @@ #![no_main] use esp_hal::{ - dma::{Channel, Dma}, + dma::Dma, dma_buffers, gpio::{Input, Level, Output, Pull}, peripheral::Peripheral, @@ -28,7 +28,7 @@ cfg_if::cfg_if! { struct Context { spi: Spi<'static, Blocking>, - dma_channel: Channel<'static, Blocking, DmaChannel>, + dma_channel: DmaChannel, bitbang_spi: BitbangSpi, } diff --git a/qa-test/src/bin/lcd_cam_ov2640.rs b/qa-test/src/bin/lcd_cam_ov2640.rs index eff058587..77e2b4727 100644 --- a/qa-test/src/bin/lcd_cam_ov2640.rs +++ b/qa-test/src/bin/lcd_cam_ov2640.rs @@ -69,7 +69,7 @@ fn main() -> ! { ); let lcd_cam = LcdCam::new(peripherals.LCD_CAM); - let camera = Camera::new(lcd_cam.cam, dma.channel0.rx, cam_data_pins, 20u32.MHz()) + let camera = Camera::new(lcd_cam.cam, dma.channel0, cam_data_pins, 20u32.MHz()) .with_master_clock(cam_xclk) .with_pixel_clock(cam_pclk) .with_ctrl_pins(cam_vsync, cam_href); diff --git a/qa-test/src/bin/lcd_i8080.rs b/qa-test/src/bin/lcd_i8080.rs index f898b70c3..e3288aeb5 100644 --- a/qa-test/src/bin/lcd_i8080.rs +++ b/qa-test/src/bin/lcd_i8080.rs @@ -71,7 +71,7 @@ fn main() -> ! { let lcd_cam = LcdCam::new(peripherals.LCD_CAM); let i8080 = I8080::new( lcd_cam.lcd, - dma.channel0.tx, + dma.channel0, tx_pins, 20.MHz(), Config::default(),