diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 1ce6bf348..c82f7cc28 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added +- Add burst transfer support to DMA buffers (#2236) ### Changed diff --git a/esp-hal/src/dma/buffers.rs b/esp-hal/src/dma/buffers.rs index 1b343a742..b3f2d4335 100644 --- a/esp-hal/src/dma/buffers.rs +++ b/esp-hal/src/dma/buffers.rs @@ -8,11 +8,22 @@ use crate::soc::is_slice_in_psram; /// Holds all the information needed to configure a DMA channel for a transfer. pub struct Preparation { pub(super) start: *mut DmaDescriptor, - /// block size for PSRAM transfers (TODO: enable burst mode for non external - /// memory?) + + /// block size for PSRAM transfers #[cfg_attr(not(esp32s3), allow(dead_code))] pub(super) block_size: Option, - // burst_mode, alignment, check_owner, etc. + + /// Specifies whether descriptor linked list specified in `start` conforms + /// to the alignment requirements required to enable burst transfers. + /// + /// Note: This only applies to burst transfer of the buffer data, not the + /// descriptors themselves. + /// + /// There are no additional alignment requirements for TX burst transfers, + /// but RX transfers require all descriptors to have buffer pointers and + /// sizes that are a multiple of 4 (word aligned). + pub(super) is_burstable: bool, + // alignment, check_owner, etc. } /// [DmaTxBuffer] is a DMA descriptor + memory combo that can be used for @@ -290,6 +301,8 @@ unsafe impl DmaTxBuffer for DmaTxBuf { Preparation { start: self.descriptors.head(), block_size: self.block_size, + // This is TX, the DMA channel is free to do a burst transfer. + is_burstable: true, } } @@ -436,6 +449,10 @@ unsafe impl DmaRxBuffer for DmaRxBuf { Preparation { start: self.descriptors.head(), block_size: None, + // DmaRxBuf doesn't currently enforce the alignment requirements required for bursting. + // In the future, it could either enforce the alignment or calculate if the alignment + // requirements happen to be met. + is_burstable: false, } } @@ -560,6 +577,9 @@ unsafe impl DmaTxBuffer for DmaRxTxBuf { Preparation { start: self.tx_descriptors.head(), block_size: None, // TODO: support block size! + + // This is TX, the DMA channel is free to do a burst transfer. + is_burstable: true, } } @@ -587,6 +607,10 @@ unsafe impl DmaRxBuffer for DmaRxTxBuf { Preparation { start: self.rx_descriptors.head(), block_size: None, // TODO: support block size! + + // DmaRxTxBuf doesn't currently enforce the alignment requirements required for + // bursting. + is_burstable: false, } } @@ -723,6 +747,10 @@ unsafe impl DmaRxBuffer for DmaRxStreamBuf { Preparation { start: self.descriptors.as_mut_ptr(), block_size: None, + + // DmaRxStreamBuf doesn't currently enforce the alignment requirements required for + // bursting. + is_burstable: false, } } @@ -927,6 +955,9 @@ unsafe impl DmaTxBuffer for EmptyBuf { Preparation { start: unsafe { core::ptr::addr_of_mut!(EMPTY).cast() }, block_size: None, + + // This is TX, the DMA channel is free to do a burst transfer. + is_burstable: true, } } @@ -951,6 +982,9 @@ unsafe impl DmaRxBuffer for EmptyBuf { Preparation { start: unsafe { core::ptr::addr_of_mut!(EMPTY).cast() }, block_size: None, + + // As much as bursting is meaningless here, the descriptor does meet the requirements. + is_burstable: true, } } diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index 646417b3f..8e9114ae3 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -1703,10 +1703,8 @@ where ) -> Result<(), DmaError> { let preparation = buffer.prepare(); - // TODO: Get burst mode from DmaBuf. - if self.burst_mode { - return Err(DmaError::InvalidAlignment); - } + self.rx_impl + .set_burst_mode(self.burst_mode && preparation.is_burstable); compiler_fence(core::sync::atomic::Ordering::SeqCst); @@ -1916,13 +1914,15 @@ where self.set_ext_mem_block_size(block_size.into()); } } else { - // we insure that block_size is some only for PSRAM addresses + // we ensure that block_size is some only for PSRAM addresses if preparation.block_size.is_some() { return Err(DmaError::UnsupportedMemoryRegion); } } ); - // TODO: Get burst mode from DmaBuf. + + self.tx_impl + .set_burst_mode(self.burst_mode && preparation.is_burstable); compiler_fence(core::sync::atomic::Ordering::SeqCst);