From 8e9f6b5015e78c7989fb17133e0f0ea318f5f5de Mon Sep 17 00:00:00 2001 From: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com> Date: Tue, 1 Oct 2024 09:11:49 +0100 Subject: [PATCH] Erase DMA channel type from Camera and AesDma drivers (#2258) * Provide AnyDmaChannel * Erase channel in Camera and Aes --------- Co-authored-by: Dominic Fischer --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/aes/mod.rs | 7 +- esp-hal/src/dma/gdma.rs | 221 ++++++++++++++++++++++--------------- esp-hal/src/dma/mod.rs | 44 ++++++++ esp-hal/src/dma/pdma.rs | 18 +++ esp-hal/src/lcd_cam/cam.rs | 3 +- 6 files changed, 206 insertions(+), 88 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 66ea89961..7667f07f7 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -48,6 +48,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - I8080 driver now decides bus width at transfer time rather than construction time. (#2171) - Replaced `AnyPin` with `InputSignal` and `OutputSignal` and renamed `ErasedPin` to `AnyPin` (#2128) - Replaced the `ErasedTimer` enum with the `AnyTimer` struct. (#2144) +- `Camera` and `AesDma` now support erasing the DMA channel type (#2258) - Changed the parameters of `Spi::with_pins` to no longer be optional (#2133) - Renamed `DummyPin` to `NoPin` and removed all internal logic from it. (#2133) - The `NO_PIN` constant has been removed. (#2133) diff --git a/esp-hal/src/aes/mod.rs b/esp-hal/src/aes/mod.rs index f138f49de..e230cf6d2 100644 --- a/esp-hal/src/aes/mod.rs +++ b/esp-hal/src/aes/mod.rs @@ -251,6 +251,11 @@ pub mod dma { }, }; + #[cfg(gdma)] + type DefaultChannel = crate::dma::AnyDmaChannel; + #[cfg(pdma)] + type DefaultChannel = (); // Replace with PDMA channel once support is added. + const ALIGN_SIZE: usize = core::mem::size_of::(); /// Specifies the block cipher modes available for AES operations. @@ -270,7 +275,7 @@ pub mod dma { } /// A DMA capable AES instance. - pub struct AesDma<'d, C> + pub struct AesDma<'d, C = DefaultChannel> where C: DmaChannel, C::P: AesPeripheral, diff --git a/esp-hal/src/dma/gdma.rs b/esp-hal/src/dma/gdma.rs index 0b5992ec0..675ad3d54 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -20,97 +20,124 @@ use crate::{ system::{Peripheral, PeripheralClockControl}, }; +#[doc(hidden)] +pub trait GdmaChannel { + fn number(&self) -> u8; +} + #[non_exhaustive] #[doc(hidden)] -pub struct ChannelTxImpl {} +pub struct AnyGdmaChannel(u8); +#[non_exhaustive] +#[doc(hidden)] +pub struct SpecificGdmaChannel {} + +impl GdmaChannel for AnyGdmaChannel { + fn number(&self) -> u8 { + self.0 + } +} +impl GdmaChannel for SpecificGdmaChannel { + fn number(&self) -> u8 { + N + } +} + +#[non_exhaustive] +#[doc(hidden)] +pub struct ChannelTxImpl(C); 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]; -impl crate::private::Sealed for ChannelTxImpl {} +impl crate::private::Sealed for ChannelTxImpl {} -impl ChannelTxImpl { +impl ChannelTxImpl { #[inline(always)] - fn ch() -> &'static crate::peripherals::dma::ch::CH { + fn ch(&self) -> &'static crate::peripherals::dma::ch::CH { let dma = unsafe { &*crate::peripherals::DMA::PTR }; - dma.ch(N as usize) + dma.ch(self.0.number() as usize) } #[cfg(any(esp32c2, esp32c3))] #[inline(always)] - fn int() -> &'static crate::peripherals::dma::int_ch::INT_CH { + fn int(&self) -> &'static crate::peripherals::dma::int_ch::INT_CH { let dma = unsafe { &*crate::peripherals::DMA::PTR }; - dma.int_ch(N as usize) + dma.int_ch(self.0.number() as usize) } #[inline(always)] #[cfg(any(esp32c6, esp32h2))] - fn int() -> &'static crate::peripherals::dma::out_int_ch::OUT_INT_CH { + fn int(&self) -> &'static crate::peripherals::dma::out_int_ch::OUT_INT_CH { let dma = unsafe { &*crate::peripherals::DMA::PTR }; - dma.out_int_ch(N as usize) + dma.out_int_ch(self.0.number() as usize) } #[cfg(esp32s3)] #[inline(always)] - fn int() -> &'static crate::peripherals::dma::ch::out_int::OUT_INT { + fn int(&self) -> &'static crate::peripherals::dma::ch::out_int::OUT_INT { let dma = unsafe { &*crate::peripherals::DMA::PTR }; - dma.ch(N as usize).out_int() + dma.ch(self.0.number() as usize).out_int() + } + + fn degrade(self) -> ChannelTxImpl { + ChannelTxImpl(AnyGdmaChannel(self.0.number())) } } -impl RegisterAccess for ChannelTxImpl { +impl RegisterAccess for ChannelTxImpl { fn reset(&self) { - let conf0 = Self::ch().out_conf0(); + let conf0 = self.ch().out_conf0(); conf0.modify(|_, w| w.out_rst().set_bit()); conf0.modify(|_, w| w.out_rst().clear_bit()); } fn set_burst_mode(&self, burst_mode: bool) { - Self::ch().out_conf0().modify(|_, w| { + self.ch().out_conf0().modify(|_, w| { w.out_data_burst_en().bit(burst_mode); w.outdscr_burst_en().bit(burst_mode) }); } fn set_priority(&self, priority: DmaPriority) { - Self::ch() + self.ch() .out_pri() .write(|w| unsafe { w.tx_pri().bits(priority as u8) }); } fn set_peripheral(&self, peripheral: u8) { - Self::ch() + self.ch() .out_peri_sel() .modify(|_, w| unsafe { w.peri_out_sel().bits(peripheral) }); } fn set_link_addr(&self, address: u32) { - Self::ch() + self.ch() .out_link() .modify(|_, w| unsafe { w.outlink_addr().bits(address) }); } fn start(&self) { - Self::ch() + self.ch() .out_link() .modify(|_, w| w.outlink_start().set_bit()); } fn stop(&self) { - Self::ch() + self.ch() .out_link() .modify(|_, w| w.outlink_stop().set_bit()); } fn restart(&self) { - Self::ch() + self.ch() .out_link() .modify(|_, w| w.outlink_restart().set_bit()); } fn clear_interrupts(&self) { #[cfg(not(esp32s3))] - Self::int().clr().write(|w| { + self.int().clr().write(|w| { w.out_eof().clear_bit_by_one(); w.out_dscr_err().clear_bit_by_one(); w.out_done().clear_bit_by_one(); @@ -120,7 +147,7 @@ impl RegisterAccess for ChannelTxImpl { }); #[cfg(esp32s3)] - Self::int().clr().write(|w| { + self.int().clr().write(|w| { w.out_eof().clear_bit_by_one(); w.out_dscr_err().clear_bit_by_one(); w.out_done().clear_bit_by_one(); @@ -134,15 +161,15 @@ impl RegisterAccess for ChannelTxImpl { #[cfg(esp32s3)] fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) { - Self::ch() + self.ch() .out_conf1() .modify(|_, w| unsafe { w.out_ext_mem_bk_size().bits(size as u8) }); } } -impl TxRegisterAccess for ChannelTxImpl { +impl TxRegisterAccess for ChannelTxImpl { fn last_dscr_address(&self) -> usize { - Self::ch() + self.ch() .out_eof_des_addr() .read() .out_eof_des_addr() @@ -150,9 +177,9 @@ impl TxRegisterAccess for ChannelTxImpl { } } -impl InterruptAccess for ChannelTxImpl { +impl InterruptAccess for ChannelTxImpl { fn listen(&self, interrupts: impl Into>) { - Self::int().ena().modify(|_, w| { + self.int().ena().modify(|_, w| { for interrupt in interrupts.into() { match interrupt { DmaTxInterrupt::TotalEof => w.out_total_eof().set_bit(), @@ -166,7 +193,7 @@ impl InterruptAccess for ChannelTxImpl { } fn unlisten(&self, interrupts: impl Into>) { - Self::int().ena().modify(|_, w| { + self.int().ena().modify(|_, w| { for interrupt in interrupts.into() { match interrupt { DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit(), @@ -182,7 +209,7 @@ impl InterruptAccess for ChannelTxImpl { fn is_listening(&self) -> EnumSet { let mut result = EnumSet::new(); - let int_ena = Self::int().ena().read(); + let int_ena = self.int().ena().read(); if int_ena.out_total_eof().bit_is_set() { result |= DmaTxInterrupt::TotalEof; } @@ -200,7 +227,7 @@ impl InterruptAccess for ChannelTxImpl { } fn clear(&self, interrupts: impl Into>) { - Self::int().clr().write(|w| { + self.int().clr().write(|w| { for interrupt in interrupts.into() { match interrupt { DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit_by_one(), @@ -216,7 +243,7 @@ impl InterruptAccess for ChannelTxImpl { fn pending_interrupts(&self) -> EnumSet { let mut result = EnumSet::new(); - let int_raw = Self::int().raw().read(); + let int_raw = self.int().raw().read(); if int_raw.out_total_eof().bit_is_set() { result |= DmaTxInterrupt::TotalEof; } @@ -234,98 +261,100 @@ impl InterruptAccess for ChannelTxImpl { } fn waker(&self) -> &'static AtomicWaker { - &TX_WAKERS[N as usize] + &TX_WAKERS[self.0.number() as usize] } } #[non_exhaustive] #[doc(hidden)] -pub struct ChannelRxImpl {} +pub struct ChannelRxImpl(C); -impl crate::private::Sealed for ChannelRxImpl {} +impl crate::private::Sealed for ChannelRxImpl {} -impl ChannelRxImpl { +impl ChannelRxImpl { #[inline(always)] - fn ch() -> &'static crate::peripherals::dma::ch::CH { + fn ch(&self) -> &'static crate::peripherals::dma::ch::CH { let dma = unsafe { &*crate::peripherals::DMA::PTR }; - dma.ch(N as usize) + dma.ch(self.0.number() as usize) } #[cfg(any(esp32c2, esp32c3))] #[inline(always)] - fn int() -> &'static crate::peripherals::dma::int_ch::INT_CH { + fn int(&self) -> &'static crate::peripherals::dma::int_ch::INT_CH { let dma = unsafe { &*crate::peripherals::DMA::PTR }; - dma.int_ch(N as usize) + dma.int_ch(self.0.number() as usize) } #[inline(always)] #[cfg(any(esp32c6, esp32h2))] - fn int() -> &'static crate::peripherals::dma::in_int_ch::IN_INT_CH { + fn int(&self) -> &'static crate::peripherals::dma::in_int_ch::IN_INT_CH { let dma = unsafe { &*crate::peripherals::DMA::PTR }; - dma.in_int_ch(N as usize) + dma.in_int_ch(self.0.number() as usize) } #[cfg(esp32s3)] #[inline(always)] - fn int() -> &'static crate::peripherals::dma::ch::in_int::IN_INT { + fn int(&self) -> &'static crate::peripherals::dma::ch::in_int::IN_INT { let dma = unsafe { &*crate::peripherals::DMA::PTR }; - dma.ch(N as usize).in_int() + dma.ch(self.0.number() as usize).in_int() + } + + fn degrade(self) -> ChannelRxImpl { + ChannelRxImpl(AnyGdmaChannel(self.0.number())) } } -impl RegisterAccess for ChannelRxImpl { +impl RegisterAccess for ChannelRxImpl { fn reset(&self) { - let conf0 = Self::ch().in_conf0(); + let conf0 = self.ch().in_conf0(); conf0.modify(|_, w| w.in_rst().set_bit()); conf0.modify(|_, w| w.in_rst().clear_bit()); } fn set_burst_mode(&self, burst_mode: bool) { - Self::ch().in_conf0().modify(|_, w| { + self.ch().in_conf0().modify(|_, w| { w.in_data_burst_en().bit(burst_mode); w.indscr_burst_en().bit(burst_mode) }); } fn set_priority(&self, priority: DmaPriority) { - Self::ch() + self.ch() .in_pri() .write(|w| unsafe { w.rx_pri().bits(priority as u8) }); } fn set_peripheral(&self, peripheral: u8) { - Self::ch() + self.ch() .in_peri_sel() .modify(|_, w| unsafe { w.peri_in_sel().bits(peripheral) }); } fn set_link_addr(&self, address: u32) { - Self::ch() + self.ch() .in_link() .modify(|_, w| unsafe { w.inlink_addr().bits(address) }); } fn start(&self) { - Self::ch() + self.ch() .in_link() .modify(|_, w| w.inlink_start().set_bit()); } fn stop(&self) { - Self::ch() - .in_link() - .modify(|_, w| w.inlink_stop().set_bit()); + self.ch().in_link().modify(|_, w| w.inlink_stop().set_bit()); } fn restart(&self) { - Self::ch() + self.ch() .in_link() .modify(|_, w| w.inlink_restart().set_bit()); } fn clear_interrupts(&self) { #[cfg(not(esp32s3))] - Self::int().clr().write(|w| { + self.int().clr().write(|w| { w.in_suc_eof().clear_bit_by_one(); w.in_err_eof().clear_bit_by_one(); w.in_dscr_err().clear_bit_by_one(); @@ -336,7 +365,7 @@ impl RegisterAccess for ChannelRxImpl { }); #[cfg(esp32s3)] - Self::int().clr().write(|w| { + self.int().clr().write(|w| { w.in_suc_eof().clear_bit_by_one(); w.in_err_eof().clear_bit_by_one(); w.in_dscr_err().clear_bit_by_one(); @@ -351,23 +380,23 @@ impl RegisterAccess for ChannelRxImpl { #[cfg(esp32s3)] fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) { - Self::ch() + self.ch() .in_conf1() .modify(|_, w| unsafe { w.in_ext_mem_bk_size().bits(size as u8) }); } } -impl RxRegisterAccess for ChannelRxImpl { +impl RxRegisterAccess for ChannelRxImpl { fn set_mem2mem_mode(&self, value: bool) { - Self::ch() + self.ch() .in_conf0() .modify(|_, w| w.mem_trans_en().bit(value)); } } -impl InterruptAccess for ChannelRxImpl { +impl InterruptAccess for ChannelRxImpl { fn listen(&self, interrupts: impl Into>) { - Self::int().ena().modify(|_, w| { + self.int().ena().modify(|_, w| { for interrupt in interrupts.into() { match interrupt { DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().set_bit(), @@ -382,7 +411,7 @@ impl InterruptAccess for ChannelRxImpl { } fn unlisten(&self, interrupts: impl Into>) { - Self::int().ena().modify(|_, w| { + self.int().ena().modify(|_, w| { for interrupt in interrupts.into() { match interrupt { DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit(), @@ -399,7 +428,7 @@ impl InterruptAccess for ChannelRxImpl { fn is_listening(&self) -> EnumSet { let mut result = EnumSet::new(); - let int_ena = Self::int().ena().read(); + let int_ena = self.int().ena().read(); if int_ena.in_dscr_err().bit_is_set() { result |= DmaRxInterrupt::DescriptorError; } @@ -420,7 +449,7 @@ impl InterruptAccess for ChannelRxImpl { } fn clear(&self, interrupts: impl Into>) { - Self::int().clr().write(|w| { + self.int().clr().write(|w| { for interrupt in interrupts.into() { match interrupt { DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit_by_one(), @@ -437,7 +466,7 @@ impl InterruptAccess for ChannelRxImpl { fn pending_interrupts(&self) -> EnumSet { let mut result = EnumSet::new(); - let int_raw = Self::int().raw().read(); + let int_raw = self.int().raw().read(); if int_raw.in_dscr_err().bit_is_set() { result |= DmaRxInterrupt::DescriptorError; } @@ -458,7 +487,7 @@ impl InterruptAccess for ChannelRxImpl { } fn waker(&self) -> &'static AtomicWaker { - &RX_WAKERS[N as usize] + &RX_WAKERS[self.0.number() as usize] } } @@ -468,49 +497,70 @@ pub struct ChannelCreator {} #[non_exhaustive] #[doc(hidden)] -pub struct SuitablePeripheral {} -impl PeripheralMarker for SuitablePeripheral {} +pub struct SuitablePeripheral {} +impl PeripheralMarker for SuitablePeripheral {} // with GDMA every channel can be used for any peripheral -impl SpiPeripheral for SuitablePeripheral {} -impl Spi2Peripheral for SuitablePeripheral {} +impl SpiPeripheral for SuitablePeripheral {} +impl Spi2Peripheral for SuitablePeripheral {} #[cfg(spi3)] -impl Spi3Peripheral for SuitablePeripheral {} +impl Spi3Peripheral for SuitablePeripheral {} #[cfg(any(i2s0, i2s1))] -impl I2sPeripheral for SuitablePeripheral {} +impl I2sPeripheral for SuitablePeripheral {} #[cfg(i2s0)] -impl I2s0Peripheral for SuitablePeripheral {} +impl I2s0Peripheral for SuitablePeripheral {} #[cfg(i2s1)] -impl I2s1Peripheral for SuitablePeripheral {} +impl I2s1Peripheral for SuitablePeripheral {} #[cfg(parl_io)] -impl ParlIoPeripheral for SuitablePeripheral {} +impl ParlIoPeripheral for SuitablePeripheral {} #[cfg(aes)] -impl AesPeripheral for SuitablePeripheral {} +impl AesPeripheral for SuitablePeripheral {} #[cfg(lcd_cam)] -impl LcdCamPeripheral for SuitablePeripheral {} +impl LcdCamPeripheral for SuitablePeripheral {} + +/// A description of any GDMA channel +#[non_exhaustive] +pub struct AnyDmaChannel {} + +impl crate::private::Sealed for AnyDmaChannel {} + +impl DmaChannel for AnyDmaChannel { + type Rx = ChannelRxImpl; + type Tx = ChannelTxImpl; + type P = SuitablePeripheral; +} macro_rules! impl_channel { ($num: literal, $async_handler: path, $($interrupt: ident),* ) => { paste::paste! { - /// A description of a GDMA channel + /// A description of a specific GDMA channel #[non_exhaustive] pub struct [] {} impl crate::private::Sealed for [] {} impl DmaChannel for [] { - type Rx = ChannelRxImpl<$num>; - type Tx = ChannelTxImpl<$num>; - type P = SuitablePeripheral<$num>; + type Rx = ChannelRxImpl>; + type Tx = ChannelTxImpl>; + type P = SuitablePeripheral; } impl DmaChannelExt for [] { + type Degraded = AnyDmaChannel; + fn get_rx_interrupts() -> impl InterruptAccess { - ChannelRxImpl::<$num> {} + ChannelRxImpl(SpecificGdmaChannel::<$num> {}) } fn get_tx_interrupts() -> impl InterruptAccess { - ChannelTxImpl::<$num> {} + ChannelTxImpl(SpecificGdmaChannel::<$num> {}) + } + + fn degrade_rx(rx: Self::Rx) -> ChannelRxImpl { + rx.degrade() + } + fn degrade_tx(tx: Self::Tx) -> ChannelTxImpl { + tx.degrade() } fn set_isr(handler: $crate::interrupt::InterruptHandler) { @@ -528,16 +578,15 @@ macro_rules! impl_channel { burst_mode: bool, priority: DmaPriority, ) -> crate::dma::Channel<'a, [], M> { - let tx_impl = ChannelTxImpl {}; + let tx_impl = ChannelTxImpl(SpecificGdmaChannel::<$num> {}); tx_impl.set_burst_mode(burst_mode); tx_impl.set_priority(priority); - let rx_impl = ChannelRxImpl {}; + let rx_impl = ChannelRxImpl(SpecificGdmaChannel::<$num> {}); rx_impl.set_burst_mode(burst_mode); rx_impl.set_priority(priority); // clear the mem2mem mode to avoid failed DMA if this // channel was previously used for a mem2mem transfer. - #[cfg(gdma)] rx_impl.set_mem2mem_mode(false); crate::dma::Channel { diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index 03aed246d..97d41a3c8 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -1509,9 +1509,14 @@ pub trait DmaChannel: crate::private::Sealed { #[doc(hidden)] pub trait DmaChannelExt: DmaChannel { + type Degraded: DmaChannel; + fn get_rx_interrupts() -> impl InterruptAccess; fn get_tx_interrupts() -> impl InterruptAccess; + fn degrade_rx(rx: Self::Rx) -> ::Rx; + fn degrade_tx(tx: Self::Tx) -> ::Tx; + #[doc(hidden)] fn set_isr(handler: InterruptHandler); } @@ -1596,6 +1601,18 @@ where _phantom: PhantomData, } } + + /// Return a type-erased (degraded) version of this channel. + pub fn degrade(self) -> ChannelRx<'a, CH::Degraded> + where + CH: DmaChannelExt, + { + ChannelRx { + burst_mode: self.burst_mode, + rx_impl: CH::degrade_rx(self.rx_impl), + _phantom: PhantomData, + } + } } impl<'a, CH> crate::private::Sealed for ChannelRx<'a, CH> where CH: DmaChannel {} @@ -1801,6 +1818,18 @@ where _phantom: PhantomData, } } + + /// Return a type-erased (degraded) version of this channel. + pub fn degrade(self) -> ChannelTx<'a, CH::Degraded> + where + CH: DmaChannelExt, + { + ChannelTx { + burst_mode: self.burst_mode, + tx_impl: CH::degrade_tx(self.tx_impl), + _phantom: PhantomData, + } + } } impl<'a, CH> crate::private::Sealed for ChannelTx<'a, CH> where CH: DmaChannel {} @@ -2054,6 +2083,21 @@ where } } +impl<'d, C, M: Mode> Channel<'d, C, M> +where + C: DmaChannelExt, +{ + /// Return a type-erased (degraded) version of this channel (both rx and + /// tx). + pub fn degrade(self) -> Channel<'d, C::Degraded, M> { + Channel { + rx: self.rx.degrade(), + tx: self.tx.degrade(), + phantom: PhantomData, + } + } +} + /// Holds all the information needed to configure a DMA channel for a transfer. pub struct Preparation { start: *mut DmaDescriptor, diff --git a/esp-hal/src/dma/pdma.rs b/esp-hal/src/dma/pdma.rs index cdd4574c2..af94f4a99 100644 --- a/esp-hal/src/dma/pdma.rs +++ b/esp-hal/src/dma/pdma.rs @@ -371,6 +371,8 @@ macro_rules! ImplSpiChannel { } impl DmaChannelExt for [] { + type Degraded = Self; + fn get_rx_interrupts() -> impl InterruptAccess { SpiDmaRxChannelImpl::(PhantomData) } @@ -378,6 +380,13 @@ macro_rules! ImplSpiChannel { SpiDmaTxChannelImpl::(PhantomData) } + fn degrade_rx(rx: Self::Rx) -> Self::Rx { + rx + } + fn degrade_tx(tx: Self::Tx) -> Self::Tx { + tx + } + fn set_isr(handler: InterruptHandler) { let interrupt = $crate::peripherals::Interrupt::[< SPI $num _DMA >]; unsafe { @@ -830,6 +839,8 @@ macro_rules! ImplI2sChannel { } impl DmaChannelExt for [] { + type Degraded = Self; + fn get_rx_interrupts() -> impl InterruptAccess { I2sDmaRxChannelImpl::(PhantomData) } @@ -837,6 +848,13 @@ macro_rules! ImplI2sChannel { I2sDmaTxChannelImpl::(PhantomData) } + fn degrade_rx(rx: Self::Rx) -> Self::Rx { + rx + } + fn degrade_tx(tx: Self::Tx) -> Self::Tx { + tx + } + fn set_isr(handler: InterruptHandler) { let interrupt = $crate::peripherals::Interrupt::[< I2S $num >]; unsafe { diff --git a/esp-hal/src/lcd_cam/cam.rs b/esp-hal/src/lcd_cam/cam.rs index 004da5224..d1cc6902f 100644 --- a/esp-hal/src/lcd_cam/cam.rs +++ b/esp-hal/src/lcd_cam/cam.rs @@ -69,6 +69,7 @@ use crate::{ clock::Clocks, dma::{ dma_private::{DmaSupport, DmaSupportRx}, + AnyDmaChannel, ChannelRx, DescriptorChain, DmaChannel, @@ -126,7 +127,7 @@ pub struct Cam<'d> { } /// Represents the camera interface with DMA support. -pub struct Camera<'d, CH: DmaChannel> { +pub struct Camera<'d, CH: DmaChannel = AnyDmaChannel> { lcd_cam: PeripheralRef<'d, LCD_CAM>, rx_channel: ChannelRx<'d, CH>, rx_chain: DescriptorChain,