Skip to content

Commit

Permalink
Move mem2mem out of GDMA module
Browse files Browse the repository at this point in the history
  • Loading branch information
Dominic Fischer committed Oct 10, 2024
1 parent c26600f commit ff9f354
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 190 deletions.
190 changes: 0 additions & 190 deletions esp-hal/src/dma/gdma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -659,193 +659,3 @@ impl<'d> Dma<'d> {
}
}
}

pub use m2m::*;
mod m2m {
#[cfg(esp32s3)]
use crate::dma::DmaExtMemBKSize;
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
///
/// 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, M>
where
M: Mode,
{
channel: Channel<'d, AnyGdmaChannel, M>,
rx_chain: DescriptorChain,
tx_chain: DescriptorChain,
peripheral: DmaPeripheral,
}

impl<'d, M> Mem2Mem<'d, M>
where
M: Mode,
{
/// Create a new Mem2Mem instance.
pub fn new<CH>(
channel: Channel<'d, CH, M>,
peripheral: impl DmaEligible,
rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor],
) -> Result<Self, DmaError>
where
CH: DmaChannelConvert<AnyGdmaChannel>,
{
unsafe {
Self::new_unsafe(
channel,
peripheral.dma_peripheral(),
rx_descriptors,
tx_descriptors,
crate::dma::CHUNK_SIZE,
)
}
}

/// Create a new Mem2Mem instance with specific chunk size.
pub fn new_with_chunk_size<CH>(
channel: Channel<'d, CH, M>,
peripheral: impl DmaEligible,
rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor],
chunk_size: usize,
) -> Result<Self, DmaError>
where
CH: DmaChannelConvert<AnyGdmaChannel>,
{
unsafe {
Self::new_unsafe(
channel,
peripheral.dma_peripheral(),
rx_descriptors,
tx_descriptors,
chunk_size,
)
}
}

/// Create a new Mem2Mem instance.
///
/// # Safety
///
/// 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<CH>(
channel: Channel<'d, CH, M>,
peripheral: DmaPeripheral,
rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor],
chunk_size: usize,
) -> Result<Self, DmaError>
where
CH: DmaChannelConvert<AnyGdmaChannel>,
{
if !(1..=4092).contains(&chunk_size) {
return Err(DmaError::InvalidChunkSize);
}
if tx_descriptors.is_empty() || rx_descriptors.is_empty() {
return Err(DmaError::OutOfDescriptors);
}
Ok(Mem2Mem {
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),
})
}

/// Start a memory to memory transfer.
pub fn start_transfer<'t, TXBUF, RXBUF>(
&mut self,
rx_buffer: &'t mut RXBUF,
tx_buffer: &'t TXBUF,
) -> Result<DmaTransferRx<'_, Self>, DmaError>
where
TXBUF: ReadBuffer,
RXBUF: WriteBuffer,
{
let (tx_ptr, tx_len) = unsafe { tx_buffer.read_buffer() };
let (rx_ptr, rx_len) = unsafe { rx_buffer.write_buffer() };
self.tx_chain.fill_for_tx(false, tx_ptr, tx_len)?;
self.rx_chain.fill_for_rx(false, rx_ptr, rx_len)?;
unsafe {
self.channel
.tx
.prepare_transfer_without_start(self.peripheral, &self.tx_chain)?;
self.channel
.rx
.prepare_transfer_without_start(self.peripheral, &self.rx_chain)?;
self.channel.rx.set_mem2mem_mode(true);
}
#[cfg(esp32s3)]
{
let align = match unsafe { crate::soc::cache_get_dcache_line_size() } {
16 => DmaExtMemBKSize::Size16,
32 => DmaExtMemBKSize::Size32,
64 => DmaExtMemBKSize::Size64,
_ => panic!("unsupported cache line size"),
};
if crate::soc::is_valid_psram_address(tx_ptr as usize) {
self.channel.tx.set_ext_mem_block_size(align);
}
if crate::soc::is_valid_psram_address(rx_ptr as usize) {
self.channel.rx.set_ext_mem_block_size(align);
}
}
self.channel.tx.start_transfer()?;
self.channel.rx.start_transfer()?;
Ok(DmaTransferRx::new(self))
}
}

impl<'d, MODE> DmaSupport for Mem2Mem<'d, MODE>
where
MODE: Mode,
{
fn peripheral_wait_dma(&mut self, _is_rx: bool, _is_tx: bool) {
while !self.channel.rx.is_done() {}
}

fn peripheral_dma_stop(&mut self) {
unreachable!("unsupported")
}
}

impl<'d, MODE> DmaSupportRx for Mem2Mem<'d, MODE>
where
MODE: Mode,
{
type RX = ChannelRx<'d, AnyGdmaChannel>;

fn rx(&mut self) -> &mut Self::RX {
&mut self.channel.rx
}

fn chain(&mut self) -> &mut DescriptorChain {
&mut self.tx_chain
}
}
}
186 changes: 186 additions & 0 deletions esp-hal/src/dma/m2m.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
#[cfg(esp32s3)]
use crate::dma::DmaExtMemBKSize;
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
///
/// 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, M>
where
M: Mode,
{
channel: Channel<'d, AnyGdmaChannel, M>,
rx_chain: DescriptorChain,
tx_chain: DescriptorChain,
peripheral: DmaPeripheral,
}

impl<'d, M> Mem2Mem<'d, M>
where
M: Mode,
{
/// Create a new Mem2Mem instance.
pub fn new<CH>(
channel: Channel<'d, CH, M>,
peripheral: impl DmaEligible,
rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor],
) -> Result<Self, DmaError>
where
CH: DmaChannelConvert<AnyGdmaChannel>,
{
unsafe {
Self::new_unsafe(
channel,
peripheral.dma_peripheral(),
rx_descriptors,
tx_descriptors,
crate::dma::CHUNK_SIZE,
)
}
}

/// Create a new Mem2Mem instance with specific chunk size.
pub fn new_with_chunk_size<CH>(
channel: Channel<'d, CH, M>,
peripheral: impl DmaEligible,
rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor],
chunk_size: usize,
) -> Result<Self, DmaError>
where
CH: DmaChannelConvert<AnyGdmaChannel>,
{
unsafe {
Self::new_unsafe(
channel,
peripheral.dma_peripheral(),
rx_descriptors,
tx_descriptors,
chunk_size,
)
}
}

/// Create a new Mem2Mem instance.
///
/// # Safety
///
/// 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<CH>(
channel: Channel<'d, CH, M>,
peripheral: DmaPeripheral,
rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor],
chunk_size: usize,
) -> Result<Self, DmaError>
where
CH: DmaChannelConvert<AnyGdmaChannel>,
{
if !(1..=4092).contains(&chunk_size) {
return Err(DmaError::InvalidChunkSize);
}
if tx_descriptors.is_empty() || rx_descriptors.is_empty() {
return Err(DmaError::OutOfDescriptors);
}
Ok(Mem2Mem {
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),
})
}

/// Start a memory to memory transfer.
pub fn start_transfer<'t, TXBUF, RXBUF>(
&mut self,
rx_buffer: &'t mut RXBUF,
tx_buffer: &'t TXBUF,
) -> Result<DmaTransferRx<'_, Self>, DmaError>
where
TXBUF: ReadBuffer,
RXBUF: WriteBuffer,
{
let (tx_ptr, tx_len) = unsafe { tx_buffer.read_buffer() };
let (rx_ptr, rx_len) = unsafe { rx_buffer.write_buffer() };
self.tx_chain.fill_for_tx(false, tx_ptr, tx_len)?;
self.rx_chain.fill_for_rx(false, rx_ptr, rx_len)?;
unsafe {
self.channel
.tx
.prepare_transfer_without_start(self.peripheral, &self.tx_chain)?;
self.channel
.rx
.prepare_transfer_without_start(self.peripheral, &self.rx_chain)?;
self.channel.rx.set_mem2mem_mode(true);
}
#[cfg(esp32s3)]
{
let align = match unsafe { crate::soc::cache_get_dcache_line_size() } {
16 => DmaExtMemBKSize::Size16,
32 => DmaExtMemBKSize::Size32,
64 => DmaExtMemBKSize::Size64,
_ => panic!("unsupported cache line size"),
};
if crate::soc::is_valid_psram_address(tx_ptr as usize) {
self.channel.tx.set_ext_mem_block_size(align);
}
if crate::soc::is_valid_psram_address(rx_ptr as usize) {
self.channel.rx.set_ext_mem_block_size(align);
}
}
self.channel.tx.start_transfer()?;
self.channel.rx.start_transfer()?;
Ok(DmaTransferRx::new(self))
}
}

impl<'d, MODE> DmaSupport for Mem2Mem<'d, MODE>
where
MODE: Mode,
{
fn peripheral_wait_dma(&mut self, _is_rx: bool, _is_tx: bool) {
while !self.channel.rx.is_done() {}
}

fn peripheral_dma_stop(&mut self) {
unreachable!("unsupported")
}
}

impl<'d, MODE> DmaSupportRx for Mem2Mem<'d, MODE>
where
MODE: Mode,
{
type RX = ChannelRx<'d, AnyGdmaChannel>;

fn rx(&mut self) -> &mut Self::RX {
&mut self.channel.rx
}

fn chain(&mut self) -> &mut DescriptorChain {
&mut self.tx_chain
}
}
4 changes: 4 additions & 0 deletions esp-hal/src/dma/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,13 +353,17 @@ use enumset::{EnumSet, EnumSetType};
pub use self::buffers::*;
#[cfg(gdma)]
pub use self::gdma::*;
#[cfg(gdma)]
pub use self::m2m::*;
#[cfg(pdma)]
pub use self::pdma::*;
use crate::{interrupt::InterruptHandler, soc::is_slice_in_dram, Mode};

mod buffers;
#[cfg(gdma)]
mod gdma;
#[cfg(gdma)]
mod m2m;
#[cfg(pdma)]
mod pdma;

Expand Down

0 comments on commit ff9f354

Please sign in to comment.