DMA experimentation
Some checks failed
Rust/va416xx-rs/pipeline/head There was a failure building this commit
Some checks failed
Rust/va416xx-rs/pipeline/head There was a failure building this commit
This commit is contained in:
parent
16d2856fb2
commit
6cd2e809d7
@ -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 {
|
||||||
|
@ -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"
|
||||||
|
@ -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(
|
||||||
|
Loading…
Reference in New Issue
Block a user