From c84c29efeef08ccf7677494974cb9508543e7aca 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] 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 | 2 +- esp-hal/src/lcd_cam/cam.rs | 5 +- esp-hal/src/lcd_cam/lcd/i8080.rs | 4 +- 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 +- 14 files changed, 359 insertions(+), 248 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 18a821fb17e..c9b44c177e7 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -173,6 +173,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 eac8f95066a..f4bcf38aafc 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 8b5c387eadf..521ad24c694 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 e88776e423b..c422ed525c8 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 098da68add1..e24edfbf4a3 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..d77d622dd3e 100644 --- a/esp-hal/src/i2s/parallel.rs +++ b/esp-hal/src/i2s/parallel.rs @@ -177,7 +177,7 @@ where I: Instance, { instance: PeripheralRef<'d, I>, - tx_channel: ChannelTx<'d, I::Dma>, + tx_channel: ChannelTx<'d, I::Dma, DM>, 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..4c6b1cfa713 100644 --- a/esp-hal/src/lcd_cam/lcd/i8080.rs +++ b/esp-hal/src/lcd_cam/lcd/i8080.rs @@ -89,7 +89,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>, + tx_channel: ChannelTx<'d, ::Dma, Blocking>, _phantom: PhantomData, } @@ -97,7 +97,7 @@ impl<'d, DM: Mode> I8080<'d, DM> { /// Creates a new instance of the I8080 LCD interface. pub fn new( lcd: Lcd<'d, DM>, - channel: ChannelTx<'d, CH>, + channel: ChannelTx<'d, CH, DM>, mut pins: P, frequency: HertzU32, config: Config, 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 57b558cc5ff..e1eaafd9c2a 100644 --- a/esp-hal/src/parl_io.rs +++ b/esp-hal/src/parl_io.rs @@ -815,7 +815,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, } @@ -894,7 +894,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, } @@ -1038,20 +1038,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, }, @@ -1098,20 +1092,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, }, @@ -1376,7 +1364,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 @@ -1418,7 +1406,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, @@ -1472,7 +1460,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 @@ -1488,7 +1476,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, } @@ -1498,7 +1486,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, } @@ -1508,7 +1496,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, } @@ -1518,7 +1506,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