diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index f129e75067b..78adae34bc2 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 - Change `DmaTxBuf` to support PSRAM on `esp32s3` (#2161) - I2c `transaction` is now also available as a inherent function, lift size limit on `write`,`read` and `write_read` (#2262) - SPI transactions are now cancelled if the transfer object (or async Future) is dropped. (#2216) +- The DMA channel types have been removed from peripherals (#2261) ### Fixed @@ -107,6 +108,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed the `place-spi-driver-in-ram` feature, this is now enabled via [esp-config](https://docs.rs/esp-config) (#2156) - Removed `esp_hal::spi::slave::prelude` (#2260) - Removed `esp_hal::spi::slave::WithDmaSpiN` traits (#2260) +- The `WithDmaAes` trait has been removed (#2261) +- The `I2s::new_i2s1` constructor has been removed (#2261) ## [0.20.1] - 2024-08-30 diff --git a/esp-hal/MIGRATING-0.20.md b/esp-hal/MIGRATING-0.20.md index 6c04aa0a4ff..8682884d1f2 100644 --- a/esp-hal/MIGRATING-0.20.md +++ b/esp-hal/MIGRATING-0.20.md @@ -121,11 +121,17 @@ When using the asymmetric variant of the macro to create DMA buffers and descrip + let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, 32000); ``` -## Removed UART constructors +## Removed constructors + +### UART The `Uart::new_with_default_pins` and `Uart::new_async_with_default_pins` constructors have been removed. Use `new` or `new_async` instead. +### I2S1 + +The `I2s::new_i2s1` constructor has been removed. Use `I2s::new` instead. + ## Timer changes ### `ErasedTimer` rename @@ -319,3 +325,17 @@ Diff of the `psram_quad.rs` example ## eFuse Calling `Efuse::read_field_le::()` no longer compiles. Use `Efuse::read_bit()` instead. + +## DMA + +The DMA channel types have been removed from peripherals. + +A non-exhausitve list demonstrating this change: + +```diff +-I2sTx<'static, I2S0, DmaChannel0, Async> ++I2sTx<'static, I2S0, Async> + +-SpiDma<'static, esp_hal::peripherals::SPI2, DmaChannel0, HalfDuplexMode, Blocking> ++SpiDma<'static, esp_hal::peripherals::SPI2, HalfDuplexMode, Blocking> +``` diff --git a/esp-hal/src/aes/mod.rs b/esp-hal/src/aes/mod.rs index e230cf6d28c..bbf18752534 100644 --- a/esp-hal/src/aes/mod.rs +++ b/esp-hal/src/aes/mod.rs @@ -235,13 +235,13 @@ pub mod dma { aes::{Key, Mode}, dma::{ dma_private::{DmaSupport, DmaSupportRx, DmaSupportTx}, - AesPeripheral, Channel, ChannelRx, ChannelTx, DescriptorChain, - DmaChannel, + DmaChannelConvert, DmaDescriptor, + DmaEligible, DmaPeripheral, DmaTransferRxTx, ReadBuffer, @@ -249,13 +249,9 @@ pub mod dma { Tx, WriteBuffer, }, + peripherals::AES, }; - #[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. @@ -275,69 +271,43 @@ pub mod dma { } /// A DMA capable AES instance. - pub struct AesDma<'d, C = DefaultChannel> - where - C: DmaChannel, - C::P: AesPeripheral, - { + pub struct AesDma<'d> { /// The underlying [`Aes`](super::Aes) driver pub aes: super::Aes<'d>, - pub(crate) channel: Channel<'d, C, crate::Blocking>, + channel: Channel<'d, ::Dma, crate::Blocking>, rx_chain: DescriptorChain, tx_chain: DescriptorChain, } - /// Functionality for using AES with DMA. - pub trait WithDmaAes<'d, C> - where - C: DmaChannel, - C::P: AesPeripheral, - { + impl<'d> crate::aes::Aes<'d> { /// Enable DMA for the current instance of the AES driver - fn with_dma( - self, - channel: Channel<'d, C, crate::Blocking>, - rx_descriptors: &'static mut [DmaDescriptor], - tx_descriptors: &'static mut [DmaDescriptor], - ) -> AesDma<'d, C>; - } - - impl<'d, C> WithDmaAes<'d, C> for crate::aes::Aes<'d> - where - C: DmaChannel, - C::P: AesPeripheral, - { - fn with_dma( + pub fn with_dma( self, channel: Channel<'d, C, crate::Blocking>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], - ) -> AesDma<'d, C> { + ) -> AesDma<'d> + where + Self: Sized, + C: DmaChannelConvert<::Dma>, + { AesDma { aes: self, - channel, + channel: channel.degrade(), rx_chain: DescriptorChain::new(rx_descriptors), tx_chain: DescriptorChain::new(tx_descriptors), } } } - impl<'d, C> core::fmt::Debug for AesDma<'d, C> - where - C: DmaChannel, - C::P: AesPeripheral, - { + impl<'d> core::fmt::Debug for AesDma<'d> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("AesDma").finish() } } - impl<'d, C> DmaSupport for AesDma<'d, C> - where - C: DmaChannel, - C::P: AesPeripheral, - { + impl<'d> DmaSupport for AesDma<'d> { fn peripheral_wait_dma(&mut self, _is_rx: bool, _is_tx: bool) { while self.aes.aes.state().read().state().bits() != 2 // DMA status DONE == 2 && !self.channel.tx.is_done() @@ -353,12 +323,8 @@ pub mod dma { } } - impl<'d, C> DmaSupportTx for AesDma<'d, C> - where - C: DmaChannel, - C::P: AesPeripheral, - { - type TX = ChannelTx<'d, C>; + impl<'d> DmaSupportTx for AesDma<'d> { + type TX = ChannelTx<'d, ::Dma>; fn tx(&mut self) -> &mut Self::TX { &mut self.channel.tx @@ -369,12 +335,8 @@ pub mod dma { } } - impl<'d, C> DmaSupportRx for AesDma<'d, C> - where - C: DmaChannel, - C::P: AesPeripheral, - { - type RX = ChannelRx<'d, C>; + impl<'d> DmaSupportRx for AesDma<'d> { + type RX = ChannelRx<'d, ::Dma>; fn rx(&mut self) -> &mut Self::RX { &mut self.channel.rx @@ -385,11 +347,7 @@ pub mod dma { } } - impl<'d, C> AesDma<'d, C> - where - C: DmaChannel, - C::P: AesPeripheral, - { + impl<'d> AesDma<'d> { /// Writes the encryption key to the AES hardware, checking that its /// length matches expected constraints. pub fn write_key(&mut self, key: K) diff --git a/esp-hal/src/dma/gdma.rs b/esp-hal/src/dma/gdma.rs index c17358dcdf3..3cd616cbef7 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -25,9 +25,16 @@ pub trait GdmaChannel { fn number(&self) -> u8; } +/// An arbitrary GDMA channel #[non_exhaustive] -#[doc(hidden)] 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 {} @@ -56,26 +63,26 @@ impl crate::private::Sealed for ChannelTxImpl {} impl ChannelTxImpl { #[inline(always)] - fn ch(&self) -> &'static crate::peripherals::dma::ch::CH { + fn ch(&self) -> &crate::peripherals::dma::ch::CH { let dma = unsafe { &*crate::peripherals::DMA::PTR }; dma.ch(self.0.number() as usize) } #[cfg(any(esp32c2, esp32c3))] #[inline(always)] - fn int(&self) -> &'static crate::peripherals::dma::int_ch::INT_CH { + 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) } #[inline(always)] #[cfg(any(esp32c6, esp32h2))] - fn int(&self) -> &'static crate::peripherals::dma::out_int_ch::OUT_INT_CH { + 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) } #[cfg(esp32s3)] #[inline(always)] - fn int(&self) -> &'static crate::peripherals::dma::ch::out_int::OUT_INT { + 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() } @@ -235,28 +242,28 @@ impl crate::private::Sealed for ChannelRxImpl {} impl ChannelRxImpl { #[inline(always)] - fn ch(&self) -> &'static crate::peripherals::dma::ch::CH { + fn ch(&self) -> &crate::peripherals::dma::ch::CH { let dma = unsafe { &*crate::peripherals::DMA::PTR }; dma.ch(self.0.number() as usize) } #[cfg(any(esp32c2, esp32c3))] #[inline(always)] - fn int(&self) -> &'static crate::peripherals::dma::int_ch::INT_CH { + 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) } #[inline(always)] #[cfg(any(esp32c6, esp32h2))] - fn int(&self) -> &'static crate::peripherals::dma::in_int_ch::IN_INT_CH { + 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) } #[cfg(esp32s3)] #[inline(always)] - fn int(&self) -> &'static crate::peripherals::dma::ch::in_int::IN_INT { + 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() } @@ -416,39 +423,14 @@ impl InterruptAccess for ChannelRxImpl { #[non_exhaustive] pub struct ChannelCreator {} -#[non_exhaustive] -#[doc(hidden)] -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 {} -#[cfg(spi3)] -impl Spi3Peripheral for SuitablePeripheral {} -#[cfg(any(i2s0, i2s1))] -impl I2sPeripheral for SuitablePeripheral {} -#[cfg(i2s0)] -impl I2s0Peripheral for SuitablePeripheral {} -#[cfg(i2s1)] -impl I2s1Peripheral for SuitablePeripheral {} -#[cfg(parl_io)] -impl ParlIoPeripheral for SuitablePeripheral {} -#[cfg(aes)] -impl AesPeripheral for SuitablePeripheral {} -#[cfg(lcd_cam)] -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; +impl Channel<'_, CH, M> { + /// 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 + } } macro_rules! impl_channel { @@ -463,12 +445,18 @@ macro_rules! impl_channel { impl DmaChannel for [] { type Rx = ChannelRxImpl>; type Tx = ChannelTxImpl>; - type P = SuitablePeripheral; } - impl DmaChannelExt for [] { - type Degraded = AnyDmaChannel; + impl DmaChannelConvert for [] { + fn degrade_rx(rx: Self::Rx) -> ChannelRxImpl { + rx.degrade() + } + fn degrade_tx(tx: Self::Tx) -> ChannelTxImpl { + tx.degrade() + } + } + impl DmaChannelExt for [] { fn get_rx_interrupts() -> impl InterruptAccess { ChannelRxImpl(SpecificGdmaChannel::<$num> {}) } @@ -477,13 +465,6 @@ macro_rules! impl_channel { 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) { let mut dma = unsafe { crate::peripherals::DMA::steal() }; $( @@ -573,6 +554,63 @@ cfg_if::cfg_if! { } } +crate::impl_dma_eligible! { + AnyGdmaChannel { + #[cfg(spi2)] + SPI2 => Spi2, + + #[cfg(spi3)] + SPI3 => Spi3, + + #[cfg(uhci0)] + UHCI0 => Uhci0, + + #[cfg(i2s0)] + I2S0 => I2s0, + + #[cfg(i2s1)] + I2S1 => I2s1, + + #[cfg(esp32s3)] + LCD_CAM => LcdCam, + + #[cfg(all(gdma, aes))] + AES => Aes, + + #[cfg(all(gdma, sha))] + SHA => Sha, + + #[cfg(any(esp32c3, esp32c6, esp32h2, esp32s3))] + ADC1 => Adc, + + #[cfg(any(esp32c3, esp32s3))] + ADC2 => Adc, + + #[cfg(esp32s3)] + RMT => Rmt, + + #[cfg(parl_io)] + PARL_IO => ParlIo, + + #[cfg(any(esp32c2, esp32c6, esp32h2))] + MEM2MEM1 => Mem2Mem1, + } +} + +#[cfg(any(esp32c6, esp32h2))] +crate::impl_dma_eligible! { + AnyGdmaChannel { + MEM2MEM4 => Mem2Mem4, + MEM2MEM5 => Mem2Mem5, + MEM2MEM10 => Mem2Mem10, + MEM2MEM11 => Mem2Mem11, + MEM2MEM12 => Mem2Mem12, + MEM2MEM13 => Mem2Mem13, + MEM2MEM14 => Mem2Mem14, + MEM2MEM15 => Mem2Mem15, + } +} + /// GDMA Peripheral /// /// This offers the available DMA channels. @@ -626,21 +664,25 @@ pub use m2m::*; mod m2m { #[cfg(esp32s3)] use crate::dma::DmaExtMemBKSize; - use crate::dma::{ - dma_private::{DmaSupport, DmaSupportRx}, - Channel, - ChannelRx, - DescriptorChain, - DmaChannel, - DmaDescriptor, - DmaEligible, - DmaError, - DmaPeripheral, - DmaTransferRx, - ReadBuffer, - Rx, - Tx, - WriteBuffer, + use crate::{ + dma::{ + dma_private::{DmaSupport, DmaSupportRx}, + AnyGdmaChannel, + Channel, + ChannelRx, + DescriptorChain, + DmaChannelConvert, + DmaDescriptor, + DmaEligible, + DmaError, + DmaPeripheral, + DmaTransferRx, + ReadBuffer, + Rx, + Tx, + WriteBuffer, + }, + Mode, }; /// DMA Memory to Memory pseudo-Peripheral @@ -648,29 +690,30 @@ mod m2m { /// This is a pseudo-peripheral that allows for memory to memory transfers. /// It is not a real peripheral, but a way to use the DMA engine for memory /// to memory transfers. - pub struct Mem2Mem<'d, C, MODE> + pub struct Mem2Mem<'d, M> where - C: DmaChannel, - MODE: crate::Mode, + M: Mode, { - channel: Channel<'d, C, MODE>, + channel: Channel<'d, AnyGdmaChannel, M>, rx_chain: DescriptorChain, tx_chain: DescriptorChain, peripheral: DmaPeripheral, } - impl<'d, C, MODE> Mem2Mem<'d, C, MODE> + impl<'d, M> Mem2Mem<'d, M> where - C: DmaChannel, - MODE: crate::Mode, + M: Mode, { /// Create a new Mem2Mem instance. - pub fn new( - channel: Channel<'d, C, MODE>, + pub fn new( + channel: Channel<'d, CH, M>, peripheral: impl DmaEligible, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], - ) -> Result { + ) -> Result + where + CH: DmaChannelConvert, + { unsafe { Self::new_unsafe( channel, @@ -683,13 +726,16 @@ mod m2m { } /// Create a new Mem2Mem instance with specific chunk size. - pub fn new_with_chunk_size( - channel: Channel<'d, C, MODE>, + pub fn new_with_chunk_size( + channel: Channel<'d, CH, M>, peripheral: impl DmaEligible, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], chunk_size: usize, - ) -> Result { + ) -> Result + where + CH: DmaChannelConvert, + { unsafe { Self::new_unsafe( channel, @@ -707,13 +753,16 @@ mod m2m { /// /// 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, C, MODE>, + pub unsafe fn new_unsafe( + channel: Channel<'d, CH, M>, peripheral: DmaPeripheral, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], chunk_size: usize, - ) -> Result { + ) -> Result + where + CH: DmaChannelConvert, + { if !(1..=4092).contains(&chunk_size) { return Err(DmaError::InvalidChunkSize); } @@ -721,7 +770,7 @@ mod m2m { return Err(DmaError::OutOfDescriptors); } Ok(Mem2Mem { - channel, + channel: 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), @@ -772,10 +821,9 @@ mod m2m { } } - impl<'d, C, MODE> DmaSupport for Mem2Mem<'d, C, MODE> + impl<'d, MODE> DmaSupport for Mem2Mem<'d, MODE> where - C: DmaChannel, - MODE: crate::Mode, + MODE: Mode, { fn peripheral_wait_dma(&mut self, _is_rx: bool, _is_tx: bool) { while !self.channel.rx.is_done() {} @@ -786,12 +834,11 @@ mod m2m { } } - impl<'d, C, MODE> DmaSupportRx for Mem2Mem<'d, C, MODE> + impl<'d, MODE> DmaSupportRx for Mem2Mem<'d, MODE> where - C: DmaChannel, - MODE: crate::Mode, + MODE: Mode, { - type RX = ChannelRx<'d, C>; + type RX = ChannelRx<'d, 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 5e66769aee6..af7f79667cd 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -890,56 +890,44 @@ impl From for Owner { } } -/// Marks channels as useable for SPI #[doc(hidden)] pub trait DmaEligible { - /// The DMA peripheral - const DMA_PERIPHERAL: DmaPeripheral; - fn dma_peripheral(&self) -> DmaPeripheral { - Self::DMA_PERIPHERAL - } -} - -/// Marks channels as useable for SPI -#[doc(hidden)] -pub trait SpiPeripheral: PeripheralMarker {} - -/// Marks channels as useable for SPI2 -#[doc(hidden)] -pub trait Spi2Peripheral: SpiPeripheral + PeripheralMarker {} + /// The most specific DMA channel type usable by this peripheral. + type Dma: DmaChannel; -/// Marks channels as useable for SPI3 -#[cfg(any(esp32, esp32s2, esp32s3))] -#[doc(hidden)] -pub trait Spi3Peripheral: SpiPeripheral + PeripheralMarker {} - -/// Marks channels as useable for I2S -#[doc(hidden)] -pub trait I2sPeripheral: PeripheralMarker {} - -/// Marks channels as useable for I2S0 -#[doc(hidden)] -pub trait I2s0Peripheral: I2sPeripheral + PeripheralMarker {} - -/// Marks channels as useable for I2S1 -#[doc(hidden)] -pub trait I2s1Peripheral: I2sPeripheral + PeripheralMarker {} + fn dma_peripheral(&self) -> DmaPeripheral; +} -/// Marks channels as useable for PARL_IO #[doc(hidden)] -pub trait ParlIoPeripheral: PeripheralMarker {} +#[macro_export] +macro_rules! impl_dma_eligible { + ([$dma_ch:ident] $name:ident => $dma:ident) => { + impl $crate::dma::DmaEligible for $crate::peripherals::$name { + type Dma = $dma_ch; -/// Marks channels as useable for AES -#[doc(hidden)] -pub trait AesPeripheral: PeripheralMarker {} + fn dma_peripheral(&self) -> $crate::dma::DmaPeripheral { + $crate::dma::DmaPeripheral::$dma + } + } + }; -/// Marks channels as usable for LCD_CAM -#[doc(hidden)] -pub trait LcdCamPeripheral: PeripheralMarker {} + ( + $dma_ch:ident { + $($(#[$cfg:meta])? $name:ident => $dma:ident,)* + } + ) => { + $( + $(#[$cfg])? + $crate::impl_dma_eligible!([$dma_ch] $name => $dma); + )* + }; +} /// Marker trait #[doc(hidden)] -pub trait PeripheralMarker {} +pub trait PeripheralMarker { + fn peripheral(&self) -> crate::system::Peripheral; +} #[doc(hidden)] #[derive(Debug)] @@ -1534,25 +1522,33 @@ pub trait DmaChannel: crate::private::Sealed { /// A description of the TX half of a DMA Channel. type Tx: TxRegisterAccess + InterruptAccess; - - /// A suitable peripheral for this DMA channel. - type P: PeripheralMarker; } #[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); } +#[doc(hidden)] +pub trait DmaChannelConvert: DmaChannel { + fn degrade_rx(rx: Self::Rx) -> DEG::Rx; + fn degrade_tx(tx: Self::Tx) -> DEG::Tx; +} + +impl DmaChannelConvert for DEG { + fn degrade_rx(rx: Self::Rx) -> DEG::Rx { + rx + } + + fn degrade_tx(tx: Self::Tx) -> DEG::Tx { + tx + } +} + /// The functions here are not meant to be used outside the HAL #[doc(hidden)] pub trait Rx: crate::private::Sealed { @@ -1634,10 +1630,11 @@ where } } - /// Return a type-erased (degraded) version of this channel. - pub fn degrade(self) -> ChannelRx<'a, CH::Degraded> + /// Return a less specific (degraded) version of this channel. + #[doc(hidden)] + pub fn degrade(self) -> ChannelRx<'a, DEG> where - CH: DmaChannelExt, + CH: DmaChannelConvert, { ChannelRx { burst_mode: self.burst_mode, @@ -1851,10 +1848,11 @@ where } } - /// Return a type-erased (degraded) version of this channel. - pub fn degrade(self) -> ChannelTx<'a, CH::Degraded> + /// Return a less specific (degraded) version of this channel. + #[doc(hidden)] + pub fn degrade(self) -> ChannelTx<'a, DEG> where - CH: DmaChannelExt, + CH: DmaChannelConvert, { ChannelTx { burst_mode: self.burst_mode, @@ -2017,6 +2015,9 @@ pub trait RegisterAccess: crate::private::Sealed { #[cfg(esp32s3)] fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize); + + #[cfg(pdma)] + fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool; } #[doc(hidden)] @@ -2122,13 +2123,17 @@ where } } -impl<'d, C, M: Mode> Channel<'d, C, M> +impl<'d, CH, M: Mode> Channel<'d, CH, M> where - C: DmaChannelExt, + CH: DmaChannel, { - /// Return a type-erased (degraded) version of this channel (both rx and + /// Return a less specific (degraded) version of this channel (both rx and /// tx). - pub fn degrade(self) -> Channel<'d, C::Degraded, M> { + #[doc(hidden)] + pub fn degrade(self) -> Channel<'d, DEG, M> + where + CH: DmaChannelConvert, + { Channel { rx: self.rx.degrade(), tx: self.tx.degrade(), diff --git a/esp-hal/src/dma/pdma.rs b/esp-hal/src/dma/pdma.rs index 423ab7f24e6..6399826e30e 100644 --- a/esp-hal/src/dma/pdma.rs +++ b/esp-hal/src/dma/pdma.rs @@ -26,28 +26,31 @@ type I2sRegisterBlock = crate::peripherals::i2s0::RegisterBlock; pub trait PdmaChannel: crate::private::Sealed { type RegisterBlock; - fn register_block() -> &'static Self::RegisterBlock; - fn tx_waker() -> &'static AtomicWaker; - fn rx_waker() -> &'static AtomicWaker; + fn register_block(&self) -> &Self::RegisterBlock; + fn tx_waker(&self) -> &'static AtomicWaker; + fn rx_waker(&self) -> &'static AtomicWaker; + fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool; } #[doc(hidden)] -pub struct SpiDmaTxChannelImpl(PhantomData); +pub struct SpiDmaRxChannelImpl(C); + +impl crate::private::Sealed for SpiDmaRxChannelImpl {} + #[doc(hidden)] -pub struct SpiDmaRxChannelImpl(PhantomData); +pub struct SpiDmaTxChannelImpl(C); impl crate::private::Sealed for SpiDmaTxChannelImpl {} -impl crate::private::Sealed for SpiDmaRxChannelImpl {} impl> RegisterAccess for SpiDmaTxChannelImpl { fn reset(&self) { - let spi = C::register_block(); + let spi = self.0.register_block(); spi.dma_conf().modify(|_, w| w.out_rst().set_bit()); spi.dma_conf().modify(|_, w| w.out_rst().clear_bit()); } fn set_burst_mode(&self, burst_mode: bool) { - let spi = C::register_block(); + let spi = self.0.register_block(); spi.dma_conf() .modify(|_, w| w.outdscr_burst_en().bit(burst_mode)); } @@ -59,32 +62,36 @@ impl> RegisterAccess for SpiDma } fn set_link_addr(&self, address: u32) { - let spi = C::register_block(); + let spi = self.0.register_block(); spi.dma_out_link() .modify(|_, w| unsafe { w.outlink_addr().bits(address) }); } fn start(&self) { - let spi = C::register_block(); + let spi = self.0.register_block(); spi.dma_out_link() .modify(|_, w| w.outlink_start().set_bit()); } fn stop(&self) { - let spi = C::register_block(); + let spi = self.0.register_block(); spi.dma_out_link().modify(|_, w| w.outlink_stop().set_bit()); } fn restart(&self) { - let spi = C::register_block(); + let spi = self.0.register_block(); spi.dma_out_link() .modify(|_, w| w.outlink_restart().set_bit()); } + + fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool { + self.0.is_compatible_with(peripheral) + } } impl> TxRegisterAccess for SpiDmaTxChannelImpl { fn last_dscr_address(&self) -> usize { - let spi = C::register_block(); + let spi = self.0.register_block(); spi.out_eof_des_addr().read().dma_out_eof_des_addr().bits() as usize } } @@ -93,8 +100,8 @@ impl> InterruptAccess { fn enable_listen(&self, interrupts: EnumSet, enable: bool) { - let spi = C::register_block(); - spi.dma_int_ena().modify(|_, w| { + let reg_block = self.0.register_block(); + reg_block.dma_int_ena().modify(|_, w| { for interrupt in interrupts { match interrupt { DmaTxInterrupt::TotalEof => w.out_total_eof().bit(enable), @@ -110,7 +117,7 @@ impl> InterruptAccess EnumSet { let mut result = EnumSet::new(); - let spi = C::register_block(); + let spi = self.0.register_block(); let int_ena = spi.dma_int_ena().read(); if int_ena.out_total_eof().bit_is_set() { result |= DmaTxInterrupt::TotalEof; @@ -129,7 +136,7 @@ impl> InterruptAccess>) { - let spi = C::register_block(); + let spi = self.0.register_block(); spi.dma_int_clr().write(|w| { for interrupt in interrupts.into() { match interrupt { @@ -146,7 +153,7 @@ impl> InterruptAccess EnumSet { let mut result = EnumSet::new(); - let spi = C::register_block(); + let spi = self.0.register_block(); let int_raw = spi.dma_int_raw().read(); if int_raw.out_total_eof().bit_is_set() { result |= DmaTxInterrupt::TotalEof; @@ -165,19 +172,19 @@ impl> InterruptAccess &'static AtomicWaker { - C::tx_waker() + self.0.tx_waker() } } impl> RegisterAccess for SpiDmaRxChannelImpl { fn reset(&self) { - let spi = C::register_block(); + let spi = self.0.register_block(); spi.dma_conf().modify(|_, w| w.in_rst().set_bit()); spi.dma_conf().modify(|_, w| w.in_rst().clear_bit()); } fn set_burst_mode(&self, burst_mode: bool) { - let spi = C::register_block(); + let spi = self.0.register_block(); spi.dma_conf() .modify(|_, w| w.indscr_burst_en().bit(burst_mode)); } @@ -189,26 +196,30 @@ impl> RegisterAccess for SpiDma } fn set_link_addr(&self, address: u32) { - let spi = C::register_block(); + let spi = self.0.register_block(); spi.dma_in_link() .modify(|_, w| unsafe { w.inlink_addr().bits(address) }); } fn start(&self) { - let spi = C::register_block(); + let spi = self.0.register_block(); spi.dma_in_link().modify(|_, w| w.inlink_start().set_bit()); } fn stop(&self) { - let spi = C::register_block(); + let spi = self.0.register_block(); spi.dma_in_link().modify(|_, w| w.inlink_stop().set_bit()); } fn restart(&self) { - let spi = C::register_block(); + let spi = self.0.register_block(); spi.dma_in_link() .modify(|_, w| w.inlink_restart().set_bit()); } + + fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool { + self.0.is_compatible_with(peripheral) + } } impl> RxRegisterAccess for SpiDmaRxChannelImpl {} @@ -217,8 +228,8 @@ impl> InterruptAccess { fn enable_listen(&self, interrupts: EnumSet, enable: bool) { - let spi = C::register_block(); - spi.dma_int_ena().modify(|_, w| { + let reg_block = self.0.register_block(); + reg_block.dma_int_ena().modify(|_, w| { for interrupt in interrupts { match interrupt { DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().bit(enable), @@ -235,7 +246,7 @@ impl> InterruptAccess EnumSet { let mut result = EnumSet::new(); - let spi = C::register_block(); + let spi = self.0.register_block(); let int_ena = spi.dma_int_ena().read(); if int_ena.inlink_dscr_error().bit_is_set() { result |= DmaRxInterrupt::DescriptorError; @@ -257,7 +268,7 @@ impl> InterruptAccess>) { - let spi = C::register_block(); + let spi = self.0.register_block(); spi.dma_int_clr().modify(|_, w| { for interrupt in interrupts.into() { match interrupt { @@ -275,7 +286,7 @@ impl> InterruptAccess EnumSet { let mut result = EnumSet::new(); - let spi = C::register_block(); + let spi = self.0.register_block(); let int_raw = spi.dma_int_raw().read(); if int_raw.inlink_dscr_error().bit_is_set() { result |= DmaRxInterrupt::DescriptorError; @@ -297,7 +308,7 @@ impl> InterruptAccess &'static AtomicWaker { - C::rx_waker() + self.0.rx_waker() } } @@ -316,24 +327,14 @@ macro_rules! ImplSpiChannel { impl DmaChannel for [] { type Rx = SpiDmaRxChannelImpl; type Tx = SpiDmaTxChannelImpl; - type P = []; } impl DmaChannelExt for [] { - type Degraded = Self; - fn get_rx_interrupts() -> impl InterruptAccess { - SpiDmaRxChannelImpl::(PhantomData) + SpiDmaRxChannelImpl(Self {}) } fn get_tx_interrupts() -> impl InterruptAccess { - SpiDmaTxChannelImpl::(PhantomData) - } - - fn degrade_rx(rx: Self::Rx) -> Self::Rx { - rx - } - fn degrade_tx(tx: Self::Tx) -> Self::Tx { - tx + SpiDmaTxChannelImpl(Self {}) } fn set_isr(handler: InterruptHandler) { @@ -348,17 +349,21 @@ macro_rules! ImplSpiChannel { impl PdmaChannel for [] { type RegisterBlock = SpiRegisterBlock; - fn register_block() -> &'static SpiRegisterBlock { + fn register_block(&self) -> &SpiRegisterBlock { unsafe { &*crate::peripherals::[]::PTR } } - fn tx_waker() -> &'static embassy_sync::waitqueue::AtomicWaker { + fn tx_waker(&self) -> &'static embassy_sync::waitqueue::AtomicWaker { static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new(); &WAKER } - fn rx_waker() -> &'static embassy_sync::waitqueue::AtomicWaker { + fn rx_waker(&self) -> &'static embassy_sync::waitqueue::AtomicWaker { static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new(); &WAKER } + + fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool { + peripheral.peripheral() == crate::system::Peripheral::[] + } } impl $crate::private::Sealed for [] {} @@ -382,11 +387,11 @@ macro_rules! ImplSpiChannel { .modify(|_, w| unsafe { w.[< spi $num _dma_chan_sel>]().bits($num - 1) }); } - let tx_impl = SpiDmaTxChannelImpl(PhantomData); + let tx_impl = SpiDmaTxChannelImpl([] {}); tx_impl.set_burst_mode(burst_mode); tx_impl.set_priority(priority); - let rx_impl = SpiDmaRxChannelImpl(PhantomData); + let rx_impl = SpiDmaRxChannelImpl([] {}); rx_impl.set_burst_mode(burst_mode); rx_impl.set_priority(priority); @@ -430,16 +435,18 @@ macro_rules! ImplSpiChannel { } #[doc(hidden)] -pub struct I2sDmaTxChannelImpl(PhantomData); +pub struct I2sDmaRxChannelImpl(C); + +impl crate::private::Sealed for I2sDmaRxChannelImpl {} + #[doc(hidden)] -pub struct I2sDmaRxChannelImpl(PhantomData); +pub struct I2sDmaTxChannelImpl(C); impl crate::private::Sealed for I2sDmaTxChannelImpl {} -impl crate::private::Sealed for I2sDmaRxChannelImpl {} impl> RegisterAccess for I2sDmaTxChannelImpl { fn set_burst_mode(&self, burst_mode: bool) { - let reg_block = C::register_block(); + let reg_block = self.0.register_block(); reg_block .lc_conf() .modify(|_, w| w.outdscr_burst_en().bit(burst_mode)); @@ -448,13 +455,13 @@ impl> RegisterAccess for I2sDma fn set_priority(&self, _priority: DmaPriority) {} fn reset(&self) { - let reg_block = C::register_block(); + 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_link_addr(&self, address: u32) { - let reg_block = C::register_block(); + let reg_block = self.0.register_block(); reg_block .out_link() .modify(|_, w| unsafe { w.outlink_addr().bits(address) }); @@ -465,30 +472,34 @@ impl> RegisterAccess for I2sDma } fn start(&self) { - let reg_block = C::register_block(); + let reg_block = self.0.register_block(); reg_block .out_link() .modify(|_, w| w.outlink_start().set_bit()); } fn stop(&self) { - let reg_block = C::register_block(); + let reg_block = self.0.register_block(); reg_block .out_link() .modify(|_, w| w.outlink_stop().set_bit()); } fn restart(&self) { - let reg_block = C::register_block(); + let reg_block = self.0.register_block(); reg_block .out_link() .modify(|_, w| w.outlink_restart().set_bit()); } + + fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool { + self.0.is_compatible_with(peripheral) + } } impl> TxRegisterAccess for I2sDmaTxChannelImpl { fn last_dscr_address(&self) -> usize { - let reg_block = C::register_block(); + let reg_block = self.0.register_block(); reg_block .out_eof_des_addr() .read() @@ -501,7 +512,7 @@ impl> InterruptAccess { fn enable_listen(&self, interrupts: EnumSet, enable: bool) { - let reg_block = C::register_block(); + let reg_block = self.0.register_block(); reg_block.int_ena().modify(|_, w| { for interrupt in interrupts { match interrupt { @@ -518,7 +529,7 @@ impl> InterruptAccess EnumSet { let mut result = EnumSet::new(); - let reg_block = C::register_block(); + let reg_block = self.0.register_block(); let int_ena = reg_block.int_ena().read(); if int_ena.out_total_eof().bit_is_set() { result |= DmaTxInterrupt::TotalEof; @@ -539,7 +550,7 @@ impl> InterruptAccess EnumSet { let mut result = EnumSet::new(); - let reg_block = C::register_block(); + let reg_block = self.0.register_block(); let int_raw = reg_block.int_raw().read(); if int_raw.out_total_eof().bit_is_set() { result |= DmaTxInterrupt::TotalEof; @@ -558,7 +569,7 @@ impl> InterruptAccess>) { - let reg_block = C::register_block(); + let reg_block = self.0.register_block(); reg_block.int_clr().write(|w| { for interrupt in interrupts.into() { match interrupt { @@ -573,13 +584,13 @@ impl> InterruptAccess &'static AtomicWaker { - C::tx_waker() + self.0.tx_waker() } } impl> RegisterAccess for I2sDmaRxChannelImpl { fn set_burst_mode(&self, burst_mode: bool) { - let reg_block = C::register_block(); + let reg_block = self.0.register_block(); reg_block .lc_conf() .modify(|_, w| w.indscr_burst_en().bit(burst_mode)); @@ -588,13 +599,13 @@ impl> RegisterAccess for I2sDma fn set_priority(&self, _priority: DmaPriority) {} fn reset(&self) { - let reg_block = C::register_block(); + 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_link_addr(&self, address: u32) { - let reg_block = C::register_block(); + let reg_block = self.0.register_block(); reg_block .in_link() .modify(|_, w| unsafe { w.inlink_addr().bits(address) }); @@ -605,23 +616,27 @@ impl> RegisterAccess for I2sDma } fn start(&self) { - let reg_block = C::register_block(); + let reg_block = self.0.register_block(); reg_block .in_link() .modify(|_, w| w.inlink_start().set_bit()); } fn stop(&self) { - let reg_block = C::register_block(); + let reg_block = self.0.register_block(); reg_block.in_link().modify(|_, w| w.inlink_stop().set_bit()); } fn restart(&self) { - let reg_block = C::register_block(); + let reg_block = self.0.register_block(); reg_block .in_link() .modify(|_, w| w.inlink_restart().set_bit()); } + + fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool { + self.0.is_compatible_with(peripheral) + } } impl> RxRegisterAccess for I2sDmaRxChannelImpl {} @@ -630,7 +645,7 @@ impl> InterruptAccess { fn enable_listen(&self, interrupts: EnumSet, enable: bool) { - let reg_block = C::register_block(); + let reg_block = self.0.register_block(); reg_block.int_ena().modify(|_, w| { for interrupt in interrupts { match interrupt { @@ -648,7 +663,7 @@ impl> InterruptAccess EnumSet { let mut result = EnumSet::new(); - let reg_block = C::register_block(); + let reg_block = self.0.register_block(); let int_ena = reg_block.int_ena().read(); if int_ena.in_dscr_err().bit_is_set() { result |= DmaRxInterrupt::DescriptorError; @@ -672,7 +687,7 @@ impl> InterruptAccess EnumSet { let mut result = EnumSet::new(); - let reg_block = C::register_block(); + let reg_block = self.0.register_block(); let int_raw = reg_block.int_raw().read(); if int_raw.in_dscr_err().bit_is_set() { result |= DmaRxInterrupt::DescriptorError; @@ -694,7 +709,7 @@ impl> InterruptAccess>) { - let reg_block = C::register_block(); + let reg_block = self.0.register_block(); reg_block.int_clr().write(|w| { for interrupt in interrupts.into() { match interrupt { @@ -710,7 +725,7 @@ impl> InterruptAccess &'static AtomicWaker { - C::rx_waker() + self.0.rx_waker() } } @@ -725,28 +740,18 @@ macro_rules! ImplI2sChannel { impl DmaChannel for [] { type Rx = I2sDmaRxChannelImpl; type Tx = I2sDmaTxChannelImpl; - type P = []; } impl DmaChannelExt for [] { - type Degraded = Self; - fn get_rx_interrupts() -> impl InterruptAccess { - I2sDmaRxChannelImpl::(PhantomData) + I2sDmaRxChannelImpl(Self {}) } fn get_tx_interrupts() -> impl InterruptAccess { - I2sDmaTxChannelImpl::(PhantomData) - } - - fn degrade_rx(rx: Self::Rx) -> Self::Rx { - rx - } - fn degrade_tx(tx: Self::Tx) -> Self::Tx { - tx + I2sDmaTxChannelImpl(Self {}) } fn set_isr(handler: InterruptHandler) { - let interrupt = $crate::peripherals::Interrupt::[< I2S $num >]; + let interrupt = $crate::peripherals::Interrupt::[< I2S $num >]; unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()); } @@ -757,17 +762,20 @@ macro_rules! ImplI2sChannel { impl PdmaChannel for [] { type RegisterBlock = I2sRegisterBlock; - fn register_block() -> &'static I2sRegisterBlock { + fn register_block(&self) -> &I2sRegisterBlock { unsafe { &*crate::peripherals::[< I2S $num >]::PTR } } - fn tx_waker() -> &'static embassy_sync::waitqueue::AtomicWaker { + fn tx_waker(&self) -> &'static embassy_sync::waitqueue::AtomicWaker { static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new(); &WAKER } - fn rx_waker() -> &'static embassy_sync::waitqueue::AtomicWaker { + fn rx_waker(&self) -> &'static embassy_sync::waitqueue::AtomicWaker { static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new(); &WAKER } + fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool { + peripheral.peripheral() == crate::system::Peripheral::[] + } } #[doc = concat!("Creates a channel for I2S", $num)] @@ -779,11 +787,11 @@ macro_rules! ImplI2sChannel { burst_mode: bool, priority: DmaPriority, ) -> Channel<'a, [], M> { - let tx_impl = I2sDmaTxChannelImpl(PhantomData); + let tx_impl = I2sDmaTxChannelImpl([] {}); tx_impl.set_burst_mode(burst_mode); tx_impl.set_priority(priority); - let rx_impl = I2sDmaRxChannelImpl(PhantomData); + let rx_impl = I2sDmaRxChannelImpl([] {}); rx_impl.set_burst_mode(burst_mode); rx_impl.set_priority(priority); @@ -826,42 +834,22 @@ macro_rules! ImplI2sChannel { }; } -#[doc(hidden)] -#[non_exhaustive] -pub struct Spi2DmaSuitablePeripheral {} -impl PeripheralMarker for Spi2DmaSuitablePeripheral {} -impl SpiPeripheral for Spi2DmaSuitablePeripheral {} -impl Spi2Peripheral for Spi2DmaSuitablePeripheral {} - -#[doc(hidden)] -#[non_exhaustive] -pub struct Spi3DmaSuitablePeripheral {} -impl PeripheralMarker for Spi3DmaSuitablePeripheral {} -impl SpiPeripheral for Spi3DmaSuitablePeripheral {} -impl Spi3Peripheral for Spi3DmaSuitablePeripheral {} - ImplSpiChannel!(2); ImplSpiChannel!(3); -#[doc(hidden)] -#[non_exhaustive] -pub struct I2s0DmaSuitablePeripheral {} -impl PeripheralMarker for I2s0DmaSuitablePeripheral {} -impl I2sPeripheral for I2s0DmaSuitablePeripheral {} -impl I2s0Peripheral for I2s0DmaSuitablePeripheral {} - ImplI2sChannel!(0); - -#[doc(hidden)] -#[non_exhaustive] -pub struct I2s1DmaSuitablePeripheral {} -impl PeripheralMarker for I2s1DmaSuitablePeripheral {} -impl I2sPeripheral for I2s1DmaSuitablePeripheral {} -impl I2s1Peripheral for I2s1DmaSuitablePeripheral {} - #[cfg(i2s1)] ImplI2sChannel!(1); +// Specific peripherals use specific channels. Note that this may be overly +// restrictive (ESP32 allows configuring 2 SPI DMA channels between 3 different +// peripherals), but for the current set of restrictions this is sufficient. +crate::impl_dma_eligible!([Spi2DmaChannel] SPI2 => Spi2); +crate::impl_dma_eligible!([Spi3DmaChannel] SPI3 => Spi3); +crate::impl_dma_eligible!([I2s0DmaChannel] I2S0 => I2s0); +#[cfg(i2s1)] +crate::impl_dma_eligible!([I2s1DmaChannel] I2S1 => I2s1); + /// DMA Peripheral /// /// This offers the available DMA channels. @@ -874,7 +862,7 @@ pub struct Dma<'d> { /// DMA channel for I2S0 pub i2s0channel: I2s0DmaChannelCreator, /// DMA channel for I2S1 - #[cfg(esp32)] + #[cfg(i2s1)] pub i2s1channel: I2s1DmaChannelCreator, } @@ -895,3 +883,17 @@ impl<'d> Dma<'d> { } } } + +impl<'d, C, M: Mode> Channel<'d, C, M> +where + C: DmaChannel, +{ + /// Asserts that the channel is compatible with the given peripheral. + pub fn runtime_ensure_compatible(&self, peripheral: &PeripheralRef<'_, impl PeripheralMarker>) { + assert!( + self.tx.tx_impl.is_compatible_with(&**peripheral), + "This DMA channel is not compatible with {:?}", + peripheral.peripheral() + ); + } +} diff --git a/esp-hal/src/i2s.rs b/esp-hal/src/i2s.rs index ce889bade8c..6b9d9035f86 100644 --- a/esp-hal/src/i2s.rs +++ b/esp-hal/src/i2s.rs @@ -84,8 +84,6 @@ use core::marker::PhantomData; use enumset::{EnumSet, EnumSetType}; use private::*; -#[cfg(i2s1)] -use crate::dma::I2s1Peripheral; use crate::{ dma::{ dma_private::{DmaSupport, DmaSupportRx, DmaSupportTx}, @@ -93,15 +91,13 @@ use crate::{ ChannelRx, ChannelTx, DescriptorChain, - DmaChannel, + DmaChannelConvert, DmaDescriptor, DmaError, DmaTransferRx, DmaTransferRxCircular, DmaTransferTx, DmaTransferTxCircular, - I2s0Peripheral, - I2sPeripheral, ReadBuffer, Rx, Tx, @@ -262,10 +258,9 @@ pub trait I2sWrite { } /// Initiate a DMA tx transfer -pub trait I2sWriteDma<'d, T, CH, TXBUF, DmaMode> +pub trait I2sWriteDma<'d, T, TXBUF, DmaMode> where T: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, Self: DmaSupportTx + Sized, { @@ -294,10 +289,9 @@ pub trait I2sRead { } /// Initiate a DMA rx transfer -pub trait I2sReadDma<'d, T, CH, RXBUF, DmaMode> +pub trait I2sReadDma<'d, T, RXBUF, DmaMode> where T: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, Self: DmaSupportRx + Sized, { @@ -320,35 +314,38 @@ where } /// Instance of the I2S peripheral driver -pub struct I2s<'d, I, CH, DmaMode> +pub struct I2s<'d, I, DmaMode> where I: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { /// Handles the reception (RX) side of the I2S peripheral. - pub i2s_rx: RxCreator<'d, I, CH, DmaMode>, + pub i2s_rx: RxCreator<'d, I, DmaMode>, /// Handles the transmission (TX) side of the I2S peripheral. - pub i2s_tx: TxCreator<'d, I, CH, DmaMode>, + pub i2s_tx: TxCreator<'d, I, DmaMode>, phantom: PhantomData, } -impl<'d, I, CH, DmaMode> I2s<'d, I, CH, DmaMode> +impl<'d, I, DmaMode> I2s<'d, I, DmaMode> where I: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { #[allow(clippy::too_many_arguments)] - fn new_internal( - _i2s: impl Peripheral

+ 'd, + fn new_internal( + i2s: impl Peripheral

+ 'd, standard: Standard, data_format: DataFormat, sample_rate: impl Into, channel: Channel<'d, CH, DmaMode>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], - ) -> Self { + ) -> Self + where + CH: DmaChannelConvert, + { + crate::into_ref!(i2s); + 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 // the targets the same and force same configuration for both, TX and RX @@ -360,6 +357,7 @@ where I::set_master(); I::update(); + let channel = channel.degrade(); Self { i2s_rx: RxCreator { register_access: PhantomData, @@ -378,10 +376,9 @@ where } } -impl<'d, I, CH, DmaMode> I2s<'d, I, CH, DmaMode> +impl<'d, I, DmaMode> I2s<'d, I, DmaMode> where I: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { /// Sets the interrupt handler @@ -412,18 +409,16 @@ where } } -impl<'d, I, CH, DmaMode> crate::private::Sealed for I2s<'d, I, CH, DmaMode> +impl<'d, I, DmaMode> crate::private::Sealed for I2s<'d, I, DmaMode> where I: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { } -impl<'d, I, CH, DmaMode> InterruptConfigurable for I2s<'d, I, CH, DmaMode> +impl<'d, I, DmaMode> InterruptConfigurable for I2s<'d, I, DmaMode> where I: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { @@ -431,16 +426,15 @@ where } } -impl<'d, I, CH, DmaMode> I2s<'d, I, CH, DmaMode> +impl<'d, I, DmaMode> I2s<'d, I, DmaMode> where I: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { /// 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, @@ -450,8 +444,7 @@ where tx_descriptors: &'static mut [DmaDescriptor], ) -> Self where - I: I2s0Instance, - CH::P: I2sPeripheral + I2s0Peripheral, + CH: DmaChannelConvert, DmaMode: Mode, { Self::new_internal( @@ -465,34 +458,6 @@ where ) } - /// Construct a new I2S peripheral driver instance for the second I2S - /// peripheral - #[allow(clippy::too_many_arguments)] - #[cfg(i2s1)] - pub fn new_i2s1( - i2s: impl Peripheral

+ 'd, - standard: Standard, - data_format: DataFormat, - sample_rate: impl Into, - channel: Channel<'d, CH, DmaMode>, - rx_descriptors: &'static mut [DmaDescriptor], - tx_descriptors: &'static mut [DmaDescriptor], - ) -> Self - where - I: I2s1Instance, - CH::P: I2sPeripheral + I2s1Peripheral, - { - Self::new_internal( - i2s, - standard, - data_format, - sample_rate, - channel, - rx_descriptors, - tx_descriptors, - ) - } - /// Configures the I2S peripheral to use a master clock (MCLK) output pin. pub fn with_mclk(self, pin: impl Peripheral

+ 'd) -> Self { into_ref!(pin); @@ -504,21 +469,19 @@ where } /// I2S TX channel -pub struct I2sTx<'d, T, CH, DmaMode> +pub struct I2sTx<'d, T, DmaMode> where T: RegisterAccess, - CH: DmaChannel, { register_access: PhantomData, - tx_channel: ChannelTx<'d, CH>, + tx_channel: ChannelTx<'d, T::Dma>, tx_chain: DescriptorChain, phantom: PhantomData, } -impl<'d, T, CH, DmaMode> core::fmt::Debug for I2sTx<'d, T, CH, DmaMode> +impl<'d, T, DmaMode> core::fmt::Debug for I2sTx<'d, T, DmaMode> where T: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -526,10 +489,9 @@ where } } -impl<'d, T, CH, DmaMode> DmaSupport for I2sTx<'d, T, CH, DmaMode> +impl<'d, T, DmaMode> DmaSupport for I2sTx<'d, T, DmaMode> where T: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { fn peripheral_wait_dma(&mut self, _is_rx: bool, _is_tx: bool) { @@ -541,13 +503,12 @@ where } } -impl<'d, T, CH, DmaMode> DmaSupportTx for I2sTx<'d, T, CH, DmaMode> +impl<'d, T, DmaMode> DmaSupportTx for I2sTx<'d, T, DmaMode> where T: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { - type TX = ChannelTx<'d, CH>; + type TX = ChannelTx<'d, T::Dma>; fn tx(&mut self) -> &mut Self::TX { &mut self.tx_channel @@ -558,13 +519,12 @@ where } } -impl<'d, T, CH, DmaMode> I2sTx<'d, T, CH, DmaMode> +impl<'d, T, DmaMode> I2sTx<'d, T, DmaMode> where T: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { - fn new(tx_channel: ChannelTx<'d, CH>, descriptors: &'static mut [DmaDescriptor]) -> Self { + fn new(tx_channel: ChannelTx<'d, T::Dma>, descriptors: &'static mut [DmaDescriptor]) -> Self { Self { register_access: PhantomData, tx_channel, @@ -633,10 +593,9 @@ where } } -impl<'d, T, W, CH, DmaMode> I2sWrite for I2sTx<'d, T, CH, DmaMode> +impl<'d, T, W, DmaMode> I2sWrite for I2sTx<'d, T, DmaMode> where T: RegisterAccess, - CH: DmaChannel, W: AcceptedWord, DmaMode: Mode, { @@ -647,10 +606,9 @@ where } } -impl<'d, T, CH, TXBUF, DmaMode> I2sWriteDma<'d, T, CH, TXBUF, DmaMode> for I2sTx<'d, T, CH, DmaMode> +impl<'d, T, TXBUF, DmaMode> I2sWriteDma<'d, T, TXBUF, DmaMode> for I2sTx<'d, T, DmaMode> where T: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { fn write_dma<'t>(&'t mut self, words: &'t TXBUF) -> Result, Error> @@ -674,22 +632,20 @@ where } /// I2S RX channel -pub struct I2sRx<'d, T, CH, DmaMode> +pub struct I2sRx<'d, T, DmaMode> where T: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { register_access: PhantomData, - rx_channel: ChannelRx<'d, CH>, + rx_channel: ChannelRx<'d, T::Dma>, rx_chain: DescriptorChain, phantom: PhantomData, } -impl<'d, T, CH, DmaMode> core::fmt::Debug for I2sRx<'d, T, CH, DmaMode> +impl<'d, T, DmaMode> core::fmt::Debug for I2sRx<'d, T, DmaMode> where T: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -697,10 +653,9 @@ where } } -impl<'d, T, CH, DmaMode> DmaSupport for I2sRx<'d, T, CH, DmaMode> +impl<'d, T, DmaMode> DmaSupport for I2sRx<'d, T, DmaMode> where T: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { fn peripheral_wait_dma(&mut self, _is_rx: bool, _is_tx: bool) { @@ -712,13 +667,12 @@ where } } -impl<'d, T, CH, DmaMode> DmaSupportRx for I2sRx<'d, T, CH, DmaMode> +impl<'d, T, DmaMode> DmaSupportRx for I2sRx<'d, T, DmaMode> where T: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { - type RX = ChannelRx<'d, CH>; + type RX = ChannelRx<'d, T::Dma>; fn rx(&mut self) -> &mut Self::RX { &mut self.rx_channel @@ -729,13 +683,12 @@ where } } -impl<'d, T, CH, DmaMode> I2sRx<'d, T, CH, DmaMode> +impl<'d, T, DmaMode> I2sRx<'d, T, DmaMode> where T: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { - fn new(rx_channel: ChannelRx<'d, CH>, descriptors: &'static mut [DmaDescriptor]) -> Self { + fn new(rx_channel: ChannelRx<'d, T::Dma>, descriptors: &'static mut [DmaDescriptor]) -> Self { Self { register_access: PhantomData, rx_channel, @@ -802,10 +755,9 @@ where } } -impl<'d, W, T, CH, DmaMode> I2sRead for I2sRx<'d, T, CH, DmaMode> +impl<'d, W, T, DmaMode> I2sRead for I2sRx<'d, T, DmaMode> where T: RegisterAccess, - CH: DmaChannel, W: AcceptedWord, DmaMode: Mode, { @@ -823,10 +775,9 @@ where } } -impl<'d, T, CH, RXBUF, DmaMode> I2sReadDma<'d, T, CH, RXBUF, DmaMode> for I2sRx<'d, T, CH, DmaMode> +impl<'d, T, RXBUF, DmaMode> I2sReadDma<'d, T, RXBUF, DmaMode> for I2sRx<'d, T, DmaMode> where T: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, Self: DmaSupportRx + Sized, { @@ -852,6 +803,7 @@ where /// Provides an abstraction for accessing the I2S peripheral registers. pub trait RegisterAccess: RegisterAccessPrivate {} +impl RegisterAccess for T where T: RegisterAccessPrivate {} mod private { use core::marker::PhantomData; @@ -875,7 +827,7 @@ mod private { #[cfg(any(esp32, esp32s3))] use crate::peripherals::{i2s1::RegisterBlock, I2S1}; use crate::{ - dma::{ChannelRx, ChannelTx, DmaChannel, DmaDescriptor, DmaPeripheral}, + dma::{ChannelRx, ChannelTx, DmaDescriptor, DmaEligible, DmaPeripheral, PeripheralMarker}, gpio::{InputSignal, OutputSignal, PeripheralInput, PeripheralOutput}, interrupt::InterruptHandler, into_ref, @@ -885,25 +837,23 @@ mod private { Mode, }; - pub struct TxCreator<'d, T, CH, DmaMode> + pub struct TxCreator<'d, T, DmaMode> where T: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { pub register_access: PhantomData, - pub tx_channel: ChannelTx<'d, CH>, + pub tx_channel: ChannelTx<'d, T::Dma>, pub descriptors: &'static mut [DmaDescriptor], pub(crate) phantom: PhantomData, } - impl<'d, T, CH, DmaMode> TxCreator<'d, T, CH, DmaMode> + impl<'d, T, DmaMode> TxCreator<'d, T, DmaMode> where T: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { - pub fn build(self) -> I2sTx<'d, T, CH, DmaMode> { + pub fn build(self) -> I2sTx<'d, T, DmaMode> { I2sTx::new(self.tx_channel, self.descriptors) } @@ -941,25 +891,23 @@ mod private { } } - pub struct RxCreator<'d, T, CH, DmaMode> + pub struct RxCreator<'d, T, DmaMode> where T: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { pub register_access: PhantomData, - pub rx_channel: ChannelRx<'d, CH>, + pub rx_channel: ChannelRx<'d, T::Dma>, pub descriptors: &'static mut [DmaDescriptor], pub(crate) phantom: PhantomData, } - impl<'d, T, CH, DmaMode> RxCreator<'d, T, CH, DmaMode> + impl<'d, T, DmaMode> RxCreator<'d, T, DmaMode> where T: RegisterAccess, - CH: DmaChannel, DmaMode: Mode, { - pub fn build(self) -> I2sRx<'d, T, CH, DmaMode> { + pub fn build(self) -> I2sRx<'d, T, DmaMode> { I2sRx::new(self.rx_channel, self.descriptors) } @@ -1017,7 +965,7 @@ mod private { fn din_signal() -> InputSignal; } - pub trait RegBlock { + pub trait RegBlock: PeripheralMarker + DmaEligible { fn register_block() -> &'static RegisterBlock; } @@ -1941,6 +1889,19 @@ mod private { } } + impl PeripheralMarker for I2S0 { + fn peripheral(&self) -> crate::system::Peripheral { + crate::system::Peripheral::I2s0 + } + } + + #[cfg(i2s1)] + impl PeripheralMarker for I2S1 { + fn peripheral(&self) -> crate::system::Peripheral { + crate::system::Peripheral::I2s1 + } + } + impl RegBlock for I2S0 { fn register_block() -> &'static RegisterBlock { unsafe { &*I2S0::PTR.cast::() } @@ -1961,7 +1922,6 @@ mod private { .unwrap(); } } - impl super::RegisterAccess for I2S0 {} #[cfg(i2s1)] impl RegisterAccessPrivate for I2S1 { @@ -1971,18 +1931,6 @@ mod private { .unwrap(); } } - #[cfg(i2s1)] - impl super::RegisterAccess for I2S1 {} - - pub trait I2s0Instance {} - - #[cfg(any(esp32s3, esp32))] - pub trait I2s1Instance {} - - impl I2s0Instance for I2S0 {} - - #[cfg(any(esp32s3, esp32))] - impl I2s1Instance for I2S1 {} pub struct I2sClockDividers { mclk_divider: u32, @@ -2066,7 +2014,6 @@ pub mod asynch { use crate::{ dma::{ asynch::{DmaRxDoneChFuture, DmaRxFuture, DmaTxDoneChFuture, DmaTxFuture}, - DmaChannel, ReadBuffer, Rx, RxCircularState, @@ -2078,10 +2025,9 @@ pub mod asynch { }; /// Initiate an async DMA tx transfer - pub trait I2sWriteDmaAsync<'d, T, CH> + pub trait I2sWriteDmaAsync<'d, T> where T: RegisterAccess, - CH: DmaChannel, { /// One-shot write I2S. async fn write_dma_async(&mut self, words: &mut [u8]) -> Result<(), Error>; @@ -2090,15 +2036,14 @@ pub mod asynch { fn write_dma_circular_async( self, words: TXBUF, - ) -> Result, Error> + ) -> Result, Error> where TXBUF: ReadBuffer; } - impl<'d, T, CH> I2sWriteDmaAsync<'d, T, CH> for super::I2sTx<'d, T, CH, Async> + impl<'d, T> I2sWriteDmaAsync<'d, T> for super::I2sTx<'d, T, Async> where T: RegisterAccess, - CH: DmaChannel, { async fn write_dma_async(&mut self, words: &mut [u8]) -> Result<(), Error> { let (ptr, len) = (words.as_ptr(), words.len()); @@ -2124,7 +2069,7 @@ pub mod asynch { fn write_dma_circular_async( mut self, words: TXBUF, - ) -> Result, Error> + ) -> Result, Error> where TXBUF: ReadBuffer, { @@ -2158,20 +2103,18 @@ pub mod asynch { } /// An in-progress async circular DMA write transfer. - pub struct I2sWriteDmaTransferAsync<'d, T, CH, BUFFER> + pub struct I2sWriteDmaTransferAsync<'d, T, BUFFER> where T: RegisterAccess, - CH: DmaChannel, { - i2s_tx: I2sTx<'d, T, CH, Async>, + i2s_tx: I2sTx<'d, T, Async>, state: TxCircularState, _buffer: BUFFER, } - impl<'d, T, CH, BUFFER> I2sWriteDmaTransferAsync<'d, T, CH, BUFFER> + impl<'d, T, BUFFER> I2sWriteDmaTransferAsync<'d, T, BUFFER> where T: RegisterAccess, - CH: DmaChannel, { /// How many bytes can be pushed into the DMA transaction. /// Will wait for more than 0 bytes available. @@ -2210,10 +2153,9 @@ pub mod asynch { } /// Initiate an async DMA rx transfer - pub trait I2sReadDmaAsync<'d, T, CH> + pub trait I2sReadDmaAsync<'d, T> where T: RegisterAccess, - CH: DmaChannel, { /// One-shot read I2S. async fn read_dma_async(&mut self, words: &mut [u8]) -> Result<(), Error>; @@ -2222,15 +2164,14 @@ pub mod asynch { fn read_dma_circular_async( self, words: RXBUF, - ) -> Result, Error> + ) -> Result, Error> where RXBUF: WriteBuffer; } - impl<'d, T, CH> I2sReadDmaAsync<'d, T, CH> for super::I2sRx<'d, T, CH, Async> + impl<'d, T> I2sReadDmaAsync<'d, T> for super::I2sRx<'d, T, Async> where T: RegisterAccess, - CH: DmaChannel, { async fn read_dma_async(&mut self, words: &mut [u8]) -> Result<(), Error> { let (ptr, len) = (words.as_mut_ptr(), words.len()); @@ -2264,7 +2205,7 @@ pub mod asynch { fn read_dma_circular_async( mut self, mut words: RXBUF, - ) -> Result, Error> + ) -> Result, Error> where RXBUF: WriteBuffer, { @@ -2300,20 +2241,18 @@ pub mod asynch { } /// An in-progress async circular DMA read transfer. - pub struct I2sReadDmaTransferAsync<'d, T, CH, BUFFER> + pub struct I2sReadDmaTransferAsync<'d, T, BUFFER> where T: RegisterAccess, - CH: DmaChannel, { - i2s_rx: I2sRx<'d, T, CH, Async>, + i2s_rx: I2sRx<'d, T, Async>, state: RxCircularState, _buffer: BUFFER, } - impl<'d, T, CH, BUFFER> I2sReadDmaTransferAsync<'d, T, CH, BUFFER> + impl<'d, T, BUFFER> I2sReadDmaTransferAsync<'d, T, BUFFER> where T: RegisterAccess, - CH: DmaChannel, { /// How many bytes can be popped from the DMA transaction. /// Will wait for more than 0 bytes available. diff --git a/esp-hal/src/lcd_cam/cam.rs b/esp-hal/src/lcd_cam/cam.rs index 282461264d1..00841606611 100644 --- a/esp-hal/src/lcd_cam/cam.rs +++ b/esp-hal/src/lcd_cam/cam.rs @@ -74,16 +74,7 @@ use fugit::HertzU32; use crate::{ clock::Clocks, - dma::{ - AnyDmaChannel, - ChannelRx, - DmaChannel, - DmaError, - DmaPeripheral, - DmaRxBuffer, - LcdCamPeripheral, - Rx, - }, + dma::{ChannelRx, DmaChannelConvert, DmaEligible, DmaError, DmaPeripheral, DmaRxBuffer, Rx}, gpio::{InputSignal, OutputSignal, PeripheralInput, PeripheralOutput, Pull}, lcd_cam::{cam::private::RxPins, private::calculate_clkm, BitOrder, ByteOrder}, peripheral::{Peripheral, PeripheralRef}, @@ -129,22 +120,23 @@ pub struct Cam<'d> { } /// Represents the camera interface with DMA support. -pub struct Camera<'d, CH: DmaChannel = AnyDmaChannel> { +pub struct Camera<'d> { lcd_cam: PeripheralRef<'d, LCD_CAM>, - rx_channel: ChannelRx<'d, CH>, + rx_channel: ChannelRx<'d, ::Dma>, } -impl<'d, CH: DmaChannel> Camera<'d, CH> -where - CH::P: LcdCamPeripheral, -{ +impl<'d> Camera<'d> { /// Creates a new `Camera` instance with DMA support. - pub fn new( + pub fn new( cam: Cam<'d>, channel: ChannelRx<'d, CH>, _pins: P, frequency: HertzU32, - ) -> Self { + ) -> Self + where + CH: DmaChannelConvert<::Dma>, + P: RxPins, + { let lcd_cam = cam.lcd_cam; let clocks = Clocks::get(); @@ -190,12 +182,12 @@ where Self { lcd_cam, - rx_channel: channel, + rx_channel: channel.degrade(), } } } -impl<'d, CH: DmaChannel> Camera<'d, CH> { +impl<'d> Camera<'d> { /// Configures the byte order for the camera data. pub fn set_byte_order(&mut self, byte_order: ByteOrder) -> &mut Self { self.lcd_cam @@ -320,7 +312,7 @@ impl<'d, CH: DmaChannel> Camera<'d, CH> { pub fn receive( mut self, mut buf: BUF, - ) -> Result, (DmaError, Self, BUF)> { + ) -> Result, (DmaError, Self, BUF)> { // Reset Camera control unit and Async Rx FIFO self.lcd_cam .cam_ctrl1() @@ -366,12 +358,12 @@ impl<'d, CH: DmaChannel> Camera<'d, CH> { /// Represents an ongoing (or potentially stopped) transfer from the Camera to a /// DMA buffer. -pub struct CameraTransfer<'d, BUF: DmaRxBuffer, CH: DmaChannel = AnyDmaChannel> { - camera: ManuallyDrop>, +pub struct CameraTransfer<'d, BUF: DmaRxBuffer> { + camera: ManuallyDrop>, buffer_view: ManuallyDrop, } -impl<'d, BUF: DmaRxBuffer, CH: DmaChannel> CameraTransfer<'d, BUF, CH> { +impl<'d, BUF: DmaRxBuffer> CameraTransfer<'d, BUF> { /// Returns true when [Self::wait] will not block. pub fn is_done(&self) -> bool { // This peripheral doesn't really "complete". As long the camera (or anything @@ -399,7 +391,7 @@ impl<'d, BUF: DmaRxBuffer, CH: DmaChannel> CameraTransfer<'d, BUF, CH> { } /// Stops this transfer on the spot and returns the peripheral and buffer. - pub fn stop(mut self) -> (Camera<'d, CH>, BUF) { + pub fn stop(mut self) -> (Camera<'d>, BUF) { self.stop_peripherals(); let (camera, view) = self.release(); (camera, BUF::from_view(view)) @@ -410,7 +402,7 @@ impl<'d, BUF: DmaRxBuffer, CH: DmaChannel> CameraTransfer<'d, BUF, CH> { /// Note: The camera doesn't really "finish" its transfer, so what you're /// really waiting for here is a DMA Error. You typically just want to /// call [Self::stop] once you have the data you need. - pub fn wait(mut self) -> (Result<(), DmaError>, Camera<'d, CH>, BUF) { + pub fn wait(mut self) -> (Result<(), DmaError>, Camera<'d>, BUF) { while !self.is_done() {} // Stop the DMA as it doesn't know that the camera has stopped. @@ -429,7 +421,7 @@ impl<'d, BUF: DmaRxBuffer, CH: DmaChannel> CameraTransfer<'d, BUF, CH> { (result, camera, BUF::from_view(view)) } - fn release(mut self) -> (Camera<'d, CH>, BUF::View) { + fn release(mut self) -> (Camera<'d>, BUF::View) { // SAFETY: Since forget is called on self, we know that self.camera and // self.buffer_view won't be touched again. let result = unsafe { @@ -453,7 +445,7 @@ impl<'d, BUF: DmaRxBuffer, CH: DmaChannel> CameraTransfer<'d, BUF, CH> { } } -impl<'d, BUF: DmaRxBuffer, CH: DmaChannel> Deref for CameraTransfer<'d, BUF, CH> { +impl<'d, BUF: DmaRxBuffer> Deref for CameraTransfer<'d, BUF> { type Target = BUF::View; fn deref(&self) -> &Self::Target { @@ -461,13 +453,13 @@ impl<'d, BUF: DmaRxBuffer, CH: DmaChannel> Deref for CameraTransfer<'d, BUF, CH> } } -impl<'d, BUF: DmaRxBuffer, CH: DmaChannel> DerefMut for CameraTransfer<'d, BUF, CH> { +impl<'d, BUF: DmaRxBuffer> DerefMut for CameraTransfer<'d, BUF> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.buffer_view } } -impl<'d, BUF: DmaRxBuffer, CH: DmaChannel> Drop for CameraTransfer<'d, BUF, CH> { +impl<'d, BUF: DmaRxBuffer> Drop for CameraTransfer<'d, BUF> { fn drop(&mut self) { self.stop_peripherals(); diff --git a/esp-hal/src/lcd_cam/lcd/i8080.rs b/esp-hal/src/lcd_cam/lcd/i8080.rs index e910c078e17..0261778f5a9 100644 --- a/esp-hal/src/lcd_cam/lcd/i8080.rs +++ b/esp-hal/src/lcd_cam/lcd/i8080.rs @@ -69,7 +69,7 @@ use fugit::HertzU32; use crate::{ clock::Clocks, - dma::{ChannelTx, DmaChannel, DmaError, DmaPeripheral, DmaTxBuffer, LcdCamPeripheral, Tx}, + dma::{ChannelTx, DmaChannelConvert, DmaEligible, DmaError, DmaPeripheral, DmaTxBuffer, Tx}, gpio::{OutputSignal, PeripheralOutput}, lcd_cam::{ asynch::LCD_DONE_WAKER, @@ -85,24 +85,25 @@ use crate::{ }; /// Represents the I8080 LCD interface. -pub struct I8080<'d, CH: DmaChannel, DM: Mode> { +pub struct I8080<'d, DM: Mode> { lcd_cam: PeripheralRef<'d, LCD_CAM>, - tx_channel: ChannelTx<'d, CH>, + tx_channel: ChannelTx<'d, ::Dma>, _phantom: PhantomData, } -impl<'d, CH: DmaChannel, DM: Mode> I8080<'d, CH, DM> -where - CH::P: LcdCamPeripheral, -{ +impl<'d, DM: Mode> I8080<'d, DM> { /// Creates a new instance of the I8080 LCD interface. - pub fn new( + pub fn new( lcd: Lcd<'d, DM>, channel: ChannelTx<'d, CH>, mut pins: P, frequency: HertzU32, config: Config, - ) -> Self { + ) -> Self + where + CH: DmaChannelConvert<::Dma>, + P: TxPins, + { let lcd_cam = lcd.lcd_cam; let clocks = Clocks::get(); @@ -205,13 +206,13 @@ where Self { lcd_cam, - tx_channel: channel, + tx_channel: channel.degrade(), _phantom: PhantomData, } } } -impl<'d, CH: DmaChannel, DM: Mode> I8080<'d, CH, DM> { +impl<'d, DM: Mode> I8080<'d, DM> { /// Configures the byte order for data transmission. pub fn set_byte_order(&mut self, byte_order: ByteOrder) -> &mut Self { let is_inverted = byte_order != ByteOrder::default(); @@ -270,7 +271,7 @@ impl<'d, CH: DmaChannel, DM: Mode> I8080<'d, CH, DM> { cmd: impl Into>, dummy: u8, mut data: BUF, - ) -> Result, (DmaError, Self, BUF)> { + ) -> Result, (DmaError, Self, BUF)> { let cmd = cmd.into(); // Reset LCD control unit and Async Tx FIFO @@ -366,7 +367,7 @@ impl<'d, CH: DmaChannel, DM: Mode> I8080<'d, CH, DM> { } } -impl<'d, CH: DmaChannel, DM: Mode> core::fmt::Debug for I8080<'d, CH, DM> { +impl<'d, DM: Mode> core::fmt::Debug for I8080<'d, DM> { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("I8080").finish() } @@ -374,12 +375,12 @@ impl<'d, CH: DmaChannel, DM: Mode> core::fmt::Debug for I8080<'d, CH, DM> { /// Represents an ongoing (or potentially finished) transfer using the I8080 LCD /// interface -pub struct I8080Transfer<'d, BUF: DmaTxBuffer, CH: DmaChannel, DM: Mode> { - i8080: ManuallyDrop>, +pub struct I8080Transfer<'d, BUF: DmaTxBuffer, DM: Mode> { + i8080: ManuallyDrop>, buf_view: ManuallyDrop, } -impl<'d, BUF: DmaTxBuffer, CH: DmaChannel, DM: Mode> I8080Transfer<'d, BUF, CH, DM> { +impl<'d, BUF: DmaTxBuffer, DM: Mode> I8080Transfer<'d, BUF, DM> { /// Returns true when [Self::wait] will not block. pub fn is_done(&self) -> bool { self.i8080 @@ -391,7 +392,7 @@ impl<'d, BUF: DmaTxBuffer, CH: DmaChannel, DM: Mode> I8080Transfer<'d, BUF, CH, } /// Stops this transfer on the spot and returns the peripheral and buffer. - pub fn cancel(mut self) -> (I8080<'d, CH, DM>, BUF) { + pub fn cancel(mut self) -> (I8080<'d, DM>, BUF) { self.stop_peripherals(); let (_, i8080, buf) = self.wait(); (i8080, buf) @@ -401,7 +402,7 @@ impl<'d, BUF: DmaTxBuffer, CH: DmaChannel, DM: Mode> I8080Transfer<'d, BUF, CH, /// /// Note: This also clears the transfer interrupt so it can be used in /// interrupt handlers to "handle" the interrupt. - pub fn wait(mut self) -> (Result<(), DmaError>, I8080<'d, CH, DM>, BUF) { + pub fn wait(mut self) -> (Result<(), DmaError>, I8080<'d, DM>, BUF) { while !self.is_done() {} // Clear "done" interrupt. @@ -440,7 +441,7 @@ impl<'d, BUF: DmaTxBuffer, CH: DmaChannel, DM: Mode> I8080Transfer<'d, BUF, CH, } } -impl<'d, BUF: DmaTxBuffer, CH: DmaChannel, DM: Mode> Deref for I8080Transfer<'d, BUF, CH, DM> { +impl<'d, BUF: DmaTxBuffer, DM: Mode> Deref for I8080Transfer<'d, BUF, DM> { type Target = BUF::View; fn deref(&self) -> &Self::Target { @@ -448,13 +449,13 @@ impl<'d, BUF: DmaTxBuffer, CH: DmaChannel, DM: Mode> Deref for I8080Transfer<'d, } } -impl<'d, BUF: DmaTxBuffer, CH: DmaChannel, DM: Mode> DerefMut for I8080Transfer<'d, BUF, CH, DM> { +impl<'d, BUF: DmaTxBuffer, DM: Mode> DerefMut for I8080Transfer<'d, BUF, DM> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.buf_view } } -impl<'d, BUF: DmaTxBuffer, CH: DmaChannel> I8080Transfer<'d, BUF, CH, crate::Async> { +impl<'d, BUF: DmaTxBuffer> I8080Transfer<'d, BUF, crate::Async> { /// Waits for [Self::is_done] to return true. pub async fn wait_for_done(&mut self) { use core::{ @@ -493,7 +494,7 @@ impl<'d, BUF: DmaTxBuffer, CH: DmaChannel> I8080Transfer<'d, BUF, CH, crate::Asy } } -impl<'d, BUF: DmaTxBuffer, CH: DmaChannel, DM: Mode> Drop for I8080Transfer<'d, BUF, CH, DM> { +impl<'d, BUF: DmaTxBuffer, DM: Mode> Drop for I8080Transfer<'d, BUF, DM> { fn drop(&mut self) { self.stop_peripherals(); diff --git a/esp-hal/src/lcd_cam/mod.rs b/esp-hal/src/lcd_cam/mod.rs index f47b639e6e5..a1f55b7e13c 100644 --- a/esp-hal/src/lcd_cam/mod.rs +++ b/esp-hal/src/lcd_cam/mod.rs @@ -136,6 +136,14 @@ pub mod asynch { } mod private { + use crate::{dma::PeripheralMarker, peripherals::LCD_CAM}; + + impl PeripheralMarker for LCD_CAM { + fn peripheral(&self) -> crate::system::Peripheral { + crate::system::Peripheral::LcdCam + } + } + pub(crate) struct Instance; // NOTE: the LCD_CAM interrupt registers are shared between LCD and Camera and @@ -143,21 +151,21 @@ mod private { // CriticalSection will be needed to protect these shared registers. impl Instance { pub(crate) fn listen_lcd_done() { - let lcd_cam = unsafe { crate::peripherals::LCD_CAM::steal() }; + let lcd_cam = unsafe { LCD_CAM::steal() }; lcd_cam .lc_dma_int_ena() .modify(|_, w| w.lcd_trans_done_int_ena().set_bit()); } pub(crate) fn unlisten_lcd_done() { - let lcd_cam = unsafe { crate::peripherals::LCD_CAM::steal() }; + let lcd_cam = unsafe { LCD_CAM::steal() }; lcd_cam .lc_dma_int_ena() .modify(|_, w| w.lcd_trans_done_int_ena().clear_bit()); } pub(crate) fn is_lcd_done_set() -> bool { - let lcd_cam = unsafe { crate::peripherals::LCD_CAM::steal() }; + let lcd_cam = unsafe { LCD_CAM::steal() }; lcd_cam .lc_dma_int_raw() .read() diff --git a/esp-hal/src/parl_io.rs b/esp-hal/src/parl_io.rs index 9f0e326d314..45267024da5 100644 --- a/esp-hal/src/parl_io.rs +++ b/esp-hal/src/parl_io.rs @@ -37,13 +37,13 @@ use crate::{ ChannelRx, ChannelTx, DescriptorChain, - DmaChannel, + DmaChannelConvert, DmaDescriptor, + DmaEligible, DmaError, DmaPeripheral, DmaTransferRx, DmaTransferTx, - ParlIoPeripheral, ReadBuffer, Rx, Tx, @@ -52,7 +52,7 @@ use crate::{ gpio::{PeripheralInput, PeripheralOutput}, interrupt::InterruptHandler, peripheral::{self, Peripheral}, - peripherals, + peripherals::{self, PARL_IO}, system::PeripheralClockControl, Blocking, InterruptConfigurable, @@ -835,9 +835,8 @@ impl<'d, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15> { } -impl<'d, CH, DM> TxCreatorFullDuplex<'d, CH, DM> +impl<'d, DM> TxCreatorFullDuplex<'d, DM> where - CH: DmaChannel, DM: Mode, { /// Configure TX to use the given pins and settings @@ -848,7 +847,7 @@ where idle_value: u16, sample_edge: SampleEdge, bit_order: BitPackOrder, - ) -> Result, Error> + ) -> Result, Error> where P: FullDuplex + TxPins + ConfigurePins, CP: TxClkPin, @@ -868,9 +867,8 @@ where } } -impl<'d, CH, DM> TxCreator<'d, CH, DM> +impl<'d, DM> TxCreator<'d, DM> where - CH: DmaChannel, DM: Mode, { /// Configure TX to use the given pins and settings @@ -881,7 +879,7 @@ where idle_value: u16, sample_edge: SampleEdge, bit_order: BitPackOrder, - ) -> Result, Error> + ) -> Result, Error> where P: TxPins + ConfigurePins, CP: TxClkPin, @@ -902,19 +900,17 @@ where } /// Parallel IO TX channel -pub struct ParlIoTx<'d, CH, DM> +pub struct ParlIoTx<'d, DM> where - CH: DmaChannel, DM: Mode, { - tx_channel: ChannelTx<'d, CH>, + tx_channel: ChannelTx<'d, ::Dma>, tx_chain: DescriptorChain, phantom: PhantomData, } -impl<'d, CH, DM> core::fmt::Debug for ParlIoTx<'d, CH, DM> +impl<'d, DM> core::fmt::Debug for ParlIoTx<'d, DM> where - CH: DmaChannel, DM: Mode, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -922,9 +918,8 @@ where } } -impl<'d, CH, DM> RxCreatorFullDuplex<'d, CH, DM> +impl<'d, DM> RxCreatorFullDuplex<'d, DM> where - CH: DmaChannel, DM: Mode, { /// Configure RX to use the given pins and settings @@ -934,7 +929,7 @@ where clk_pin: &'d mut CP, bit_order: BitPackOrder, timeout_ticks: Option, - ) -> Result, Error> + ) -> Result, Error> where P: FullDuplex + RxPins + ConfigurePins, CP: RxClkPin, @@ -953,9 +948,8 @@ where } } -impl<'d, CH, DM> RxCreator<'d, CH, DM> +impl<'d, DM> RxCreator<'d, DM> where - CH: DmaChannel, DM: Mode, { /// Configure RX to use the given pins and settings @@ -965,7 +959,7 @@ where clk_pin: &'d mut CP, bit_order: BitPackOrder, timeout_ticks: Option, - ) -> Result, Error> + ) -> Result, Error> where P: RxPins + ConfigurePins, CP: RxClkPin, @@ -985,19 +979,17 @@ where } /// Parallel IO RX channel -pub struct ParlIoRx<'d, CH, DM> +pub struct ParlIoRx<'d, DM> where - CH: DmaChannel, DM: Mode, { - rx_channel: ChannelRx<'d, CH>, + rx_channel: ChannelRx<'d, ::Dma>, rx_chain: DescriptorChain, phantom: PhantomData, } -impl<'d, CH, DM> core::fmt::Debug for ParlIoRx<'d, CH, DM> +impl<'d, DM> core::fmt::Debug for ParlIoRx<'d, DM> where - CH: DmaChannel, DM: Mode, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -1008,17 +1000,15 @@ where fn internal_set_interrupt_handler(handler: InterruptHandler) { #[cfg(esp32c6)] { - unsafe { crate::peripherals::PARL_IO::steal() }.bind_parl_io_interrupt(handler.handler()); + unsafe { PARL_IO::steal() }.bind_parl_io_interrupt(handler.handler()); crate::interrupt::enable(crate::peripherals::Interrupt::PARL_IO, handler.priority()) .unwrap(); } #[cfg(esp32h2)] { - unsafe { crate::peripherals::PARL_IO::steal() } - .bind_parl_io_tx_interrupt(handler.handler()); - unsafe { crate::peripherals::PARL_IO::steal() } - .bind_parl_io_rx_interrupt(handler.handler()); + unsafe { PARL_IO::steal() }.bind_parl_io_tx_interrupt(handler.handler()); + unsafe { PARL_IO::steal() }.bind_parl_io_rx_interrupt(handler.handler()); crate::interrupt::enable( crate::peripherals::Interrupt::PARL_IO_TX, @@ -1034,7 +1024,7 @@ fn internal_set_interrupt_handler(handler: InterruptHandler) { } fn internal_listen(interrupts: EnumSet, enable: bool) { - let parl_io = unsafe { crate::peripherals::PARL_IO::steal() }; + let parl_io = unsafe { PARL_IO::steal() }; for interrupt in interrupts { match interrupt { ParlIoInterrupt::TxFifoReEmpty => parl_io @@ -1050,7 +1040,7 @@ fn internal_listen(interrupts: EnumSet, enable: bool) { fn internal_interrupts() -> EnumSet { let mut res = EnumSet::new(); - let parl_io = unsafe { crate::peripherals::PARL_IO::steal() }; + let parl_io = unsafe { PARL_IO::steal() }; let ints = parl_io.int_st().read(); if ints.tx_fifo_rempty().bit() { res.insert(ParlIoInterrupt::TxFifoReEmpty); @@ -1066,7 +1056,7 @@ fn internal_interrupts() -> EnumSet { } fn internal_clear_interrupts(interrupts: EnumSet) { - let parl_io = unsafe { crate::peripherals::PARL_IO::steal() }; + let parl_io = unsafe { PARL_IO::steal() }; for interrupt in interrupts { match interrupt { ParlIoInterrupt::TxFifoReEmpty => parl_io @@ -1083,44 +1073,43 @@ fn internal_clear_interrupts(interrupts: EnumSet) { /// Parallel IO in full duplex mode /// /// Full duplex mode might limit the maximum possible bit width. -pub struct ParlIoFullDuplex<'d, CH, DM> +pub struct ParlIoFullDuplex<'d, DM> where - CH: DmaChannel, - CH::P: ParlIoPeripheral, DM: Mode, { /// The transmitter (TX) channel responsible for handling DMA transfers in /// the parallel I/O full-duplex operation. - pub tx: TxCreatorFullDuplex<'d, CH, DM>, + pub tx: TxCreatorFullDuplex<'d, DM>, /// The receiver (RX) channel responsible for handling DMA transfers in the /// parallel I/O full-duplex operation. - pub rx: RxCreatorFullDuplex<'d, CH, DM>, + pub rx: RxCreatorFullDuplex<'d, DM>, } -impl<'d, CH, DM> ParlIoFullDuplex<'d, CH, DM> +impl<'d, DM> ParlIoFullDuplex<'d, DM> where - CH: DmaChannel, - CH::P: ParlIoPeripheral, DM: Mode, { /// Create a new instance of [ParlIoFullDuplex] - pub fn new( + pub fn new( _parl_io: impl Peripheral

+ 'd, dma_channel: Channel<'d, CH, DM>, tx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor], frequency: HertzU32, - ) -> Result { + ) -> Result + where + CH: DmaChannelConvert<::Dma>, + { internal_init(frequency)?; Ok(Self { tx: TxCreatorFullDuplex { - tx_channel: dma_channel.tx, + tx_channel: dma_channel.tx.degrade(), descriptors: tx_descriptors, phantom: PhantomData, }, rx: RxCreatorFullDuplex { - rx_channel: dma_channel.rx, + rx_channel: dma_channel.rx.degrade(), descriptors: rx_descriptors, phantom: PhantomData, }, @@ -1128,11 +1117,7 @@ where } } -impl<'d, CH> ParlIoFullDuplex<'d, CH, Blocking> -where - CH: DmaChannel, - CH::P: ParlIoPeripheral, -{ +impl<'d> ParlIoFullDuplex<'d, Blocking> { /// Sets the interrupt handler, enables it with /// [crate::interrupt::Priority::min()] /// @@ -1162,53 +1147,44 @@ where } } -impl<'d, CH> crate::private::Sealed for ParlIoFullDuplex<'d, CH, Blocking> -where - CH: DmaChannel, - CH::P: ParlIoPeripheral, -{ -} +impl<'d> crate::private::Sealed for ParlIoFullDuplex<'d, Blocking> {} -impl<'d, CH> InterruptConfigurable for ParlIoFullDuplex<'d, CH, Blocking> -where - CH: DmaChannel, - CH::P: ParlIoPeripheral, -{ +impl<'d> InterruptConfigurable for ParlIoFullDuplex<'d, Blocking> { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { ParlIoFullDuplex::set_interrupt_handler(self, handler); } } /// Parallel IO in half duplex / TX only mode -pub struct ParlIoTxOnly<'d, CH, DM> +pub struct ParlIoTxOnly<'d, DM> where - CH: DmaChannel, - CH::P: ParlIoPeripheral, DM: Mode, { /// The transmitter (TX) channel responsible for handling DMA transfers in /// the parallel I/O operation. - pub tx: TxCreator<'d, CH, DM>, + pub tx: TxCreator<'d, DM>, } -impl<'d, CH, DM> ParlIoTxOnly<'d, CH, DM> +impl<'d, DM> ParlIoTxOnly<'d, DM> where - CH: DmaChannel, - CH::P: ParlIoPeripheral, DM: Mode, { /// Create a new [ParlIoTxOnly] - pub fn new( + // TODO: only take a TX DMA channel? + pub fn new( _parl_io: impl Peripheral

+ 'd, dma_channel: Channel<'d, CH, DM>, descriptors: &'static mut [DmaDescriptor], frequency: HertzU32, - ) -> Result { + ) -> Result + where + CH: DmaChannelConvert<::Dma>, + { internal_init(frequency)?; Ok(Self { tx: TxCreator { - tx_channel: dma_channel.tx, + tx_channel: dma_channel.tx.degrade(), descriptors, phantom: PhantomData, }, @@ -1216,11 +1192,7 @@ where } } -impl<'d, CH> ParlIoTxOnly<'d, CH, Blocking> -where - CH: DmaChannel, - CH::P: ParlIoPeripheral, -{ +impl<'d> ParlIoTxOnly<'d, Blocking> { /// Sets the interrupt handler, enables it with /// [crate::interrupt::Priority::min()] /// @@ -1250,53 +1222,44 @@ where } } -impl<'d, CH> crate::private::Sealed for ParlIoTxOnly<'d, CH, Blocking> -where - CH: DmaChannel, - CH::P: ParlIoPeripheral, -{ -} +impl<'d> crate::private::Sealed for ParlIoTxOnly<'d, Blocking> {} -impl<'d, CH> InterruptConfigurable for ParlIoTxOnly<'d, CH, Blocking> -where - CH: DmaChannel, - CH::P: ParlIoPeripheral, -{ +impl<'d> InterruptConfigurable for ParlIoTxOnly<'d, Blocking> { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { ParlIoTxOnly::set_interrupt_handler(self, handler); } } /// Parallel IO in half duplex / RX only mode -pub struct ParlIoRxOnly<'d, CH, DM> +pub struct ParlIoRxOnly<'d, DM> where - CH: DmaChannel, - CH::P: ParlIoPeripheral, DM: Mode, { /// The receiver (RX) channel responsible for handling DMA transfers in the /// parallel I/O operation. - pub rx: RxCreator<'d, CH, DM>, + pub rx: RxCreator<'d, DM>, } -impl<'d, CH, DM> ParlIoRxOnly<'d, CH, DM> +impl<'d, DM> ParlIoRxOnly<'d, DM> where - CH: DmaChannel, - CH::P: ParlIoPeripheral, DM: Mode, { /// Create a new [ParlIoRxOnly] instance - pub fn new( + // TODO: only take a RX DMA channel? + pub fn new( _parl_io: impl Peripheral

+ 'd, dma_channel: Channel<'d, CH, DM>, descriptors: &'static mut [DmaDescriptor], frequency: HertzU32, - ) -> Result { + ) -> Result + where + CH: DmaChannelConvert<::Dma>, + { internal_init(frequency)?; Ok(Self { rx: RxCreator { - rx_channel: dma_channel.rx, + rx_channel: dma_channel.rx.degrade(), descriptors, phantom: PhantomData, }, @@ -1304,11 +1267,7 @@ where } } -impl<'d, CH> ParlIoRxOnly<'d, CH, Blocking> -where - CH: DmaChannel, - CH::P: ParlIoPeripheral, -{ +impl<'d> ParlIoRxOnly<'d, Blocking> { /// Sets the interrupt handler, enables it with /// [crate::interrupt::Priority::min()] /// @@ -1338,18 +1297,9 @@ where } } -impl<'d, CH> crate::private::Sealed for ParlIoRxOnly<'d, CH, Blocking> -where - CH: DmaChannel, - CH::P: ParlIoPeripheral, -{ -} +impl<'d> crate::private::Sealed for ParlIoRxOnly<'d, Blocking> {} -impl<'d, CH> InterruptConfigurable for ParlIoRxOnly<'d, CH, Blocking> -where - CH: DmaChannel, - CH::P: ParlIoPeripheral, -{ +impl<'d> InterruptConfigurable for ParlIoRxOnly<'d, Blocking> { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { ParlIoRxOnly::set_interrupt_handler(self, handler); } @@ -1388,10 +1338,8 @@ fn internal_init(frequency: HertzU32) -> Result<(), Error> { Ok(()) } -impl<'d, CH, DM> ParlIoTx<'d, CH, DM> +impl<'d, DM> ParlIoTx<'d, DM> where - CH: DmaChannel, - CH::P: ParlIoPeripheral, DM: Mode, { /// Perform a DMA write. @@ -1434,11 +1382,7 @@ where .and_then(|_| self.tx_channel.start_transfer())?; } - loop { - if Instance::is_tx_ready() { - break; - } - } + while !Instance::is_tx_ready() {} Instance::set_tx_start(true); @@ -1449,10 +1393,8 @@ where } } -impl<'d, CH, DM> DmaSupport for ParlIoTx<'d, CH, DM> +impl<'d, DM> DmaSupport for ParlIoTx<'d, DM> where - CH: DmaChannel, - CH::P: ParlIoPeripheral, DM: Mode, { fn peripheral_wait_dma(&mut self, _is_rx: bool, _is_tx: bool) { @@ -1466,13 +1408,11 @@ where } } -impl<'d, CH, DM> DmaSupportTx for ParlIoTx<'d, CH, DM> +impl<'d, DM> DmaSupportTx for ParlIoTx<'d, DM> where - CH: DmaChannel, - CH::P: ParlIoPeripheral, DM: Mode, { - type TX = ChannelTx<'d, CH>; + type TX = ChannelTx<'d, ::Dma>; fn tx(&mut self) -> &mut Self::TX { &mut self.tx_channel @@ -1483,10 +1423,8 @@ where } } -impl<'d, CH, DM> ParlIoRx<'d, CH, DM> +impl<'d, DM> ParlIoRx<'d, DM> where - CH: DmaChannel, - CH::P: ParlIoPeripheral, DM: Mode, { /// Perform a DMA read. @@ -1516,7 +1454,7 @@ where } fn start_receive_bytes_dma( - rx_channel: &mut ChannelRx<'d, CH>, + rx_channel: &mut ChannelRx<'d, ::Dma>, rx_chain: &mut DescriptorChain, ptr: *mut u8, len: usize, @@ -1544,10 +1482,8 @@ where } } -impl<'d, CH, DM> DmaSupport for ParlIoRx<'d, CH, DM> +impl<'d, DM> DmaSupport for ParlIoRx<'d, DM> where - CH: DmaChannel, - CH::P: ParlIoPeripheral, DM: Mode, { fn peripheral_wait_dma(&mut self, _is_rx: bool, _is_tx: bool) { @@ -1568,13 +1504,11 @@ where } } -impl<'d, CH, DM> DmaSupportRx for ParlIoRx<'d, CH, DM> +impl<'d, DM> DmaSupportRx for ParlIoRx<'d, DM> where - CH: DmaChannel, - CH::P: ParlIoPeripheral, DM: Mode, { - type RX = ChannelRx<'d, CH>; + type RX = ChannelRx<'d, ::Dma>; fn rx(&mut self) -> &mut Self::RX { &mut self.rx_channel @@ -1586,45 +1520,41 @@ where } /// Creates a TX channel -pub struct TxCreator<'d, CH, DM> +pub struct TxCreator<'d, DM> where - CH: DmaChannel, DM: Mode, { - tx_channel: ChannelTx<'d, CH>, + tx_channel: ChannelTx<'d, ::Dma>, descriptors: &'static mut [DmaDescriptor], phantom: PhantomData, } /// Creates a RX channel -pub struct RxCreator<'d, CH, DM> +pub struct RxCreator<'d, DM> where - CH: DmaChannel, DM: Mode, { - rx_channel: ChannelRx<'d, CH>, + rx_channel: ChannelRx<'d, ::Dma>, descriptors: &'static mut [DmaDescriptor], phantom: PhantomData, } /// Creates a TX channel -pub struct TxCreatorFullDuplex<'d, CH, DM> +pub struct TxCreatorFullDuplex<'d, DM> where - CH: DmaChannel, DM: Mode, { - tx_channel: ChannelTx<'d, CH>, + tx_channel: ChannelTx<'d, ::Dma>, descriptors: &'static mut [DmaDescriptor], phantom: PhantomData, } /// Creates a RX channel -pub struct RxCreatorFullDuplex<'d, CH, DM> +pub struct RxCreatorFullDuplex<'d, DM> where - CH: DmaChannel, DM: Mode, { - rx_channel: ChannelRx<'d, CH>, + rx_channel: ChannelRx<'d, ::Dma>, descriptors: &'static mut [DmaDescriptor], phantom: PhantomData, } @@ -1638,7 +1568,7 @@ pub mod asynch { use super::{private::Instance, Error, ParlIoRx, ParlIoTx, MAX_DMA_SIZE}; use crate::{ - dma::{asynch::DmaRxFuture, DmaChannel, ParlIoPeripheral, ReadBuffer, WriteBuffer}, + dma::{asynch::DmaRxFuture, ReadBuffer, WriteBuffer}, peripherals::Interrupt, }; @@ -1693,11 +1623,7 @@ pub mod asynch { } } - impl<'d, CH> ParlIoTx<'d, CH, crate::Async> - where - CH: DmaChannel, - CH::P: ParlIoPeripheral, - { + impl<'d> ParlIoTx<'d, crate::Async> { /// Perform a DMA write. /// /// The maximum amount of data to be sent is 32736 bytes. @@ -1719,11 +1645,7 @@ pub mod asynch { } } - impl<'d, CH> ParlIoRx<'d, CH, crate::Async> - where - CH: DmaChannel, - CH::P: ParlIoPeripheral, - { + impl<'d> ParlIoRx<'d, crate::Async> { /// Perform a DMA write. /// /// The maximum amount of data to be sent is 32736 bytes. diff --git a/esp-hal/src/peripheral.rs b/esp-hal/src/peripheral.rs index 8b20a1e8cd2..887835f2214 100644 --- a/esp-hal/src/peripheral.rs +++ b/esp-hal/src/peripheral.rs @@ -166,23 +166,6 @@ where impl crate::private::Sealed for &mut T where T: crate::private::Sealed {} mod peripheral_macros { - #[doc(hidden)] - #[macro_export] - macro_rules! impl_dma_eligible { - ($name:ident => $dma:ident) => { - impl $crate::dma::DmaEligible for $name { - const DMA_PERIPHERAL: $crate::dma::DmaPeripheral = $crate::dma::DmaPeripheral::$dma; - } - }; - - ($($(#[$cfg:meta])? $name:ident => $dma:ident),*) => { - $( - $(#[$cfg])? - $crate::impl_dma_eligible!($name => $dma); - )* - }; - } - #[doc(hidden)] #[macro_export] macro_rules! peripherals { @@ -194,59 +177,6 @@ mod peripheral_macros { $( $crate::create_peripheral!($(#[$cfg])? $name <= $from_pac); )* - - $crate::impl_dma_eligible! { - #[cfg(spi2)] - SPI2 => Spi2, - - #[cfg(spi3)] - SPI3 => Spi3, - - #[cfg(all(uhci0, gdma))] // TODO: S2? - UHCI0 => Uhci0, - - #[cfg(i2s0)] - I2S0 => I2s0, - - #[cfg(i2s1)] - I2S1 => I2s1, - - #[cfg(esp32s3)] - LCD_CAM => LcdCam, - - #[cfg(all(gdma, aes))] - AES => Aes, - - #[cfg(all(gdma, sha))] - SHA => Sha, - - #[cfg(any(esp32c3, esp32c6, esp32h2, esp32s3))] - ADC1 => Adc, - - #[cfg(any(esp32c3, esp32s3))] - ADC2 => Adc, - - #[cfg(esp32s3)] - RMT => Rmt, - - #[cfg(parl_io)] - PARL_IO => ParlIo, - - #[cfg(any(esp32c2, esp32c6, esp32h2))] - MEM2MEM1 => Mem2Mem1 - } - - #[cfg(any(esp32c6, esp32h2))] - $crate::impl_dma_eligible! { - MEM2MEM4 => Mem2Mem4, - MEM2MEM5 => Mem2Mem5, - MEM2MEM10 => Mem2Mem10, - MEM2MEM11 => Mem2Mem11, - MEM2MEM12 => Mem2Mem12, - MEM2MEM13 => Mem2Mem13, - MEM2MEM14 => Mem2Mem14, - MEM2MEM15 => Mem2Mem15 - } } /// The `Peripherals` struct provides access to all of the hardware peripherals on the chip. diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index 0ebbc086c1d..5c2b6b86e48 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -81,13 +81,14 @@ use super::{ }; use crate::{ clock::Clocks, - dma::{DmaPeripheral, DmaRxBuffer, DmaTxBuffer, Rx, Tx}, + dma::{DmaChannelConvert, DmaEligible, DmaRxBuffer, DmaTxBuffer, PeripheralMarker, Rx, Tx}, gpio::{InputSignal, NoPin, OutputSignal, PeripheralInput, PeripheralOutput}, interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, peripherals::spi2::RegisterBlock, private, system::PeripheralClockControl, + Mode, }; /// Enumeration of possible SPI interrupt events. @@ -485,6 +486,28 @@ where } } +impl<'d, T, M> Spi<'d, T, M> +where + T: InstanceDma, + M: DuplexMode, +{ + /// 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: crate::dma::Channel<'d, CH, DmaMode>, + ) -> SpiDma<'d, T, M, DmaMode> + where + CH: DmaChannelConvert, + DmaMode: Mode, + { + SpiDma::new(self.spi, channel) + } +} + impl<'d, T> Spi<'d, T, FullDuplexMode> where T: Instance, @@ -913,71 +936,21 @@ mod dma { }; use super::*; - #[cfg(spi3)] - use crate::dma::Spi3Peripheral; use crate::{ dma::{ asynch::{DmaRxFuture, DmaTxFuture}, Channel, - DmaChannel, DmaRxBuf, DmaRxBuffer, DmaTxBuf, DmaTxBuffer, Rx, - Spi2Peripheral, - SpiPeripheral, Tx, }, InterruptConfigurable, Mode, }; - impl<'d, M> Spi<'d, crate::peripherals::SPI2, M> - where - M: DuplexMode, - { - /// Configures the SPI instance to use DMA with the specified channel. - /// - /// This method prepares the SPI instance for DMA transfers. It - /// initializes the DMA channel for transmission and returns an - /// instance of `SpiDma` that supports DMA operations. - pub fn with_dma( - self, - channel: Channel<'d, C, DmaMode>, - ) -> SpiDma<'d, crate::peripherals::SPI2, C, M, DmaMode> - where - C: DmaChannel, - C::P: SpiPeripheral + Spi2Peripheral, - DmaMode: Mode, - { - SpiDma::new(self.spi, channel) - } - } - - #[cfg(spi3)] - impl<'d, M> Spi<'d, crate::peripherals::SPI3, M> - where - M: DuplexMode, - { - /// Configures the SPI3 instance to use DMA with the specified channel. - /// - /// This method prepares the SPI instance for DMA transfers using SPI3 - /// and returns an instance of `SpiDma` that supports DMA - /// operations. - pub fn with_dma( - self, - channel: Channel<'d, C, DmaMode>, - ) -> SpiDma<'d, crate::peripherals::SPI3, C, M, DmaMode> - where - C: DmaChannel, - C::P: SpiPeripheral + Spi3Peripheral, - DmaMode: Mode, - { - SpiDma::new(self.spi, channel) - } - } - /// A DMA capable SPI instance. /// /// Using `SpiDma` is not recommended unless you wish @@ -985,15 +958,14 @@ mod dma { /// [`SpiDmaBus`] via `with_buffers` to get access /// to a DMA capable SPI bus that implements the /// embedded-hal traits. - pub struct SpiDma<'d, T, C, D, M> + pub struct SpiDma<'d, T, D, M> where - C: DmaChannel, - C::P: SpiPeripheral, + T: InstanceDma, D: DuplexMode, M: Mode, { pub(crate) spi: PeripheralRef<'d, T>, - pub(crate) channel: Channel<'d, C, M>, + pub(crate) channel: Channel<'d, T::Dma, M>, tx_transfer_in_progress: bool, rx_transfer_in_progress: bool, #[cfg(all(esp32, spi_address_workaround))] @@ -1002,19 +974,17 @@ mod dma { } #[cfg(all(esp32, spi_address_workaround))] - unsafe impl<'d, T, C, D, M> Send for SpiDma<'d, T, C, D, M> + unsafe impl<'d, T, D, M> Send for SpiDma<'d, T, D, M> where - C: DmaChannel, - C::P: SpiPeripheral, + T: InstanceDma, D: DuplexMode, M: Mode, { } - impl<'d, T, C, D, M> core::fmt::Debug for SpiDma<'d, T, C, D, M> + impl<'d, T, D, M> core::fmt::Debug for SpiDma<'d, T, D, M> where - C: DmaChannel, - C::P: SpiPeripheral, + T: InstanceDma, D: DuplexMode, M: Mode, { @@ -1027,15 +997,17 @@ mod dma { } } - impl<'d, T, C, D, M> SpiDma<'d, T, C, D, M> + impl<'d, T, D, M> SpiDma<'d, T, D, M> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, D: DuplexMode, M: Mode, { - fn new(spi: PeripheralRef<'d, T>, channel: Channel<'d, C, M>) -> Self { + pub(super) fn new(spi: PeripheralRef<'d, T>, channel: Channel<'d, CH, M>) -> Self + where + CH: DmaChannelConvert, + { + channel.runtime_ensure_compatible(&spi); #[cfg(all(esp32, spi_address_workaround))] let address_buffer = { use crate::dma::DmaDescriptor; @@ -1054,7 +1026,7 @@ mod dma { Self { spi, - channel, + channel: channel.degrade(), #[cfg(all(esp32, spi_address_workaround))] address_buffer, tx_transfer_in_progress: false, @@ -1263,21 +1235,17 @@ mod dma { } } - impl<'d, T, C, D, M> crate::private::Sealed for SpiDma<'d, T, C, D, M> + impl<'d, T, D, M> crate::private::Sealed for SpiDma<'d, T, D, M> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, D: DuplexMode, M: Mode, { } - impl<'d, T, C, D, M> InterruptConfigurable for SpiDma<'d, T, C, D, M> + impl<'d, T, D, M> InterruptConfigurable for SpiDma<'d, T, D, M> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, D: DuplexMode, M: Mode, { @@ -1287,11 +1255,9 @@ mod dma { } } - impl<'d, T, C, D, M> SpiDma<'d, T, C, D, M> + impl<'d, T, D, M> SpiDma<'d, T, D, M> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, D: DuplexMode, M: Mode, { @@ -1309,7 +1275,7 @@ mod dma { self, dma_rx_buf: DmaRxBuf, dma_tx_buf: DmaTxBuf, - ) -> SpiDmaBus<'d, T, C, D, M> { + ) -> SpiDmaBus<'d, T, D, M> { SpiDmaBus::new(self, dma_rx_buf, dma_tx_buf) } } @@ -1318,27 +1284,23 @@ mod dma { /// /// This structure holds references to the SPI instance, DMA buffers, and /// transfer status. - pub struct SpiDmaTransfer<'d, T, C, D, M, Buf> + pub struct SpiDmaTransfer<'d, T, D, M, Buf> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, D: DuplexMode, M: Mode, { - spi_dma: ManuallyDrop>, + spi_dma: ManuallyDrop>, dma_buf: ManuallyDrop, } - impl<'d, T, C, D, M, Buf> SpiDmaTransfer<'d, T, C, D, M, Buf> + impl<'d, T, D, M, Buf> SpiDmaTransfer<'d, T, D, M, Buf> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, D: DuplexMode, M: Mode, { - fn new(spi_dma: SpiDma<'d, T, C, D, M>, dma_buf: Buf) -> Self { + fn new(spi_dma: SpiDma<'d, T, D, M>, dma_buf: Buf) -> Self { Self { spi_dma: ManuallyDrop::new(spi_dma), dma_buf: ManuallyDrop::new(dma_buf), @@ -1357,7 +1319,7 @@ mod dma { /// /// This method blocks until the transfer is finished and returns the /// `SpiDma` instance and the associated buffer. - pub fn wait(mut self) -> (SpiDma<'d, T, C, D, M>, Buf) { + pub fn wait(mut self) -> (SpiDma<'d, T, D, M>, Buf) { self.spi_dma.wait_for_idle(); let retval = unsafe { ( @@ -1377,11 +1339,9 @@ mod dma { } } - impl<'d, T, C, D, M, Buf> Drop for SpiDmaTransfer<'d, T, C, D, M, Buf> + impl<'d, T, D, M, Buf> Drop for SpiDmaTransfer<'d, T, D, M, Buf> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, D: DuplexMode, M: Mode, { @@ -1398,11 +1358,9 @@ mod dma { } } - impl<'d, T, C, D, Buf> SpiDmaTransfer<'d, T, C, D, crate::Async, Buf> + impl<'d, T, D, Buf> SpiDmaTransfer<'d, T, D, crate::Async, Buf> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, D: DuplexMode, { /// Waits for the DMA transfer to complete asynchronously. @@ -1413,11 +1371,9 @@ mod dma { } } - impl<'d, T, C, M> SpiDma<'d, T, C, FullDuplexMode, M> + impl<'d, T, M> SpiDma<'d, T, FullDuplexMode, M> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, M: Mode, { /// # Safety: @@ -1444,7 +1400,7 @@ mod dma { pub fn dma_write( mut self, mut buffer: TX, - ) -> Result, (Error, Self, TX)> { + ) -> Result, (Error, Self, TX)> { self.wait_for_idle(); match unsafe { self.start_dma_write(&mut buffer) } { @@ -1477,7 +1433,7 @@ mod dma { pub fn dma_read( mut self, mut buffer: RX, - ) -> Result, (Error, Self, RX)> { + ) -> Result, (Error, Self, RX)> { self.wait_for_idle(); match unsafe { self.start_dma_read(&mut buffer) } { Ok(_) => Ok(SpiDmaTransfer::new(self, buffer)), @@ -1516,7 +1472,7 @@ mod dma { mut self, mut rx_buffer: RX, mut tx_buffer: TX, - ) -> Result, (Error, Self, RX, TX)> + ) -> Result, (Error, Self, RX, TX)> { self.wait_for_idle(); match unsafe { self.start_dma_transfer(&mut rx_buffer, &mut tx_buffer) } { @@ -1526,11 +1482,9 @@ mod dma { } } - impl<'d, T, C, M> SpiDma<'d, T, C, HalfDuplexMode, M> + impl<'d, T, M> SpiDma<'d, T, HalfDuplexMode, M> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, M: Mode, { /// # Safety: @@ -1574,7 +1528,7 @@ mod dma { address: Address, dummy: u8, mut buffer: RX, - ) -> Result, (Error, Self, RX)> { + ) -> Result, (Error, Self, RX)> { self.wait_for_idle(); match unsafe { @@ -1635,7 +1589,7 @@ mod dma { address: Address, dummy: u8, mut buffer: TX, - ) -> Result, (Error, Self, TX)> { + ) -> Result, (Error, Self, TX)> { self.wait_for_idle(); match unsafe { @@ -1651,30 +1605,26 @@ mod dma { /// /// This structure is responsible for managing SPI transfers using DMA /// buffers. - pub struct SpiDmaBus<'d, T, C, D, M> + pub struct SpiDmaBus<'d, T, D, M> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, D: DuplexMode, M: Mode, { - spi_dma: SpiDma<'d, T, C, D, M>, + spi_dma: SpiDma<'d, T, D, M>, rx_buf: DmaRxBuf, tx_buf: DmaTxBuf, } - impl<'d, T, C, D, M> SpiDmaBus<'d, T, C, D, M> + impl<'d, T, D, M> SpiDmaBus<'d, T, D, M> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, D: DuplexMode, M: Mode, { /// Creates a new `SpiDmaBus` with the specified SPI instance and DMA /// buffers. - pub fn new(spi_dma: SpiDma<'d, T, C, D, M>, rx_buf: DmaRxBuf, tx_buf: DmaTxBuf) -> Self { + pub fn new(spi_dma: SpiDma<'d, T, D, M>, rx_buf: DmaRxBuf, tx_buf: DmaTxBuf) -> Self { Self { spi_dma, rx_buf, @@ -1723,11 +1673,9 @@ mod dma { } } - impl<'d, T, C, D, M> InterruptConfigurable for SpiDmaBus<'d, T, C, D, M> + impl<'d, T, D, M> InterruptConfigurable for SpiDmaBus<'d, T, D, M> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, D: DuplexMode, M: Mode, { @@ -1737,21 +1685,17 @@ mod dma { } } - impl<'d, T, C, D, M> crate::private::Sealed for SpiDmaBus<'d, T, C, D, M> + impl<'d, T, D, M> crate::private::Sealed for SpiDmaBus<'d, T, D, M> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, D: DuplexMode, M: Mode, { } - impl<'d, T, C, M> SpiDmaBus<'d, T, C, FullDuplexMode, M> + impl<'d, T, M> SpiDmaBus<'d, T, FullDuplexMode, M> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, M: Mode, { /// Reads data from the SPI bus using DMA. @@ -1843,11 +1787,9 @@ mod dma { } } - impl<'d, T, C, M> HalfDuplexReadWrite for SpiDmaBus<'d, T, C, HalfDuplexMode, M> + impl<'d, T, M> HalfDuplexReadWrite for SpiDmaBus<'d, T, HalfDuplexMode, M> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, M: Mode, { type Error = Error; @@ -1916,12 +1858,10 @@ mod dma { } } - impl<'d, T, C> embedded_hal_02::blocking::spi::Transfer - for SpiDmaBus<'d, T, C, FullDuplexMode, crate::Blocking> + impl<'d, T> embedded_hal_02::blocking::spi::Transfer + for SpiDmaBus<'d, T, FullDuplexMode, crate::Blocking> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, { type Error = Error; @@ -1931,12 +1871,10 @@ mod dma { } } - impl<'d, T, C> embedded_hal_02::blocking::spi::Write - for SpiDmaBus<'d, T, C, FullDuplexMode, crate::Blocking> + impl<'d, T> embedded_hal_02::blocking::spi::Write + for SpiDmaBus<'d, T, FullDuplexMode, crate::Blocking> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, { type Error = Error; @@ -1993,11 +1931,9 @@ mod dma { } } - impl<'d, T, C> SpiDmaBus<'d, T, C, FullDuplexMode, crate::Async> + impl<'d, T> SpiDmaBus<'d, T, FullDuplexMode, crate::Async> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, { /// Fill the given buffer with data from the bus. pub async fn read_async(&mut self, words: &mut [u8]) -> Result<(), Error> { @@ -2111,11 +2047,9 @@ mod dma { } } - impl<'d, T, C> embedded_hal_async::spi::SpiBus for SpiDmaBus<'d, T, C, FullDuplexMode, crate::Async> + impl<'d, T> embedded_hal_async::spi::SpiBus for SpiDmaBus<'d, T, FullDuplexMode, crate::Async> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, { async fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { self.read_async(words).await @@ -2145,21 +2079,17 @@ mod dma { use super::*; - impl<'d, T, C, M> ErrorType for SpiDmaBus<'d, T, C, FullDuplexMode, M> + impl<'d, T, M> ErrorType for SpiDmaBus<'d, T, FullDuplexMode, M> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, M: Mode, { type Error = Error; } - impl<'d, T, C, M> SpiBus for SpiDmaBus<'d, T, C, FullDuplexMode, M> + impl<'d, T, M> SpiBus for SpiDmaBus<'d, T, FullDuplexMode, M> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, M: Mode, { fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { @@ -2284,7 +2214,7 @@ mod ehal1 { } #[doc(hidden)] -pub trait InstanceDma: Instance { +pub trait InstanceDma: Instance + DmaEligible { #[allow(clippy::too_many_arguments)] unsafe fn start_transfer_dma( &mut self, @@ -2406,15 +2336,6 @@ pub trait InstanceDma: Instance { Ok(()) } - fn dma_peripheral(&self) -> DmaPeripheral { - match self.spi_num() { - 2 => DmaPeripheral::Spi2, - #[cfg(spi3)] - 3 => DmaPeripheral::Spi3, - _ => panic!("Illegal SPI instance"), - } - } - fn enable_dma(&self) { #[cfg(gdma)] { @@ -2513,9 +2434,7 @@ pub trait ExtendedInstance: Instance { } #[doc(hidden)] -pub trait Instance: private::Sealed { - fn peripheral(&self) -> crate::system::Peripheral; - +pub trait Instance: private::Sealed + PeripheralMarker { fn register_block(&self) -> &RegisterBlock; fn sclk_signal(&self) -> OutputSignal; @@ -3198,11 +3117,6 @@ impl Instance for crate::peripherals::SPI2 { 2 } - #[inline(always)] - fn peripheral(&self) -> crate::system::Peripheral { - crate::system::Peripheral::Spi2 - } - #[inline(always)] fn set_interrupt_handler(&mut self, handler: InterruptHandler) { self.bind_spi2_interrupt(handler.handler()); @@ -3337,11 +3251,6 @@ impl Instance for crate::peripherals::SPI3 { 3 } - #[inline(always)] - fn peripheral(&self) -> crate::system::Peripheral { - crate::system::Peripheral::Spi3 - } - #[inline(always)] fn set_interrupt_handler(&mut self, handler: InterruptHandler) { self.bind_spi3_interrupt(handler.handler()); diff --git a/esp-hal/src/spi/mod.rs b/esp-hal/src/spi/mod.rs index 32786fb24c0..250ed0e2b4b 100644 --- a/esp-hal/src/spi/mod.rs +++ b/esp-hal/src/spi/mod.rs @@ -9,7 +9,7 @@ //! more information on these modes, please refer to the documentation in their //! respective modules. -use crate::dma::DmaError; +use crate::dma::{DmaError, PeripheralMarker}; pub mod master; pub mod slave; @@ -100,3 +100,19 @@ impl crate::private::Sealed for FullDuplexMode {} pub struct HalfDuplexMode {} impl DuplexMode for HalfDuplexMode {} impl crate::private::Sealed for HalfDuplexMode {} + +#[cfg(spi2)] +impl PeripheralMarker for crate::peripherals::SPI2 { + #[inline(always)] + fn peripheral(&self) -> crate::system::Peripheral { + crate::system::Peripheral::Spi2 + } +} + +#[cfg(spi3)] +impl PeripheralMarker for crate::peripherals::SPI3 { + #[inline(always)] + fn peripheral(&self) -> crate::system::Peripheral { + crate::system::Peripheral::Spi3 + } +} diff --git a/esp-hal/src/spi/slave.rs b/esp-hal/src/spi/slave.rs index 98d7bf318de..71e62967aae 100644 --- a/esp-hal/src/spi/slave.rs +++ b/esp-hal/src/spi/slave.rs @@ -73,7 +73,7 @@ use core::marker::PhantomData; use super::{Error, FullDuplexMode, SpiMode}; use crate::{ - dma::{DescriptorChain, DmaPeripheral, Rx, Tx}, + dma::{DescriptorChain, DmaChannelConvert, DmaEligible, PeripheralMarker, Rx, Tx}, gpio::{InputSignal, OutputSignal, PeripheralInput, PeripheralOutput}, peripheral::{Peripheral, PeripheralRef}, peripherals::spi2::RegisterBlock, @@ -150,8 +150,6 @@ where /// DMA (Direct Memory Access) functionality (Slave). pub mod dma { use super::*; - #[cfg(spi3)] - use crate::dma::Spi3Peripheral; use crate::{ dma::{ dma_private::{DmaSupport, DmaSupportRx, DmaSupportTx}, @@ -159,89 +157,55 @@ pub mod dma { ChannelRx, ChannelTx, DescriptorChain, - DmaChannel, DmaDescriptor, DmaTransferRx, DmaTransferRxTx, DmaTransferTx, ReadBuffer, Rx, - Spi2Peripheral, - SpiPeripheral, Tx, WriteBuffer, }, Mode, }; - impl<'d> Spi<'d, crate::peripherals::SPI2, FullDuplexMode> { - /// Configures the SPI3 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( - mut self, - channel: Channel<'d, C, DmaMode>, - rx_descriptors: &'static mut [DmaDescriptor], - tx_descriptors: &'static mut [DmaDescriptor], - ) -> SpiDma<'d, crate::peripherals::SPI2, C, DmaMode> - where - C: DmaChannel, - C::P: SpiPeripheral + Spi2Peripheral, - DmaMode: Mode, - { - self.spi.set_data_mode(self.data_mode, true); - SpiDma { - spi: self.spi, - channel, - rx_chain: DescriptorChain::new(rx_descriptors), - tx_chain: DescriptorChain::new(tx_descriptors), - } - } - } - - #[cfg(spi3)] - impl<'d> Spi<'d, crate::peripherals::SPI3, FullDuplexMode> { + impl<'d, T> Spi<'d, T, FullDuplexMode> + where + T: InstanceDma, + { /// Configures the SPI3 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( mut self, - channel: Channel<'d, C, DmaMode>, + channel: Channel<'d, CH, DmaMode>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], - ) -> SpiDma<'d, crate::peripherals::SPI3, C, DmaMode> + ) -> SpiDma<'d, T, DmaMode> where - C: DmaChannel, - C::P: SpiPeripheral + Spi3Peripheral, + CH: DmaChannelConvert, DmaMode: Mode, { self.spi.set_data_mode(self.data_mode, true); - SpiDma { - spi: self.spi, - channel, - rx_chain: DescriptorChain::new(rx_descriptors), - tx_chain: DescriptorChain::new(tx_descriptors), - } + SpiDma::new(self.spi, channel, rx_descriptors, tx_descriptors) } } /// A DMA capable SPI instance. - pub struct SpiDma<'d, T, C, DmaMode> + pub struct SpiDma<'d, T, DmaMode> where - C: DmaChannel, - C::P: SpiPeripheral, + T: InstanceDma, DmaMode: Mode, { pub(crate) spi: PeripheralRef<'d, T>, - pub(crate) channel: Channel<'d, C, DmaMode>, + pub(crate) channel: Channel<'d, T::Dma, DmaMode>, rx_chain: DescriptorChain, tx_chain: DescriptorChain, } - impl<'d, T, C, DmaMode> core::fmt::Debug for SpiDma<'d, T, C, DmaMode> + impl<'d, T, DmaMode> core::fmt::Debug for SpiDma<'d, T, DmaMode> where - C: DmaChannel, - C::P: SpiPeripheral, + T: InstanceDma, DmaMode: Mode, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -249,11 +213,9 @@ pub mod dma { } } - impl<'d, T, C, DmaMode> DmaSupport for SpiDma<'d, T, C, DmaMode> + impl<'d, T, DmaMode> DmaSupport for SpiDma<'d, T, DmaMode> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, DmaMode: Mode, { fn peripheral_wait_dma(&mut self, is_rx: bool, is_tx: bool) { @@ -270,14 +232,12 @@ pub mod dma { } } - impl<'d, T, C, DmaMode> DmaSupportTx for SpiDma<'d, T, C, DmaMode> + impl<'d, T, DmaMode> DmaSupportTx for SpiDma<'d, T, DmaMode> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, DmaMode: Mode, { - type TX = ChannelTx<'d, C>; + type TX = ChannelTx<'d, T::Dma>; fn tx(&mut self) -> &mut Self::TX { &mut self.channel.tx @@ -288,14 +248,12 @@ pub mod dma { } } - impl<'d, T, C, DmaMode> DmaSupportRx for SpiDma<'d, T, C, DmaMode> + impl<'d, T, DmaMode> DmaSupportRx for SpiDma<'d, T, DmaMode> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, DmaMode: Mode, { - type RX = ChannelRx<'d, C>; + type RX = ChannelRx<'d, T::Dma>; fn rx(&mut self) -> &mut Self::RX { &mut self.channel.rx @@ -306,13 +264,28 @@ pub mod dma { } } - impl<'d, T, C, DmaMode> SpiDma<'d, T, C, DmaMode> + impl<'d, T, DmaMode> SpiDma<'d, T, DmaMode> where T: InstanceDma, - C: DmaChannel, - C::P: SpiPeripheral, DmaMode: Mode, { + fn new( + spi: PeripheralRef<'d, T>, + channel: Channel<'d, CH, DmaMode>, + rx_descriptors: &'static mut [DmaDescriptor], + tx_descriptors: &'static mut [DmaDescriptor], + ) -> Self + where + CH: DmaChannelConvert, + { + channel.runtime_ensure_compatible(&spi); + Self { + spi, + channel: channel.degrade(), + rx_chain: DescriptorChain::new(rx_descriptors), + tx_chain: DescriptorChain::new(tx_descriptors), + } + } /// Register a buffer for a DMA write. /// /// This will return a [DmaTransferTx]. The maximum amount of data to be @@ -425,9 +398,7 @@ pub mod dma { } #[doc(hidden)] -pub trait InstanceDma: Instance { - fn dma_peripheral(&self) -> DmaPeripheral; - +pub trait InstanceDma: Instance + DmaEligible { #[allow(clippy::too_many_arguments)] unsafe fn start_transfer_dma( &mut self, @@ -569,24 +540,14 @@ fn reset_dma_before_usr_cmd(reg_block: &RegisterBlock) { let _ = reg_block; } -impl InstanceDma for crate::peripherals::SPI2 { - fn dma_peripheral(&self) -> DmaPeripheral { - DmaPeripheral::Spi2 - } -} +impl InstanceDma for crate::peripherals::SPI2 {} #[cfg(spi3)] -impl InstanceDma for crate::peripherals::SPI3 { - fn dma_peripheral(&self) -> DmaPeripheral { - DmaPeripheral::Spi3 - } -} +impl InstanceDma for crate::peripherals::SPI3 {} #[doc(hidden)] -pub trait Instance: private::Sealed { +pub trait Instance: private::Sealed + PeripheralMarker { fn register_block(&self) -> &RegisterBlock; - fn peripheral(&self) -> crate::system::Peripheral; - fn sclk_signal(&self) -> InputSignal; fn mosi_signal(&self) -> InputSignal; @@ -772,11 +733,6 @@ impl Instance for crate::peripherals::SPI2 { 2 } - #[inline(always)] - fn peripheral(&self) -> crate::system::Peripheral { - crate::system::Peripheral::Spi2 - } - #[inline(always)] fn sclk_signal(&self) -> InputSignal { cfg_if::cfg_if! { @@ -834,11 +790,6 @@ impl Instance for crate::peripherals::SPI3 { 3 } - #[inline(always)] - fn peripheral(&self) -> crate::system::Peripheral { - crate::system::Peripheral::Spi3 - } - #[inline(always)] fn sclk_signal(&self) -> InputSignal { cfg_if::cfg_if! { diff --git a/esp-hal/src/system.rs b/esp-hal/src/system.rs index 4b031e91c17..0406d89d0f4 100755 --- a/esp-hal/src/system.rs +++ b/esp-hal/src/system.rs @@ -15,6 +15,8 @@ use crate::peripherals::SYSTEM; // FIXME: This enum needs to be public because it's exposed via a bunch of traits, but it's not // useful to users. #[doc(hidden)] +#[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Peripheral { /// SPI2 peripheral. #[cfg(spi2)] diff --git a/examples/src/bin/lcd_i8080.rs b/examples/src/bin/lcd_i8080.rs index a87c1a2ea72..2937f427cae 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, DmaChannel0, DmaPriority, DmaTxBuf}, + dma::{Dma, DmaPriority, DmaTxBuf}, dma_tx_buffer, gpio::{Input, Io, Level, Output, Pull}, lcd_cam::{ @@ -88,15 +88,12 @@ fn main() -> ! { // 8 vs 16 bit, non-native primitives like Rgb565, Rgb888, etc. This Bus is just provided as // an example of how to implement your own. struct Bus<'d> { - resources: Option<(I8080<'d, DmaChannel0, Blocking>, DmaTxBuf)>, + resources: Option<(I8080<'d, Blocking>, DmaTxBuf)>, } impl<'d> Bus<'d> { fn use_resources( &mut self, - func: impl FnOnce( - I8080<'d, DmaChannel0, Blocking>, - DmaTxBuf, - ) -> (T, I8080<'d, DmaChannel0, Blocking>, DmaTxBuf), + func: impl FnOnce(I8080<'d, Blocking>, DmaTxBuf) -> (T, I8080<'d, Blocking>, DmaTxBuf), ) -> T { let (i8080, buf) = self.resources.take().unwrap(); let (result, i8080, buf) = func(i8080, buf); diff --git a/hil-test/tests/aes_dma.rs b/hil-test/tests/aes_dma.rs index 3d0accd1fd5..3fdb98db1ff 100644 --- a/hil-test/tests/aes_dma.rs +++ b/hil-test/tests/aes_dma.rs @@ -6,11 +6,7 @@ #![no_main] use esp_hal::{ - aes::{ - dma::{CipherMode, WithDmaAes}, - Aes, - Mode, - }, + aes::{dma::CipherMode, Aes, Mode}, dma::{Dma, DmaPriority}, dma_buffers, peripherals::Peripherals, diff --git a/hil-test/tests/dma_mem2mem.rs b/hil-test/tests/dma_mem2mem.rs index 9abd073db65..f65873ae6c5 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::{Channel, Dma, DmaError, DmaPriority, Mem2Mem}, + dma::{AnyGdmaChannel, Channel, Dma, DmaError, DmaPriority, Mem2Mem}, dma_buffers, dma_buffers_chunk_size, dma_descriptors, @@ -24,10 +24,8 @@ cfg_if::cfg_if! { } } -use esp_hal::dma::DmaChannel0; - struct Context { - channel: Channel<'static, DmaChannel0, Blocking>, + channel: Channel<'static, AnyGdmaChannel, Blocking>, dma_peripheral: DmaPeripheralType, } @@ -52,7 +50,9 @@ mod tests { } Context { - channel: dma_channel.configure(false, DmaPriority::Priority0), + channel: dma_channel + .configure(false, DmaPriority::Priority0) + .degrade(), dma_peripheral, } } diff --git a/hil-test/tests/embassy_interrupt_spi_dma.rs b/hil-test/tests/embassy_interrupt_spi_dma.rs index b1fac2b3c0c..86177a23c6a 100644 --- a/hil-test/tests/embassy_interrupt_spi_dma.rs +++ b/hil-test/tests/embassy_interrupt_spi_dma.rs @@ -25,17 +25,6 @@ use esp_hal::{ use esp_hal_embassy::InterruptExecutor; use hil_test as _; -cfg_if::cfg_if! { - if #[cfg(any( - feature = "esp32", - feature = "esp32s2", - ))] { - use esp_hal::dma::Spi3DmaChannel as DmaChannel1; - } else { - use esp_hal::dma::DmaChannel1; - } -} - macro_rules! mk_static { ($t:ty,$val:expr) => {{ static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); @@ -46,7 +35,7 @@ macro_rules! mk_static { } #[embassy_executor::task] -async fn interrupt_driven_task(spi: SpiDma<'static, SPI3, DmaChannel1, FullDuplexMode, Async>) { +async fn interrupt_driven_task(spi: SpiDma<'static, SPI3, FullDuplexMode, Async>) { let mut ticker = Ticker::every(Duration::from_millis(1)); let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(128); diff --git a/hil-test/tests/i2s.rs b/hil-test/tests/i2s.rs index 537e6622177..a9351bd5141 100644 --- a/hil-test/tests/i2s.rs +++ b/hil-test/tests/i2s.rs @@ -23,10 +23,8 @@ use hil_test as _; cfg_if::cfg_if! { if #[cfg(any(esp32, esp32s2))] { - use esp_hal::dma::I2s0DmaChannel as DmaChannel0; type DmaChannel0Creator = esp_hal::dma::I2s0DmaChannelCreator; } else { - use esp_hal::dma::DmaChannel0; type DmaChannel0Creator = esp_hal::dma::ChannelCreator<0>; } } @@ -59,7 +57,7 @@ impl Iterator for SampleSource { } #[embassy_executor::task] -async fn writer(tx_buffer: &'static mut [u8], i2s_tx: I2sTx<'static, I2S0, DmaChannel0, Async>) { +async fn writer(tx_buffer: &'static mut [u8], i2s_tx: I2sTx<'static, I2S0, Async>) { let mut samples = SampleSource::new(); for b in tx_buffer.iter_mut() { *b = samples.next().unwrap(); diff --git a/hil-test/tests/qspi.rs b/hil-test/tests/qspi.rs index af9132bede8..d1ec44dcebb 100644 --- a/hil-test/tests/qspi.rs +++ b/hil-test/tests/qspi.rs @@ -23,7 +23,7 @@ use esp_hal::{ use hil_test as _; cfg_if::cfg_if! { - if #[cfg(any(esp32, esp32s2))] { + if #[cfg(pdma)] { use esp_hal::dma::Spi2DmaChannel as DmaChannel0; } else { use esp_hal::dma::DmaChannel0; @@ -38,8 +38,7 @@ cfg_if::cfg_if! { } } -type SpiUnderTest = - SpiDma<'static, esp_hal::peripherals::SPI2, DmaChannel0, HalfDuplexMode, Blocking>; +type SpiUnderTest = SpiDma<'static, esp_hal::peripherals::SPI2, HalfDuplexMode, Blocking>; struct Context { spi: esp_hal::peripherals::SPI2, diff --git a/hil-test/tests/spi_half_duplex_read.rs b/hil-test/tests/spi_half_duplex_read.rs index 48e5dc3d446..5f0c379f4b3 100644 --- a/hil-test/tests/spi_half_duplex_read.rs +++ b/hil-test/tests/spi_half_duplex_read.rs @@ -21,16 +21,8 @@ use esp_hal::{ }; use hil_test as _; -cfg_if::cfg_if! { - if #[cfg(any(esp32, esp32s2))] { - use esp_hal::dma::Spi2DmaChannel as DmaChannel0; - } else { - use esp_hal::dma::DmaChannel0; - } -} - struct Context { - spi: SpiDma<'static, SPI2, DmaChannel0, HalfDuplexMode, Blocking>, + spi: SpiDma<'static, SPI2, HalfDuplexMode, Blocking>, miso_mirror: Output<'static>, } diff --git a/hil-test/tests/spi_half_duplex_write.rs b/hil-test/tests/spi_half_duplex_write.rs index fb6cc0fcfce..eb653963aca 100644 --- a/hil-test/tests/spi_half_duplex_write.rs +++ b/hil-test/tests/spi_half_duplex_write.rs @@ -22,19 +22,8 @@ use esp_hal::{ }; use hil_test as _; -cfg_if::cfg_if! { - if #[cfg(any( - feature = "esp32", - feature = "esp32s2", - ))] { - use esp_hal::dma::Spi2DmaChannel as DmaChannel0; - } else { - use esp_hal::dma::DmaChannel0; - } -} - struct Context { - spi: SpiDma<'static, SPI2, DmaChannel0, HalfDuplexMode, Blocking>, + spi: SpiDma<'static, SPI2, HalfDuplexMode, Blocking>, pcnt_unit: Unit<'static, 0>, pcnt_source: InputSignal, } diff --git a/hil-test/tests/spi_half_duplex_write_psram.rs b/hil-test/tests/spi_half_duplex_write_psram.rs index eb7987e2315..b5a6845b196 100644 --- a/hil-test/tests/spi_half_duplex_write_psram.rs +++ b/hil-test/tests/spi_half_duplex_write_psram.rs @@ -25,17 +25,6 @@ use esp_hal::{ use hil_test as _; extern crate alloc; -cfg_if::cfg_if! { - if #[cfg(any( - feature = "esp32", - feature = "esp32s2", - ))] { - use esp_hal::dma::Spi2DmaChannel as DmaChannel0; - } else { - use esp_hal::dma::DmaChannel0; - } -} - macro_rules! dma_alloc_buffer { ($size:expr, $align:expr) => {{ let layout = core::alloc::Layout::from_size_align($size, $align).unwrap(); @@ -51,7 +40,7 @@ macro_rules! dma_alloc_buffer { } struct Context { - spi: SpiDma<'static, SPI2, DmaChannel0, HalfDuplexMode, Blocking>, + spi: SpiDma<'static, SPI2, HalfDuplexMode, Blocking>, pcnt_unit: Unit<'static, 0>, pcnt_source: InputSignal, }