DMA experimentation
Some checks failed
Rust/va416xx-rs/pipeline/head There was a failure building this commit

This commit is contained in:
Robin Müller 2024-07-03 11:21:48 +02:00
parent 16d2856fb2
commit 6cd2e809d7
Signed by: muellerr
GPG Key ID: A649FB78196E3849
3 changed files with 44 additions and 12 deletions

View File

@ -92,7 +92,8 @@ fn transfer_example_8_bit(
cortex_m::interrupt::free(|cs| { cortex_m::interrupt::free(|cs| {
DMA_ACTIVE_FLAG.borrow(cs).set(false); DMA_ACTIVE_FLAG.borrow(cs).set(false);
}); });
dma0.prepare_mem_to_mem_transfer_8_bit(src_buf, dest_buf) let dma_transfer = dma0
.prepare_mem_to_mem_transfer_8_bit(src_buf, dest_buf)
.expect("error preparing transfer"); .expect("error preparing transfer");
// Enable all interrupts. // Enable all interrupts.
// Safety: Not using mask based critical sections. // Safety: Not using mask based critical sections.
@ -104,6 +105,7 @@ fn transfer_example_8_bit(
dma0.enable(); dma0.enable();
// We still need to manually trigger the DMA request. // We still need to manually trigger the DMA request.
dma0.trigger_with_sw_request(); dma0.trigger_with_sw_request();
let dest_buf;
// Use polling for completion status. // Use polling for completion status.
loop { loop {
let mut dma_done = false; let mut dma_done = false;
@ -118,6 +120,8 @@ fn transfer_example_8_bit(
}); });
if dma_done { if dma_done {
rprintln!("8-bit transfer done"); rprintln!("8-bit transfer done");
// Safety: We checked for transfer completion.
dest_buf = unsafe { dma_transfer.release() };
break; break;
} }
delay_ms.delay_ms(1); delay_ms.delay_ms(1);
@ -146,8 +150,10 @@ fn transfer_example_16_bit(
cortex_m::interrupt::free(|cs| { cortex_m::interrupt::free(|cs| {
DMA_ACTIVE_FLAG.borrow(cs).set(false); DMA_ACTIVE_FLAG.borrow(cs).set(false);
}); });
dma0.prepare_mem_to_mem_transfer_16_bit(src_buf, dest_buf) let dma_transfer = dma0
.prepare_mem_to_mem_transfer_16_bit(src_buf, dest_buf)
.expect("error preparing transfer"); .expect("error preparing transfer");
dest_buf[5] = 2;
// Enable all interrupts. // Enable all interrupts.
// Safety: Not using mask based critical sections. // Safety: Not using mask based critical sections.
unsafe { unsafe {

View File

@ -17,6 +17,7 @@ paste = "1"
embedded-hal-nb = "1" embedded-hal-nb = "1"
embedded-hal = "1" embedded-hal = "1"
embedded-io = "0.6" embedded-io = "0.6"
embedded-dma = "0.2"
num_enum = { version = "0.7", default-features = false } num_enum = { version = "0.7", default-features = false }
typenum = "1" typenum = "1"
bitflags = "2" bitflags = "2"

View File

@ -3,6 +3,8 @@
//! ## Examples //! ## Examples
//! //!
//! - [Simple DMA example](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/examples/simple/examples/dma.rs) //! - [Simple DMA example](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/examples/simple/examples/dma.rs)
use embedded_dma::WriteBuffer;
use crate::{ use crate::{
clock::{PeripheralClock, PeripheralSelect}, clock::{PeripheralClock, PeripheralSelect},
enable_interrupt, pac, enable_interrupt, pac,
@ -203,6 +205,28 @@ pub struct DmaChannel {
pub ch_ctrl_alt: &'static mut DmaChannelControl, pub ch_ctrl_alt: &'static mut DmaChannelControl,
} }
/// This transfer structure takes ownership of the mutable destination slice.
///
/// This avoids accidental violation of the ownership rules because the DMA now has mutable
/// access to that slice as well. The mutable slice can be retrieved after DMA transfer completion
/// by using the [Self::release] method.
pub struct DmaTransfer<W> {
buf: W,
//ch: DmaChannel
}
impl<W: WriteBuffer> DmaTransfer<W> {
/// Retrieve the mutable destination slice once the DMA transfer has completed.
///
/// # Safety
///
/// - The user MUST ensure that the DMA transfer has completed, for example by polling a
/// completion flag set by the DMA_DONE ISR.
pub unsafe fn release(self) -> W {
self.buf
}
}
impl DmaChannel { impl DmaChannel {
#[inline(always)] #[inline(always)]
pub fn channel(&self) -> u8 { pub fn channel(&self) -> u8 {
@ -281,24 +305,25 @@ impl DmaChannel {
/// You can use [Self::enable], [Self::enable_done_interrupt], [Self::enable_active_interrupt] /// You can use [Self::enable], [Self::enable_done_interrupt], [Self::enable_active_interrupt]
/// to finish the transfer preparation and then use [Self::trigger_with_sw_request] to /// to finish the transfer preparation and then use [Self::trigger_with_sw_request] to
/// start the DMA transfer. /// start the DMA transfer.
pub fn prepare_mem_to_mem_transfer_8_bit( pub fn prepare_mem_to_mem_transfer_8_bit<W: WriteBuffer<Word = u8>>(
&mut self, &mut self,
source: &[u8], source: &[u8],
dest: &mut [u8], mut dest: W,
) -> Result<(), DmaTransferInitError> { ) -> Result<DmaTransfer<W>, DmaTransferInitError> {
let len = Self::common_mem_transfer_checks(source.len(), dest.len())?; let (write_ptr, len) = unsafe { dest.write_buffer() };
let len = Self::common_mem_transfer_checks(source.len(), len)?;
self.generic_mem_to_mem_transfer_init( self.generic_mem_to_mem_transfer_init(
len, len,
(source.as_ptr() as u32) (source.as_ptr() as u32)
.checked_add(len as u32) .checked_add(len as u32)
.ok_or(DmaTransferInitError::AddrOverflow)?, .ok_or(DmaTransferInitError::AddrOverflow)?,
(dest.as_ptr() as u32) (write_ptr as u32)
.checked_add(len as u32) .checked_add(len as u32)
.ok_or(DmaTransferInitError::AddrOverflow)?, .ok_or(DmaTransferInitError::AddrOverflow)?,
DataSize::Byte, DataSize::Byte,
AddrIncrement::Byte, AddrIncrement::Byte,
); );
Ok(()) Ok(DmaTransfer { buf: dest })
} }
/// Prepares a 16-bit DMA transfer from memory to memory. /// Prepares a 16-bit DMA transfer from memory to memory.
@ -310,10 +335,10 @@ impl DmaChannel {
/// You can use [Self::enable], [Self::enable_done_interrupt], [Self::enable_active_interrupt] /// You can use [Self::enable], [Self::enable_done_interrupt], [Self::enable_active_interrupt]
/// to finish the transfer preparation and then use [Self::trigger_with_sw_request] to /// to finish the transfer preparation and then use [Self::trigger_with_sw_request] to
/// start the DMA transfer. /// start the DMA transfer.
pub fn prepare_mem_to_mem_transfer_16_bit( pub fn prepare_mem_to_mem_transfer_16_bit<'dest>(
&mut self, &mut self,
source: &[u16], source: &[u16],
dest: &mut [u16], dest: &'dest mut [u16],
) -> Result<(), DmaTransferInitError> { ) -> Result<(), DmaTransferInitError> {
let len = Self::common_mem_transfer_checks(source.len(), dest.len())?; let len = Self::common_mem_transfer_checks(source.len(), dest.len())?;
self.generic_mem_to_mem_transfer_init( self.generic_mem_to_mem_transfer_init(
@ -339,10 +364,10 @@ impl DmaChannel {
/// You can use [Self::enable], [Self::enable_done_interrupt], [Self::enable_active_interrupt] /// You can use [Self::enable], [Self::enable_done_interrupt], [Self::enable_active_interrupt]
/// to finish the transfer preparation and then use [Self::trigger_with_sw_request] to /// to finish the transfer preparation and then use [Self::trigger_with_sw_request] to
/// start the DMA transfer. /// start the DMA transfer.
pub fn prepare_mem_to_mem_transfer_32_bit( pub fn prepare_mem_to_mem_transfer_32_bit<'dest>(
&mut self, &mut self,
source: &[u32], source: &[u32],
dest: &mut [u32], dest: &'dest mut [u32],
) -> Result<(), DmaTransferInitError> { ) -> Result<(), DmaTransferInitError> {
let len = Self::common_mem_transfer_checks(source.len(), dest.len())?; let len = Self::common_mem_transfer_checks(source.len(), dest.len())?;
self.generic_mem_to_mem_transfer_init( self.generic_mem_to_mem_transfer_init(