Skip to content

Commit

Permalink
Implement burst configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
bugadani committed Nov 15, 2024
1 parent 7f19c61 commit 40d711e
Show file tree
Hide file tree
Showing 10 changed files with 593 additions and 268 deletions.
558 changes: 385 additions & 173 deletions esp-hal/src/dma/buffers.rs

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions esp-hal/src/dma/gdma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@ impl RegisterAccess for AnyGdmaTxChannel {
.out_conf1()
.modify(|_, w| unsafe { w.out_ext_mem_bk_size().bits(size as u8) });
}

#[cfg(psram_dma)]
fn can_access_psram(&self) -> bool {
true
}
}

impl TxRegisterAccess for AnyGdmaTxChannel {
Expand Down Expand Up @@ -416,6 +421,11 @@ impl RegisterAccess for AnyGdmaRxChannel {
.in_conf1()
.modify(|_, w| unsafe { w.in_ext_mem_bk_size().bits(size as u8) });
}

#[cfg(psram_dma)]
fn can_access_psram(&self) -> bool {
true
}
}

impl RxRegisterAccess for AnyGdmaRxChannel {
Expand Down
161 changes: 79 additions & 82 deletions esp-hal/src/dma/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,13 @@ pub use self::gdma::*;
pub use self::m2m::*;
#[cfg(pdma)]
pub use self::pdma::*;
#[cfg(psram_dma)]
use crate::soc::is_valid_psram_address;
use crate::{
interrupt::InterruptHandler,
peripheral::{Peripheral, PeripheralRef},
peripherals::Interrupt,
soc::is_slice_in_dram,
soc::{is_slice_in_dram, is_valid_memory_address, is_valid_ram_address},
Async,
Blocking,
Cpu,
Expand Down Expand Up @@ -367,6 +369,26 @@ impl DmaDescriptor {
true => Owner::Dma,
}
}

fn iter(&self) -> impl Iterator<Item = &DmaDescriptor> {
core::iter::successors(Some(self), |d| {
if d.next.is_null() {
None
} else {
Some(unsafe { &*d.next })
}
})
}

fn iter_mut(&mut self) -> impl Iterator<Item = &mut DmaDescriptor> {
core::iter::successors(Some(self), |d| {
if d.next.is_null() {
None
} else {
Some(unsafe { &mut *d.next })
}
})
}
}

// The pointers in the descriptor can be Sent.
Expand Down Expand Up @@ -679,6 +701,14 @@ macro_rules! dma_buffers_impl {
)
}
}};

($size:expr, is_circular = $circular:tt) => {
$crate::dma_buffers_impl!(
$size,
$crate::dma::BurstTransfer::DEFAULT.max_compatible_chunk_size(),
is_circular = $circular
);
};
}

#[doc(hidden)]
Expand Down Expand Up @@ -726,19 +756,14 @@ macro_rules! dma_descriptor_count {
/// ```rust,no_run
#[doc = crate::before_snippet!()]
/// use esp_hal::dma_tx_buffer;
/// use esp_hal::dma::DmaBufBlkSize;
///
/// let tx_buf = dma_tx_buffer!(32000);
/// # }
/// ```
#[macro_export]
macro_rules! dma_tx_buffer {
($tx_size:expr) => {{
let (tx_buffer, tx_descriptors) = $crate::dma_buffers_impl!(
$tx_size,
$crate::dma::DmaTxBuf::compute_chunk_size(None),
is_circular = false
);
let (tx_buffer, tx_descriptors) = $crate::dma_buffers_impl!($tx_size, is_circular = false);

$crate::dma::DmaTxBuf::new(tx_descriptors, tx_buffer)
}};
Expand Down Expand Up @@ -1028,10 +1053,10 @@ impl DescriptorChain {
len: usize,
prepare_descriptor: impl Fn(&mut DmaDescriptor, usize),
) -> Result<(), DmaError> {
if !crate::soc::is_valid_ram_address(self.first() as usize)
|| !crate::soc::is_valid_ram_address(self.last() as usize)
|| !crate::soc::is_valid_memory_address(data as usize)
|| !crate::soc::is_valid_memory_address(unsafe { data.add(len) } as usize)
if !is_valid_ram_address(self.first() as usize)
|| !is_valid_ram_address(self.last() as usize)
|| !is_valid_memory_address(data as usize)
|| !is_valid_memory_address(unsafe { data.add(len) } as usize)
{
return Err(DmaError::UnsupportedMemoryRegion);
}
Expand Down Expand Up @@ -1078,17 +1103,6 @@ pub const fn descriptor_count(buffer_size: usize, chunk_size: usize, is_circular
buffer_size.div_ceil(chunk_size)
}

/// Compute max chunk size based on block size.
const fn max_chunk_size(block_size: Option<DmaBufBlkSize>) -> usize {
match block_size {
Some(size) => 4096 - size as usize,
#[cfg(esp32)]
None => 4092, // esp32 requires 4 byte alignment
#[cfg(not(esp32))]
None => 4095,
}
}

#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
struct DescriptorSet<'a> {
Expand Down Expand Up @@ -1131,28 +1145,15 @@ impl<'a> DescriptorSet<'a> {

/// Returns an iterator over the linked descriptors.
fn linked_iter(&self) -> impl Iterator<Item = &DmaDescriptor> {
let mut was_last = false;
self.descriptors.iter().take_while(move |d| {
if was_last {
false
} else {
was_last = d.next.is_null();
true
}
})
self.descriptors.first().into_iter().flat_map(|d| d.iter())
}

/// Returns an iterator over the linked descriptors.
fn linked_iter_mut(&mut self) -> impl Iterator<Item = &mut DmaDescriptor> {
let mut was_last = false;
self.descriptors.iter_mut().take_while(move |d| {
if was_last {
false
} else {
was_last = d.next.is_null();
true
}
})
self.descriptors
.first_mut()
.into_iter()
.flat_map(|d| d.iter_mut())
}

/// Associate each descriptor with a chunk of the buffer.
Expand Down Expand Up @@ -1284,6 +1285,7 @@ impl<'a> DescriptorSet<'a> {
}

/// Block size for transfers to/from PSRAM
#[cfg(psram_dma)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum DmaExtMemBKSize {
/// External memory block size of 16 bytes.
Expand All @@ -1294,12 +1296,13 @@ pub enum DmaExtMemBKSize {
Size64 = 2,
}

impl From<DmaBufBlkSize> for DmaExtMemBKSize {
fn from(size: DmaBufBlkSize) -> Self {
#[cfg(psram_dma)]
impl From<ExternalBurstSize> for DmaExtMemBKSize {
fn from(size: ExternalBurstSize) -> Self {
match size {
DmaBufBlkSize::Size16 => DmaExtMemBKSize::Size16,
DmaBufBlkSize::Size32 => DmaExtMemBKSize::Size32,
DmaBufBlkSize::Size64 => DmaExtMemBKSize::Size64,
ExternalBurstSize::Size16 => DmaExtMemBKSize::Size16,
ExternalBurstSize::Size32 => DmaExtMemBKSize::Size32,
ExternalBurstSize::Size64 => DmaExtMemBKSize::Size64,
}
}
}
Expand Down Expand Up @@ -1715,7 +1718,7 @@ pub trait Rx: crate::private::Sealed {

fn stop_transfer(&mut self);

#[cfg(esp32s3)]
#[cfg(psram_dma)]
fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize);

#[cfg(gdma)]
Expand Down Expand Up @@ -1851,6 +1854,8 @@ where
) -> Result<(), DmaError> {
debug_assert_eq!(preparation.direction, TransferDirection::In);

#[cfg(psram_dma)]
self.set_ext_mem_block_size(preparation.burst_transfer.external.into());
self.rx_impl.set_burst_mode(preparation.burst_transfer);
self.rx_impl.set_descr_burst_mode(true);
self.rx_impl.set_check_owner(preparation.check_owner);
Expand Down Expand Up @@ -1885,17 +1890,17 @@ where
peri: DmaPeripheral,
chain: &DescriptorChain,
) -> Result<(), DmaError> {
// For ESP32-S3 we check each descriptor buffer that points to PSRAM for
// We check each descriptor buffer that points to PSRAM for
// alignment and invalidate the cache for that buffer.
// NOTE: for RX the `buffer` and `size` need to be aligned but the `len` does
// not. TRM section 3.4.9
// Note that DmaBuffer implementations are required to do this for us.
#[cfg(esp32s3)]
#[cfg(psram_dma)]
for des in chain.descriptors.iter() {
// we are forcing the DMA alignment to the cache line size
// required when we are using dcache
let alignment = crate::soc::cache_get_dcache_line_size() as usize;
if crate::soc::is_valid_psram_address(des.buffer as usize) {
if is_valid_psram_address(des.buffer as usize) {
// both the size and address of the buffer must be aligned
if des.buffer as usize % alignment != 0 && des.size() % alignment != 0 {
return Err(DmaError::InvalidAlignment);
Expand All @@ -1904,17 +1909,13 @@ where
}
}

self.do_prepare(
Preparation {
start: chain.first().cast_mut(),
#[cfg(esp32s3)]
external_memory_block_size: None,
direction: TransferDirection::In,
burst_transfer: BurstTransfer::Disabled,
check_owner: Some(false),
},
peri,
)
let preparation = Preparation {
start: chain.first().cast_mut(),
direction: TransferDirection::In,
burst_transfer: BurstTransfer::default(),
check_owner: Some(false),
};
self.do_prepare(preparation, peri)
}

unsafe fn prepare_transfer<BUF: DmaRxBuffer>(
Expand Down Expand Up @@ -1944,7 +1945,7 @@ where
self.rx_impl.stop()
}

#[cfg(esp32s3)]
#[cfg(psram_dma)]
fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) {
self.rx_impl.set_ext_mem_block_size(size);
}
Expand Down Expand Up @@ -2017,7 +2018,7 @@ pub trait Tx: crate::private::Sealed {

fn stop_transfer(&mut self);

#[cfg(esp32s3)]
#[cfg(psram_dma)]
fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize);

fn is_done(&self) -> bool {
Expand Down Expand Up @@ -2128,11 +2129,8 @@ where
) -> Result<(), DmaError> {
debug_assert_eq!(preparation.direction, TransferDirection::Out);

#[cfg(esp32s3)]
if let Some(block_size) = preparation.external_memory_block_size {
self.set_ext_mem_block_size(block_size.into());
}

#[cfg(psram_dma)]
self.set_ext_mem_block_size(preparation.burst_transfer.external.into());
self.tx_impl.set_burst_mode(preparation.burst_transfer);
self.tx_impl.set_descr_burst_mode(true);
self.tx_impl.set_check_owner(preparation.check_owner);
Expand Down Expand Up @@ -2169,10 +2167,10 @@ where
) -> Result<(), DmaError> {
// Based on the ESP32-S3 TRM the alignment check is not needed for TX

// For esp32s3 we check each descriptor buffer that points to PSRAM for
// We check each descriptor buffer that points to PSRAM for
// alignment and writeback the cache for that buffer.
// Note that DmaBuffer implementations are required to do this for us.
#[cfg(esp32s3)]
#[cfg(psram_dma)]
for des in chain.descriptors.iter() {
// we are forcing the DMA alignment to the cache line size
// required when we are using dcache
Expand All @@ -2186,17 +2184,13 @@ where
}
}

self.do_prepare(
Preparation {
start: chain.first().cast_mut(),
#[cfg(esp32s3)]
external_memory_block_size: None,
direction: TransferDirection::Out,
burst_transfer: BurstTransfer::Disabled,
check_owner: Some(false),
},
peri,
)?;
let preparation = Preparation {
start: chain.first().cast_mut(),
direction: TransferDirection::Out,
burst_transfer: BurstTransfer::default(),
check_owner: Some(false),
};
self.do_prepare(preparation, peri)?;

// enable descriptor write back in circular mode
self.tx_impl
Expand Down Expand Up @@ -2232,7 +2226,7 @@ where
self.tx_impl.stop()
}

#[cfg(esp32s3)]
#[cfg(psram_dma)]
fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) {
self.tx_impl.set_ext_mem_block_size(size);
}
Expand Down Expand Up @@ -2307,11 +2301,14 @@ pub trait RegisterAccess: crate::private::Sealed {
/// descriptor.
fn set_check_owner(&self, check_owner: Option<bool>);

#[cfg(esp32s3)]
#[cfg(psram_dma)]
fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize);

#[cfg(pdma)]
fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool;

#[cfg(psram_dma)]
fn can_access_psram(&self) -> bool;
}

#[doc(hidden)]
Expand Down
Loading

0 comments on commit 40d711e

Please sign in to comment.