From d292d11269cbb5910fb5d2d3f3997101b130eb70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 12 Nov 2024 08:59:06 +0100 Subject: [PATCH 01/13] Add mode to DMA channel drivers --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/aes/mod.rs | 4 +- esp-hal/src/dma/gdma.rs | 143 ++++++++++++------- esp-hal/src/dma/m2m.rs | 6 +- esp-hal/src/dma/mod.rs | 193 ++++++++++++++++++++------ esp-hal/src/dma/pdma.rs | 127 ++++++++--------- esp-hal/src/i2s/master.rs | 48 ++----- esp-hal/src/i2s/parallel.rs | 5 +- esp-hal/src/lcd_cam/cam.rs | 5 +- esp-hal/src/lcd_cam/lcd/i8080.rs | 16 ++- esp-hal/src/macros.rs | 13 ++ esp-hal/src/parl_io.rs | 38 ++--- esp-hal/src/spi/master.rs | 19 +-- esp-hal/src/spi/slave.rs | 4 +- hil-test/tests/lcd_cam_i8080.rs | 21 --- hil-test/tests/lcd_cam_i8080_async.rs | 27 ---- 16 files changed, 366 insertions(+), 304 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 90ea7f5edb3..861be92aa54 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -180,6 +180,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The DMA channel types have been removed from peripherals (#2261) - `I2C` driver renamed to `I2c` (#2320) - The GPIO pins are now accessible via `Peripherals` and are no longer part of the `Io` struct (#2508) +- `dma::{ChannelRx, ChannelTx}` now have a `Mode` type parameter (#2519) ### Fixed diff --git a/esp-hal/src/aes/mod.rs b/esp-hal/src/aes/mod.rs index e6815b8877b..07356137159 100644 --- a/esp-hal/src/aes/mod.rs +++ b/esp-hal/src/aes/mod.rs @@ -324,7 +324,7 @@ pub mod dma { } impl<'d> DmaSupportTx for AesDma<'d> { - type TX = ChannelTx<'d, ::Dma>; + type TX = ChannelTx<'d, ::Dma, Blocking>; fn tx(&mut self) -> &mut Self::TX { &mut self.channel.tx @@ -336,7 +336,7 @@ pub mod dma { } impl<'d> DmaSupportRx for AesDma<'d> { - type RX = ChannelRx<'d, ::Dma>; + type RX = ChannelRx<'d, ::Dma, Blocking>; 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 8ac8b6b4731..1fdb7534d13 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -25,48 +25,78 @@ use crate::{ #[doc(hidden)] pub trait GdmaChannel { fn number(&self) -> u8; -} -/// An arbitrary GDMA channel -#[non_exhaustive] -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 crate::private::Sealed for AnyGdmaChannel {} -impl DmaChannel for AnyGdmaChannel { - type Rx = ChannelRxImpl; - type Tx = ChannelTxImpl; + 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(ch: &Channel<'_, Self, M>) -> InterruptHandler { - match ch.tx.tx_impl.0.number() { - 0 => DmaChannel0::handler(), + fn async_handler_in(&self) -> Option { + match self.number() { + 0 => DmaChannel0::handler_in(), #[cfg(not(esp32c2))] - 1 => DmaChannel1::handler(), + 1 => DmaChannel1::handler_in(), #[cfg(not(esp32c2))] - 2 => DmaChannel2::handler(), + 2 => DmaChannel2::handler_in(), #[cfg(esp32s3)] - 3 => DmaChannel3::handler(), + 3 => DmaChannel3::handler_in(), #[cfg(esp32s3)] - 4 => DmaChannel4::handler(), + 4 => DmaChannel4::handler_in(), _ => unreachable!(), } } - fn interrupts(ch: &Channel<'_, Self, M>) -> &'static [Interrupt] { - match ch.tx.tx_impl.0.number() { - 0 => DmaChannel0::isrs(), + fn peripheral_interrupt_in(&self) -> Option { + match self.number() { + 0 => DmaChannel0::isr_in(), #[cfg(not(esp32c2))] - 1 => DmaChannel1::isrs(), + 1 => DmaChannel1::isr_in(), #[cfg(not(esp32c2))] - 2 => DmaChannel2::isrs(), + 2 => DmaChannel2::isr_in(), #[cfg(esp32s3)] - 3 => DmaChannel3::isrs(), + 3 => DmaChannel3::isr_in(), #[cfg(esp32s3)] - 4 => DmaChannel4::isrs(), + 4 => DmaChannel4::isr_in(), _ => unreachable!(), } } } +/// 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; +} + #[non_exhaustive] #[doc(hidden)] pub struct SpecificGdmaChannel {} @@ -202,6 +232,14 @@ impl TxRegisterAccess for ChannelTxImpl { .out_eof_des_addr() .bits() as _ } + + fn async_handler(&self) -> Option { + self.0.async_handler_out() + } + + fn peripheral_interrupt(&self) -> Option { + self.0.peripheral_interrupt_out() + } } impl InterruptAccess for ChannelTxImpl { @@ -385,6 +423,14 @@ impl RxRegisterAccess for ChannelRxImpl { .in_conf0() .modify(|_, w| w.mem_trans_en().bit(value)); } + + fn async_handler(&self) -> Option { + self.0.async_handler_in() + } + + fn peripheral_interrupt(&self) -> Option { + self.0.peripheral_interrupt_in() + } } impl InterruptAccess for ChannelRxImpl { @@ -481,7 +527,7 @@ impl Channel<'_, CH, M> { } macro_rules! impl_channel { - ($num: literal, $async_handler: path, $($interrupt: ident),* ) => { + ($num:literal, $interrupt_in:ident, $async_handler:path $(, $interrupt_out:ident , $async_handler_out:path)? ) => { paste::paste! { /// A description of a specific GDMA channel #[non_exhaustive] @@ -490,26 +536,26 @@ macro_rules! impl_channel { impl crate::private::Sealed for [] {} impl [] { - fn handler() -> InterruptHandler { - $async_handler + fn handler_in() -> Option { + Some($async_handler) + } + + fn isr_in() -> Option { + Some(Interrupt::$interrupt_in) + } + + fn handler_out() -> Option { + $crate::if_set! { $(Some($async_handler_out))?, None } } - fn isrs() -> &'static [Interrupt] { - &[$(Interrupt::$interrupt),*] + fn isr_out() -> Option { + $crate::if_set! { $(Some(Interrupt::$interrupt_out))?, None } } } impl DmaChannel for [] { type Rx = ChannelRxImpl>; type Tx = ChannelTxImpl>; - - fn async_handler(_ch: &Channel<'_, Self, M>) -> InterruptHandler { - Self::handler() - } - - fn interrupts(_ch: &Channel<'_, Self, M>,) -> &'static [Interrupt] { - Self::isrs() - } } impl DmaChannelConvert for [] { @@ -541,7 +587,6 @@ macro_rules! impl_channel { let mut this = Channel { tx: ChannelTx::new(ChannelTxImpl(SpecificGdmaChannel::<$num> {})), rx: ChannelRx::new(ChannelRxImpl(SpecificGdmaChannel::<$num> {})), - phantom: PhantomData, }; this.configure(burst_mode, priority); @@ -553,27 +598,29 @@ macro_rules! impl_channel { }; } +use super::asynch::interrupt as asynch_handler; + cfg_if::cfg_if! { if #[cfg(esp32c2)] { const CHANNEL_COUNT: usize = 1; - impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_CH0); + impl_channel!(0, DMA_CH0, asynch_handler::interrupt_handler_ch0); } else if #[cfg(esp32c3)] { const CHANNEL_COUNT: usize = 3; - impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_CH0); - impl_channel!(1, super::asynch::interrupt::interrupt_handler_ch1, DMA_CH1); - impl_channel!(2, super::asynch::interrupt::interrupt_handler_ch2, DMA_CH2); + impl_channel!(0, DMA_CH0, asynch_handler::interrupt_handler_ch0); + impl_channel!(1, DMA_CH1, asynch_handler::interrupt_handler_ch1); + impl_channel!(2, DMA_CH2, asynch_handler::interrupt_handler_ch2); } else if #[cfg(any(esp32c6, esp32h2))] { const CHANNEL_COUNT: usize = 3; - impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_IN_CH0, DMA_OUT_CH0); - impl_channel!(1, super::asynch::interrupt::interrupt_handler_ch1, DMA_IN_CH1, DMA_OUT_CH1); - impl_channel!(2, super::asynch::interrupt::interrupt_handler_ch2, DMA_IN_CH2, DMA_OUT_CH2); + impl_channel!(0, DMA_IN_CH0, asynch_handler::interrupt_handler_ch0, DMA_OUT_CH0, asynch_handler::interrupt_handler_ch0); + impl_channel!(1, DMA_IN_CH1, asynch_handler::interrupt_handler_ch1, DMA_OUT_CH1, asynch_handler::interrupt_handler_ch1); + impl_channel!(2, DMA_IN_CH2, asynch_handler::interrupt_handler_ch2, DMA_OUT_CH2, asynch_handler::interrupt_handler_ch2); } else if #[cfg(esp32s3)] { const CHANNEL_COUNT: usize = 5; - impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_IN_CH0, DMA_OUT_CH0); - impl_channel!(1, super::asynch::interrupt::interrupt_handler_ch1, DMA_IN_CH1, DMA_OUT_CH1); - impl_channel!(2, super::asynch::interrupt::interrupt_handler_ch2, DMA_IN_CH2, DMA_OUT_CH2); - impl_channel!(3, super::asynch::interrupt::interrupt_handler_ch3, DMA_IN_CH3, DMA_OUT_CH3); - impl_channel!(4, super::asynch::interrupt::interrupt_handler_ch4, DMA_IN_CH4, DMA_OUT_CH4); + impl_channel!(0, DMA_IN_CH0, asynch_handler::interrupt_handler_ch0, DMA_OUT_CH0, asynch_handler::interrupt_handler_ch0); + impl_channel!(1, DMA_IN_CH1, asynch_handler::interrupt_handler_ch1, DMA_OUT_CH1, asynch_handler::interrupt_handler_ch1); + impl_channel!(2, DMA_IN_CH2, asynch_handler::interrupt_handler_ch2, DMA_OUT_CH2, asynch_handler::interrupt_handler_ch2); + impl_channel!(3, DMA_IN_CH3, asynch_handler::interrupt_handler_ch3, DMA_OUT_CH3, asynch_handler::interrupt_handler_ch3); + impl_channel!(4, DMA_IN_CH4, asynch_handler::interrupt_handler_ch4, DMA_OUT_CH4, asynch_handler::interrupt_handler_ch4); } } diff --git a/esp-hal/src/dma/m2m.rs b/esp-hal/src/dma/m2m.rs index b1ff0f60bc5..dc2d5a54815 100644 --- a/esp-hal/src/dma/m2m.rs +++ b/esp-hal/src/dma/m2m.rs @@ -190,11 +190,11 @@ where } } -impl<'d, MODE> DmaSupportRx for Mem2Mem<'d, MODE> +impl<'d, M> DmaSupportRx for Mem2Mem<'d, M> where - MODE: Mode, + M: Mode, { - type RX = ChannelRx<'d, AnyGdmaChannel>; + type RX = ChannelRx<'d, AnyGdmaChannel, M>; 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 6deca41d657..a49f53d83d9 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -1571,12 +1571,6 @@ pub trait DmaChannel: crate::private::Sealed + Sized { /// A description of the TX half of a DMA Channel. type Tx: TxRegisterAccess + InterruptAccess; - - /// Returns the async interrupt handler. - fn async_handler(ch: &Channel<'_, Self, M>) -> InterruptHandler; - - /// Returns the interrupt. - fn interrupts(ch: &Channel<'_, Self, M>) -> &'static [Interrupt]; } #[doc(hidden)] @@ -1666,16 +1660,17 @@ pub trait Rx: crate::private::Sealed { // DMA receive channel #[non_exhaustive] #[doc(hidden)] -pub struct ChannelRx<'a, CH> +pub struct ChannelRx<'a, CH, M> where CH: DmaChannel, { pub(crate) burst_mode: bool, pub(crate) rx_impl: CH::Rx, + pub(crate) mode: PhantomData, pub(crate) _phantom: PhantomData<(&'a (), CH)>, } -impl<'a, CH> ChannelRx<'a, CH> +impl<'a, CH> ChannelRx<'a, CH, Blocking> where CH: DmaChannel, { @@ -1688,19 +1683,74 @@ where Self { burst_mode: false, rx_impl, + mode: PhantomData, + _phantom: PhantomData, + } + } + + /// Converts a blocking channel to an async channel. + pub(crate) fn into_async(mut self) -> ChannelRx<'a, CH, Async> { + if let Some(handler) = self.rx_impl.async_handler() { + self.set_interrupt_handler(handler); + } + ChannelRx { + burst_mode: false, + rx_impl: self.rx_impl, + mode: PhantomData, + _phantom: PhantomData, + } + } + + fn set_interrupt_handler(&mut self, handler: InterruptHandler) + where + CH: DmaChannel, + { + self.unlisten_in(EnumSet::all()); + self.clear_in(EnumSet::all()); + + if let Some(interrupt) = self.rx_impl.peripheral_interrupt() { + for core in crate::Cpu::other() { + crate::interrupt::disable(core, interrupt); + } + unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) }; + unwrap!(crate::interrupt::enable(interrupt, handler.priority())); + } + } +} + +impl<'a, CH> ChannelRx<'a, CH, Async> +where + CH: DmaChannel, +{ + /// Converts an async channel into a blocking channel. + pub(crate) fn into_blocking(self) -> ChannelRx<'a, CH, Blocking> { + if let Some(interrupt) = self.rx_impl.peripheral_interrupt() { + crate::interrupt::disable(Cpu::current(), interrupt); + } + ChannelRx { + burst_mode: false, + rx_impl: self.rx_impl, + mode: PhantomData, _phantom: PhantomData, } } +} +impl<'a, CH, M> ChannelRx<'a, CH, M> +where + CH: DmaChannel, + M: Mode, +{ /// Return a less specific (degraded) version of this channel. #[doc(hidden)] - pub fn degrade(self) -> ChannelRx<'a, DEG> + pub fn degrade(self) -> ChannelRx<'a, DEG, M> where CH: DmaChannelConvert, { ChannelRx { burst_mode: self.burst_mode, rx_impl: CH::degrade_rx(self.rx_impl), + mode: PhantomData, _phantom: PhantomData, } } @@ -1712,11 +1762,17 @@ where } } -impl crate::private::Sealed for ChannelRx<'_, CH> where CH: DmaChannel {} +impl crate::private::Sealed for ChannelRx<'_, CH, M> +where + CH: DmaChannel, + M: Mode, +{ +} -impl Rx for ChannelRx<'_, CH> +impl Rx for ChannelRx<'_, CH, M> where CH: DmaChannel, + M: Mode, { unsafe fn prepare_transfer_without_start( &mut self, @@ -1894,17 +1950,18 @@ pub trait Tx: crate::private::Sealed { /// DMA transmit channel #[doc(hidden)] -pub struct ChannelTx<'a, CH> +pub struct ChannelTx<'a, CH, M> where CH: DmaChannel, { #[allow(unused)] pub(crate) burst_mode: bool, pub(crate) tx_impl: CH::Tx, + pub(crate) mode: PhantomData, pub(crate) _phantom: PhantomData<(&'a (), CH)>, } -impl<'a, CH> ChannelTx<'a, CH> +impl<'a, CH> ChannelTx<'a, CH, Blocking> where CH: DmaChannel, { @@ -1912,19 +1969,74 @@ where Self { burst_mode: false, tx_impl, + mode: PhantomData, + _phantom: PhantomData, + } + } + + /// Converts a blocking channel to an async channel. + pub(crate) fn into_async(mut self) -> ChannelTx<'a, CH, Async> { + if let Some(handler) = self.tx_impl.async_handler() { + self.set_interrupt_handler(handler); + } + ChannelTx { + burst_mode: false, + tx_impl: self.tx_impl, + mode: PhantomData, + _phantom: PhantomData, + } + } + + fn set_interrupt_handler(&mut self, handler: InterruptHandler) + where + CH: DmaChannel, + { + self.unlisten_out(EnumSet::all()); + self.clear_out(EnumSet::all()); + + if let Some(interrupt) = self.tx_impl.peripheral_interrupt() { + for core in crate::Cpu::other() { + crate::interrupt::disable(core, interrupt); + } + unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) }; + unwrap!(crate::interrupt::enable(interrupt, handler.priority())); + } + } +} + +impl<'a, CH> ChannelTx<'a, CH, Async> +where + CH: DmaChannel, +{ + /// Converts an async channel into a blocking channel. + pub(crate) fn into_blocking(self) -> ChannelTx<'a, CH, Blocking> { + if let Some(interrupt) = self.tx_impl.peripheral_interrupt() { + crate::interrupt::disable(Cpu::current(), interrupt); + } + ChannelTx { + burst_mode: false, + tx_impl: self.tx_impl, + mode: PhantomData, _phantom: PhantomData, } } +} +impl<'a, CH, M> ChannelTx<'a, CH, M> +where + CH: DmaChannel, + M: Mode, +{ /// Return a less specific (degraded) version of this channel. #[doc(hidden)] - pub fn degrade(self) -> ChannelTx<'a, DEG> + pub fn degrade(self) -> ChannelTx<'a, DEG, M> where CH: DmaChannelConvert, { ChannelTx { burst_mode: self.burst_mode, tx_impl: CH::degrade_tx(self.tx_impl), + mode: PhantomData, _phantom: PhantomData, } } @@ -1936,11 +2048,17 @@ where } } -impl crate::private::Sealed for ChannelTx<'_, CH> where CH: DmaChannel {} +impl crate::private::Sealed for ChannelTx<'_, CH, M> +where + CH: DmaChannel, + M: Mode, +{ +} -impl Tx for ChannelTx<'_, CH> +impl Tx for ChannelTx<'_, CH, M> where CH: DmaChannel, + M: Mode, { unsafe fn prepare_transfer_without_start( &mut self, @@ -2116,6 +2234,9 @@ pub trait RegisterAccess: crate::private::Sealed { pub trait RxRegisterAccess: RegisterAccess { #[cfg(gdma)] fn set_mem2mem_mode(&self, value: bool); + + fn peripheral_interrupt(&self) -> Option; + fn async_handler(&self) -> Option; } #[doc(hidden)] @@ -2125,6 +2246,9 @@ pub trait TxRegisterAccess: RegisterAccess { /// Outlink descriptor address when EOF occurs of Tx channel. fn last_dscr_address(&self) -> usize; + + fn peripheral_interrupt(&self) -> Option; + fn async_handler(&self) -> Option; } #[doc(hidden)] @@ -2154,10 +2278,9 @@ where M: Mode, { /// RX half of the channel - pub rx: ChannelRx<'d, CH>, + pub rx: ChannelRx<'d, CH, M>, /// TX half of the channel - pub tx: ChannelTx<'d, CH>, - pub(crate) phantom: PhantomData, + pub tx: ChannelTx<'d, CH, M>, } impl<'d, C> Channel<'d, C, Blocking> @@ -2171,15 +2294,8 @@ where where C: DmaChannel, { - self.unlisten(EnumSet::all()); - self.clear_interrupts(EnumSet::all()); - for interrupt in C::interrupts(self).iter().copied() { - for core in crate::Cpu::other() { - crate::interrupt::disable(core, interrupt); - } - unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) }; - unwrap!(crate::interrupt::enable(interrupt, handler.priority())); - } + self.rx.set_interrupt_handler(handler); + self.tx.set_interrupt_handler(handler); } /// Listen for the given interrupts @@ -2226,18 +2342,15 @@ where /// Configure the channel. pub fn configure(&mut self, burst_mode: bool, priority: DmaPriority) { - self.tx.configure(burst_mode, priority); self.rx.configure(burst_mode, priority); + self.tx.configure(burst_mode, priority); } /// Converts a blocking channel to an async channel. - pub fn into_async(mut self) -> Channel<'d, C, Async> { - self.set_interrupt_handler(C::async_handler(&self)); - + pub fn into_async(self) -> Channel<'d, C, Async> { Channel { - tx: self.tx, - rx: self.rx, - phantom: PhantomData, + rx: self.rx.into_async(), + tx: self.tx.into_async(), } } } @@ -2248,14 +2361,9 @@ where { /// Converts an async channel to a blocking channel. pub fn into_blocking(self) -> Channel<'d, C, Blocking> { - for interrupt in C::interrupts(&self).iter().copied() { - crate::interrupt::disable(Cpu::current(), interrupt); - } - Channel { - tx: self.tx, - rx: self.rx, - phantom: PhantomData, + rx: self.rx.into_blocking(), + tx: self.tx.into_blocking(), } } } @@ -2286,7 +2394,6 @@ where Channel { rx: self.rx.degrade(), tx: self.tx.degrade(), - phantom: PhantomData, } } } diff --git a/esp-hal/src/dma/pdma.rs b/esp-hal/src/dma/pdma.rs index bfbaee48dfc..35f8425d698 100644 --- a/esp-hal/src/dma/pdma.rs +++ b/esp-hal/src/dma/pdma.rs @@ -32,6 +32,9 @@ pub trait PdmaChannel: crate::private::Sealed { fn tx_waker(&self) -> &'static AtomicWaker; fn rx_waker(&self) -> &'static AtomicWaker; fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool; + + fn peripheral_interrupt(&self) -> Interrupt; + fn async_handler(&self) -> InterruptHandler; } #[doc(hidden)] @@ -107,6 +110,14 @@ impl> TxRegisterAccess for SpiD let spi = self.0.register_block(); spi.out_eof_des_addr().read().dma_out_eof_des_addr().bits() as usize } + + fn peripheral_interrupt(&self) -> Option { + None + } + + fn async_handler(&self) -> Option { + None + } } impl> InterruptAccess @@ -241,7 +252,15 @@ impl> RegisterAccess for SpiDma } } -impl> RxRegisterAccess for SpiDmaRxChannelImpl {} +impl> RxRegisterAccess for SpiDmaRxChannelImpl { + fn peripheral_interrupt(&self) -> Option { + Some(self.0.peripheral_interrupt()) + } + + fn async_handler(&self) -> Option { + Some(self.0.async_handler()) + } +} impl> InterruptAccess for SpiDmaRxChannelImpl @@ -343,27 +362,9 @@ macro_rules! ImplSpiChannel { #[non_exhaustive] pub struct [] {} - impl [] { - fn handler() -> InterruptHandler { - super::asynch::interrupt::[< interrupt_handler_spi $num _dma >] - } - - fn isrs() -> &'static [Interrupt] { - &[Interrupt::[< SPI $num _DMA >]] - } - } - impl DmaChannel for [] { type Rx = SpiDmaRxChannelImpl; type Tx = SpiDmaTxChannelImpl; - - fn async_handler(_ch: &Channel<'_, Self, M>) -> InterruptHandler { - Self::handler() - } - - fn interrupts(_ch: &Channel<'_, Self, M>) -> &'static [Interrupt] { - Self::isrs() - } } impl DmaChannelExt for [] { @@ -393,6 +394,14 @@ macro_rules! ImplSpiChannel { fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool { peripheral == DmaPeripheral::[] } + + fn peripheral_interrupt(&self) -> Interrupt { + Interrupt::[< SPI $num _DMA >] + } + + fn async_handler(&self) -> InterruptHandler { + super::asynch::interrupt::[< interrupt_handler_spi $num _dma >] + } } impl DmaChannelConvert for [] { @@ -420,7 +429,6 @@ macro_rules! ImplSpiChannel { let mut this = Channel { tx: ChannelTx::new(SpiDmaTxChannelImpl([] {})), rx: ChannelRx::new(SpiDmaRxChannelImpl([] {})), - phantom: PhantomData, }; this.configure(burst_mode, priority); @@ -518,6 +526,14 @@ impl> TxRegisterAccess for I2sD .out_eof_des_addr() .bits() as usize } + + fn peripheral_interrupt(&self) -> Option { + None + } + + fn async_handler(&self) -> Option { + None + } } impl> InterruptAccess @@ -658,7 +674,15 @@ impl> RegisterAccess for I2sDma } } -impl> RxRegisterAccess for I2sDmaRxChannelImpl {} +impl> RxRegisterAccess for I2sDmaRxChannelImpl { + fn peripheral_interrupt(&self) -> Option { + Some(self.0.peripheral_interrupt()) + } + + fn async_handler(&self) -> Option { + Some(self.0.async_handler()) + } +} impl> InterruptAccess for I2sDmaRxChannelImpl @@ -756,27 +780,9 @@ macro_rules! ImplI2sChannel { impl $crate::private::Sealed for [] {} - impl [] { - fn handler() -> InterruptHandler { - super::asynch::interrupt::[< interrupt_handler_i2s $num _dma >] - } - - fn isrs() -> &'static [Interrupt] { - &[Interrupt::[< I2S $num >]] - } - } - impl DmaChannel for [] { type Rx = I2sDmaRxChannelImpl; type Tx = I2sDmaTxChannelImpl; - - fn async_handler(_ch: &Channel<'_, Self, M>) -> InterruptHandler { - Self::handler() - } - - fn interrupts(_ch: &Channel<'_, Self, M>) -> &'static [Interrupt] { - Self::isrs() - } } impl DmaChannelExt for [] { @@ -805,6 +811,14 @@ macro_rules! ImplI2sChannel { fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool { peripheral == DmaPeripheral::[] } + + fn peripheral_interrupt(&self) -> Interrupt { + Interrupt::[< I2S $num >] + } + + fn async_handler(&self) -> InterruptHandler { + super::asynch::interrupt::[< interrupt_handler_i2s $num _dma >] + } } impl DmaChannelConvert for [] { @@ -829,7 +843,6 @@ macro_rules! ImplI2sChannel { let mut this = Channel { tx: ChannelTx::new(I2sDmaTxChannelImpl([] {})), rx: ChannelRx::new(I2sDmaRxChannelImpl([] {})), - phantom: PhantomData, }; this.configure(burst_mode, priority); @@ -928,20 +941,6 @@ impl crate::private::Sealed for AnySpiDmaChannel {} impl DmaChannel for AnySpiDmaChannel { type Rx = SpiDmaRxChannelImpl; type Tx = SpiDmaTxChannelImpl; - - fn async_handler(ch: &Channel<'_, Self, M>) -> InterruptHandler { - match &ch.tx.tx_impl.0 { - AnySpiDmaChannelInner::Spi2(_) => Spi2DmaChannel::handler(), - AnySpiDmaChannelInner::Spi3(_) => Spi3DmaChannel::handler(), - } - } - - fn interrupts(ch: &Channel<'_, Self, M>) -> &'static [Interrupt] { - match &ch.tx.tx_impl.0 { - AnySpiDmaChannelInner::Spi2(_) => Spi2DmaChannel::isrs(), - AnySpiDmaChannelInner::Spi3(_) => Spi3DmaChannel::isrs(), - } - } } crate::any_enum! { @@ -966,6 +965,8 @@ impl PdmaChannel for AnySpiDmaChannelInner { fn tx_waker(&self) -> &'static AtomicWaker; fn rx_waker(&self) -> &'static AtomicWaker; fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool; + fn peripheral_interrupt(&self) -> Interrupt; + fn async_handler(&self) -> InterruptHandler; } } } @@ -978,22 +979,6 @@ impl crate::private::Sealed for AnyI2sDmaChannel {} impl DmaChannel for AnyI2sDmaChannel { type Rx = I2sDmaRxChannelImpl; type Tx = I2sDmaTxChannelImpl; - - fn async_handler(ch: &Channel<'_, Self, M>) -> InterruptHandler { - match &ch.tx.tx_impl.0 { - AnyI2sDmaChannelInner::I2s0(_) => I2s0DmaChannel::handler(), - #[cfg(i2s1)] - AnyI2sDmaChannelInner::I2s1(_) => I2s1DmaChannel::handler(), - } - } - - fn interrupts(ch: &Channel<'_, Self, M>) -> &'static [Interrupt] { - match &ch.tx.tx_impl.0 { - AnyI2sDmaChannelInner::I2s0(_) => I2s0DmaChannel::isrs(), - #[cfg(i2s1)] - AnyI2sDmaChannelInner::I2s1(_) => I2s1DmaChannel::isrs(), - } - } } crate::any_enum! { @@ -1020,6 +1005,8 @@ impl PdmaChannel for AnyI2sDmaChannelInner { fn tx_waker(&self) -> &'static AtomicWaker; fn rx_waker(&self) -> &'static AtomicWaker; fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool; + fn peripheral_interrupt(&self) -> Interrupt; + fn async_handler(&self) -> InterruptHandler; } } } diff --git a/esp-hal/src/i2s/master.rs b/esp-hal/src/i2s/master.rs index 95a33d62399..aad2f309191 100644 --- a/esp-hal/src/i2s/master.rs +++ b/esp-hal/src/i2s/master.rs @@ -74,8 +74,6 @@ //! //! - Only TDM Philips standard is supported. -use core::marker::PhantomData; - use enumset::{EnumSet, EnumSetType}; use private::*; @@ -251,6 +249,7 @@ impl DataFormat { } /// Instance of the I2S peripheral driver +#[non_exhaustive] pub struct I2s<'d, M, T = AnyI2s> where T: RegisterAccess, @@ -260,7 +259,6 @@ where pub i2s_rx: RxCreator<'d, M, T>, /// Handles the transmission (TX) side of the I2S peripheral. pub i2s_tx: TxCreator<'d, M, T>, - phantom: PhantomData, } impl<'d, DmaMode, T> I2s<'d, DmaMode, T> @@ -299,15 +297,12 @@ where i2s: unsafe { i2s.clone_unchecked() }, rx_channel: channel.rx, descriptors: rx_descriptors, - phantom: PhantomData, }, i2s_tx: TxCreator { i2s, tx_channel: channel.tx, descriptors: tx_descriptors, - phantom: PhantomData, }, - phantom: PhantomData, } } } @@ -432,26 +427,17 @@ where /// Converts the SPI instance into async mode. pub fn into_async(self) -> I2s<'d, Async, T> { - let channel = Channel { - rx: self.i2s_rx.rx_channel, - tx: self.i2s_tx.tx_channel, - phantom: PhantomData::, - }; - let channel = channel.into_async(); I2s { i2s_rx: RxCreator { i2s: self.i2s_rx.i2s, - rx_channel: channel.rx, + rx_channel: self.i2s_rx.rx_channel.into_async(), descriptors: self.i2s_rx.descriptors, - phantom: PhantomData, }, i2s_tx: TxCreator { i2s: self.i2s_tx.i2s, - tx_channel: channel.tx, + tx_channel: self.i2s_tx.tx_channel.into_async(), descriptors: self.i2s_tx.descriptors, - phantom: PhantomData, }, - phantom: PhantomData, } } } @@ -477,9 +463,8 @@ where T: RegisterAccess, { i2s: PeripheralRef<'d, T>, - tx_channel: ChannelTx<'d, T::Dma>, + tx_channel: ChannelTx<'d, T::Dma, DmaMode>, tx_chain: DescriptorChain, - phantom: PhantomData, } impl core::fmt::Debug for I2sTx<'_, DmaMode, T> @@ -511,7 +496,7 @@ where T: RegisterAccess, DmaMode: Mode, { - type TX = ChannelTx<'d, T::Dma>; + type TX = ChannelTx<'d, T::Dma, DmaMode>; fn tx(&mut self) -> &mut Self::TX { &mut self.tx_channel @@ -610,9 +595,8 @@ where DmaMode: Mode, { i2s: PeripheralRef<'d, T>, - rx_channel: ChannelRx<'d, T::Dma>, + rx_channel: ChannelRx<'d, T::Dma, DmaMode>, rx_chain: DescriptorChain, - phantom: PhantomData, } impl core::fmt::Debug for I2sRx<'_, DmaMode, T> @@ -644,7 +628,7 @@ where T: RegisterAccess, DmaMode: Mode, { - type RX = ChannelRx<'d, T::Dma>; + type RX = ChannelRx<'d, T::Dma, DmaMode>; fn rx(&mut self) -> &mut Self::RX { &mut self.rx_channel @@ -750,8 +734,6 @@ pub trait RegisterAccess: RegisterAccessPrivate {} impl RegisterAccess for T where T: RegisterAccessPrivate {} mod private { - use core::marker::PhantomData; - use enumset::EnumSet; use fugit::HertzU32; @@ -790,22 +772,20 @@ mod private { M: Mode, { pub i2s: PeripheralRef<'d, T>, - pub tx_channel: ChannelTx<'d, T::Dma>, + pub tx_channel: ChannelTx<'d, T::Dma, M>, pub descriptors: &'static mut [DmaDescriptor], - pub(crate) phantom: PhantomData, } - impl<'d, DmaMode, T> TxCreator<'d, DmaMode, T> + impl<'d, M, T> TxCreator<'d, M, T> where + M: Mode, T: RegisterAccess, - DmaMode: Mode, { - pub fn build(self) -> I2sTx<'d, DmaMode, T> { + pub fn build(self) -> I2sTx<'d, M, T> { I2sTx { i2s: self.i2s, tx_channel: self.tx_channel, tx_chain: DescriptorChain::new(self.descriptors), - phantom: PhantomData, } } @@ -849,22 +829,20 @@ mod private { M: Mode, { pub i2s: PeripheralRef<'d, T>, - pub rx_channel: ChannelRx<'d, T::Dma>, + pub rx_channel: ChannelRx<'d, T::Dma, M>, pub descriptors: &'static mut [DmaDescriptor], - pub(crate) phantom: PhantomData, } impl<'d, M, T> RxCreator<'d, M, T> where - T: RegisterAccess, M: Mode, + T: RegisterAccess, { pub fn build(self) -> I2sRx<'d, M, T> { I2sRx { i2s: self.i2s, rx_channel: self.rx_channel, rx_chain: DescriptorChain::new(self.descriptors), - phantom: PhantomData, } } diff --git a/esp-hal/src/i2s/parallel.rs b/esp-hal/src/i2s/parallel.rs index 865346fb648..dce4ae1a3d1 100644 --- a/esp-hal/src/i2s/parallel.rs +++ b/esp-hal/src/i2s/parallel.rs @@ -35,7 +35,6 @@ //! - `DMA` //! - `system` (to configure and enable the I2S peripheral) use core::{ - marker::PhantomData, mem::ManuallyDrop, ops::{Deref, DerefMut}, }; @@ -177,8 +176,7 @@ where I: Instance, { instance: PeripheralRef<'d, I>, - tx_channel: ChannelTx<'d, I::Dma>, - mode: PhantomData, + tx_channel: ChannelTx<'d, I::Dma, DM>, } impl<'d, DM> I2sParallel<'d, DM> @@ -234,7 +232,6 @@ where Self { instance: i2s, tx_channel: channel.tx, - mode: PhantomData, } } diff --git a/esp-hal/src/lcd_cam/cam.rs b/esp-hal/src/lcd_cam/cam.rs index 5125d8b343d..a16e2adc24c 100644 --- a/esp-hal/src/lcd_cam/cam.rs +++ b/esp-hal/src/lcd_cam/cam.rs @@ -82,6 +82,7 @@ use crate::{ lcd_cam::{calculate_clkm, BitOrder, ByteOrder}, peripheral::{Peripheral, PeripheralRef}, peripherals::LCD_CAM, + Blocking, }; /// Generation of GDMA SUC EOF @@ -125,14 +126,14 @@ 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, ::Dma>, + rx_channel: ChannelRx<'d, ::Dma, Blocking>, } impl<'d> Camera<'d> { /// Creates a new `Camera` instance with DMA support. pub fn new( cam: Cam<'d>, - channel: ChannelRx<'d, CH>, + channel: ChannelRx<'d, CH, Blocking>, _pins: P, frequency: HertzU32, ) -> Self diff --git a/esp-hal/src/lcd_cam/lcd/i8080.rs b/esp-hal/src/lcd_cam/lcd/i8080.rs index 109b658aa39..9cbf41290ef 100644 --- a/esp-hal/src/lcd_cam/lcd/i8080.rs +++ b/esp-hal/src/lcd_cam/lcd/i8080.rs @@ -83,21 +83,25 @@ use crate::{ }, peripheral::{Peripheral, PeripheralRef}, peripherals::LCD_CAM, + Blocking, Mode, }; /// Represents the I8080 LCD interface. pub struct I8080<'d, DM: Mode> { lcd_cam: PeripheralRef<'d, LCD_CAM>, - tx_channel: ChannelTx<'d, ::Dma>, - _phantom: PhantomData, + tx_channel: ChannelTx<'d, ::Dma, Blocking>, + _mode: PhantomData, } -impl<'d, DM: Mode> I8080<'d, DM> { +impl<'d, DM> I8080<'d, DM> +where + DM: Mode, +{ /// Creates a new instance of the I8080 LCD interface. pub fn new( lcd: Lcd<'d, DM>, - channel: ChannelTx<'d, CH>, + channel: ChannelTx<'d, CH, Blocking>, mut pins: P, frequency: HertzU32, config: Config, @@ -209,12 +213,10 @@ impl<'d, DM: Mode> I8080<'d, DM> { Self { lcd_cam, tx_channel: channel.degrade(), - _phantom: PhantomData, + _mode: PhantomData, } } -} -impl<'d, DM: Mode> I8080<'d, DM> { /// Configures the byte order for data transmission in 16-bit mode. /// This must be set to [ByteOrder::default()] when transmitting in 8-bit /// mode. diff --git a/esp-hal/src/macros.rs b/esp-hal/src/macros.rs index f4274d8033d..1b5764d7b06 100644 --- a/esp-hal/src/macros.rs +++ b/esp-hal/src/macros.rs @@ -118,3 +118,16 @@ macro_rules! any_peripheral { } }; } + +/// Macro to choose between two expressions. Useful for implementing "else" for +/// `$()?` macro syntax. +#[macro_export] +#[doc(hidden)] +macro_rules! if_set { + (, $not_set:expr) => { + $not_set + }; + ($set:expr, $not_set:expr) => { + $set + }; +} diff --git a/esp-hal/src/parl_io.rs b/esp-hal/src/parl_io.rs index 2d95e1427ec..f1f2a8c35a9 100644 --- a/esp-hal/src/parl_io.rs +++ b/esp-hal/src/parl_io.rs @@ -811,7 +811,7 @@ pub struct ParlIoTx<'d, DM> where DM: Mode, { - tx_channel: ChannelTx<'d, ::Dma>, + tx_channel: ChannelTx<'d, ::Dma, DM>, tx_chain: DescriptorChain, phantom: PhantomData, } @@ -890,7 +890,7 @@ pub struct ParlIoRx<'d, DM> where DM: Mode, { - rx_channel: ChannelRx<'d, ::Dma>, + rx_channel: ChannelRx<'d, ::Dma, DM>, rx_chain: DescriptorChain, phantom: PhantomData, } @@ -1034,20 +1034,14 @@ impl<'d> ParlIoFullDuplex<'d, Blocking> { /// Convert to an async version. pub fn into_async(self) -> ParlIoFullDuplex<'d, Async> { - let channel = Channel { - tx: self.tx.tx_channel, - rx: self.rx.rx_channel, - phantom: PhantomData::, - }; - let channel = channel.into_async(); ParlIoFullDuplex { tx: TxCreatorFullDuplex { - tx_channel: channel.tx, + tx_channel: self.tx.tx_channel.into_async(), descriptors: self.tx.descriptors, phantom: PhantomData, }, rx: RxCreatorFullDuplex { - rx_channel: channel.rx, + rx_channel: self.rx.rx_channel.into_async(), descriptors: self.rx.descriptors, phantom: PhantomData, }, @@ -1094,20 +1088,14 @@ impl InterruptConfigurable for ParlIoFullDuplex<'_, Blocking> { impl<'d> ParlIoFullDuplex<'d, Async> { /// Convert to a blocking version. pub fn into_blocking(self) -> ParlIoFullDuplex<'d, Blocking> { - let channel = Channel { - tx: self.tx.tx_channel, - rx: self.rx.rx_channel, - phantom: PhantomData::, - }; - let channel = channel.into_blocking(); ParlIoFullDuplex { tx: TxCreatorFullDuplex { - tx_channel: channel.tx, + tx_channel: self.tx.tx_channel.into_blocking(), descriptors: self.tx.descriptors, phantom: PhantomData, }, rx: RxCreatorFullDuplex { - rx_channel: channel.rx, + rx_channel: self.rx.rx_channel.into_blocking(), descriptors: self.rx.descriptors, phantom: PhantomData, }, @@ -1372,7 +1360,7 @@ impl<'d, DM> DmaSupportTx for ParlIoTx<'d, DM> where DM: Mode, { - type TX = ChannelTx<'d, ::Dma>; + type TX = ChannelTx<'d, ::Dma, DM>; fn tx(&mut self) -> &mut Self::TX { &mut self.tx_channel @@ -1414,7 +1402,7 @@ where } fn start_receive_bytes_dma( - rx_channel: &mut ChannelRx<'d, ::Dma>, + rx_channel: &mut ChannelRx<'d, ::Dma, DM>, rx_chain: &mut DescriptorChain, ptr: *mut u8, len: usize, @@ -1468,7 +1456,7 @@ impl<'d, DM> DmaSupportRx for ParlIoRx<'d, DM> where DM: Mode, { - type RX = ChannelRx<'d, ::Dma>; + type RX = ChannelRx<'d, ::Dma, DM>; fn rx(&mut self) -> &mut Self::RX { &mut self.rx_channel @@ -1484,7 +1472,7 @@ pub struct TxCreator<'d, DM> where DM: Mode, { - tx_channel: ChannelTx<'d, ::Dma>, + tx_channel: ChannelTx<'d, ::Dma, DM>, descriptors: &'static mut [DmaDescriptor], phantom: PhantomData, } @@ -1494,7 +1482,7 @@ pub struct RxCreator<'d, DM> where DM: Mode, { - rx_channel: ChannelRx<'d, ::Dma>, + rx_channel: ChannelRx<'d, ::Dma, DM>, descriptors: &'static mut [DmaDescriptor], phantom: PhantomData, } @@ -1504,7 +1492,7 @@ pub struct TxCreatorFullDuplex<'d, DM> where DM: Mode, { - tx_channel: ChannelTx<'d, ::Dma>, + tx_channel: ChannelTx<'d, ::Dma, DM>, descriptors: &'static mut [DmaDescriptor], phantom: PhantomData, } @@ -1514,7 +1502,7 @@ pub struct RxCreatorFullDuplex<'d, DM> where DM: Mode, { - rx_channel: ChannelRx<'d, ::Dma>, + rx_channel: ChannelRx<'d, ::Dma, DM>, descriptors: &'static mut [DmaDescriptor], phantom: PhantomData, } diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index 1430a5269c3..ba2b5080a94 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -3003,10 +3003,10 @@ macro_rules! spi_instance { cs: OutputSignal::$cs, sio0_input: InputSignal::$mosi, sio1_output: OutputSignal::$miso, - sio2_output: if_set!($(Some(OutputSignal::$sio2))?, None), - sio2_input: if_set!($(Some(InputSignal::$sio2))?, None), - sio3_output: if_set!($(Some(OutputSignal::$sio3))?, None), - sio3_input: if_set!($(Some(InputSignal::$sio3))?, None), + sio2_output: $crate::if_set!($(Some(OutputSignal::$sio2))?, None), + sio2_input: $crate::if_set!($(Some(InputSignal::$sio2))?, None), + sio3_output: $crate::if_set!($(Some(OutputSignal::$sio3))?, None), + sio3_input: $crate::if_set!($(Some(InputSignal::$sio3))?, None), }; &INFO @@ -3022,17 +3022,6 @@ macro_rules! spi_instance { } } -/// Macro to choose between two expressions. Useful for implementing "else" for -/// `$()?` macro syntax. -macro_rules! if_set { - (, $not_set:expr) => { - $not_set - }; - ($set:expr, $not_set:expr) => { - $set - }; -} - #[cfg(spi2)] cfg_if::cfg_if! { if #[cfg(esp32)] { diff --git a/esp-hal/src/spi/slave.rs b/esp-hal/src/spi/slave.rs index 0ffd707d1eb..93af03ae7e7 100644 --- a/esp-hal/src/spi/slave.rs +++ b/esp-hal/src/spi/slave.rs @@ -262,7 +262,7 @@ pub mod dma { T: InstanceDma, DmaMode: Mode, { - type TX = ChannelTx<'d, T::Dma>; + type TX = ChannelTx<'d, T::Dma, DmaMode>; fn tx(&mut self) -> &mut Self::TX { &mut self.channel.tx @@ -278,7 +278,7 @@ pub mod dma { T: InstanceDma, DmaMode: Mode, { - type RX = ChannelRx<'d, T::Dma>; + type RX = ChannelRx<'d, T::Dma, DmaMode>; fn rx(&mut self) -> &mut Self::RX { &mut self.channel.rx diff --git a/hil-test/tests/lcd_cam_i8080.rs b/hil-test/tests/lcd_cam_i8080.rs index 987a0ad543a..ae34f4506ef 100644 --- a/hil-test/tests/lcd_cam_i8080.rs +++ b/hil-test/tests/lcd_cam_i8080.rs @@ -90,27 +90,6 @@ mod tests { xfer.wait().0.unwrap(); } - #[test] - fn test_i8080_8bit_async_channel(ctx: Context<'static>) { - let channel = ctx - .dma - .channel0 - .configure(false, DmaPriority::Priority0) - .into_async(); - let pins = TxEightBits::new(NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin); - - let i8080 = I8080::new( - ctx.lcd_cam.lcd, - channel.tx, - pins, - 20.MHz(), - Config::default(), - ); - - let xfer = i8080.send(Command::::None, 0, ctx.dma_buf).unwrap(); - xfer.wait().0.unwrap(); - } - #[test] fn test_i8080_8bit_is_seen_by_pcnt(ctx: Context<'static>) { // FIXME: Update this test to exercise all the I8080 output signals once the diff --git a/hil-test/tests/lcd_cam_i8080_async.rs b/hil-test/tests/lcd_cam_i8080_async.rs index df44d002289..855d925df58 100644 --- a/hil-test/tests/lcd_cam_i8080_async.rs +++ b/hil-test/tests/lcd_cam_i8080_async.rs @@ -70,31 +70,4 @@ mod tests { transfer.wait().0.unwrap(); } - - #[test] - async fn test_i8080_8bit_async_channel(ctx: Context<'static>) { - let channel = ctx - .dma - .channel0 - .configure(false, DmaPriority::Priority0) - .into_async(); - let pins = TxEightBits::new(NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin); - - let i8080 = I8080::new( - ctx.lcd_cam.lcd, - channel.tx, - pins, - 20.MHz(), - Config::default(), - ); - - let mut transfer = i8080.send(Command::::None, 0, ctx.dma_buf).unwrap(); - - transfer.wait_for_done().await; - - // This should not block forever and should immediately return. - transfer.wait_for_done().await; - - transfer.wait().0.unwrap(); - } } From e9f7cc3f16b8c2b43b89da2ea33236d7edb5c43d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 12 Nov 2024 14:56:03 +0100 Subject: [PATCH 02/13] Swap dma Channel CH and DM --- esp-hal/CHANGELOG.md | 1 + esp-hal/MIGRATING-0.21.md | 66 +++++++++++++++++++++- esp-hal/src/aes/mod.rs | 12 ++-- esp-hal/src/dma/gdma.rs | 4 +- esp-hal/src/dma/m2m.rs | 18 +++--- esp-hal/src/dma/mod.rs | 97 +++++++++++++++----------------- esp-hal/src/dma/pdma.rs | 9 +-- esp-hal/src/i2s/master.rs | 22 ++++---- esp-hal/src/i2s/parallel.rs | 6 +- esp-hal/src/lcd_cam/cam.rs | 4 +- esp-hal/src/lcd_cam/lcd/i8080.rs | 4 +- esp-hal/src/parl_io.rs | 48 +++++----------- esp-hal/src/spi/master.rs | 8 +-- esp-hal/src/spi/slave.rs | 12 ++-- hil-test/tests/dma_mem2mem.rs | 2 +- hil-test/tests/qspi.rs | 2 +- 16 files changed, 175 insertions(+), 140 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 861be92aa54..5332245a68c 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -65,6 +65,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `I2c` SCL timeout is now defined in bus clock cycles. (#2477) - Trying to send a single-shot RMT transmission will result in an error now, `RMT` deals with `u32` now, `PulseCode` is a convenience trait now (#2463) - Removed `get_` prefixes from functions (#2528) +- The `I8080` driver's constructor now only accepts blocking-mode DMA channels. (#2519) ### Fixed diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index 6211533dba6..0da8378e233 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -276,7 +276,9 @@ For example: } ``` -## Circular DMA transfer's `available` returns `Result` now +## DMA related changes + +### Circular DMA transfer's `available` returns `Result` now In case of any error you should drop the transfer and restart it. @@ -293,6 +295,22 @@ In case of any error you should drop the transfer and restart it. + }; ``` +### Channel, ChannelRx and ChannelTx types have changed + +- `Channel`'s `Async`/`Blocking` mode has been moved before the channel instance parameter. +- `ChannelRx` and `ChannelTx` have gained a new `Async`/`Blocking` mode parameter. + +```diff +-Channel<'d, DmaChannel0, Async> ++Channel<'d, Async, DmaChannel0> + +-ChannelRx<'d, DmaChannel0> ++ChannelRx<'d, Async, DmaChannel0> + +-ChannelTx<'d, DmaChannel0> ++ChannelTx<'d, Async, DmaChannel0> +``` + ## Removed `peripheral_input` and `into_peripheral_output` from GPIO pin types Creating peripheral interconnect signals now consume the GPIO pin used for the connection. @@ -357,7 +375,9 @@ refer to the `Config` struct as `uart::Config`. +) ``` -## I8080 driver split `set_byte_order()` into `set_8bits_order()` and `set_byte_order()`. +## I8080 changes + +### I8080 driver split `set_byte_order()` into `set_8bits_order()` and `set_byte_order()`. If you were using an 8-bit bus. @@ -371,6 +391,48 @@ If you were using an 16-bit bus, you don't need to change anything, `set_byte_or If you were sharing the bus between an 8-bit and 16-bit device, you will have to call the corresponding method when you switch between devices. Be sure to read the documentation of the new methods. +### Mixed mode constructor + +It is no longer possible to construct an `I8080` driver using a blocking-mode `Lcd` and an async-mode +DMA channel. Convert the DMA channel into blocking, or set up an async `LcdCam` first. + +```diff + let lcd_cam = LcdCam::new(peripherals.LCD_CAM); + let channel = ctx + .dma + .channel0 +- .configure(false, DmaPriority::Priority0) +- .into_async(); ++ .configure(false, DmaPriority::Priority0); + + let i8080 = I8080::new( + lcd_cam.lcd, + channel.tx, + pins, + 20.MHz(), + Config::default(), + ); +``` + +Or: + +```diff +-let lcd_cam = LcdCam::new(peripherals.LCD_CAM); ++let lcd_cam = LcdCam::new(peripherals.LCD_CAM).into_async(); + let channel = ctx + .dma + .channel0 + .into_async(); + + let i8080 = I8080::new( + lcd_cam.lcd, + channel.tx, + pins, + 20.MHz(), + Config::default(), + ); +``` + ## `rmt::Channel::transmit` now returns `Result`, `PulseCode` is now `u32` When trying to send a one-shot transmission will fail if it doesn't end with an end-marker. diff --git a/esp-hal/src/aes/mod.rs b/esp-hal/src/aes/mod.rs index 07356137159..34a14f03ce9 100644 --- a/esp-hal/src/aes/mod.rs +++ b/esp-hal/src/aes/mod.rs @@ -276,21 +276,21 @@ pub mod dma { /// The underlying [`Aes`](super::Aes) driver pub aes: super::Aes<'d>, - channel: Channel<'d, ::Dma, Blocking>, + channel: Channel<'d, Blocking, ::Dma>, rx_chain: DescriptorChain, tx_chain: DescriptorChain, } impl<'d> crate::aes::Aes<'d> { /// Enable DMA for the current instance of the AES driver - pub fn with_dma( + pub fn with_dma( self, - channel: Channel<'d, C, Blocking>, + channel: Channel<'d, Blocking, CH>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], ) -> AesDma<'d> where - C: DmaChannelConvert<::Dma>, + CH: DmaChannelConvert<::Dma>, { AesDma { aes: self, @@ -324,7 +324,7 @@ pub mod dma { } impl<'d> DmaSupportTx for AesDma<'d> { - type TX = ChannelTx<'d, ::Dma, Blocking>; + type TX = ChannelTx<'d, Blocking, ::Dma>; fn tx(&mut self) -> &mut Self::TX { &mut self.channel.tx @@ -336,7 +336,7 @@ pub mod dma { } impl<'d> DmaSupportRx for AesDma<'d> { - type RX = ChannelRx<'d, ::Dma, Blocking>; + type RX = ChannelRx<'d, Blocking, ::Dma>; 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 1fdb7534d13..21459966429 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -519,7 +519,7 @@ impl InterruptAccess for ChannelRxImpl { #[non_exhaustive] pub struct ChannelCreator {} -impl Channel<'_, CH, M> { +impl Channel<'_, M, CH> { /// Asserts that the channel is compatible with the given peripheral. pub fn runtime_ensure_compatible(&self, _peripheral: &PeripheralRef<'_, P>) { // No runtime checks; GDMA channels are compatible with any peripheral @@ -583,7 +583,7 @@ macro_rules! impl_channel { self, burst_mode: bool, priority: DmaPriority, - ) -> Channel<'a, [], Blocking> { + ) -> Channel<'a, Blocking, []> { let mut this = Channel { tx: ChannelTx::new(ChannelTxImpl(SpecificGdmaChannel::<$num> {})), rx: ChannelRx::new(ChannelRxImpl(SpecificGdmaChannel::<$num> {})), diff --git a/esp-hal/src/dma/m2m.rs b/esp-hal/src/dma/m2m.rs index dc2d5a54815..0b2009950eb 100644 --- a/esp-hal/src/dma/m2m.rs +++ b/esp-hal/src/dma/m2m.rs @@ -32,7 +32,7 @@ pub struct Mem2Mem<'d, M> where M: Mode, { - channel: Channel<'d, AnyGdmaChannel, M>, + channel: Channel<'d, M, AnyGdmaChannel>, rx_chain: DescriptorChain, tx_chain: DescriptorChain, peripheral: DmaPeripheral, @@ -41,7 +41,7 @@ where impl<'d> Mem2Mem<'d, Blocking> { /// Create a new Mem2Mem instance. pub fn new( - channel: Channel<'d, CH, DM>, + channel: Channel<'d, DM, CH>, peripheral: impl DmaEligible, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], @@ -49,7 +49,7 @@ impl<'d> Mem2Mem<'d, Blocking> { where CH: DmaChannelConvert, DM: Mode, - Channel<'d, CH, Blocking>: From>, + Channel<'d, Blocking, CH>: From>, { unsafe { Self::new_unsafe( @@ -64,7 +64,7 @@ impl<'d> Mem2Mem<'d, Blocking> { /// Create a new Mem2Mem instance with specific chunk size. pub fn new_with_chunk_size( - channel: Channel<'d, CH, DM>, + channel: Channel<'d, DM, CH>, peripheral: impl DmaEligible, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], @@ -73,7 +73,7 @@ impl<'d> Mem2Mem<'d, Blocking> { where CH: DmaChannelConvert, DM: Mode, - Channel<'d, CH, Blocking>: From>, + Channel<'d, Blocking, CH>: From>, { unsafe { Self::new_unsafe( @@ -93,7 +93,7 @@ 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, CH, DM>, + channel: Channel<'d, DM, CH>, peripheral: DmaPeripheral, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], @@ -102,7 +102,7 @@ impl<'d> Mem2Mem<'d, Blocking> { where CH: DmaChannelConvert, DM: Mode, - Channel<'d, CH, Blocking>: From>, + Channel<'d, Blocking, CH>: From>, { if !(1..=4092).contains(&chunk_size) { return Err(DmaError::InvalidChunkSize); @@ -111,7 +111,7 @@ impl<'d> Mem2Mem<'d, Blocking> { return Err(DmaError::OutOfDescriptors); } Ok(Mem2Mem { - channel: Channel::<_, Blocking>::from(channel).degrade(), + channel: Channel::::from(channel).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 +194,7 @@ impl<'d, M> DmaSupportRx for Mem2Mem<'d, M> where M: Mode, { - type RX = ChannelRx<'d, AnyGdmaChannel, M>; + type RX = ChannelRx<'d, M, AnyGdmaChannel>; 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 a49f53d83d9..2cda5bebda6 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -1660,17 +1660,16 @@ pub trait Rx: crate::private::Sealed { // DMA receive channel #[non_exhaustive] #[doc(hidden)] -pub struct ChannelRx<'a, CH, M> +pub struct ChannelRx<'a, M, CH> where CH: DmaChannel, { pub(crate) burst_mode: bool, pub(crate) rx_impl: CH::Rx, - pub(crate) mode: PhantomData, - pub(crate) _phantom: PhantomData<(&'a (), CH)>, + pub(crate) _phantom: PhantomData<(&'a (), CH, M)>, } -impl<'a, CH> ChannelRx<'a, CH, Blocking> +impl<'a, CH> ChannelRx<'a, Blocking, CH> where CH: DmaChannel, { @@ -1683,20 +1682,18 @@ where Self { burst_mode: false, rx_impl, - mode: PhantomData, _phantom: PhantomData, } } /// Converts a blocking channel to an async channel. - pub(crate) fn into_async(mut self) -> ChannelRx<'a, CH, Async> { + pub(crate) fn into_async(mut self) -> ChannelRx<'a, Async, CH> { if let Some(handler) = self.rx_impl.async_handler() { self.set_interrupt_handler(handler); } ChannelRx { burst_mode: false, rx_impl: self.rx_impl, - mode: PhantomData, _phantom: PhantomData, } } @@ -1718,39 +1715,37 @@ where } } -impl<'a, CH> ChannelRx<'a, CH, Async> +impl<'a, CH> ChannelRx<'a, Async, CH> where CH: DmaChannel, { /// Converts an async channel into a blocking channel. - pub(crate) fn into_blocking(self) -> ChannelRx<'a, CH, Blocking> { + pub(crate) fn into_blocking(self) -> ChannelRx<'a, Blocking, CH> { if let Some(interrupt) = self.rx_impl.peripheral_interrupt() { crate::interrupt::disable(Cpu::current(), interrupt); } ChannelRx { burst_mode: false, rx_impl: self.rx_impl, - mode: PhantomData, _phantom: PhantomData, } } } -impl<'a, CH, M> ChannelRx<'a, CH, M> +impl<'a, M, CH> ChannelRx<'a, M, CH> where - CH: DmaChannel, M: Mode, + CH: DmaChannel, { /// Return a less specific (degraded) version of this channel. #[doc(hidden)] - pub fn degrade(self) -> ChannelRx<'a, DEG, M> + pub fn degrade(self) -> ChannelRx<'a, M, DEG> where CH: DmaChannelConvert, { ChannelRx { burst_mode: self.burst_mode, rx_impl: CH::degrade_rx(self.rx_impl), - mode: PhantomData, _phantom: PhantomData, } } @@ -1762,17 +1757,17 @@ where } } -impl crate::private::Sealed for ChannelRx<'_, CH, M> +impl crate::private::Sealed for ChannelRx<'_, M, CH> where - CH: DmaChannel, M: Mode, + CH: DmaChannel, { } -impl Rx for ChannelRx<'_, CH, M> +impl Rx for ChannelRx<'_, M, CH> where - CH: DmaChannel, M: Mode, + CH: DmaChannel, { unsafe fn prepare_transfer_without_start( &mut self, @@ -1950,18 +1945,17 @@ pub trait Tx: crate::private::Sealed { /// DMA transmit channel #[doc(hidden)] -pub struct ChannelTx<'a, CH, M> +pub struct ChannelTx<'a, M, CH> where CH: DmaChannel, { #[allow(unused)] pub(crate) burst_mode: bool, pub(crate) tx_impl: CH::Tx, - pub(crate) mode: PhantomData, - pub(crate) _phantom: PhantomData<(&'a (), CH)>, + pub(crate) _phantom: PhantomData<(&'a (), CH, M)>, } -impl<'a, CH> ChannelTx<'a, CH, Blocking> +impl<'a, CH> ChannelTx<'a, Blocking, CH> where CH: DmaChannel, { @@ -1969,20 +1963,18 @@ where Self { burst_mode: false, tx_impl, - mode: PhantomData, _phantom: PhantomData, } } /// Converts a blocking channel to an async channel. - pub(crate) fn into_async(mut self) -> ChannelTx<'a, CH, Async> { + pub(crate) fn into_async(mut self) -> ChannelTx<'a, Async, CH> { if let Some(handler) = self.tx_impl.async_handler() { self.set_interrupt_handler(handler); } ChannelTx { burst_mode: false, tx_impl: self.tx_impl, - mode: PhantomData, _phantom: PhantomData, } } @@ -2004,39 +1996,37 @@ where } } -impl<'a, CH> ChannelTx<'a, CH, Async> +impl<'a, CH> ChannelTx<'a, Async, CH> where CH: DmaChannel, { /// Converts an async channel into a blocking channel. - pub(crate) fn into_blocking(self) -> ChannelTx<'a, CH, Blocking> { + pub(crate) fn into_blocking(self) -> ChannelTx<'a, Blocking, CH> { if let Some(interrupt) = self.tx_impl.peripheral_interrupt() { crate::interrupt::disable(Cpu::current(), interrupt); } ChannelTx { burst_mode: false, tx_impl: self.tx_impl, - mode: PhantomData, _phantom: PhantomData, } } } -impl<'a, CH, M> ChannelTx<'a, CH, M> +impl<'a, M, CH> ChannelTx<'a, M, CH> where - CH: DmaChannel, M: Mode, + CH: DmaChannel, { /// Return a less specific (degraded) version of this channel. #[doc(hidden)] - pub fn degrade(self) -> ChannelTx<'a, DEG, M> + pub fn degrade(self) -> ChannelTx<'a, M, DEG> where CH: DmaChannelConvert, { ChannelTx { burst_mode: self.burst_mode, tx_impl: CH::degrade_tx(self.tx_impl), - mode: PhantomData, _phantom: PhantomData, } } @@ -2048,17 +2038,17 @@ where } } -impl crate::private::Sealed for ChannelTx<'_, CH, M> +impl crate::private::Sealed for ChannelTx<'_, M, CH> where - CH: DmaChannel, M: Mode, + CH: DmaChannel, { } -impl Tx for ChannelTx<'_, CH, M> +impl Tx for ChannelTx<'_, M, CH> where - CH: DmaChannel, M: Mode, + CH: DmaChannel, { unsafe fn prepare_transfer_without_start( &mut self, @@ -2272,27 +2262,27 @@ pub trait InterruptAccess: crate::private::Sealed { } /// DMA Channel -pub struct Channel<'d, CH, M> +pub struct Channel<'d, M, CH> where - CH: DmaChannel, M: Mode, + CH: DmaChannel, { /// RX half of the channel - pub rx: ChannelRx<'d, CH, M>, + pub rx: ChannelRx<'d, M, CH>, /// TX half of the channel - pub tx: ChannelTx<'d, CH, M>, + pub tx: ChannelTx<'d, M, CH>, } -impl<'d, C> Channel<'d, C, Blocking> +impl<'d, CH> Channel<'d, Blocking, CH> where - C: DmaChannel, + CH: DmaChannel, { /// 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 - C: DmaChannel, + CH: DmaChannel, { self.rx.set_interrupt_handler(handler); self.tx.set_interrupt_handler(handler); @@ -2347,7 +2337,7 @@ where } /// Converts a blocking channel to an async channel. - pub fn into_async(self) -> Channel<'d, C, Async> { + pub fn into_async(self) -> Channel<'d, Async, CH> { Channel { rx: self.rx.into_async(), tx: self.tx.into_async(), @@ -2355,12 +2345,12 @@ where } } -impl<'d, C> Channel<'d, C, Async> +impl<'d, CH> Channel<'d, Async, CH> where - C: DmaChannel, + CH: DmaChannel, { /// Converts an async channel to a blocking channel. - pub fn into_blocking(self) -> Channel<'d, C, Blocking> { + pub fn into_blocking(self) -> Channel<'d, Blocking, CH> { Channel { rx: self.rx.into_blocking(), tx: self.tx.into_blocking(), @@ -2368,26 +2358,27 @@ where } } -impl<'d, C: DmaChannel> From> for Channel<'d, C, Async> { - fn from(channel: Channel<'d, C, Blocking>) -> Self { +impl<'d, CH: DmaChannel> From> for Channel<'d, Async, CH> { + fn from(channel: Channel<'d, Blocking, CH>) -> Self { channel.into_async() } } -impl<'d, C: DmaChannel> From> for Channel<'d, C, Blocking> { - fn from(channel: Channel<'d, C, Async>) -> Self { +impl<'d, CH: DmaChannel> From> for Channel<'d, Blocking, CH> { + fn from(channel: Channel<'d, Async, CH>) -> Self { channel.into_blocking() } } -impl<'d, CH, M: Mode> Channel<'d, CH, M> +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, DEG, M> + pub fn degrade(self) -> Channel<'d, M, DEG> where CH: DmaChannelConvert, { diff --git a/esp-hal/src/dma/pdma.rs b/esp-hal/src/dma/pdma.rs index 35f8425d698..776ea57fd07 100644 --- a/esp-hal/src/dma/pdma.rs +++ b/esp-hal/src/dma/pdma.rs @@ -425,7 +425,7 @@ macro_rules! ImplSpiChannel { self, burst_mode: bool, priority: DmaPriority, - ) -> Channel<'a, [], Blocking> { + ) -> Channel<'a, Blocking, []> { let mut this = Channel { tx: ChannelTx::new(SpiDmaTxChannelImpl([] {})), rx: ChannelRx::new(SpiDmaRxChannelImpl([] {})), @@ -839,7 +839,7 @@ macro_rules! ImplI2sChannel { self, burst_mode: bool, priority: DmaPriority, - ) -> Channel<'a, [], Blocking> { + ) -> Channel<'a, Blocking, []> { let mut this = Channel { tx: ChannelTx::new(I2sDmaTxChannelImpl([] {})), rx: ChannelRx::new(I2sDmaRxChannelImpl([] {})), @@ -917,9 +917,10 @@ impl<'d> Dma<'d> { } } -impl<'d, C, M: Mode> Channel<'d, C, M> +impl<'d, CH, M> Channel<'d, M, CH> where - C: DmaChannel, + CH: DmaChannel, + M: Mode, { /// Asserts that the channel is compatible with the given peripheral. pub fn runtime_ensure_compatible(&self, peripheral: &PeripheralRef<'_, impl DmaEligible>) { diff --git a/esp-hal/src/i2s/master.rs b/esp-hal/src/i2s/master.rs index aad2f309191..111596ae9ff 100644 --- a/esp-hal/src/i2s/master.rs +++ b/esp-hal/src/i2s/master.rs @@ -272,7 +272,7 @@ where standard: Standard, data_format: DataFormat, sample_rate: impl Into, - channel: Channel<'d, CH, DmaMode>, + channel: Channel<'d, DmaMode, CH>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], ) -> Self @@ -371,14 +371,14 @@ impl<'d> I2s<'d, Blocking> { standard: Standard, data_format: DataFormat, sample_rate: impl Into, - channel: Channel<'d, CH, DM>, + channel: Channel<'d, DM, CH>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], ) -> Self where CH: DmaChannelConvert<::Dma>, DM: Mode, - Channel<'d, CH, Blocking>: From>, + Channel<'d, Blocking, CH>: From>, { Self::new_typed( i2s.map_into(), @@ -404,14 +404,14 @@ where standard: Standard, data_format: DataFormat, sample_rate: impl Into, - channel: Channel<'d, CH, DM>, + channel: Channel<'d, DM, CH>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], ) -> Self where CH: DmaChannelConvert, DM: Mode, - Channel<'d, CH, Blocking>: From>, + Channel<'d, Blocking, CH>: From>, { crate::into_ref!(i2s); Self::new_internal( @@ -463,7 +463,7 @@ where T: RegisterAccess, { i2s: PeripheralRef<'d, T>, - tx_channel: ChannelTx<'d, T::Dma, DmaMode>, + tx_channel: ChannelTx<'d, DmaMode, T::Dma>, tx_chain: DescriptorChain, } @@ -496,7 +496,7 @@ where T: RegisterAccess, DmaMode: Mode, { - type TX = ChannelTx<'d, T::Dma, DmaMode>; + type TX = ChannelTx<'d, DmaMode, T::Dma>; fn tx(&mut self) -> &mut Self::TX { &mut self.tx_channel @@ -595,7 +595,7 @@ where DmaMode: Mode, { i2s: PeripheralRef<'d, T>, - rx_channel: ChannelRx<'d, T::Dma, DmaMode>, + rx_channel: ChannelRx<'d, DmaMode, T::Dma>, rx_chain: DescriptorChain, } @@ -628,7 +628,7 @@ where T: RegisterAccess, DmaMode: Mode, { - type RX = ChannelRx<'d, T::Dma, DmaMode>; + type RX = ChannelRx<'d, DmaMode, T::Dma>; fn rx(&mut self) -> &mut Self::RX { &mut self.rx_channel @@ -772,7 +772,7 @@ mod private { M: Mode, { pub i2s: PeripheralRef<'d, T>, - pub tx_channel: ChannelTx<'d, T::Dma, M>, + pub tx_channel: ChannelTx<'d, M, T::Dma>, pub descriptors: &'static mut [DmaDescriptor], } @@ -829,7 +829,7 @@ mod private { M: Mode, { pub i2s: PeripheralRef<'d, T>, - pub rx_channel: ChannelRx<'d, T::Dma, M>, + pub rx_channel: ChannelRx<'d, M, T::Dma>, pub descriptors: &'static mut [DmaDescriptor], } diff --git a/esp-hal/src/i2s/parallel.rs b/esp-hal/src/i2s/parallel.rs index dce4ae1a3d1..c7b84e630ce 100644 --- a/esp-hal/src/i2s/parallel.rs +++ b/esp-hal/src/i2s/parallel.rs @@ -176,7 +176,7 @@ where I: Instance, { instance: PeripheralRef<'d, I>, - tx_channel: ChannelTx<'d, I::Dma, DM>, + tx_channel: ChannelTx<'d, DM, I::Dma>, } impl<'d, DM> I2sParallel<'d, DM> @@ -186,7 +186,7 @@ where /// Create a new I2S Parallel Interface pub fn new( i2s: impl Peripheral

+ 'd, - channel: Channel<'d, CH, DM>, + channel: Channel<'d, DM, CH>, frequency: impl Into, pins: impl TxPins<'d>, clock_pin: impl Peripheral

+ 'd, @@ -206,7 +206,7 @@ where /// Create a new I2S Parallel Interface pub fn new_typed( i2s: impl Peripheral

+ 'd, - channel: Channel<'d, CH, DM>, + channel: Channel<'d, DM, CH>, frequency: impl Into, mut pins: impl TxPins<'d>, clock_pin: impl Peripheral

+ 'd, diff --git a/esp-hal/src/lcd_cam/cam.rs b/esp-hal/src/lcd_cam/cam.rs index a16e2adc24c..358643e871e 100644 --- a/esp-hal/src/lcd_cam/cam.rs +++ b/esp-hal/src/lcd_cam/cam.rs @@ -126,14 +126,14 @@ 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, ::Dma, Blocking>, + rx_channel: ChannelRx<'d, Blocking, ::Dma>, } impl<'d> Camera<'d> { /// Creates a new `Camera` instance with DMA support. pub fn new( cam: Cam<'d>, - channel: ChannelRx<'d, CH, Blocking>, + channel: ChannelRx<'d, Blocking, CH>, _pins: P, frequency: HertzU32, ) -> Self diff --git a/esp-hal/src/lcd_cam/lcd/i8080.rs b/esp-hal/src/lcd_cam/lcd/i8080.rs index 9cbf41290ef..bfc7465a623 100644 --- a/esp-hal/src/lcd_cam/lcd/i8080.rs +++ b/esp-hal/src/lcd_cam/lcd/i8080.rs @@ -90,7 +90,7 @@ use crate::{ /// Represents the I8080 LCD interface. pub struct I8080<'d, DM: Mode> { lcd_cam: PeripheralRef<'d, LCD_CAM>, - tx_channel: ChannelTx<'d, ::Dma, Blocking>, + tx_channel: ChannelTx<'d, Blocking, ::Dma>, _mode: PhantomData, } @@ -101,7 +101,7 @@ where /// Creates a new instance of the I8080 LCD interface. pub fn new( lcd: Lcd<'d, DM>, - channel: ChannelTx<'d, CH, Blocking>, + channel: ChannelTx<'d, Blocking, CH>, mut pins: P, frequency: HertzU32, config: Config, diff --git a/esp-hal/src/parl_io.rs b/esp-hal/src/parl_io.rs index f1f2a8c35a9..1b81ca2901e 100644 --- a/esp-hal/src/parl_io.rs +++ b/esp-hal/src/parl_io.rs @@ -23,8 +23,6 @@ //! //! [Parallel IO TX]: https://github.com/esp-rs/esp-hal/blob/main/examples/src/bin/parl_io_tx.rs -use core::marker::PhantomData; - use enumset::{EnumSet, EnumSetType}; use fugit::HertzU32; use peripheral::PeripheralRef; @@ -769,7 +767,6 @@ where Ok(ParlIoTx { tx_channel: self.tx_channel, tx_chain: DescriptorChain::new(self.descriptors), - phantom: PhantomData, }) } } @@ -801,7 +798,6 @@ where Ok(ParlIoTx { tx_channel: self.tx_channel, tx_chain: DescriptorChain::new(self.descriptors), - phantom: PhantomData, }) } } @@ -811,9 +807,8 @@ pub struct ParlIoTx<'d, DM> where DM: Mode, { - tx_channel: ChannelTx<'d, ::Dma, DM>, + tx_channel: ChannelTx<'d, DM, ::Dma>, tx_chain: DescriptorChain, - phantom: PhantomData, } impl core::fmt::Debug for ParlIoTx<'_, DM> @@ -850,7 +845,6 @@ where Ok(ParlIoRx { rx_channel: self.rx_channel, rx_chain: DescriptorChain::new(self.descriptors), - phantom: PhantomData, }) } } @@ -880,7 +874,6 @@ where Ok(ParlIoRx { rx_channel: self.rx_channel, rx_chain: DescriptorChain::new(self.descriptors), - phantom: PhantomData, }) } } @@ -890,9 +883,8 @@ pub struct ParlIoRx<'d, DM> where DM: Mode, { - rx_channel: ChannelRx<'d, ::Dma, DM>, + rx_channel: ChannelRx<'d, DM, ::Dma>, rx_chain: DescriptorChain, - phantom: PhantomData, } impl core::fmt::Debug for ParlIoRx<'_, DM> @@ -1005,7 +997,7 @@ impl<'d> ParlIoFullDuplex<'d, Blocking> { /// Create a new instance of [ParlIoFullDuplex] pub fn new( _parl_io: impl Peripheral

+ 'd, - dma_channel: Channel<'d, CH, DM>, + dma_channel: Channel<'d, DM, CH>, tx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor], frequency: HertzU32, @@ -1013,21 +1005,19 @@ impl<'d> ParlIoFullDuplex<'d, Blocking> { where DM: Mode, CH: DmaChannelConvert<::Dma>, - Channel<'d, CH, Blocking>: From>, + Channel<'d, Blocking, CH>: From>, { - let dma_channel = Channel::<'d, CH, Blocking>::from(dma_channel); + let dma_channel = Channel::::from(dma_channel); internal_init(frequency)?; Ok(Self { tx: TxCreatorFullDuplex { tx_channel: dma_channel.tx.degrade(), descriptors: tx_descriptors, - phantom: PhantomData, }, rx: RxCreatorFullDuplex { rx_channel: dma_channel.rx.degrade(), descriptors: rx_descriptors, - phantom: PhantomData, }, }) } @@ -1038,12 +1028,10 @@ impl<'d> ParlIoFullDuplex<'d, Blocking> { tx: TxCreatorFullDuplex { tx_channel: self.tx.tx_channel.into_async(), descriptors: self.tx.descriptors, - phantom: PhantomData, }, rx: RxCreatorFullDuplex { rx_channel: self.rx.rx_channel.into_async(), descriptors: self.rx.descriptors, - phantom: PhantomData, }, } } @@ -1092,12 +1080,10 @@ impl<'d> ParlIoFullDuplex<'d, Async> { tx: TxCreatorFullDuplex { tx_channel: self.tx.tx_channel.into_blocking(), descriptors: self.tx.descriptors, - phantom: PhantomData, }, rx: RxCreatorFullDuplex { rx_channel: self.rx.rx_channel.into_blocking(), descriptors: self.rx.descriptors, - phantom: PhantomData, }, } } @@ -1121,7 +1107,7 @@ where // TODO: only take a TX DMA channel? pub fn new( _parl_io: impl Peripheral

+ 'd, - dma_channel: Channel<'d, CH, DM>, + dma_channel: Channel<'d, DM, CH>, descriptors: &'static mut [DmaDescriptor], frequency: HertzU32, ) -> Result @@ -1134,7 +1120,6 @@ where tx: TxCreator { tx_channel: dma_channel.tx.degrade(), descriptors, - phantom: PhantomData, }, }) } @@ -1196,7 +1181,7 @@ where // TODO: only take a RX DMA channel? pub fn new( _parl_io: impl Peripheral

+ 'd, - dma_channel: Channel<'d, CH, DM>, + dma_channel: Channel<'d, DM, CH>, descriptors: &'static mut [DmaDescriptor], frequency: HertzU32, ) -> Result @@ -1209,7 +1194,6 @@ where rx: RxCreator { rx_channel: dma_channel.rx.degrade(), descriptors, - phantom: PhantomData, }, }) } @@ -1360,7 +1344,7 @@ impl<'d, DM> DmaSupportTx for ParlIoTx<'d, DM> where DM: Mode, { - type TX = ChannelTx<'d, ::Dma, DM>; + type TX = ChannelTx<'d, DM, ::Dma>; fn tx(&mut self) -> &mut Self::TX { &mut self.tx_channel @@ -1402,7 +1386,7 @@ where } fn start_receive_bytes_dma( - rx_channel: &mut ChannelRx<'d, ::Dma, DM>, + rx_channel: &mut ChannelRx<'d, DM, ::Dma>, rx_chain: &mut DescriptorChain, ptr: *mut u8, len: usize, @@ -1456,7 +1440,7 @@ impl<'d, DM> DmaSupportRx for ParlIoRx<'d, DM> where DM: Mode, { - type RX = ChannelRx<'d, ::Dma, DM>; + type RX = ChannelRx<'d, DM, ::Dma>; fn rx(&mut self) -> &mut Self::RX { &mut self.rx_channel @@ -1472,9 +1456,8 @@ pub struct TxCreator<'d, DM> where DM: Mode, { - tx_channel: ChannelTx<'d, ::Dma, DM>, + tx_channel: ChannelTx<'d, DM, ::Dma>, descriptors: &'static mut [DmaDescriptor], - phantom: PhantomData, } /// Creates a RX channel @@ -1482,9 +1465,8 @@ pub struct RxCreator<'d, DM> where DM: Mode, { - rx_channel: ChannelRx<'d, ::Dma, DM>, + rx_channel: ChannelRx<'d, DM, ::Dma>, descriptors: &'static mut [DmaDescriptor], - phantom: PhantomData, } /// Creates a TX channel @@ -1492,9 +1474,8 @@ pub struct TxCreatorFullDuplex<'d, DM> where DM: Mode, { - tx_channel: ChannelTx<'d, ::Dma, DM>, + tx_channel: ChannelTx<'d, DM, ::Dma>, descriptors: &'static mut [DmaDescriptor], - phantom: PhantomData, } /// Creates a RX channel @@ -1502,9 +1483,8 @@ pub struct RxCreatorFullDuplex<'d, DM> where DM: Mode, { - rx_channel: ChannelRx<'d, ::Dma, DM>, + rx_channel: ChannelRx<'d, DM, ::Dma>, descriptors: &'static mut [DmaDescriptor], - phantom: PhantomData, } #[doc(hidden)] diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index ba2b5080a94..2bc93c5d61c 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -474,11 +474,11 @@ where /// 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, CH, DM>) -> SpiDma<'d, M, T> + pub fn with_dma(self, channel: Channel<'d, DM, CH>) -> SpiDma<'d, M, T> where CH: DmaChannelConvert, DM: Mode, - Channel<'d, CH, M>: From>, + Channel<'d, M, CH>: From>, { SpiDma::new(self.spi, channel.into()) } @@ -880,7 +880,7 @@ mod dma { M: Mode, { pub(crate) spi: PeripheralRef<'d, T>, - pub(crate) channel: Channel<'d, T::Dma, M>, + pub(crate) channel: Channel<'d, M, T::Dma>, tx_transfer_in_progress: bool, rx_transfer_in_progress: bool, #[cfg(all(esp32, spi_address_workaround))] @@ -990,7 +990,7 @@ mod dma { T: Instance, M: Mode, { - pub(super) fn new(spi: PeripheralRef<'d, T>, channel: Channel<'d, CH, M>) -> Self + pub(super) fn new(spi: PeripheralRef<'d, T>, channel: Channel<'d, M, CH>) -> Self where CH: DmaChannelConvert, { diff --git a/esp-hal/src/spi/slave.rs b/esp-hal/src/spi/slave.rs index 93af03ae7e7..7e00288f48f 100644 --- a/esp-hal/src/spi/slave.rs +++ b/esp-hal/src/spi/slave.rs @@ -202,14 +202,14 @@ pub mod dma { #[cfg_attr(esp32, doc = "\n\n**Note**: ESP32 only supports Mode 1 and 3.")] pub fn with_dma( self, - channel: Channel<'d, CH, DM>, + channel: Channel<'d, DM, CH>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], ) -> SpiDma<'d, M, T> where CH: DmaChannelConvert, DM: Mode, - Channel<'d, CH, M>: From>, + Channel<'d, M, CH>: From>, { self.spi.info().set_data_mode(self.data_mode, true); SpiDma::new(self.spi, channel.into(), rx_descriptors, tx_descriptors) @@ -223,7 +223,7 @@ pub mod dma { M: Mode, { pub(crate) spi: PeripheralRef<'d, T>, - pub(crate) channel: Channel<'d, T::Dma, M>, + pub(crate) channel: Channel<'d, M, T::Dma>, rx_chain: DescriptorChain, tx_chain: DescriptorChain, } @@ -262,7 +262,7 @@ pub mod dma { T: InstanceDma, DmaMode: Mode, { - type TX = ChannelTx<'d, T::Dma, DmaMode>; + type TX = ChannelTx<'d, DmaMode, T::Dma>; fn tx(&mut self) -> &mut Self::TX { &mut self.channel.tx @@ -278,7 +278,7 @@ pub mod dma { T: InstanceDma, DmaMode: Mode, { - type RX = ChannelRx<'d, T::Dma, DmaMode>; + type RX = ChannelRx<'d, DmaMode, T::Dma>; fn rx(&mut self) -> &mut Self::RX { &mut self.channel.rx @@ -296,7 +296,7 @@ pub mod dma { { fn new( spi: PeripheralRef<'d, T>, - channel: Channel<'d, CH, DmaMode>, + channel: Channel<'d, DmaMode, CH>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], ) -> Self diff --git a/hil-test/tests/dma_mem2mem.rs b/hil-test/tests/dma_mem2mem.rs index f65873ae6c5..d9a3a362be3 100644 --- a/hil-test/tests/dma_mem2mem.rs +++ b/hil-test/tests/dma_mem2mem.rs @@ -25,7 +25,7 @@ cfg_if::cfg_if! { } struct Context { - channel: Channel<'static, AnyGdmaChannel, Blocking>, + channel: Channel<'static, Blocking, AnyGdmaChannel>, dma_peripheral: DmaPeripheralType, } diff --git a/hil-test/tests/qspi.rs b/hil-test/tests/qspi.rs index c2f69b9ebdf..43b500d9a7a 100644 --- a/hil-test/tests/qspi.rs +++ b/hil-test/tests/qspi.rs @@ -43,7 +43,7 @@ struct Context { spi: Spi<'static, Blocking>, #[cfg(pcnt)] pcnt: esp_hal::peripherals::PCNT, - dma_channel: Channel<'static, DmaChannel0, Blocking>, + dma_channel: Channel<'static, Blocking, DmaChannel0>, gpios: [AnyPin; 3], } From 74e2548c660801952700e2b066fab2f6cf4804a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 12 Nov 2024 19:45:12 +0100 Subject: [PATCH 03/13] Separate IN/OUT handlers --- esp-hal/src/dma/gdma.rs | 16 ++--- esp-hal/src/dma/mod.rs | 128 ++++++++++++++++++++++------------------ 2 files changed, 79 insertions(+), 65 deletions(-) diff --git a/esp-hal/src/dma/gdma.rs b/esp-hal/src/dma/gdma.rs index 21459966429..2a45c50f37b 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -611,16 +611,16 @@ cfg_if::cfg_if! { impl_channel!(2, DMA_CH2, asynch_handler::interrupt_handler_ch2); } else if #[cfg(any(esp32c6, esp32h2))] { const CHANNEL_COUNT: usize = 3; - impl_channel!(0, DMA_IN_CH0, asynch_handler::interrupt_handler_ch0, DMA_OUT_CH0, asynch_handler::interrupt_handler_ch0); - impl_channel!(1, DMA_IN_CH1, asynch_handler::interrupt_handler_ch1, DMA_OUT_CH1, asynch_handler::interrupt_handler_ch1); - impl_channel!(2, DMA_IN_CH2, asynch_handler::interrupt_handler_ch2, DMA_OUT_CH2, asynch_handler::interrupt_handler_ch2); + impl_channel!(0, DMA_IN_CH0, asynch_handler::interrupt_handler_in_ch0, DMA_OUT_CH0, asynch_handler::interrupt_handler_out_ch0); + impl_channel!(1, DMA_IN_CH1, asynch_handler::interrupt_handler_in_ch1, DMA_OUT_CH1, asynch_handler::interrupt_handler_out_ch1); + impl_channel!(2, DMA_IN_CH2, asynch_handler::interrupt_handler_in_ch2, DMA_OUT_CH2, asynch_handler::interrupt_handler_out_ch2); } else if #[cfg(esp32s3)] { const CHANNEL_COUNT: usize = 5; - impl_channel!(0, DMA_IN_CH0, asynch_handler::interrupt_handler_ch0, DMA_OUT_CH0, asynch_handler::interrupt_handler_ch0); - impl_channel!(1, DMA_IN_CH1, asynch_handler::interrupt_handler_ch1, DMA_OUT_CH1, asynch_handler::interrupt_handler_ch1); - impl_channel!(2, DMA_IN_CH2, asynch_handler::interrupt_handler_ch2, DMA_OUT_CH2, asynch_handler::interrupt_handler_ch2); - impl_channel!(3, DMA_IN_CH3, asynch_handler::interrupt_handler_ch3, DMA_OUT_CH3, asynch_handler::interrupt_handler_ch3); - impl_channel!(4, DMA_IN_CH4, asynch_handler::interrupt_handler_ch4, DMA_OUT_CH4, asynch_handler::interrupt_handler_ch4); + impl_channel!(0, DMA_IN_CH0, asynch_handler::interrupt_handler_in_ch0, DMA_OUT_CH0, asynch_handler::interrupt_handler_out_ch0); + impl_channel!(1, DMA_IN_CH1, asynch_handler::interrupt_handler_in_ch1, DMA_OUT_CH1, asynch_handler::interrupt_handler_out_ch1); + impl_channel!(2, DMA_IN_CH2, asynch_handler::interrupt_handler_in_ch2, DMA_OUT_CH2, asynch_handler::interrupt_handler_out_ch2); + impl_channel!(3, DMA_IN_CH3, asynch_handler::interrupt_handler_in_ch3, DMA_OUT_CH3, asynch_handler::interrupt_handler_out_ch3); + impl_channel!(4, DMA_IN_CH4, asynch_handler::interrupt_handler_in_ch4, DMA_OUT_CH4, asynch_handler::interrupt_handler_out_ch4); } } diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index 2cda5bebda6..483061105e8 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -2982,9 +2982,8 @@ pub(crate) mod asynch { } } - fn handle_interrupt() { + fn handle_in_interrupt() { let rx = CH::rx_interrupts(); - let tx = CH::tx_interrupts(); if rx.pending_interrupts().is_disjoint( DmaRxInterrupt::DescriptorError @@ -3001,16 +3000,6 @@ pub(crate) mod asynch { rx.waker().wake() } - if tx - .pending_interrupts() - .contains(DmaTxInterrupt::DescriptorError) - { - tx.unlisten( - DmaTxInterrupt::DescriptorError | DmaTxInterrupt::TotalEof | DmaTxInterrupt::Done, - ); - tx.waker().wake() - } - if rx .pending_interrupts() .contains(DmaRxInterrupt::SuccessfulEof) @@ -3023,6 +3012,20 @@ pub(crate) mod asynch { rx.unlisten(DmaRxInterrupt::Done); rx.waker().wake() } + } + + fn handle_out_interrupt() { + let tx = CH::tx_interrupts(); + + if tx + .pending_interrupts() + .contains(DmaTxInterrupt::DescriptorError) + { + tx.unlisten( + DmaTxInterrupt::DescriptorError | DmaTxInterrupt::TotalEof | DmaTxInterrupt::Done, + ); + tx.waker().wake() + } if tx.pending_interrupts().contains(DmaTxInterrupt::TotalEof) && tx.is_listening().contains(DmaTxInterrupt::TotalEof) @@ -3037,69 +3040,80 @@ pub(crate) mod asynch { } } - #[cfg(not(any(esp32, esp32s2)))] + #[cfg(gdma)] pub(crate) mod interrupt { - use procmacros::handler; - use super::*; - - #[handler(priority = crate::interrupt::Priority::max())] - pub(crate) fn interrupt_handler_ch0() { - handle_interrupt::(); + use crate::{interrupt::Priority, macros::handler}; + + // Single interrupt handler for IN and OUT + // TODO: add a global flag to only call the half that is configured for async + #[cfg(any(esp32c2, esp32c3))] + macro_rules! interrupt_handler { + ($ch:literal) => { + paste::paste! { + #[handler(priority = Priority::max())] + pub(crate) fn []() { + handle_in_interrupt::<[< DmaChannel $ch >]>(); + handle_out_interrupt::<[< DmaChannel $ch >]>(); + } + } + }; } - #[cfg(not(esp32c2))] - #[handler(priority = crate::interrupt::Priority::max())] - pub(crate) fn interrupt_handler_ch1() { - handle_interrupt::(); - } + #[cfg(not(any(esp32c2, esp32c3)))] + macro_rules! interrupt_handler { + ($ch:literal) => { + paste::paste! { + #[handler(priority = Priority::max())] + pub(crate) fn []() { + handle_in_interrupt::<[< DmaChannel $ch >]>(); + } - #[cfg(not(esp32c2))] - #[handler(priority = crate::interrupt::Priority::max())] - pub(crate) fn interrupt_handler_ch2() { - handle_interrupt::(); + #[handler(priority = Priority::max())] + pub(crate) fn []() { + handle_out_interrupt::<[< DmaChannel $ch >]>(); + } + } + }; } + interrupt_handler!(0); + #[cfg(not(esp32c2))] + interrupt_handler!(1); + #[cfg(not(esp32c2))] + interrupt_handler!(2); #[cfg(esp32s3)] - #[handler(priority = crate::interrupt::Priority::max())] - pub(crate) fn interrupt_handler_ch3() { - handle_interrupt::(); - } - + interrupt_handler!(3); #[cfg(esp32s3)] - #[handler(priority = crate::interrupt::Priority::max())] - pub(crate) fn interrupt_handler_ch4() { - handle_interrupt::(); - } + interrupt_handler!(4); } - #[cfg(any(esp32, esp32s2))] + #[cfg(pdma)] pub(crate) mod interrupt { - use procmacros::handler; - use super::*; - - #[handler(priority = crate::interrupt::Priority::max())] - pub(crate) fn interrupt_handler_spi2_dma() { - handle_interrupt::(); + use crate::{interrupt::Priority, macros::handler}; + + // Single interrupt handler for IN and OUT + // TODO: add a global flag to only call the half that is configured for async + macro_rules! interrupt_handler { + ($ch:ident) => { + paste::paste! { + #[handler(priority = Priority::max())] + pub(crate) fn []() { + handle_in_interrupt::<[< $ch DmaChannel >]>(); + handle_out_interrupt::<[< $ch DmaChannel >]>(); + } + } + }; } + interrupt_handler!(Spi2); #[cfg(spi3)] - #[handler(priority = crate::interrupt::Priority::max())] - pub(crate) fn interrupt_handler_spi3_dma() { - handle_interrupt::(); - } + interrupt_handler!(Spi3); #[cfg(i2s0)] - #[handler(priority = crate::interrupt::Priority::max())] - pub(crate) fn interrupt_handler_i2s0_dma() { - handle_interrupt::(); - } - + interrupt_handler!(I2s0); #[cfg(i2s1)] - #[handler(priority = crate::interrupt::Priority::max())] - pub(crate) fn interrupt_handler_i2s1_dma() { - handle_interrupt::(); - } + interrupt_handler!(I2s1); } } From c44fa0272b0b38d96c90c198e35368d180cddc13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 12 Nov 2024 19:58:09 +0100 Subject: [PATCH 04/13] Split DMA IN/OUT handlers --- esp-hal/src/dma/gdma.rs | 44 +++++++++++++++++++++++++ esp-hal/src/dma/mod.rs | 15 +++++++++ esp-hal/src/dma/pdma.rs | 71 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 122 insertions(+), 8 deletions(-) diff --git a/esp-hal/src/dma/gdma.rs b/esp-hal/src/dma/gdma.rs index 2a45c50f37b..8c2ca9a2468 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -121,6 +121,14 @@ use embassy_sync::waitqueue::AtomicWaker; static TX_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT]; static RX_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT]; +cfg_if::cfg_if! { + if #[cfg(any(esp32c2, esp32c3))] { + use portable_atomic::AtomicBool; + static TX_IS_ASYNC: [AtomicBool; CHANNEL_COUNT] = [const { AtomicBool::new(false) }; CHANNEL_COUNT]; + static RX_IS_ASYNC: [AtomicBool; CHANNEL_COUNT] = [const { AtomicBool::new(false) }; CHANNEL_COUNT]; + } +} + impl crate::private::Sealed for ChannelTxImpl {} impl ChannelTxImpl { @@ -314,6 +322,24 @@ impl InterruptAccess for ChannelTxImpl { fn waker(&self) -> &'static AtomicWaker { &TX_WAKERS[self.0.number() 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) + } else { + true + } + } + } + + 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); + } + } + } } #[non_exhaustive] @@ -513,6 +539,24 @@ impl InterruptAccess for ChannelRxImpl { fn waker(&self) -> &'static AtomicWaker { &RX_WAKERS[self.0.number() 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) + } else { + true + } + } + } + + 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); + } + } + } } /// A Channel can be created from this diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index 483061105e8..f08cd0df3dc 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -1691,6 +1691,7 @@ where if let Some(handler) = self.rx_impl.async_handler() { self.set_interrupt_handler(handler); } + self.rx_impl.set_async(true); ChannelRx { burst_mode: false, rx_impl: self.rx_impl, @@ -1724,6 +1725,7 @@ where if let Some(interrupt) = self.rx_impl.peripheral_interrupt() { crate::interrupt::disable(Cpu::current(), interrupt); } + self.rx_impl.set_async(false); ChannelRx { burst_mode: false, rx_impl: self.rx_impl, @@ -1972,6 +1974,7 @@ where if let Some(handler) = self.tx_impl.async_handler() { self.set_interrupt_handler(handler); } + self.tx_impl.set_async(true); ChannelTx { burst_mode: false, tx_impl: self.tx_impl, @@ -2005,6 +2008,7 @@ where if let Some(interrupt) = self.tx_impl.peripheral_interrupt() { crate::interrupt::disable(Cpu::current(), interrupt); } + self.tx_impl.set_async(false); ChannelTx { burst_mode: false, tx_impl: self.tx_impl, @@ -2259,6 +2263,9 @@ pub trait InterruptAccess: crate::private::Sealed { fn clear(&self, interrupts: impl Into>); fn pending_interrupts(&self) -> EnumSet; fn waker(&self) -> &'static embassy_sync::waitqueue::AtomicWaker; + + fn is_async(&self) -> bool; + fn set_async(&self, is_async: bool); } /// DMA Channel @@ -2985,6 +2992,10 @@ pub(crate) mod asynch { fn handle_in_interrupt() { let rx = CH::rx_interrupts(); + if !rx.is_async() { + return; + } + if rx.pending_interrupts().is_disjoint( DmaRxInterrupt::DescriptorError | DmaRxInterrupt::DescriptorEmpty @@ -3017,6 +3028,10 @@ pub(crate) mod asynch { fn handle_out_interrupt() { let tx = CH::tx_interrupts(); + if !tx.is_async() { + return; + } + if tx .pending_interrupts() .contains(DmaTxInterrupt::DescriptorError) diff --git a/esp-hal/src/dma/pdma.rs b/esp-hal/src/dma/pdma.rs index 776ea57fd07..609c89f24e4 100644 --- a/esp-hal/src/dma/pdma.rs +++ b/esp-hal/src/dma/pdma.rs @@ -12,6 +12,7 @@ //! [I2S]: ../i2s/index.html use embassy_sync::waitqueue::AtomicWaker; +use portable_atomic::{AtomicBool, Ordering}; use crate::{ dma::*, @@ -35,6 +36,8 @@ pub trait PdmaChannel: crate::private::Sealed { fn peripheral_interrupt(&self) -> Interrupt; fn async_handler(&self) -> InterruptHandler; + fn rx_async_flag(&self) -> &'static AtomicBool; + fn tx_async_flag(&self) -> &'static AtomicBool; } #[doc(hidden)] @@ -198,6 +201,14 @@ impl> InterruptAccess &'static AtomicWaker { self.0.tx_waker() } + + fn is_async(&self) -> bool { + self.0.tx_async_flag().load(Ordering::Acquire) + } + + fn set_async(&self, is_async: bool) { + self.0.tx_async_flag().store(is_async, Ordering::Release); + } } impl> RegisterAccess for SpiDmaRxChannelImpl { @@ -348,6 +359,14 @@ impl> InterruptAccess &'static AtomicWaker { self.0.rx_waker() } + + fn is_async(&self) -> bool { + self.0.rx_async_flag().load(Ordering::Relaxed) + } + + fn set_async(&self, _is_async: bool) { + self.0.rx_async_flag().store(_is_async, Ordering::Relaxed); + } } #[doc(hidden)] @@ -382,12 +401,12 @@ macro_rules! ImplSpiChannel { fn register_block(&self) -> &SpiRegisterBlock { unsafe { &*crate::peripherals::[]::PTR } } - fn tx_waker(&self) -> &'static embassy_sync::waitqueue::AtomicWaker { - static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new(); + fn tx_waker(&self) -> &'static AtomicWaker { + static WAKER: AtomicWaker = AtomicWaker::new(); &WAKER } - fn rx_waker(&self) -> &'static embassy_sync::waitqueue::AtomicWaker { - static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new(); + fn rx_waker(&self) -> &'static AtomicWaker { + static WAKER: AtomicWaker = AtomicWaker::new(); &WAKER } @@ -402,6 +421,14 @@ macro_rules! ImplSpiChannel { fn async_handler(&self) -> InterruptHandler { super::asynch::interrupt::[< interrupt_handler_spi $num _dma >] } + fn rx_async_flag(&self) -> &'static AtomicBool { + static FLAG: AtomicBool = AtomicBool::new(false); + &FLAG + } + fn tx_async_flag(&self) -> &'static AtomicBool { + static FLAG: AtomicBool = AtomicBool::new(false); + &FLAG + } } impl DmaChannelConvert for [] { @@ -614,6 +641,14 @@ impl> InterruptAccess &'static AtomicWaker { self.0.tx_waker() } + + fn is_async(&self) -> bool { + self.0.tx_async_flag().load(Ordering::Relaxed) + } + + fn set_async(&self, _is_async: bool) { + self.0.tx_async_flag().store(_is_async, Ordering::Relaxed); + } } impl> RegisterAccess for I2sDmaRxChannelImpl { @@ -770,6 +805,14 @@ impl> InterruptAccess &'static AtomicWaker { self.0.rx_waker() } + + fn is_async(&self) -> bool { + self.0.rx_async_flag().load(Ordering::Relaxed) + } + + fn set_async(&self, _is_async: bool) { + self.0.rx_async_flag().store(_is_async, Ordering::Relaxed); + } } macro_rules! ImplI2sChannel { @@ -800,12 +843,12 @@ macro_rules! ImplI2sChannel { fn register_block(&self) -> &I2sRegisterBlock { unsafe { &*crate::peripherals::[< I2S $num >]::PTR } } - fn tx_waker(&self) -> &'static embassy_sync::waitqueue::AtomicWaker { - static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new(); + fn tx_waker(&self) -> &'static AtomicWaker { + static WAKER: AtomicWaker = AtomicWaker::new(); &WAKER } - fn rx_waker(&self) -> &'static embassy_sync::waitqueue::AtomicWaker { - static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new(); + fn rx_waker(&self) -> &'static AtomicWaker { + static WAKER: AtomicWaker = AtomicWaker::new(); &WAKER } fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool { @@ -819,6 +862,14 @@ macro_rules! ImplI2sChannel { fn async_handler(&self) -> InterruptHandler { super::asynch::interrupt::[< interrupt_handler_i2s $num _dma >] } + fn rx_async_flag(&self) -> &'static AtomicBool { + static FLAG: AtomicBool = AtomicBool::new(false); + &FLAG + } + fn tx_async_flag(&self) -> &'static AtomicBool { + static FLAG: AtomicBool = AtomicBool::new(false); + &FLAG + } } impl DmaChannelConvert for [] { @@ -968,6 +1019,8 @@ impl PdmaChannel for AnySpiDmaChannelInner { fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool; fn peripheral_interrupt(&self) -> Interrupt; fn async_handler(&self) -> InterruptHandler; + fn rx_async_flag(&self) -> &'static AtomicBool; + fn tx_async_flag(&self) -> &'static AtomicBool; } } } @@ -1008,6 +1061,8 @@ impl PdmaChannel for AnyI2sDmaChannelInner { fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool; fn peripheral_interrupt(&self) -> Interrupt; fn async_handler(&self) -> InterruptHandler; + fn rx_async_flag(&self) -> &'static AtomicBool; + fn tx_async_flag(&self) -> &'static AtomicBool; } } } From afc52e47a9fa75b54bc32e7b4e6cc58d985ec72e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 13 Nov 2024 19:08:14 +0100 Subject: [PATCH 05/13] Reset channel async status when re-creating --- esp-hal/src/dma/mod.rs | 14 ++++++++++++++ esp-hal/src/lib.rs | 12 ++++++++++++ 2 files changed, 26 insertions(+) diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index f08cd0df3dc..cd2f0699b9d 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -1679,6 +1679,13 @@ where // channel was previously used for a mem2mem transfer. rx_impl.set_mem2mem_mode(false); + if let Some(interrupt) = rx_impl.peripheral_interrupt() { + for cpu in Cpu::all() { + crate::interrupt::disable(cpu, interrupt); + } + } + rx_impl.set_async(false); + Self { burst_mode: false, rx_impl, @@ -1962,6 +1969,13 @@ where CH: DmaChannel, { fn new(tx_impl: CH::Tx) -> Self { + if let Some(interrupt) = tx_impl.peripheral_interrupt() { + for cpu in Cpu::all() { + crate::interrupt::disable(cpu, interrupt); + } + } + tx_impl.set_async(false); + Self { burst_mode: false, tx_impl, diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index 2214852fe4b..ccb6afa0f55 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -397,6 +397,18 @@ impl Cpu { } } } + + /// Returns an iterator over all cores. + #[inline(always)] + pub fn all() -> impl Iterator { + cfg_if::cfg_if! { + if #[cfg(multi_core)] { + [Cpu::ProCpu, Cpu::AppCpu].into_iter() + } else { + [Cpu::ProCpu].into_iter() + } + } + } } /// Returns the raw value of the mhartid register. From de617647a37c8955bedc45833b97ef3a525d1348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Thu, 24 Oct 2024 17:24:32 +0200 Subject: [PATCH 06/13] Remove ChannelCreator types and burst mode --- esp-hal/CHANGELOG.md | 2 + esp-hal/MIGRATING-0.21.md | 6 ++ esp-hal/src/dma/buffers.rs | 24 +++--- esp-hal/src/dma/gdma.rs | 50 +++++------ esp-hal/src/dma/mod.rs | 72 ++++++---------- esp-hal/src/dma/pdma.rs | 83 +++++++------------ esp-hal/src/i2s/master.rs | 7 +- esp-hal/src/lcd_cam/cam.rs | 7 +- esp-hal/src/lcd_cam/lcd/i8080.rs | 7 +- esp-hal/src/spi/master.rs | 2 + esp-hal/src/spi/slave.rs | 6 +- examples/src/bin/dma_extmem2mem.rs | 5 +- examples/src/bin/dma_mem2mem.rs | 5 +- examples/src/bin/embassy_i2s_read.rs | 4 +- examples/src/bin/embassy_i2s_sound.rs | 4 +- examples/src/bin/embassy_parl_io_rx.rs | 7 +- examples/src/bin/embassy_parl_io_tx.rs | 7 +- examples/src/bin/embassy_spi.rs | 2 +- examples/src/bin/i2s_read.rs | 4 +- examples/src/bin/i2s_sound.rs | 4 +- examples/src/bin/lcd_cam_ov2640.rs | 7 +- examples/src/bin/lcd_i8080.rs | 7 +- examples/src/bin/parl_io_rx.rs | 11 +-- examples/src/bin/parl_io_tx.rs | 11 +-- examples/src/bin/qspi_flash.rs | 4 +- examples/src/bin/spi_loopback_dma.rs | 4 +- examples/src/bin/spi_loopback_dma_psram.rs | 4 +- examples/src/bin/spi_slave_dma.rs | 8 +- hil-test/tests/aes_dma.rs | 30 ++----- hil-test/tests/dma_mem2mem.rs | 6 +- hil-test/tests/embassy_interrupt_spi_dma.rs | 22 ++--- hil-test/tests/i2s.rs | 17 ++-- hil-test/tests/lcd_cam_i8080.rs | 11 +-- hil-test/tests/lcd_cam_i8080_async.rs | 5 +- hil-test/tests/parl_io_tx.rs | 23 ++--- hil-test/tests/parl_io_tx_async.rs | 29 ++----- hil-test/tests/qspi.rs | 3 +- hil-test/tests/spi_full_duplex.rs | 53 +++++------- hil-test/tests/spi_half_duplex_read.rs | 4 +- hil-test/tests/spi_half_duplex_write.rs | 4 +- hil-test/tests/spi_half_duplex_write_psram.rs | 4 +- hil-test/tests/spi_slave.rs | 16 ++-- 42 files changed, 227 insertions(+), 364 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 5332245a68c..953e18c7766 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - I8080: Added `set_8bits_order()` to set the byte order in 8-bit mode (#2487) - `I2c::{apply_config(), with_sda(), with_scl()}` (#2477) - ESP32-S2: Added missing GPIO alternate functions (#2512) +- `dma::{Channel, ChannelRx, ChannelTx}::set_priority` for GDMA devices (#2403) ### Changed @@ -98,6 +99,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed the pin type parameters from `lcd_cam::cam::{RxEightBits, RxSixteenBits}` (#2388) - Most of the async-specific constructors (`new_async`, `new_async_no_transceiver`) have been removed. (#2430) - The `configure_for_async` DMA functions have been removed (#2430) +- The `configure` DMA channel functions has been removed (#2403) - The `Uart::{change_baud, change_stop_bits}` functions have been removed (#2449) - `gpio::{Input, Output, OutputOpenDrain, Flex, GpioPin}::{peripheral_input, into_peripheral_output}` have been removed. (#2418) - The `GpioEtm` prefix has been removed from `gpio::etm` types (#2427) diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index 0da8378e233..ae8fc41f3de 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -311,6 +311,12 @@ In case of any error you should drop the transfer and restart it. +ChannelTx<'d, Async, DmaChannel0> ``` +## Configuration changes + +- `configure_for_async` and `configure` have been removed +- PDMA devices (ESP32, ESP32-S2) provide no configurability +- GDMA devices provide `set_priority` to change DMA in/out channel priority + ## Removed `peripheral_input` and `into_peripheral_output` from GPIO pin types Creating peripheral interconnect signals now consume the GPIO pin used for the connection. diff --git a/esp-hal/src/dma/buffers.rs b/esp-hal/src/dma/buffers.rs index c00b9c46912..53f5a19a2b5 100644 --- a/esp-hal/src/dma/buffers.rs +++ b/esp-hal/src/dma/buffers.rs @@ -14,16 +14,16 @@ pub struct Preparation { #[cfg_attr(not(esp32s3), allow(dead_code))] pub block_size: Option, - /// Specifies whether descriptor linked list specified in `start` conforms - /// to the alignment requirements required to enable burst transfers. + /// Specifies whether the data should be transferred in burst mode. /// - /// Note: This only applies to burst transfer of the buffer data, not the - /// descriptors themselves. + /// The implementation of the buffer must ensure that burst mode is only + /// enabled when alignment requirements are met. /// /// There are no additional alignment requirements for TX burst transfers, /// but RX transfers require all descriptors to have buffer pointers and /// sizes that are a multiple of 4 (word aligned). - pub is_burstable: bool, + // TODO: currently unused, buffers should not hardcode their preference. + pub burst: bool, /// Configures the "check owner" feature of the DMA channel. /// @@ -330,7 +330,7 @@ unsafe impl DmaTxBuffer for DmaTxBuf { start: self.descriptors.head(), block_size: self.block_size, // This is TX, the DMA channel is free to do a burst transfer. - is_burstable: true, + burst: true, check_owner: None, } } @@ -481,7 +481,7 @@ unsafe impl DmaRxBuffer for DmaRxBuf { // DmaRxBuf doesn't currently enforce the alignment requirements required for bursting. // In the future, it could either enforce the alignment or calculate if the alignment // requirements happen to be met. - is_burstable: false, + burst: false, check_owner: None, } } @@ -609,7 +609,7 @@ unsafe impl DmaTxBuffer for DmaRxTxBuf { block_size: None, // TODO: support block size! // This is TX, the DMA channel is free to do a burst transfer. - is_burstable: true, + burst: true, check_owner: None, } } @@ -641,7 +641,7 @@ unsafe impl DmaRxBuffer for DmaRxTxBuf { // DmaRxTxBuf doesn't currently enforce the alignment requirements required for // bursting. - is_burstable: false, + burst: false, check_owner: None, } } @@ -782,7 +782,7 @@ unsafe impl DmaRxBuffer for DmaRxStreamBuf { // DmaRxStreamBuf doesn't currently enforce the alignment requirements required for // bursting. - is_burstable: false, + burst: false, // Whilst we give ownership of the descriptors the DMA, the correctness of this buffer // implementation doesn't rely on the DMA checking for descriptor ownership. @@ -995,7 +995,7 @@ unsafe impl DmaTxBuffer for EmptyBuf { block_size: None, // This is TX, the DMA channel is free to do a burst transfer. - is_burstable: true, + burst: true, // As we don't give ownership of the descriptor to the DMA, it's important that the DMA // channel does *NOT* check for ownership, otherwise the channel will return an error. @@ -1026,7 +1026,7 @@ unsafe impl DmaRxBuffer for EmptyBuf { block_size: None, // As much as bursting is meaningless here, the descriptor does meet the requirements. - is_burstable: true, + burst: true, // As we don't give ownership of the descriptor to the DMA, it's important that the DMA // channel does *NOT* check for ownership, otherwise the channel will return an error. diff --git a/esp-hal/src/dma/gdma.rs b/esp-hal/src/dma/gdma.rs index 8c2ca9a2468..ef96c7ff20f 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -621,19 +621,19 @@ macro_rules! impl_channel { } } - impl ChannelCreator<$num> { - /// Configure the channel for use with blocking APIs - pub fn configure<'a>( - self, - burst_mode: bool, - priority: DmaPriority, - ) -> Channel<'a, Blocking, []> { + 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.configure(burst_mode, priority); + this.set_priority(DmaPriority::Priority0); this } @@ -731,19 +731,19 @@ crate::impl_dma_eligible! { pub struct Dma<'d> { _inner: PeripheralRef<'d, crate::peripherals::DMA>, /// Channel 0 - pub channel0: ChannelCreator<0>, + pub channel0: Channel<'d, Blocking, DmaChannel0>, /// Channel 1 #[cfg(not(esp32c2))] - pub channel1: ChannelCreator<1>, + pub channel1: Channel<'d, Blocking, DmaChannel1>, /// Channel 2 #[cfg(not(esp32c2))] - pub channel2: ChannelCreator<2>, + pub channel2: Channel<'d, Blocking, DmaChannel2>, /// Channel 3 #[cfg(esp32s3)] - pub channel3: ChannelCreator<3>, + pub channel3: Channel<'d, Blocking, DmaChannel3>, /// Channel 4 #[cfg(esp32s3)] - pub channel4: ChannelCreator<4>, + pub channel4: Channel<'d, Blocking, DmaChannel4>, } impl<'d> Dma<'d> { @@ -759,17 +759,19 @@ impl<'d> Dma<'d> { .modify(|_, w| w.ahbm_rst_inter().clear_bit()); dma.misc_conf().modify(|_, w| w.clk_en().set_bit()); - Dma { - _inner: dma, - channel0: ChannelCreator {}, - #[cfg(not(esp32c2))] - channel1: ChannelCreator {}, - #[cfg(not(esp32c2))] - channel2: ChannelCreator {}, - #[cfg(esp32s3)] - channel3: ChannelCreator {}, - #[cfg(esp32s3)] - channel4: ChannelCreator {}, + unsafe { + Dma { + _inner: dma, + channel0: DmaChannel0::steal(), + #[cfg(not(esp32c2))] + channel1: DmaChannel1::steal(), + #[cfg(not(esp32c2))] + channel2: DmaChannel2::steal(), + #[cfg(esp32s3)] + channel3: DmaChannel3::steal(), + #[cfg(esp32s3)] + channel4: DmaChannel4::steal(), + } } } } diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index cd2f0699b9d..1ea2b1de4f6 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -19,7 +19,7 @@ #![doc = crate::before_snippet!()] //! # use esp_hal::dma_buffers; //! # use esp_hal::spi::{master::{Config, Spi}, SpiMode}; -//! # use esp_hal::dma::{Dma, DmaPriority}; +//! # use esp_hal::dma::Dma; //! let dma = Dma::new(peripherals.DMA); #![cfg_attr(any(esp32, esp32s2), doc = "let dma_channel = dma.spi2channel;")] #![cfg_attr(not(any(esp32, esp32s2)), doc = "let dma_channel = dma.channel0;")] @@ -40,10 +40,7 @@ //! .with_mosi(mosi) //! .with_miso(miso) //! .with_cs(cs) -//! .with_dma(dma_channel.configure( -//! false, -//! DmaPriority::Priority0, -//! )); +//! .with_dma(dma_channel); //! # } //! ``` //! @@ -1664,7 +1661,6 @@ pub struct ChannelRx<'a, M, CH> where CH: DmaChannel, { - pub(crate) burst_mode: bool, pub(crate) rx_impl: CH::Rx, pub(crate) _phantom: PhantomData<(&'a (), CH, M)>, } @@ -1687,7 +1683,6 @@ where rx_impl.set_async(false); Self { - burst_mode: false, rx_impl, _phantom: PhantomData, } @@ -1700,7 +1695,6 @@ where } self.rx_impl.set_async(true); ChannelRx { - burst_mode: false, rx_impl: self.rx_impl, _phantom: PhantomData, } @@ -1734,7 +1728,6 @@ where } self.rx_impl.set_async(false); ChannelRx { - burst_mode: false, rx_impl: self.rx_impl, _phantom: PhantomData, } @@ -1753,16 +1746,15 @@ where CH: DmaChannelConvert, { ChannelRx { - burst_mode: self.burst_mode, rx_impl: CH::degrade_rx(self.rx_impl), _phantom: PhantomData, } } /// Configure the channel. - pub fn configure(&mut self, burst_mode: bool, priority: DmaPriority) { - self.burst_mode = burst_mode; - self.rx_impl.configure(burst_mode, priority); + #[cfg(gdma)] + pub fn set_priority(&mut self, priority: DmaPriority) { + self.rx_impl.set_priority(priority); } } @@ -1783,14 +1775,14 @@ where peri: DmaPeripheral, chain: &DescriptorChain, ) -> Result<(), DmaError> { - if self.burst_mode - && chain - .descriptors - .iter() - .any(|d| d.len() % 4 != 0 || d.buffer as u32 % 4 != 0) - { - return Err(DmaError::InvalidAlignment); - } + // if self.burst_mode + // && chain + // .descriptors + // .iter() + // .any(|d| d.len() % 4 != 0 || d.buffer as u32 % 4 != 0) + //{ + // return Err(DmaError::InvalidAlignment); + //} // for esp32s3 we check each descriptor buffer that points to psram for // alignment and invalidate the cache for that buffer @@ -1827,9 +1819,7 @@ where ) -> Result<(), DmaError> { let preparation = buffer.prepare(); - self.rx_impl - .set_burst_mode(self.burst_mode && preparation.is_burstable); - + self.rx_impl.set_burst_mode(false); self.rx_impl.set_check_owner(preparation.check_owner); compiler_fence(core::sync::atomic::Ordering::SeqCst); @@ -1958,8 +1948,6 @@ pub struct ChannelTx<'a, M, CH> where CH: DmaChannel, { - #[allow(unused)] - pub(crate) burst_mode: bool, pub(crate) tx_impl: CH::Tx, pub(crate) _phantom: PhantomData<(&'a (), CH, M)>, } @@ -1977,7 +1965,6 @@ where tx_impl.set_async(false); Self { - burst_mode: false, tx_impl, _phantom: PhantomData, } @@ -1990,7 +1977,6 @@ where } self.tx_impl.set_async(true); ChannelTx { - burst_mode: false, tx_impl: self.tx_impl, _phantom: PhantomData, } @@ -2024,7 +2010,6 @@ where } self.tx_impl.set_async(false); ChannelTx { - burst_mode: false, tx_impl: self.tx_impl, _phantom: PhantomData, } @@ -2043,16 +2028,15 @@ where CH: DmaChannelConvert, { ChannelTx { - burst_mode: self.burst_mode, tx_impl: CH::degrade_tx(self.tx_impl), _phantom: PhantomData, } } - /// Configure the channel. - pub fn configure(&mut self, burst_mode: bool, priority: DmaPriority) { - self.burst_mode = burst_mode; - self.tx_impl.configure(burst_mode, priority); + /// Configure the channel priority. + #[cfg(gdma)] + pub fn set_priority(&mut self, priority: DmaPriority) { + self.tx_impl.set_priority(priority); } } @@ -2123,9 +2107,7 @@ where } ); - self.tx_impl - .set_burst_mode(self.burst_mode && preparation.is_burstable); - + self.tx_impl.set_burst_mode(false); self.tx_impl.set_check_owner(preparation.check_owner); compiler_fence(core::sync::atomic::Ordering::SeqCst); @@ -2204,6 +2186,7 @@ pub trait RegisterAccess: crate::private::Sealed { /// The priority of the channel. The larger the value, the higher the /// priority. + #[cfg(gdma)] fn set_priority(&self, priority: DmaPriority); /// Select a peripheral for the channel. @@ -2230,12 +2213,6 @@ pub trait RegisterAccess: crate::private::Sealed { #[cfg(pdma)] fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool; - - /// Configure the channel. - fn configure(&self, burst_mode: bool, priority: DmaPriority) { - self.set_burst_mode(burst_mode); - self.set_priority(priority); - } } #[doc(hidden)] @@ -2351,10 +2328,11 @@ where } } - /// Configure the channel. - pub fn configure(&mut self, burst_mode: bool, priority: DmaPriority) { - self.rx.configure(burst_mode, priority); - self.tx.configure(burst_mode, priority); + /// Configure the channel priorities. + #[cfg(gdma)] + pub fn set_priority(&mut self, priority: DmaPriority) { + self.tx.set_priority(priority); + self.rx.set_priority(priority); } /// Converts a blocking channel to an async channel. diff --git a/esp-hal/src/dma/pdma.rs b/esp-hal/src/dma/pdma.rs index 609c89f24e4..667767c3eb9 100644 --- a/esp-hal/src/dma/pdma.rs +++ b/esp-hal/src/dma/pdma.rs @@ -63,8 +63,6 @@ impl> RegisterAccess for SpiDma .modify(|_, w| w.outdscr_burst_en().bit(burst_mode)); } - fn set_priority(&self, _priority: DmaPriority) {} - fn set_peripheral(&self, _peripheral: u8) { // no-op } @@ -224,8 +222,6 @@ impl> RegisterAccess for SpiDma .modify(|_, w| w.indscr_burst_en().bit(burst_mode)); } - fn set_priority(&self, _priority: DmaPriority) {} - fn set_peripheral(&self, _peripheral: u8) { // no-op } @@ -442,25 +438,17 @@ macro_rules! ImplSpiChannel { impl $crate::private::Sealed for [] {} - #[doc = concat!("Creates a channel for SPI", $num)] - #[non_exhaustive] - pub struct [] {} - - impl [] { - /// Configure the channel for use with blocking APIs - pub fn configure<'a>( - self, - burst_mode: bool, - priority: DmaPriority, - ) -> Channel<'a, Blocking, []> { - let mut this = Channel { + 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([] {})), - }; - - this.configure(burst_mode, priority); - - this + } } } } @@ -485,8 +473,6 @@ impl> RegisterAccess for I2sDma .modify(|_, w| w.outdscr_burst_en().bit(burst_mode)); } - fn set_priority(&self, _priority: DmaPriority) {} - fn reset(&self) { let reg_block = self.0.register_block(); reg_block.lc_conf().modify(|_, w| w.out_rst().set_bit()); @@ -659,8 +645,6 @@ impl> RegisterAccess for I2sDma .modify(|_, w| w.indscr_burst_en().bit(burst_mode)); } - fn set_priority(&self, _priority: DmaPriority) {} - fn reset(&self) { let reg_block = self.0.register_block(); reg_block.lc_conf().modify(|_, w| w.in_rst().set_bit()); @@ -881,24 +865,17 @@ macro_rules! ImplI2sChannel { } } - #[doc = concat!("Creates a channel for I2S", $num)] - pub struct [] {} - - impl [] { - /// Configure the channel for use with blocking APIs - pub fn configure<'a>( - self, - burst_mode: bool, - priority: DmaPriority, - ) -> Channel<'a, Blocking, []> { - let mut this = Channel { + 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([] {})), - }; - - this.configure(burst_mode, priority); - - this + } } } } @@ -927,14 +904,14 @@ crate::impl_dma_eligible!([I2s1DmaChannel] I2S1 => I2s1); pub struct Dma<'d> { _inner: PeripheralRef<'d, crate::peripherals::DMA>, /// DMA channel for SPI2 - pub spi2channel: Spi2DmaChannelCreator, + pub spi2channel: Channel<'d, Blocking, Spi2DmaChannel>, /// DMA channel for SPI3 - pub spi3channel: Spi3DmaChannelCreator, + pub spi3channel: Channel<'d, Blocking, Spi3DmaChannel>, /// DMA channel for I2S0 - pub i2s0channel: I2s0DmaChannelCreator, + pub i2s0channel: Channel<'d, Blocking, I2s0DmaChannel>, /// DMA channel for I2S1 #[cfg(i2s1)] - pub i2s1channel: I2s1DmaChannelCreator, + pub i2s1channel: Channel<'d, Blocking, I2s1DmaChannel>, } impl<'d> Dma<'d> { @@ -957,13 +934,15 @@ impl<'d> Dma<'d> { }); } - Dma { - _inner: dma.into_ref(), - spi2channel: Spi2DmaChannelCreator {}, - spi3channel: Spi3DmaChannelCreator {}, - i2s0channel: I2s0DmaChannelCreator {}, - #[cfg(i2s1)] - i2s1channel: I2s1DmaChannelCreator {}, + unsafe { + Dma { + _inner: dma.into_ref(), + spi2channel: Spi2DmaChannel::steal(), + spi3channel: Spi3DmaChannel::steal(), + i2s0channel: I2s0DmaChannel::steal(), + #[cfg(i2s1)] + i2s1channel: I2s1DmaChannel::steal(), + } } } } diff --git a/esp-hal/src/i2s/master.rs b/esp-hal/src/i2s/master.rs index 111596ae9ff..1a238e6c6fc 100644 --- a/esp-hal/src/i2s/master.rs +++ b/esp-hal/src/i2s/master.rs @@ -31,7 +31,7 @@ #![doc = crate::before_snippet!()] //! # use esp_hal::i2s::master::{I2s, Standard, DataFormat}; //! # use esp_hal::dma_buffers; -//! # use esp_hal::dma::{Dma, DmaPriority}; +//! # use esp_hal::dma::Dma; //! let dma = Dma::new(peripherals.DMA); #![cfg_attr(any(esp32, esp32s2), doc = "let dma_channel = dma.i2s0channel;")] #![cfg_attr(not(any(esp32, esp32s2)), doc = "let dma_channel = dma.channel0;")] @@ -43,10 +43,7 @@ //! Standard::Philips, //! DataFormat::Data16Channel16, //! 44100.Hz(), -//! dma_channel.configure( -//! false, -//! DmaPriority::Priority0, -//! ), +//! dma_channel, //! rx_descriptors, //! tx_descriptors, //! ); diff --git a/esp-hal/src/lcd_cam/cam.rs b/esp-hal/src/lcd_cam/cam.rs index 358643e871e..6b237470de2 100644 --- a/esp-hal/src/lcd_cam/cam.rs +++ b/esp-hal/src/lcd_cam/cam.rs @@ -19,18 +19,13 @@ //! # use esp_hal::lcd_cam::{cam::{Camera, RxEightBits}, LcdCam}; //! # use fugit::RateExtU32; //! # use esp_hal::dma_rx_stream_buffer; -//! # use esp_hal::dma::{Dma, DmaPriority}; +//! # use esp_hal::dma::Dma; //! //! # let dma = Dma::new(peripherals.DMA); //! # let channel = dma.channel0; //! //! # let dma_buf = dma_rx_stream_buffer!(20 * 1000, 1000); //! -//! # let channel = channel.configure( -//! # false, -//! # DmaPriority::Priority0, -//! # ); -//! //! let mclk_pin = peripherals.GPIO15; //! let vsync_pin = peripherals.GPIO6; //! let href_pin = peripherals.GPIO7; diff --git a/esp-hal/src/lcd_cam/lcd/i8080.rs b/esp-hal/src/lcd_cam/lcd/i8080.rs index bfc7465a623..5dab70ce986 100644 --- a/esp-hal/src/lcd_cam/lcd/i8080.rs +++ b/esp-hal/src/lcd_cam/lcd/i8080.rs @@ -17,18 +17,13 @@ #![doc = crate::before_snippet!()] //! # use esp_hal::lcd_cam::{LcdCam, lcd::i8080::{Config, I8080, TxEightBits}}; //! # use esp_hal::dma_tx_buffer; -//! # use esp_hal::dma::{Dma, DmaPriority, DmaTxBuf}; +//! # use esp_hal::dma::{Dma, DmaTxBuf}; //! //! # let dma = Dma::new(peripherals.DMA); //! # let channel = dma.channel0; //! //! # let mut dma_buf = dma_tx_buffer!(32678).unwrap(); //! -//! # let channel = channel.configure( -//! # false, -//! # DmaPriority::Priority0, -//! # ); -//! //! let tx_pins = TxEightBits::new( //! peripherals.GPIO9, //! peripherals.GPIO46, diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index 2bc93c5d61c..dacb255866b 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -864,6 +864,8 @@ mod dma { Rx, Tx, }, + Async, + Blocking, InterruptConfigurable, }; diff --git a/esp-hal/src/spi/slave.rs b/esp-hal/src/spi/slave.rs index 7e00288f48f..80f76e22b6b 100644 --- a/esp-hal/src/spi/slave.rs +++ b/esp-hal/src/spi/slave.rs @@ -15,7 +15,6 @@ //! //! ```rust, no_run #![doc = crate::before_snippet!()] -//! # use esp_hal::dma::DmaPriority; //! # use esp_hal::dma_buffers; //! # use esp_hal::spi::SpiMode; //! # use esp_hal::spi::slave::Spi; @@ -39,10 +38,7 @@ //! .with_miso(miso) //! .with_cs(cs) //! .with_dma( -//! dma_channel.configure( -//! false, -//! DmaPriority::Priority0, -//! ), +//! dma_channel, //! rx_descriptors, //! tx_descriptors, //! ); diff --git a/examples/src/bin/dma_extmem2mem.rs b/examples/src/bin/dma_extmem2mem.rs index 063197a7f6e..4fab1087c77 100644 --- a/examples/src/bin/dma_extmem2mem.rs +++ b/examples/src/bin/dma_extmem2mem.rs @@ -11,7 +11,7 @@ use esp_alloc as _; use esp_backtrace as _; use esp_hal::{ delay::Delay, - dma::{Dma, DmaPriority, Mem2Mem}, + dma::{Dma, Mem2Mem}, dma_descriptors_chunk_size, prelude::*, }; @@ -68,11 +68,10 @@ fn main() -> ! { let (rx_descriptors, tx_descriptors) = dma_descriptors_chunk_size!(DATA_SIZE, CHUNK_SIZE); let dma = Dma::new(peripherals.DMA); - let channel = dma.channel0.configure(false, DmaPriority::Priority0); let dma_peripheral = peripherals.SPI2; let mut mem2mem = Mem2Mem::new_with_chunk_size( - channel, + dma.channel0, dma_peripheral, rx_descriptors, tx_descriptors, diff --git a/examples/src/bin/dma_mem2mem.rs b/examples/src/bin/dma_mem2mem.rs index 795e158d290..23dda706764 100644 --- a/examples/src/bin/dma_mem2mem.rs +++ b/examples/src/bin/dma_mem2mem.rs @@ -9,7 +9,7 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, - dma::{Dma, DmaPriority, Mem2Mem}, + dma::{Dma, Mem2Mem}, dma_buffers, prelude::*, }; @@ -28,14 +28,13 @@ fn main() -> ! { let (mut rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(DATA_SIZE); let dma = Dma::new(peripherals.DMA); - let channel = dma.channel0.configure(false, DmaPriority::Priority0); #[cfg(any(feature = "esp32c2", feature = "esp32c3", feature = "esp32s3"))] let dma_peripheral = peripherals.SPI2; #[cfg(not(any(feature = "esp32c2", feature = "esp32c3", feature = "esp32s3")))] let dma_peripheral = peripherals.MEM2MEM1; let mut mem2mem = - Mem2Mem::new(channel, dma_peripheral, rx_descriptors, tx_descriptors).unwrap(); + Mem2Mem::new(dma.channel0, dma_peripheral, rx_descriptors, tx_descriptors).unwrap(); for i in 0..core::mem::size_of_val(tx_buffer) { tx_buffer[i] = (i % 256) as u8; diff --git a/examples/src/bin/embassy_i2s_read.rs b/examples/src/bin/embassy_i2s_read.rs index 612ee4ad9f5..a60ab718326 100644 --- a/examples/src/bin/embassy_i2s_read.rs +++ b/examples/src/bin/embassy_i2s_read.rs @@ -20,7 +20,7 @@ use embassy_executor::Spawner; use esp_backtrace as _; use esp_hal::{ - dma::{Dma, DmaPriority}, + dma::Dma, dma_buffers, i2s::master::{DataFormat, I2s, Standard}, prelude::*, @@ -49,7 +49,7 @@ async fn main(_spawner: Spawner) { Standard::Philips, DataFormat::Data16Channel16, 44100u32.Hz(), - dma_channel.configure(false, DmaPriority::Priority0), + dma_channel, rx_descriptors, tx_descriptors, ) diff --git a/examples/src/bin/embassy_i2s_sound.rs b/examples/src/bin/embassy_i2s_sound.rs index fd06eff7a00..3809bb7eb44 100644 --- a/examples/src/bin/embassy_i2s_sound.rs +++ b/examples/src/bin/embassy_i2s_sound.rs @@ -34,7 +34,7 @@ use embassy_executor::Spawner; use esp_backtrace as _; use esp_hal::{ - dma::{Dma, DmaPriority}, + dma::Dma, dma_buffers, i2s::master::{DataFormat, I2s, Standard}, prelude::*, @@ -71,7 +71,7 @@ async fn main(_spawner: Spawner) { Standard::Philips, DataFormat::Data16Channel16, 44100u32.Hz(), - dma_channel.configure(false, DmaPriority::Priority0), + dma_channel, rx_descriptors, tx_descriptors, ) diff --git a/examples/src/bin/embassy_parl_io_rx.rs b/examples/src/bin/embassy_parl_io_rx.rs index 33749c91f36..3e57728ebdc 100644 --- a/examples/src/bin/embassy_parl_io_rx.rs +++ b/examples/src/bin/embassy_parl_io_rx.rs @@ -14,7 +14,7 @@ use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; use esp_backtrace as _; use esp_hal::{ - dma::{Dma, DmaPriority}, + dma::Dma, dma_buffers, gpio::NoPin, parl_io::{BitPackOrder, ParlIoRxOnly, RxFourBits}, @@ -34,7 +34,6 @@ async fn main(_spawner: Spawner) { let (rx_buffer, rx_descriptors, _, _) = dma_buffers!(32000, 0); let dma = Dma::new(peripherals.DMA); - let dma_channel = dma.channel0; let mut rx_pins = RxFourBits::new( peripherals.GPIO1, @@ -46,9 +45,7 @@ async fn main(_spawner: Spawner) { let parl_io = ParlIoRxOnly::new( peripherals.PARL_IO, - dma_channel - .configure(false, DmaPriority::Priority0) - .into_async(), + dma.channel0.into_async(), rx_descriptors, 1.MHz(), ) diff --git a/examples/src/bin/embassy_parl_io_tx.rs b/examples/src/bin/embassy_parl_io_tx.rs index 44302552bde..ff99b2dc738 100644 --- a/examples/src/bin/embassy_parl_io_tx.rs +++ b/examples/src/bin/embassy_parl_io_tx.rs @@ -18,7 +18,7 @@ use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; use esp_backtrace as _; use esp_hal::{ - dma::{Dma, DmaPriority}, + dma::Dma, dma_buffers, parl_io::{ BitPackOrder, @@ -44,7 +44,6 @@ async fn main(_spawner: Spawner) { let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, 32000); let dma = Dma::new(peripherals.DMA); - let dma_channel = dma.channel0; let tx_pins = TxFourBits::new( peripherals.GPIO1, @@ -57,9 +56,7 @@ async fn main(_spawner: Spawner) { let parl_io = ParlIoTxOnly::new( peripherals.PARL_IO, - dma_channel - .configure(false, DmaPriority::Priority0) - .into_async(), + dma.channel0.into_async(), tx_descriptors, 1.MHz(), ) diff --git a/examples/src/bin/embassy_spi.rs b/examples/src/bin/embassy_spi.rs index 82a7813f884..becc3e96134 100644 --- a/examples/src/bin/embassy_spi.rs +++ b/examples/src/bin/embassy_spi.rs @@ -71,7 +71,7 @@ async fn main(_spawner: Spawner) { .with_mosi(mosi) .with_miso(miso) .with_cs(cs) - .with_dma(dma_channel.configure(false, DmaPriority::Priority0)) + .with_dma(dma_channel) .with_buffers(dma_rx_buf, dma_tx_buf) .into_async(); diff --git a/examples/src/bin/i2s_read.rs b/examples/src/bin/i2s_read.rs index 6697053cedb..1e5cdc5503b 100644 --- a/examples/src/bin/i2s_read.rs +++ b/examples/src/bin/i2s_read.rs @@ -18,7 +18,7 @@ use esp_backtrace as _; use esp_hal::{ - dma::{Dma, DmaPriority}, + dma::Dma, dma_buffers, i2s::master::{DataFormat, I2s, Standard}, prelude::*, @@ -46,7 +46,7 @@ fn main() -> ! { Standard::Philips, DataFormat::Data16Channel16, 44100.Hz(), - dma_channel.configure(false, DmaPriority::Priority0), + dma_channel, rx_descriptors, tx_descriptors, ); diff --git a/examples/src/bin/i2s_sound.rs b/examples/src/bin/i2s_sound.rs index de24c709b18..6cf407c4a50 100644 --- a/examples/src/bin/i2s_sound.rs +++ b/examples/src/bin/i2s_sound.rs @@ -32,7 +32,7 @@ use esp_backtrace as _; use esp_hal::{ - dma::{Dma, DmaPriority}, + dma::Dma, dma_buffers, i2s::master::{DataFormat, I2s, Standard}, prelude::*, @@ -63,7 +63,7 @@ fn main() -> ! { Standard::Philips, DataFormat::Data16Channel16, 44100.Hz(), - dma_channel.configure(false, DmaPriority::Priority0), + dma_channel, rx_descriptors, tx_descriptors, ); diff --git a/examples/src/bin/lcd_cam_ov2640.rs b/examples/src/bin/lcd_cam_ov2640.rs index 4a419a5d3f2..fa7e3a0a308 100644 --- a/examples/src/bin/lcd_cam_ov2640.rs +++ b/examples/src/bin/lcd_cam_ov2640.rs @@ -26,7 +26,7 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, - dma::{Dma, DmaPriority}, + dma::Dma, dma_rx_stream_buffer, i2c::{ self, @@ -46,12 +46,9 @@ fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); let dma = Dma::new(peripherals.DMA); - let channel = dma.channel0; let dma_rx_buf = dma_rx_stream_buffer!(20 * 1000, 1000); - let channel = channel.configure(false, DmaPriority::Priority0); - let cam_siod = peripherals.GPIO4; let cam_sioc = peripherals.GPIO5; let cam_xclk = peripherals.GPIO15; @@ -70,7 +67,7 @@ fn main() -> ! { ); let lcd_cam = LcdCam::new(peripherals.LCD_CAM); - let camera = Camera::new(lcd_cam.cam, channel.rx, cam_data_pins, 20u32.MHz()) + let camera = Camera::new(lcd_cam.cam, dma.channel0.rx, 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/examples/src/bin/lcd_i8080.rs b/examples/src/bin/lcd_i8080.rs index 749c5a546ee..f6f7260cad5 100644 --- a/examples/src/bin/lcd_i8080.rs +++ b/examples/src/bin/lcd_i8080.rs @@ -25,7 +25,7 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, - dma::{Dma, DmaPriority, DmaTxBuf}, + dma::{Dma, DmaTxBuf}, dma_tx_buffer, gpio::{Input, Level, Output, Pull}, lcd_cam::{ @@ -48,12 +48,9 @@ fn main() -> ! { let lcd_te = peripherals.GPIO48; // Frame sync let dma = Dma::new(peripherals.DMA); - let channel = dma.channel0; let dma_tx_buf = dma_tx_buffer!(4000).unwrap(); - let channel = channel.configure(false, DmaPriority::Priority0); - let delay = Delay::new(); let mut backlight = Output::new(lcd_backlight, Level::Low); @@ -74,7 +71,7 @@ fn main() -> ! { let lcd_cam = LcdCam::new(peripherals.LCD_CAM); let i8080 = I8080::new( lcd_cam.lcd, - channel.tx, + dma.channel0.tx, tx_pins, 20.MHz(), Config::default(), diff --git a/examples/src/bin/parl_io_rx.rs b/examples/src/bin/parl_io_rx.rs index 2a0390878ce..3fddcde318b 100644 --- a/examples/src/bin/parl_io_rx.rs +++ b/examples/src/bin/parl_io_rx.rs @@ -12,7 +12,7 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, - dma::{Dma, DmaPriority}, + dma::Dma, dma_buffers, gpio::NoPin, parl_io::{BitPackOrder, ParlIoRxOnly, RxFourBits}, @@ -37,13 +37,8 @@ fn main() -> ! { ); let mut rx_clk_pin = NoPin; - let parl_io = ParlIoRxOnly::new( - peripherals.PARL_IO, - dma_channel.configure(false, DmaPriority::Priority0), - rx_descriptors, - 1.MHz(), - ) - .unwrap(); + let parl_io = + ParlIoRxOnly::new(peripherals.PARL_IO, dma_channel, rx_descriptors, 1.MHz()).unwrap(); let mut parl_io_rx = parl_io .rx diff --git a/examples/src/bin/parl_io_tx.rs b/examples/src/bin/parl_io_tx.rs index fc790349e78..9e7a441d3d7 100644 --- a/examples/src/bin/parl_io_tx.rs +++ b/examples/src/bin/parl_io_tx.rs @@ -16,7 +16,7 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, - dma::{Dma, DmaPriority}, + dma::Dma, dma_buffers, parl_io::{ BitPackOrder, @@ -48,13 +48,8 @@ fn main() -> ! { let mut pin_conf = TxPinConfigWithValidPin::new(tx_pins, peripherals.GPIO5); - let parl_io = ParlIoTxOnly::new( - peripherals.PARL_IO, - dma_channel.configure(false, DmaPriority::Priority0), - tx_descriptors, - 1.MHz(), - ) - .unwrap(); + let parl_io = + ParlIoTxOnly::new(peripherals.PARL_IO, dma_channel, tx_descriptors, 1.MHz()).unwrap(); let mut clock_pin = ClkOutPin::new(peripherals.GPIO6); diff --git a/examples/src/bin/qspi_flash.rs b/examples/src/bin/qspi_flash.rs index a7e9df83b54..46552163fa9 100644 --- a/examples/src/bin/qspi_flash.rs +++ b/examples/src/bin/qspi_flash.rs @@ -30,7 +30,7 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, - dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf}, + dma::{Dma, DmaRxBuf, DmaTxBuf}, dma_buffers, prelude::*, spi::{ @@ -91,7 +91,7 @@ fn main() -> ! { .with_sio2(sio2) .with_sio3(sio3) .with_cs(cs) - .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); + .with_dma(dma_channel); let delay = Delay::new(); diff --git a/examples/src/bin/spi_loopback_dma.rs b/examples/src/bin/spi_loopback_dma.rs index 639ac030927..2d1e0567b91 100644 --- a/examples/src/bin/spi_loopback_dma.rs +++ b/examples/src/bin/spi_loopback_dma.rs @@ -21,7 +21,7 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, - dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf}, + dma::{Dma, DmaRxBuf, DmaTxBuf}, dma_buffers, prelude::*, spi::{ @@ -66,7 +66,7 @@ fn main() -> ! { .with_mosi(mosi) .with_miso(miso) .with_cs(cs) - .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); + .with_dma(dma_channel); let delay = Delay::new(); diff --git a/examples/src/bin/spi_loopback_dma_psram.rs b/examples/src/bin/spi_loopback_dma_psram.rs index 0a8fe54445b..5aeb74b8621 100644 --- a/examples/src/bin/spi_loopback_dma_psram.rs +++ b/examples/src/bin/spi_loopback_dma_psram.rs @@ -25,7 +25,7 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, - dma::{Dma, DmaBufBlkSize, DmaPriority, DmaRxBuf, DmaTxBuf}, + dma::{Dma, DmaBufBlkSize, DmaRxBuf, DmaTxBuf}, peripheral::Peripheral, prelude::*, spi::{ @@ -103,7 +103,7 @@ fn main() -> ! { .with_miso(miso) .with_mosi(mosi) .with_cs(cs) - .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); + .with_dma(dma_channel); delay.delay_millis(100); // delay to let the above messages display diff --git a/examples/src/bin/spi_slave_dma.rs b/examples/src/bin/spi_slave_dma.rs index 142816166f9..eaee969c415 100644 --- a/examples/src/bin/spi_slave_dma.rs +++ b/examples/src/bin/spi_slave_dma.rs @@ -32,7 +32,7 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, - dma::{Dma, DmaPriority}, + dma::Dma, dma_buffers, gpio::{Input, Level, Output, Pull}, prelude::*, @@ -70,11 +70,7 @@ fn main() -> ! { .with_mosi(slave_mosi) .with_miso(slave_miso) .with_cs(slave_cs) - .with_dma( - dma_channel.configure(false, DmaPriority::Priority0), - rx_descriptors, - tx_descriptors, - ); + .with_dma(dma_channel, rx_descriptors, tx_descriptors); let delay = Delay::new(); diff --git a/hil-test/tests/aes_dma.rs b/hil-test/tests/aes_dma.rs index 3fdb98db1ff..e560e041dd3 100644 --- a/hil-test/tests/aes_dma.rs +++ b/hil-test/tests/aes_dma.rs @@ -7,7 +7,7 @@ use esp_hal::{ aes::{dma::CipherMode, Aes, Mode}, - dma::{Dma, DmaPriority}, + dma::Dma, dma_buffers, peripherals::Peripherals, }; @@ -32,11 +32,8 @@ mod tests { let (mut output, rx_descriptors, input, tx_descriptors) = dma_buffers!(DMA_BUFFER_SIZE); - let mut aes = Aes::new(peripherals.AES).with_dma( - dma_channel.configure(false, DmaPriority::Priority0), - rx_descriptors, - tx_descriptors, - ); + let mut aes = + Aes::new(peripherals.AES).with_dma(dma_channel, rx_descriptors, tx_descriptors); let keytext = b"SUp4SeCp@sSw0rd"; let mut keybuf = [0_u8; 16]; @@ -74,11 +71,8 @@ mod tests { let (mut output, rx_descriptors, input, tx_descriptors) = dma_buffers!(DMA_BUFFER_SIZE); - let mut aes = Aes::new(peripherals.AES).with_dma( - dma_channel.configure(false, DmaPriority::Priority0), - rx_descriptors, - tx_descriptors, - ); + let mut aes = + Aes::new(peripherals.AES).with_dma(dma_channel, rx_descriptors, tx_descriptors); let keytext = b"SUp4SeCp@sSw0rd"; let mut keybuf = [0_u8; 16]; @@ -115,11 +109,8 @@ mod tests { let (mut output, rx_descriptors, input, tx_descriptors) = dma_buffers!(DMA_BUFFER_SIZE); - let mut aes = Aes::new(peripherals.AES).with_dma( - dma_channel.configure(false, DmaPriority::Priority0), - rx_descriptors, - tx_descriptors, - ); + let mut aes = + Aes::new(peripherals.AES).with_dma(dma_channel, rx_descriptors, tx_descriptors); let keytext = b"SUp4SeCp@sSw0rd"; let mut keybuf = [0_u8; 16]; @@ -157,11 +148,8 @@ mod tests { let (mut output, rx_descriptors, input, tx_descriptors) = dma_buffers!(DMA_BUFFER_SIZE); - let mut aes = Aes::new(peripherals.AES).with_dma( - dma_channel.configure(false, DmaPriority::Priority0), - rx_descriptors, - tx_descriptors, - ); + let mut aes = + Aes::new(peripherals.AES).with_dma(dma_channel, rx_descriptors, tx_descriptors); let keytext = b"SUp4SeCp@sSw0rd"; let mut keybuf = [0_u8; 16]; diff --git a/hil-test/tests/dma_mem2mem.rs b/hil-test/tests/dma_mem2mem.rs index d9a3a362be3..6a8af032877 100644 --- a/hil-test/tests/dma_mem2mem.rs +++ b/hil-test/tests/dma_mem2mem.rs @@ -6,7 +6,7 @@ #![no_main] use esp_hal::{ - dma::{AnyGdmaChannel, Channel, Dma, DmaError, DmaPriority, Mem2Mem}, + dma::{AnyGdmaChannel, Channel, Dma, DmaError, Mem2Mem}, dma_buffers, dma_buffers_chunk_size, dma_descriptors, @@ -50,9 +50,7 @@ mod tests { } Context { - channel: dma_channel - .configure(false, DmaPriority::Priority0) - .degrade(), + channel: dma_channel.degrade(), dma_peripheral, } } diff --git a/hil-test/tests/embassy_interrupt_spi_dma.rs b/hil-test/tests/embassy_interrupt_spi_dma.rs index 082fd2dceca..37bed2fdeb0 100644 --- a/hil-test/tests/embassy_interrupt_spi_dma.rs +++ b/hil-test/tests/embassy_interrupt_spi_dma.rs @@ -9,7 +9,7 @@ use embassy_time::{Duration, Instant, Ticker}; use esp_hal::{ - dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf}, + dma::{Dma, DmaRxBuf, DmaTxBuf}, dma_buffers, interrupt::{software::SoftwareInterruptControl, Priority}, peripheral::Peripheral, @@ -129,7 +129,7 @@ mod test { ) .with_miso(unsafe { mosi.clone_unchecked() }) .with_mosi(mosi) - .with_dma(dma_channel1.configure(false, DmaPriority::Priority0)) + .with_dma(dma_channel1) .with_buffers(dma_rx_buf, dma_tx_buf) .into_async(); @@ -142,7 +142,7 @@ mod test { ..Config::default() }, ) - .with_dma(dma_channel2.configure(false, DmaPriority::Priority0)) + .with_dma(dma_channel2) .into_async(); #[cfg(not(any(esp32, esp32s2, esp32s3)))] @@ -154,7 +154,7 @@ mod test { esp_hal::i2s::master::Standard::Philips, esp_hal::i2s::master::DataFormat::Data8Channel8, 8u32.kHz(), - dma_channel2.configure(false, DmaPriority::Priority0), + dma_channel2, rx_descriptors, tx_descriptors, ) @@ -205,14 +205,14 @@ mod test { #[timeout(3)] async fn dma_does_not_lock_up_on_core_1() { use embassy_time::Timer; - use esp_hal::peripherals::SPI2; + use esp_hal::{dma::Channel, peripherals::SPI2, Blocking}; use portable_atomic::{AtomicU32, Ordering}; cfg_if::cfg_if! { if #[cfg(pdma)] { - use esp_hal::dma::Spi2DmaChannelCreator as DmaChannelCreator; + use esp_hal::dma::Spi2DmaChannel as DmaChannel; } else { - type DmaChannelCreator = esp_hal::dma::ChannelCreator<0>; + type DmaChannel = esp_hal::dma::DmaChannel0; } } @@ -221,7 +221,7 @@ mod test { pub struct SpiPeripherals { pub spi: SPI2, - pub dma_channel: DmaChannelCreator, + pub dma_channel: Channel<'static, Blocking, DmaChannel>, } #[embassy_executor::task] @@ -238,11 +238,7 @@ mod test { ..Config::default() }, ) - .with_dma( - peripherals - .dma_channel - .configure(false, DmaPriority::Priority0), - ) + .with_dma(peripherals.dma_channel) .with_buffers(dma_rx_buf, dma_tx_buf) .into_async(); diff --git a/hil-test/tests/i2s.rs b/hil-test/tests/i2s.rs index 5fd85ca9e5f..a7e88e88344 100644 --- a/hil-test/tests/i2s.rs +++ b/hil-test/tests/i2s.rs @@ -12,21 +12,22 @@ use esp_hal::{ delay::Delay, - dma::{Dma, DmaPriority}, + dma::{Channel, Dma}, dma_buffers, gpio::{AnyPin, NoPin, Pin}, i2s::master::{DataFormat, I2s, I2sTx, Standard}, peripherals::I2S0, prelude::*, Async, + Blocking, }; use hil_test as _; cfg_if::cfg_if! { if #[cfg(any(esp32, esp32s2))] { - type DmaChannel0Creator = esp_hal::dma::I2s0DmaChannelCreator; + type DmaChannel0 = esp_hal::dma::I2s0DmaChannel; } else { - type DmaChannel0Creator = esp_hal::dma::ChannelCreator<0>; + type DmaChannel0 = esp_hal::dma::DmaChannel0; } } @@ -104,7 +105,7 @@ mod tests { struct Context { dout: AnyPin, - dma_channel: DmaChannel0Creator, + dma_channel: Channel<'static, Blocking, DmaChannel0>, i2s: I2S0, } @@ -143,7 +144,7 @@ mod tests { Standard::Philips, DataFormat::Data16Channel16, 16000.Hz(), - ctx.dma_channel.configure(false, DmaPriority::Priority0), + ctx.dma_channel, rx_descriptors, tx_descriptors, ) @@ -196,7 +197,7 @@ mod tests { Standard::Philips, DataFormat::Data16Channel16, 16000.Hz(), - ctx.dma_channel.configure(false, DmaPriority::Priority0), + ctx.dma_channel, rx_descriptors, tx_descriptors, ); @@ -305,7 +306,7 @@ mod tests { Standard::Philips, DataFormat::Data16Channel16, 16000.Hz(), - ctx.dma_channel.configure(false, DmaPriority::Priority0), + ctx.dma_channel, rx_descriptors, tx_descriptors, ); @@ -335,7 +336,7 @@ mod tests { Standard::Philips, DataFormat::Data16Channel16, 16000.Hz(), - ctx.dma_channel.configure(false, DmaPriority::Priority0), + ctx.dma_channel, rx_descriptors, tx_descriptors, ); diff --git a/hil-test/tests/lcd_cam_i8080.rs b/hil-test/tests/lcd_cam_i8080.rs index ae34f4506ef..8f35c649a0e 100644 --- a/hil-test/tests/lcd_cam_i8080.rs +++ b/hil-test/tests/lcd_cam_i8080.rs @@ -6,7 +6,7 @@ #![no_main] use esp_hal::{ - dma::{Dma, DmaPriority, DmaTxBuf}, + dma::{Dma, DmaTxBuf}, dma_buffers, gpio::{GpioPin, NoPin}, lcd_cam::{ @@ -74,13 +74,11 @@ mod tests { #[test] fn test_i8080_8bit(ctx: Context<'static>) { - let channel = ctx.dma.channel0.configure(false, DmaPriority::Priority0); - let pins = TxEightBits::new(NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin); let i8080 = I8080::new( ctx.lcd_cam.lcd, - channel.tx, + ctx.dma.channel0.tx, pins, 20.MHz(), Config::default(), @@ -130,7 +128,6 @@ mod tests { .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); - let channel = ctx.dma.channel0.configure(false, DmaPriority::Priority0); let pins = TxEightBits::new( unit0_signal, unit1_signal, @@ -144,7 +141,7 @@ mod tests { let mut i8080 = I8080::new( ctx.lcd_cam.lcd, - channel.tx, + ctx.dma.channel0.tx, pins, 20.MHz(), Config::default(), @@ -241,7 +238,7 @@ mod tests { .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); - let channel = ctx.dma.channel0.configure(false, DmaPriority::Priority0); + let channel = ctx.dma.channel0; let pins = TxSixteenBits::new( NoPin, NoPin, diff --git a/hil-test/tests/lcd_cam_i8080_async.rs b/hil-test/tests/lcd_cam_i8080_async.rs index 855d925df58..705447038f8 100644 --- a/hil-test/tests/lcd_cam_i8080_async.rs +++ b/hil-test/tests/lcd_cam_i8080_async.rs @@ -7,7 +7,7 @@ #![no_main] use esp_hal::{ - dma::{Dma, DmaPriority, DmaTxBuf}, + dma::{Dma, DmaTxBuf}, dma_buffers, gpio::NoPin, lcd_cam::{ @@ -50,12 +50,11 @@ mod tests { #[test] async fn test_i8080_8bit(ctx: Context<'static>) { - let channel = ctx.dma.channel0.configure(false, DmaPriority::Priority0); let pins = TxEightBits::new(NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin); let i8080 = I8080::new( ctx.lcd_cam.lcd, - channel.tx, + ctx.dma.channel0.tx, pins, 20.MHz(), Config::default(), diff --git a/hil-test/tests/parl_io_tx.rs b/hil-test/tests/parl_io_tx.rs index a43659bdc8c..e9cc12aa03e 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::{ChannelCreator, Dma, DmaPriority}, + dma::{Channel, Dma, DmaChannel0}, gpio::{ interconnect::{InputSignal, OutputSignal}, NoPin, @@ -27,12 +27,13 @@ use esp_hal::{ }, peripherals::PARL_IO, prelude::*, + Blocking, }; use hil_test as _; struct Context { parl_io: PARL_IO, - dma_channel: ChannelCreator<0>, + dma_channel: Channel<'static, Blocking, DmaChannel0>, clock: OutputSignal, valid: OutputSignal, clock_loopback: InputSignal, @@ -88,13 +89,8 @@ 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.configure(false, DmaPriority::Priority0), - tx_descriptors, - 10.MHz(), - ) - .unwrap(); + let pio = + ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz()).unwrap(); let mut pio = pio .tx @@ -155,13 +151,8 @@ mod tests { let mut clock_pin = ClkOutPin::new(ctx.clock); - let pio = ParlIoTxOnly::new( - ctx.parl_io, - ctx.dma_channel.configure(false, DmaPriority::Priority0), - tx_descriptors, - 10.MHz(), - ) - .unwrap(); + let pio = + ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz()).unwrap(); let mut pio = pio .tx diff --git a/hil-test/tests/parl_io_tx_async.rs b/hil-test/tests/parl_io_tx_async.rs index 240a805c0e6..09c4d6899fa 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::{ChannelCreator, Dma, DmaPriority}, + dma::{Channel, Dma, DmaChannel0}, gpio::{ interconnect::{InputSignal, OutputSignal}, NoPin, @@ -29,12 +29,13 @@ use esp_hal::{ }, peripherals::PARL_IO, prelude::*, + Async, }; use hil_test as _; struct Context { parl_io: PARL_IO, - dma_channel: ChannelCreator<0>, + dma_channel: Channel<'static, Async, DmaChannel0>, clock: OutputSignal, valid: OutputSignal, clock_loopback: InputSignal, @@ -60,7 +61,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; + let dma_channel = dma.channel0.into_async(); let parl_io = peripherals.PARL_IO; @@ -90,15 +91,8 @@ 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 - .configure(false, DmaPriority::Priority0) - .into_async(), - tx_descriptors, - 10.MHz(), - ) - .unwrap(); + let pio = + ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz()).unwrap(); let mut pio = pio .tx @@ -158,15 +152,8 @@ mod tests { let mut clock_pin = ClkOutPin::new(ctx.clock); - let pio = ParlIoTxOnly::new( - ctx.parl_io, - ctx.dma_channel - .configure(false, DmaPriority::Priority0) - .into_async(), - tx_descriptors, - 10.MHz(), - ) - .unwrap(); + let pio = + ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz()).unwrap(); let mut pio = pio .tx diff --git a/hil-test/tests/qspi.rs b/hil-test/tests/qspi.rs index 43b500d9a7a..4c5a1e6a2f4 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, DmaPriority, DmaRxBuf, DmaTxBuf}, + dma::{Channel, Dma, DmaRxBuf, DmaTxBuf}, dma_buffers, gpio::{AnyPin, Input, Level, Output, Pull}, prelude::*, @@ -202,7 +202,6 @@ mod tests { } } - let dma_channel = dma_channel.configure(false, DmaPriority::Priority0); let spi = Spi::new_with_config( peripherals.SPI2, Config { diff --git a/hil-test/tests/spi_full_duplex.rs b/hil-test/tests/spi_full_duplex.rs index 1b893dcb132..a32a267e5e9 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::{Dma, DmaDescriptor, DmaPriority, DmaRxBuf, DmaTxBuf}, + dma::{Channel, Dma, DmaDescriptor, DmaRxBuf, DmaTxBuf}, dma_buffers, gpio::{Level, NoPin}, peripheral::Peripheral, @@ -29,15 +29,15 @@ use hil_test as _; cfg_if::cfg_if! { if #[cfg(any(esp32, esp32s2))] { - type DmaChannelCreator = esp_hal::dma::Spi2DmaChannelCreator; + type DmaChannel = esp_hal::dma::Spi2DmaChannel; } else { - type DmaChannelCreator = esp_hal::dma::ChannelCreator<0>; + type DmaChannel = esp_hal::dma::DmaChannel0; } } struct Context { spi: Spi<'static, Blocking>, - dma_channel: DmaChannelCreator, + dma_channel: Channel<'static, Blocking, 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], @@ -204,9 +204,7 @@ mod tests { let mut dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); let unit = ctx.pcnt_unit; - let mut spi = ctx - .spi - .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)); + let mut spi = ctx.spi.with_dma(ctx.dma_channel); unit.channel0.set_edge_signal(ctx.pcnt_source); unit.channel0 @@ -237,9 +235,7 @@ mod tests { let mut dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); let unit = ctx.pcnt_unit; - let mut spi = ctx - .spi - .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)); + let mut spi = ctx.spi.with_dma(ctx.dma_channel); unit.channel0.set_edge_signal(ctx.pcnt_source); unit.channel0 @@ -274,9 +270,7 @@ mod tests { *v = (i % 255) as u8; } - let mut spi = ctx - .spi - .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)); + let mut spi = ctx.spi.with_dma(ctx.dma_channel); for i in 0..4 { dma_tx_buf.as_mut_slice()[0] = i as u8; @@ -304,9 +298,7 @@ mod tests { dma_tx_buf.fill(&[0xde, 0xad, 0xbe, 0xef]); - let spi = ctx - .spi - .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)); + let spi = ctx.spi.with_dma(ctx.dma_channel); let transfer = spi .transfer(dma_rx_buf, dma_tx_buf) .map_err(|e| e.0) @@ -335,7 +327,7 @@ mod tests { let mut spi = ctx .spi - .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)) + .with_dma(ctx.dma_channel) .with_buffers(dma_rx_buf, dma_tx_buf); let tx_buf = [0xde, 0xad, 0xbe, 0xef]; @@ -355,7 +347,7 @@ mod tests { let mut spi = ctx .spi - .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)) + .with_dma(ctx.dma_channel) .with_buffers(dma_rx_buf, dma_tx_buf); let tx_buf = [0xde, 0xad, 0xbe, 0xef]; @@ -377,7 +369,7 @@ mod tests { let mut spi = ctx .spi - .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)) + .with_dma(ctx.dma_channel) .with_buffers(dma_rx_buf, dma_tx_buf); let tx_buf = core::array::from_fn(|i| i as _); @@ -398,7 +390,7 @@ mod tests { let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); let mut spi = ctx .spi - .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)) + .with_dma(ctx.dma_channel) .with_buffers(dma_rx_buf, dma_tx_buf) .into_async(); @@ -432,9 +424,9 @@ mod tests { let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); let mut spi = ctx .spi - .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)) - .with_buffers(dma_rx_buf, dma_tx_buf) - .into_async(); + .into_async() + .with_dma(ctx.dma_channel) + .with_buffers(dma_rx_buf, dma_tx_buf); ctx.pcnt_unit.channel0.set_edge_signal(ctx.pcnt_source); ctx.pcnt_unit @@ -465,7 +457,7 @@ mod tests { .spi .with_mosi(NoPin) .with_miso(Level::High) - .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)); + .with_dma(ctx.dma_channel); let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(4); let mut dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap(); @@ -507,9 +499,7 @@ mod tests { let dma_rx_buf = DmaRxBuf::new(ctx.rx_descriptors, ctx.rx_buffer).unwrap(); let dma_tx_buf = DmaTxBuf::new(ctx.tx_descriptors, ctx.tx_buffer).unwrap(); - let spi = ctx - .spi - .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)); + let spi = ctx.spi.with_dma(ctx.dma_channel); let mut transfer = spi .transfer(dma_rx_buf, dma_tx_buf) @@ -535,9 +525,7 @@ mod tests { let mut dma_rx_buf = DmaRxBuf::new(ctx.rx_descriptors, ctx.rx_buffer).unwrap(); let mut dma_tx_buf = DmaTxBuf::new(ctx.tx_descriptors, ctx.tx_buffer).unwrap(); - let mut spi = ctx - .spi - .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)); + let mut spi = ctx.spi.with_dma(ctx.dma_channel); let mut transfer = spi .transfer(dma_rx_buf, dma_tx_buf) @@ -573,10 +561,7 @@ mod tests { let dma_rx_buf = DmaRxBuf::new(ctx.rx_descriptors, ctx.rx_buffer).unwrap(); let dma_tx_buf = DmaTxBuf::new(ctx.tx_descriptors, ctx.tx_buffer).unwrap(); - let spi = ctx - .spi - .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)) - .into_async(); + let spi = ctx.spi.with_dma(ctx.dma_channel).into_async(); let mut transfer = spi .transfer(dma_rx_buf, dma_tx_buf) diff --git a/hil-test/tests/spi_half_duplex_read.rs b/hil-test/tests/spi_half_duplex_read.rs index 212e764424a..12b77d1b065 100644 --- a/hil-test/tests/spi_half_duplex_read.rs +++ b/hil-test/tests/spi_half_duplex_read.rs @@ -6,7 +6,7 @@ #![no_main] use esp_hal::{ - dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf}, + dma::{Dma, DmaRxBuf, DmaTxBuf}, dma_buffers, gpio::{Level, Output}, prelude::*, @@ -58,7 +58,7 @@ mod tests { ) .with_sck(sclk) .with_miso(miso) - .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); + .with_dma(dma_channel); Context { spi, miso_mirror } } diff --git a/hil-test/tests/spi_half_duplex_write.rs b/hil-test/tests/spi_half_duplex_write.rs index 1db9ad2cb13..a07ecd65ca5 100644 --- a/hil-test/tests/spi_half_duplex_write.rs +++ b/hil-test/tests/spi_half_duplex_write.rs @@ -6,7 +6,7 @@ #![no_main] use esp_hal::{ - dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf}, + dma::{Dma, DmaRxBuf, DmaTxBuf}, dma_buffers, gpio::interconnect::InputSignal, pcnt::{channel::EdgeMode, unit::Unit, Pcnt}, @@ -61,7 +61,7 @@ mod tests { ) .with_sck(sclk) .with_mosi(mosi) - .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); + .with_dma(dma_channel); Context { spi, diff --git a/hil-test/tests/spi_half_duplex_write_psram.rs b/hil-test/tests/spi_half_duplex_write_psram.rs index 91f29804adb..e0eead9bde9 100644 --- a/hil-test/tests/spi_half_duplex_write_psram.rs +++ b/hil-test/tests/spi_half_duplex_write_psram.rs @@ -7,7 +7,7 @@ use defmt::error; use esp_alloc as _; use esp_hal::{ - dma::{Dma, DmaBufBlkSize, DmaPriority, DmaRxBuf, DmaTxBuf}, + dma::{Dma, DmaBufBlkSize, DmaRxBuf, DmaTxBuf}, dma_buffers, dma_descriptors_chunk_size, gpio::interconnect::InputSignal, @@ -73,7 +73,7 @@ mod tests { ) .with_sck(sclk) .with_mosi(mosi) - .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); + .with_dma(dma_channel); Context { spi, diff --git a/hil-test/tests/spi_slave.rs b/hil-test/tests/spi_slave.rs index 0ccda85e86f..3485587aeac 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::{Dma, DmaPriority}, + dma::{Channel, Dma}, dma_buffers, gpio::{Input, Level, Output, Pull}, peripheral::Peripheral, @@ -20,15 +20,15 @@ use hil_test as _; cfg_if::cfg_if! { if #[cfg(any(esp32, esp32s2))] { - type DmaChannelCreator = esp_hal::dma::Spi2DmaChannelCreator; + type DmaChannel = esp_hal::dma::Spi2DmaChannel; } else { - type DmaChannelCreator = esp_hal::dma::ChannelCreator<0>; + type DmaChannel = esp_hal::dma::DmaChannel0; } } struct Context { spi: Spi<'static, Blocking>, - dma_channel: DmaChannelCreator, + dma_channel: Channel<'static, Blocking, DmaChannel>, bitbang_spi: BitbangSpi, } @@ -143,11 +143,9 @@ mod tests { fn test_basic(mut ctx: Context) { const DMA_SIZE: usize = 32; let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(DMA_SIZE); - let mut spi = ctx.spi.with_dma( - ctx.dma_channel.configure(false, DmaPriority::Priority0), - rx_descriptors, - tx_descriptors, - ); + let mut spi = ctx + .spi + .with_dma(ctx.dma_channel, rx_descriptors, tx_descriptors); let slave_send = tx_buffer; let slave_receive = rx_buffer; From 19ffa186a54333eba8f95f8af91d2f75cf1441e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 13 Nov 2024 20:46:46 +0100 Subject: [PATCH 07/13] Fix up I2sParallel --- esp-hal/src/i2s/master.rs | 2 +- esp-hal/src/i2s/parallel.rs | 40 +++++++++++++++++++----- examples/src/bin/embassy_i2s_parallel.rs | 12 ++----- examples/src/bin/i2s_parallel.rs | 10 ++---- 4 files changed, 37 insertions(+), 27 deletions(-) diff --git a/esp-hal/src/i2s/master.rs b/esp-hal/src/i2s/master.rs index 1a238e6c6fc..75d56341644 100644 --- a/esp-hal/src/i2s/master.rs +++ b/esp-hal/src/i2s/master.rs @@ -422,7 +422,7 @@ where ) } - /// Converts the SPI instance into async mode. + /// Converts the I2S instance into async mode. pub fn into_async(self) -> I2s<'d, Async, T> { I2s { i2s_rx: RxCreator { diff --git a/esp-hal/src/i2s/parallel.rs b/esp-hal/src/i2s/parallel.rs index c7b84e630ce..7746ac42f55 100644 --- a/esp-hal/src/i2s/parallel.rs +++ b/esp-hal/src/i2s/parallel.rs @@ -62,6 +62,7 @@ use crate::{ private::Internal, system::PeripheralClockControl, Async, + Blocking, Mode, }; @@ -179,14 +180,11 @@ where tx_channel: ChannelTx<'d, DM, I::Dma>, } -impl<'d, DM> I2sParallel<'d, DM> -where - DM: Mode, -{ +impl<'d> I2sParallel<'d, Blocking> { /// Create a new I2S Parallel Interface pub fn new( i2s: impl Peripheral

+ 'd, - channel: Channel<'d, DM, CH>, + channel: Channel<'d, Blocking, CH>, frequency: impl Into, pins: impl TxPins<'d>, clock_pin: impl Peripheral

+ 'd, @@ -198,15 +196,14 @@ where } } -impl<'d, I, DM> I2sParallel<'d, DM, I> +impl<'d, I> I2sParallel<'d, Blocking, I> where I: Instance, - DM: Mode, { /// Create a new I2S Parallel Interface pub fn new_typed( i2s: impl Peripheral

+ 'd, - channel: Channel<'d, DM, CH>, + channel: Channel<'d, Blocking, CH>, frequency: impl Into, mut pins: impl TxPins<'d>, clock_pin: impl Peripheral

+ 'd, @@ -235,6 +232,33 @@ where } } + /// Converts the I2S instance into async mode. + pub fn into_async(self) -> I2sParallel<'d, Async, I> { + I2sParallel { + instance: self.instance, + tx_channel: self.tx_channel.into_async(), + } + } +} + +impl<'d, I> I2sParallel<'d, Async, I> +where + I: Instance, +{ + /// Converts the I2S instance into async mode. + pub fn into_blocking(self) -> I2sParallel<'d, Blocking, I> { + I2sParallel { + instance: self.instance, + tx_channel: self.tx_channel.into_blocking(), + } + } +} + +impl<'d, I, DM> I2sParallel<'d, DM, I> +where + I: Instance, + DM: Mode, +{ /// Write data to the I2S peripheral pub fn send( mut self, diff --git a/examples/src/bin/embassy_i2s_parallel.rs b/examples/src/bin/embassy_i2s_parallel.rs index 927b95ded17..3ece585c35c 100644 --- a/examples/src/bin/embassy_i2s_parallel.rs +++ b/examples/src/bin/embassy_i2s_parallel.rs @@ -18,7 +18,7 @@ use embassy_executor::Spawner; use embassy_time::Timer; use esp_backtrace as _; use esp_hal::{ - dma::{Dma, DmaPriority, DmaTxBuf}, + dma::{Dma, DmaTxBuf}, dma_buffers, i2s::parallel::{I2sParallel, TxEightBits}, prelude::*, @@ -56,15 +56,7 @@ async fn main(_spawner: Spawner) { ); let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, BUFFER_SIZE); - let mut parallel = I2sParallel::new( - i2s, - dma_channel - .configure(false, DmaPriority::Priority0) - .into_async(), - 1.MHz(), - pins, - clock, - ); + let mut parallel = I2sParallel::new(i2s, dma_channel, 1.MHz(), pins, clock).into_async(); for (i, data) in tx_buffer.chunks_mut(4).enumerate() { let offset = i * 4; diff --git a/examples/src/bin/i2s_parallel.rs b/examples/src/bin/i2s_parallel.rs index 5f1bd400a3f..6d4d8a2633f 100644 --- a/examples/src/bin/i2s_parallel.rs +++ b/examples/src/bin/i2s_parallel.rs @@ -16,7 +16,7 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, - dma::{Dma, DmaPriority, DmaTxBuf}, + dma::{Dma, DmaTxBuf}, dma_buffers, i2s::parallel::{I2sParallel, TxEightBits}, prelude::*, @@ -50,13 +50,7 @@ fn main() -> ! { ); let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, BUFFER_SIZE); - let mut parallel = I2sParallel::new( - i2s, - dma_channel.configure(false, DmaPriority::Priority0), - 1.MHz(), - pins, - clock, - ); + let mut parallel = I2sParallel::new(i2s, dma_channel, 1.MHz(), pins, clock); for (i, data) in tx_buffer.chunks_mut(4).enumerate() { let offset = i * 4; From f6ead84f766b41233d068d01c2feecb9f8792078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 13 Nov 2024 18:35:45 +0100 Subject: [PATCH 08/13] Always enable burst transfering descriptors --- esp-hal/src/dma/gdma.rs | 26 ++++++++++++++++++-------- esp-hal/src/dma/mod.rs | 8 +++++++- esp-hal/src/dma/pdma.rs | 41 +++++++++++++++++++++++++++++------------ 3 files changed, 54 insertions(+), 21 deletions(-) diff --git a/esp-hal/src/dma/gdma.rs b/esp-hal/src/dma/gdma.rs index ef96c7ff20f..f5b4efd9091 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -170,10 +170,15 @@ impl RegisterAccess for ChannelTxImpl { } fn set_burst_mode(&self, burst_mode: bool) { - self.ch().out_conf0().modify(|_, w| { - w.out_data_burst_en().bit(burst_mode); - w.outdscr_burst_en().bit(burst_mode) - }); + self.ch() + .out_conf0() + .modify(|_, w| w.out_data_burst_en().bit(burst_mode)); + } + + fn set_descr_burst_mode(&self, burst_mode: bool) { + self.ch() + .out_conf0() + .modify(|_, w| w.outdscr_burst_en().bit(burst_mode)); } fn set_priority(&self, priority: DmaPriority) { @@ -389,10 +394,15 @@ impl RegisterAccess for ChannelRxImpl { } fn set_burst_mode(&self, burst_mode: bool) { - self.ch().in_conf0().modify(|_, w| { - w.in_data_burst_en().bit(burst_mode); - w.indscr_burst_en().bit(burst_mode) - }); + self.ch() + .in_conf0() + .modify(|_, w| w.in_data_burst_en().bit(burst_mode)); + } + + fn set_descr_burst_mode(&self, burst_mode: bool) { + self.ch() + .in_conf0() + .modify(|_, w| w.indscr_burst_en().bit(burst_mode)); } fn set_priority(&self, priority: DmaPriority) { diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index 1ea2b1de4f6..8bf9f92b1c1 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -1820,6 +1820,7 @@ where let preparation = buffer.prepare(); self.rx_impl.set_burst_mode(false); + self.rx_impl.set_descr_burst_mode(true); self.rx_impl.set_check_owner(preparation.check_owner); compiler_fence(core::sync::atomic::Ordering::SeqCst); @@ -2108,6 +2109,7 @@ where ); self.tx_impl.set_burst_mode(false); + self.tx_impl.set_descr_burst_mode(true); self.tx_impl.set_check_owner(preparation.check_owner); compiler_fence(core::sync::atomic::Ordering::SeqCst); @@ -2181,9 +2183,13 @@ pub trait RegisterAccess: crate::private::Sealed { fn reset(&self); /// Enable/Disable INCR burst transfer for channel reading - /// descriptor and accessing data in internal RAM. + /// accessing data in internal RAM. fn set_burst_mode(&self, burst_mode: bool); + /// Enable/Disable burst transfer for channel reading + /// descriptors in internal RAM. + fn set_descr_burst_mode(&self, burst_mode: bool); + /// The priority of the channel. The larger the value, the higher the /// priority. #[cfg(gdma)] diff --git a/esp-hal/src/dma/pdma.rs b/esp-hal/src/dma/pdma.rs index 667767c3eb9..c7856fc4105 100644 --- a/esp-hal/src/dma/pdma.rs +++ b/esp-hal/src/dma/pdma.rs @@ -58,6 +58,12 @@ impl> RegisterAccess for SpiDma } fn set_burst_mode(&self, burst_mode: bool) { + let spi = self.0.register_block(); + spi.dma_conf() + .modify(|_, w| w.out_data_burst_en().bit(burst_mode)); + } + + fn set_descr_burst_mode(&self, burst_mode: bool) { let spi = self.0.register_block(); spi.dma_conf() .modify(|_, w| w.outdscr_burst_en().bit(burst_mode)); @@ -216,7 +222,9 @@ impl> RegisterAccess for SpiDma spi.dma_conf().modify(|_, w| w.in_rst().clear_bit()); } - fn set_burst_mode(&self, burst_mode: bool) { + fn set_burst_mode(&self, _burst_mode: bool) {} + + fn set_descr_burst_mode(&self, burst_mode: bool) { let spi = self.0.register_block(); spi.dma_conf() .modify(|_, w| w.indscr_burst_en().bit(burst_mode)); @@ -466,17 +474,24 @@ pub struct I2sDmaTxChannelImpl(C); impl crate::private::Sealed for I2sDmaTxChannelImpl {} impl> RegisterAccess for I2sDmaTxChannelImpl { + fn reset(&self) { + let reg_block = self.0.register_block(); + reg_block.lc_conf().modify(|_, w| w.out_rst().set_bit()); + reg_block.lc_conf().modify(|_, w| w.out_rst().clear_bit()); + } + fn set_burst_mode(&self, burst_mode: bool) { let reg_block = self.0.register_block(); reg_block .lc_conf() - .modify(|_, w| w.outdscr_burst_en().bit(burst_mode)); + .modify(|_, w| w.out_data_burst_en().bit(burst_mode)); } - fn reset(&self) { + fn set_descr_burst_mode(&self, burst_mode: bool) { let reg_block = self.0.register_block(); - reg_block.lc_conf().modify(|_, w| w.out_rst().set_bit()); - reg_block.lc_conf().modify(|_, w| w.out_rst().clear_bit()); + reg_block + .lc_conf() + .modify(|_, w| w.outdscr_burst_en().bit(burst_mode)); } fn set_link_addr(&self, address: u32) { @@ -638,19 +653,21 @@ impl> InterruptAccess> RegisterAccess for I2sDmaRxChannelImpl { - fn set_burst_mode(&self, burst_mode: bool) { - let reg_block = self.0.register_block(); - reg_block - .lc_conf() - .modify(|_, w| w.indscr_burst_en().bit(burst_mode)); - } - fn reset(&self) { let reg_block = self.0.register_block(); reg_block.lc_conf().modify(|_, w| w.in_rst().set_bit()); reg_block.lc_conf().modify(|_, w| w.in_rst().clear_bit()); } + fn set_burst_mode(&self, _burst_mode: bool) {} + + fn set_descr_burst_mode(&self, burst_mode: bool) { + let reg_block = self.0.register_block(); + reg_block + .lc_conf() + .modify(|_, w| w.indscr_burst_en().bit(burst_mode)); + } + fn set_link_addr(&self, address: u32) { let reg_block = self.0.register_block(); reg_block From fb828db20ffa5d900a49d12e8d8cdecc0d955913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 11 Nov 2024 17:17:15 +0100 Subject: [PATCH 09/13] Create DMA Channels inside peripherals --- esp-hal/src/aes/mod.rs | 19 +- esp-hal/src/dma/gdma.rs | 310 +++++++++++++------------- esp-hal/src/dma/m2m.rs | 24 +- esp-hal/src/dma/mod.rs | 174 +++++++-------- esp-hal/src/dma/pdma.rs | 289 ++++++++++++++---------- esp-hal/src/i2s/master.rs | 58 ++--- esp-hal/src/i2s/parallel.rs | 14 +- esp-hal/src/lcd_cam/cam.rs | 11 +- esp-hal/src/lcd_cam/lcd/i8080.rs | 11 +- esp-hal/src/parl_io.rs | 74 +++--- esp-hal/src/peripheral.rs | 31 ++- esp-hal/src/spi/master.rs | 62 +++--- esp-hal/src/spi/slave.rs | 52 +++-- hil-test/tests/lcd_cam_i8080.rs | 16 +- hil-test/tests/lcd_cam_i8080_async.rs | 2 +- 15 files changed, 606 insertions(+), 541 deletions(-) diff --git a/esp-hal/src/aes/mod.rs b/esp-hal/src/aes/mod.rs index 34a14f03ce9..b832ce9a0da 100644 --- a/esp-hal/src/aes/mod.rs +++ b/esp-hal/src/aes/mod.rs @@ -240,15 +240,18 @@ pub mod dma { ChannelTx, DescriptorChain, DmaChannelConvert, + DmaChannelFor, DmaDescriptor, - DmaEligible, DmaPeripheral, DmaTransferRxTx, ReadBuffer, Rx, + RxChannelFor, Tx, + TxChannelFor, WriteBuffer, }, + peripheral::Peripheral, peripherals::AES, Blocking, }; @@ -276,7 +279,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, } @@ -285,16 +288,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), } @@ -324,7 +329,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 @@ -336,7 +341,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 f5b4efd9091..e1a6c6085dd 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -16,106 +16,54 @@ 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; + + unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) { + (AnyGdmaRxChannel(self.0), AnyGdmaTxChannel(self.0)) + } } -#[non_exhaustive] -#[doc(hidden)] -pub struct SpecificGdmaChannel {} +/// An arbitrary GDMA RX channel +pub struct AnyGdmaRxChannel(u8); -impl GdmaChannel for AnyGdmaChannel { - fn number(&self) -> u8 { - self.0 +impl Peripheral for AnyGdmaRxChannel { + type P = Self; + + unsafe fn clone_unchecked(&self) -> Self::P { + Self(self.0) } } -impl GdmaChannel for SpecificGdmaChannel { - fn number(&self) -> u8 { - N + +/// 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) } } -#[non_exhaustive] -#[doc(hidden)] -pub struct ChannelTxImpl(C); - use embassy_sync::waitqueue::AtomicWaker; static TX_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT]; @@ -129,40 +77,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 +176,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 +192,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 +292,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 +308,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 ChannelRxImpl {} +impl crate::private::Sealed for AnyGdmaRxChannel {} +impl DmaRxChannel for AnyGdmaRxChannel {} -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 +413,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 +421,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 +529,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 +545,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); } } } @@ -587,7 +569,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 { @@ -608,44 +609,39 @@ macro_rules! impl_channel { } impl DmaChannel for [] { - type Rx = ChannelRxImpl>; - type Tx = ChannelTxImpl>; + type Rx = AnyGdmaRxChannel; + type Tx = AnyGdmaTxChannel; + + 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_tx(tx: Self::Tx) -> ChannelTxImpl { - tx.degrade() + fn degrade(self) -> AnyGdmaChannel { + AnyGdmaChannel($num) } } - impl DmaChannelExt for [] { - fn rx_interrupts() -> impl InterruptAccess { - ChannelRxImpl(SpecificGdmaChannel::<$num> {}) + impl DmaChannelConvert for [] { + fn degrade(self) -> AnyGdmaRxChannel { + AnyGdmaRxChannel($num) } + } - fn tx_interrupts() -> impl InterruptAccess { - ChannelTxImpl(SpecificGdmaChannel::<$num> {}) + impl DmaChannelConvert for [] { + fn degrade(self) -> AnyGdmaTxChannel { + AnyGdmaTxChannel($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); + impl DmaChannelExt for [] { + fn rx_interrupts() -> impl InterruptAccess { + AnyGdmaRxChannel($num) + } - this + fn tx_interrupts() -> impl InterruptAccess { + AnyGdmaTxChannel($num) } } } @@ -741,29 +737,27 @@ 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); - PeripheralClockControl::enable(Peripheral::Gdma); + PeripheralClockControl::enable(system::Peripheral::Gdma); dma.misc_conf().modify(|_, w| w.ahbm_rst_inter().set_bit()); dma.misc_conf() .modify(|_, w| w.ahbm_rst_inter().clear_bit()); diff --git a/esp-hal/src/dma/m2m.rs b/esp-hal/src/dma/m2m.rs index 0b2009950eb..495d6378843 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 8bf9f92b1c1..142950f1d13 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, @@ -919,6 +920,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 { @@ -1561,13 +1569,42 @@ 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; + + /// Splits the DMA channel into its RX and TX halves. + #[cfg(any(not(esp32c2), not(esp32s3)))] + 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)] @@ -1582,18 +1619,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 } } @@ -1659,17 +1691,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. @@ -1700,10 +1735,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()); @@ -1719,7 +1751,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> { @@ -1737,20 +1769,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) { @@ -1761,14 +1781,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, { unsafe fn prepare_transfer_without_start( &mut self, @@ -1947,24 +1967,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, @@ -1983,10 +2005,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()); @@ -2002,7 +2021,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> { @@ -2020,20 +2039,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) { @@ -2044,14 +2051,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, { unsafe fn prepare_transfer_without_start( &mut self, @@ -2266,28 +2273,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); } @@ -2375,25 +2392,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 c7856fc4105..b6410fa1c41 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()) + } +} + +/// The TX half of an arbitrary SPI DMA channel. +pub struct AnySpiDmaTxChannel(AnySpiDmaChannel); -impl crate::private::Sealed for SpiDmaTxChannelImpl {} +impl crate::private::Sealed for AnySpiDmaTxChannel {} +impl DmaTxChannel for AnySpiDmaTxChannel {} +impl Peripheral for AnySpiDmaTxChannel { + type P = Self; -impl> RegisterAccess for SpiDmaTxChannelImpl { + 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()) + } +} + +/// The TX half of an arbitrary I2S DMA channel. +pub struct AnyI2sDmaTxChannel(AnyI2sDmaChannel); -impl crate::private::Sealed 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 I2sDmaTxChannelImpl { +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(self) -> AnyI2sDmaChannel { + self.into() } - fn degrade_tx(tx: I2sDmaTxChannelImpl) -> I2sDmaTxChannelImpl { - I2sDmaTxChannelImpl(tx.0.into()) + } + + impl DmaChannelConvert for [] { + fn degrade(self) -> AnyI2sDmaRxChannel { + AnyI2sDmaRxChannel(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) -> AnyI2sDmaTxChannel { + AnyI2sDmaTxChannel(Self {}.into()) } } } @@ -921,22 +980,20 @@ 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> { - PeripheralClockControl::enable(Peripheral::Dma); + pub fn new(dma: impl Peripheral

+ 'd) -> Dma<'d> { + PeripheralClockControl::enable(system::Peripheral::Dma); #[cfg(esp32)] { @@ -981,31 +1038,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; + + 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 AnySpiDmaChannelInner { +impl PdmaChannel for AnySpiDmaChannel { type RegisterBlock = SpiRegisterBlock; delegate::delegate! { - to match self { + to match &self.0 { AnySpiDmaChannelInner::Spi2(channel) => channel, AnySpiDmaChannelInner::Spi3(channel) => channel, } { @@ -1021,32 +1078,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; + + 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 AnyI2sDmaChannelInner { +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 75d56341644..1130644d965 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 @@ -288,7 +288,6 @@ where i2s.set_master(); i2s.update(); - let channel = channel.degrade(); Self { i2s_rx: RxCreator { i2s: unsafe { i2s.clone_unchecked() }, @@ -363,19 +362,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(), @@ -396,19 +393,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( @@ -416,7 +411,7 @@ where standard, data_format, sample_rate, - channel.into(), + channel.map(|ch| ch.degrade()).into_ref(), rx_descriptors, tx_descriptors, ) @@ -458,9 +453,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, } @@ -493,7 +489,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 @@ -592,7 +588,7 @@ where DmaMode: Mode, { i2s: PeripheralRef<'d, T>, - rx_channel: ChannelRx<'d, DmaMode, T::Dma>, + rx_channel: ChannelRx<'d, DmaMode, RxChannelFor>, rx_chain: DescriptorChain, } @@ -625,7 +621,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 @@ -734,15 +730,7 @@ mod private { use enumset::EnumSet; use fugit::HertzU32; - use super::{ - DataFormat, - I2sInterrupt, - I2sRx, - I2sTx, - 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 @@ -769,7 +757,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], } @@ -826,7 +814,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], } diff --git a/esp-hal/src/i2s/parallel.rs b/esp-hal/src/i2s/parallel.rs index 7746ac42f55..6ee84fefb1e 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,20 +179,20 @@ where I: Instance, { instance: PeripheralRef<'d, I>, - tx_channel: ChannelTx<'d, DM, I::Dma>, + tx_channel: ChannelTx<'d, DM, TxChannelFor>, } 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) } @@ -203,19 +205,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(); PeripheralClockControl::reset(i2s.peripheral()); PeripheralClockControl::enable(i2s.peripheral()); diff --git a/esp-hal/src/lcd_cam/cam.rs b/esp-hal/src/lcd_cam/cam.rs index 6b237470de2..cd5682d978c 100644 --- a/esp-hal/src/lcd_cam/cam.rs +++ b/esp-hal/src/lcd_cam/cam.rs @@ -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, @@ -121,21 +121,22 @@ 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>, } 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(); @@ -181,7 +182,7 @@ impl<'d> Camera<'d> { Self { lcd_cam, - rx_channel: channel.degrade(), + rx_channel, } } } diff --git a/esp-hal/src/lcd_cam/lcd/i8080.rs b/esp-hal/src/lcd_cam/lcd/i8080.rs index 5dab70ce986..b3c2ab13d4a 100644 --- a/esp-hal/src/lcd_cam/lcd/i8080.rs +++ b/esp-hal/src/lcd_cam/lcd/i8080.rs @@ -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 1b81ca2901e..dbde71b6648 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::PeripheralClockControl, Async, Blocking, @@ -807,7 +809,7 @@ pub struct ParlIoTx<'d, DM> where DM: Mode, { - tx_channel: ChannelTx<'d, DM, ::Dma>, + tx_channel: ChannelTx<'d, DM, TxChannelFor>, tx_chain: DescriptorChain, } @@ -883,7 +885,7 @@ pub struct ParlIoRx<'d, DM> where DM: Mode, { - rx_channel: ChannelRx<'d, DM, ::Dma>, + rx_channel: ChannelRx<'d, DM, RxChannelFor>, rx_chain: DescriptorChain, } @@ -995,28 +997,26 @@ 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 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, }, rx: RxCreatorFullDuplex { - rx_channel: dma_channel.rx.degrade(), + rx_channel: dma_channel.rx, descriptors: rx_descriptors, }, }) @@ -1099,26 +1099,24 @@ 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] + // TODO: into_async() 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 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, }, }) @@ -1173,26 +1171,24 @@ 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? + // TODO: into_async() 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 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, }, }) @@ -1344,7 +1340,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 @@ -1386,7 +1382,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, @@ -1440,7 +1436,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 @@ -1456,7 +1452,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], } @@ -1465,7 +1461,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], } @@ -1474,7 +1470,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], } @@ -1483,7 +1479,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], } diff --git a/esp-hal/src/peripheral.rs b/esp-hal/src/peripheral.rs index c2c10a417fe..622470d859b 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 dacb255866b..527514d8b34 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}, @@ -464,26 +464,6 @@ pub struct Spi<'d, M, T = AnySpi> { _mode: PhantomData, } -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, @@ -547,6 +527,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> { @@ -856,6 +853,7 @@ mod dma { dma::{ asynch::{DmaRxFuture, DmaTxFuture}, Channel, + DmaChannelFor, DmaRxBuf, DmaRxBuffer, DmaTxBuf, @@ -882,7 +880,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))] @@ -987,15 +985,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 = { @@ -1019,14 +1017,20 @@ mod dma { Self { spi, - channel: channel.degrade(), + channel, #[cfg(all(esp32, spi_address_workaround))] address_buffer, tx_transfer_in_progress: false, rx_transfer_in_progress: false, } } + } + 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 80f76e22b6b..0c6a5efe65a 100644 --- a/esp-hal/src/spi/slave.rs +++ b/esp-hal/src/spi/slave.rs @@ -176,39 +176,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, + ) } } @@ -219,7 +224,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, } @@ -258,7 +263,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 @@ -274,7 +279,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 @@ -285,29 +290,32 @@ 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); Self { spi, - channel: channel.degrade(), + channel, rx_chain: DescriptorChain::new(rx_descriptors), tx_chain: DescriptorChain::new(tx_descriptors), } } + } + 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/hil-test/tests/lcd_cam_i8080.rs b/hil-test/tests/lcd_cam_i8080.rs index 8f35c649a0e..da5ad4df11f 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 705447038f8..b2da394fb0c 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(), From 92273404a1a69e6d3c10449d02689d309a613893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 13 Nov 2024 13:45:11 +0100 Subject: [PATCH 10/13] Add PARL_IO into_async functions --- esp-hal/src/parl_io.rs | 117 ++++++++++++++++++++++++++++++++++------- 1 file changed, 97 insertions(+), 20 deletions(-) diff --git a/esp-hal/src/parl_io.rs b/esp-hal/src/parl_io.rs index dbde71b6648..01f8b12723c 100644 --- a/esp-hal/src/parl_io.rs +++ b/esp-hal/src/parl_io.rs @@ -1024,6 +1024,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(), @@ -1101,7 +1112,6 @@ where impl<'d> ParlIoTxOnly<'d, Blocking> { /// Creates a new [ParlIoTxOnly] - // TODO: into_async() pub fn new( _parl_io: impl Peripheral

+ 'd, dma_channel: impl Peripheral

+ 'd, @@ -1121,9 +1131,28 @@ impl<'d> ParlIoTxOnly<'d, Blocking> { }, }) } -} -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, + }, + } + } + /// Sets the interrupt handler, enables it with /// [crate::interrupt::Priority::min()] /// @@ -1153,6 +1182,18 @@ 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, + }, + } + } +} + impl crate::private::Sealed for ParlIoTxOnly<'_, Blocking> {} impl InterruptConfigurable for ParlIoTxOnly<'_, Blocking> { @@ -1173,7 +1214,6 @@ where impl<'d> ParlIoRxOnly<'d, Blocking> { /// Create a new [ParlIoRxOnly] instance - // TODO: into_async() pub fn new( _parl_io: impl Peripheral

+ 'd, dma_channel: impl Peripheral

+ 'd, @@ -1193,9 +1233,29 @@ impl<'d> ParlIoRxOnly<'d, Blocking> { }, }) } -} -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, + }, + } + } + /// Sets the interrupt handler, enables it with /// [crate::interrupt::Priority::min()] /// @@ -1225,6 +1285,18 @@ 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, + }, + } + } +} + impl crate::private::Sealed for ParlIoRxOnly<'_, Blocking> {} impl InterruptConfigurable for ParlIoRxOnly<'_, Blocking> { @@ -1504,31 +1576,36 @@ pub mod asynch { impl TxDoneFuture { pub fn new() -> Self { Instance::listen_tx_done(); - Self {} - } - } - - impl core::future::Future for TxDoneFuture { - type Output = (); - - fn poll( - 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(); + unwrap!(crate::interrupt::enable( + Interrupt::PARL_IO, + interrupt_handler.priority() + )); } #[cfg(esp32h2)] { parl_io.bind_parl_io_tx_interrupt(interrupt_handler.handler()); - crate::interrupt::enable(Interrupt::PARL_IO_TX, interrupt_handler.priority()) - .unwrap(); + unwrap!(crate::interrupt::enable( + Interrupt::PARL_IO_TX, + interrupt_handler.priority() + )); } + Self {} + } + } + + impl core::future::Future for TxDoneFuture { + type Output = (); + + fn poll( + self: core::pin::Pin<&mut Self>, + cx: &mut core::task::Context<'_>, + ) -> Poll { TX_WAKER.register(cx.waker()); if Instance::is_listening_tx_done() { Poll::Pending From 014a4f4441d2c92811d93e678d0f1ec4445b1122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 12 Nov 2024 21:34:58 +0100 Subject: [PATCH 11/13] Update tests and examples --- examples/src/bin/embassy_parl_io_rx.rs | 10 +++------- examples/src/bin/embassy_parl_io_tx.rs | 10 +++------- examples/src/bin/lcd_cam_ov2640.rs | 2 +- examples/src/bin/lcd_i8080.rs | 2 +- hil-test/tests/dma_mem2mem.rs | 5 ++--- hil-test/tests/embassy_interrupt_spi_dma.rs | 4 ++-- hil-test/tests/i2s.rs | 5 ++--- hil-test/tests/parl_io_tx.rs | 5 ++--- hil-test/tests/parl_io_tx_async.rs | 20 +++++++++++--------- hil-test/tests/qspi.rs | 4 ++-- hil-test/tests/spi_full_duplex.rs | 8 ++++---- hil-test/tests/spi_slave.rs | 4 ++-- 12 files changed, 35 insertions(+), 44 deletions(-) diff --git a/examples/src/bin/embassy_parl_io_rx.rs b/examples/src/bin/embassy_parl_io_rx.rs index 3e57728ebdc..5117252fa8d 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 ff99b2dc738..ca5c3a2aa59 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_cam_ov2640.rs b/examples/src/bin/lcd_cam_ov2640.rs index fa7e3a0a308..73a07095c33 100644 --- a/examples/src/bin/lcd_cam_ov2640.rs +++ b/examples/src/bin/lcd_cam_ov2640.rs @@ -67,7 +67,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/examples/src/bin/lcd_i8080.rs b/examples/src/bin/lcd_i8080.rs index f6f7260cad5..5e7f1f1d893 100644 --- a/examples/src/bin/lcd_i8080.rs +++ b/examples/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(), diff --git a/hil-test/tests/dma_mem2mem.rs b/hil-test/tests/dma_mem2mem.rs index 6a8af032877..20ac1cfe89b 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 37bed2fdeb0..648aca55268 100644 --- a/hil-test/tests/embassy_interrupt_spi_dma.rs +++ b/hil-test/tests/embassy_interrupt_spi_dma.rs @@ -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 a7e88e88344..e5191581085 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/parl_io_tx.rs b/hil-test/tests/parl_io_tx.rs index e9cc12aa03e..54fbe1f27ba 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 09c4d6899fa..ab7b202003b 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 4c5a1e6a2f4..8960f767dea 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 a32a267e5e9..35a9209acc0 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 3485587aeac..299a592a2b4 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, } From 390d6e071ea8d53eeb0ff671d8c3e1a5c73a2e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 13 Nov 2024 12:35:01 +0100 Subject: [PATCH 12/13] Restore configurable priority via DmaChannel --- esp-hal/src/dma/gdma.rs | 9 +++++++++ esp-hal/src/dma/mod.rs | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/esp-hal/src/dma/gdma.rs b/esp-hal/src/dma/gdma.rs index e1a6c6085dd..cadacc3ae19 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -37,6 +37,11 @@ impl DmaChannel for AnyGdmaChannel { type Rx = AnyGdmaRxChannel; type Tx = AnyGdmaTxChannel; + fn set_priority(&self, priority: DmaPriority) { + AnyGdmaRxChannel(self.0).set_priority(priority); + AnyGdmaTxChannel(self.0).set_priority(priority); + } + unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) { (AnyGdmaRxChannel(self.0), AnyGdmaTxChannel(self.0)) } @@ -612,6 +617,10 @@ macro_rules! impl_channel { 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)) } diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index 142950f1d13..efba9aede79 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -1589,6 +1589,10 @@ pub trait DmaChannel: Peripheral

{ /// A description of the TX half of a DMA Channel. 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(not(esp32c2), not(esp32s3)))] fn split(self) -> (Self::Rx, Self::Tx) { From 44a0ea1952464926aa1308f7e4e32924a2453353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 13 Nov 2024 11:39:45 +0100 Subject: [PATCH 13/13] Deduplicate PDMA channel impl macro --- esp-hal/src/dma/pdma.rs | 175 ++++++++-------------------------------- 1 file changed, 34 insertions(+), 141 deletions(-) diff --git a/esp-hal/src/dma/pdma.rs b/esp-hal/src/dma/pdma.rs index b6410fa1c41..810d0c4adc7 100644 --- a/esp-hal/src/dma/pdma.rs +++ b/esp-hal/src/dma/pdma.rs @@ -384,114 +384,6 @@ impl InterruptAccess for AnySpiDmaRxChannel { } } -#[doc(hidden)] -pub struct SpiDmaChannel(PhantomData); - -impl crate::private::Sealed for SpiDmaChannel {} - -macro_rules! ImplSpiChannel { - ($num: literal) => { - paste::paste! { - #[doc = concat!("DMA channel suitable for SPI", $num)] - #[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 = 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 { - AnySpiDmaRxChannel(Self {}.into()) - } - fn tx_interrupts() -> impl InterruptAccess { - AnySpiDmaTxChannel(Self {}.into()) - } - } - - impl PdmaChannel for [] { - type RegisterBlock = SpiRegisterBlock; - - fn register_block(&self) -> &SpiRegisterBlock { - unsafe { &*$crate::peripherals::[]::PTR } - } - fn tx_waker(&self) -> &'static AtomicWaker { - static WAKER: AtomicWaker = AtomicWaker::new(); - &WAKER - } - fn rx_waker(&self) -> &'static AtomicWaker { - static WAKER: AtomicWaker = AtomicWaker::new(); - &WAKER - } - - fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool { - peripheral == DmaPeripheral::[] - } - - fn peripheral_interrupt(&self) -> Interrupt { - Interrupt::[< SPI $num _DMA >] - } - - fn async_handler(&self) -> InterruptHandler { - super::asynch::interrupt::[< interrupt_handler_spi $num _dma >] - } - fn rx_async_flag(&self) -> &'static AtomicBool { - static FLAG: AtomicBool = AtomicBool::new(false); - &FLAG - } - fn tx_async_flag(&self) -> &'static AtomicBool { - static FLAG: AtomicBool = AtomicBool::new(false); - &FLAG - } - } - - impl DmaChannelConvert for [] { - fn degrade(self) -> AnySpiDmaChannel { - self.into() - } - } - - impl DmaChannelConvert for [] { - fn degrade(self) -> AnySpiDmaRxChannel { - AnySpiDmaRxChannel(Self {}.into()) - } - } - - impl DmaChannelConvert for [] { - fn degrade(self) -> AnySpiDmaTxChannel { - AnySpiDmaTxChannel(Self {}.into()) - } - } - } - }; -} - /// The RX half of an arbitrary I2S DMA channel. pub struct AnyI2sDmaRxChannel(AnyI2sDmaChannel); @@ -857,15 +749,16 @@ impl InterruptAccess for AnyI2sDmaRxChannel { } } -macro_rules! ImplI2sChannel { - ($num: literal) => { +macro_rules! ImplPdmaChannel { + ($peri:ident, $num:literal, $int:ident) => { paste::paste! { - #[doc = concat!("DMA channel suitable for I2S", $num)] - pub struct [] {} + #[doc = concat!("DMA channel suitable for ", stringify!([< $peri:upper >]), $num)] + #[non_exhaustive] + pub struct [<$peri $num DmaChannel>] {} - impl $crate::private::Sealed for [] {} + impl $crate::private::Sealed for [<$peri $num DmaChannel>] {} - impl Peripheral for [] { + impl Peripheral for [<$peri $num DmaChannel>] { type P = Self; unsafe fn clone_unchecked(&self) -> Self::P { @@ -873,7 +766,7 @@ macro_rules! ImplI2sChannel { } } - impl [] { + impl [<$peri $num DmaChannel>] { /// Unsafely constructs a new DMA channel. /// /// # Safety @@ -884,29 +777,29 @@ macro_rules! ImplI2sChannel { } } - impl DmaChannel for [] { - type Rx = AnyI2sDmaRxChannel; - type Tx = AnyI2sDmaTxChannel; + impl DmaChannel for [<$peri $num DmaChannel>] { + type Rx = []; + type Tx = []; unsafe fn split_internal(self, _: $crate::private::Internal) -> (Self::Rx, Self::Tx) { - (AnyI2sDmaRxChannel(Self {}.into()), AnyI2sDmaTxChannel(Self {}.into())) + ([](Self {}.into()), [](Self {}.into())) } } - impl DmaChannelExt for [] { + impl DmaChannelExt for [<$peri $num DmaChannel>] { fn rx_interrupts() -> impl InterruptAccess { - AnyI2sDmaRxChannel(Self {}.into()) + [](Self {}.into()) } fn tx_interrupts() -> impl InterruptAccess { - AnyI2sDmaTxChannel(Self {}.into()) + [](Self {}.into()) } } - impl PdmaChannel for [] { - type RegisterBlock = I2sRegisterBlock; + impl PdmaChannel for [<$peri $num DmaChannel>] { + type RegisterBlock = [<$peri RegisterBlock>]; - fn register_block(&self) -> &I2sRegisterBlock { - unsafe { &*crate::peripherals::[< I2S $num >]::PTR } + fn register_block(&self) -> &Self::RegisterBlock { + unsafe { &*crate::peripherals::[< $peri:upper $num >]::PTR } } fn tx_waker(&self) -> &'static AtomicWaker { static WAKER: AtomicWaker = AtomicWaker::new(); @@ -917,15 +810,15 @@ macro_rules! ImplI2sChannel { &WAKER } fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool { - peripheral == DmaPeripheral::[] + peripheral == DmaPeripheral::[<$peri $num>] } fn peripheral_interrupt(&self) -> Interrupt { - Interrupt::[< I2S $num >] + Interrupt::$int } fn async_handler(&self) -> InterruptHandler { - super::asynch::interrupt::[< interrupt_handler_i2s $num _dma >] + super::asynch::interrupt::[< interrupt_handler_ $peri:lower $num _dma >] } fn rx_async_flag(&self) -> &'static AtomicBool { static FLAG: AtomicBool = AtomicBool::new(false); @@ -937,33 +830,33 @@ macro_rules! ImplI2sChannel { } } - impl DmaChannelConvert for [] { - fn degrade(self) -> AnyI2sDmaChannel { + impl DmaChannelConvert<[]> for [<$peri $num DmaChannel>] { + fn degrade(self) -> [] { self.into() } } - impl DmaChannelConvert for [] { - fn degrade(self) -> AnyI2sDmaRxChannel { - AnyI2sDmaRxChannel(Self {}.into()) + impl DmaChannelConvert<[]> for [<$peri $num DmaChannel>] { + fn degrade(self) -> [] { + [](self.into()) } } - impl DmaChannelConvert for [] { - fn degrade(self) -> AnyI2sDmaTxChannel { - AnyI2sDmaTxChannel(Self {}.into()) + impl DmaChannelConvert<[]> for [<$peri $num DmaChannel>] { + fn degrade(self) -> [] { + [](self.into()) } } } }; } -ImplSpiChannel!(2); -ImplSpiChannel!(3); +ImplPdmaChannel!(Spi, 2, SPI2_DMA); +ImplPdmaChannel!(Spi, 3, SPI3_DMA); -ImplI2sChannel!(0); +ImplPdmaChannel!(I2s, 0, I2S0); #[cfg(i2s1)] -ImplI2sChannel!(1); +ImplPdmaChannel!(I2s, 1, I2S1); // Specific peripherals use specific channels. Note that this may be overly // restrictive (ESP32 allows configuring 2 SPI DMA channels between 3 different