support dma chunk sizes other than 4092 (#1758)
* support dma chunk sizes other than 4092 * fmt * update CHANGELOG * fix 0 size static assert * review changes: - `.div_ceil()` - return errors for bad chunk size and buffer sizes in Mem2Mem constructors - correct 0 chunk size check in descripter macros * dma: clear the mem2mem bit when channel is configured instead of in Drop
This commit is contained in:
parent
7e981a5376
commit
1631f22083
@ -44,6 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Improved interrupt latency on RISC-V based chips (#1679)
|
- Improved interrupt latency on RISC-V based chips (#1679)
|
||||||
- `esp_wifi::initialize` no longer requires running maximum CPU clock, instead check it runs above 80MHz. (#1688)
|
- `esp_wifi::initialize` no longer requires running maximum CPU clock, instead check it runs above 80MHz. (#1688)
|
||||||
- Move DMA descriptors from DMA Channel to each individual peripheral driver. (#1719)
|
- Move DMA descriptors from DMA Channel to each individual peripheral driver. (#1719)
|
||||||
|
- Support DMA chunk sizes other than the default 4092 (#1758)
|
||||||
- Improved interrupt latency on Xtensa based chips (#1735)
|
- Improved interrupt latency on Xtensa based chips (#1735)
|
||||||
- Improve PCNT api (#1765)
|
- Improve PCNT api (#1765)
|
||||||
|
|
||||||
|
|||||||
@ -653,18 +653,38 @@ mod m2m {
|
|||||||
{
|
{
|
||||||
/// Create a new Mem2Mem instance.
|
/// Create a new Mem2Mem instance.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
mut channel: Channel<'d, C, MODE>,
|
channel: Channel<'d, C, MODE>,
|
||||||
peripheral: impl DmaEligible,
|
peripheral: impl DmaEligible,
|
||||||
tx_descriptors: &'static mut [DmaDescriptor],
|
tx_descriptors: &'static mut [DmaDescriptor],
|
||||||
rx_descriptors: &'static mut [DmaDescriptor],
|
rx_descriptors: &'static mut [DmaDescriptor],
|
||||||
) -> Self {
|
) -> Result<Self, DmaError> {
|
||||||
channel.tx.init_channel();
|
unsafe {
|
||||||
channel.rx.init_channel();
|
Self::new_unsafe(
|
||||||
Mem2Mem {
|
channel,
|
||||||
channel,
|
peripheral.dma_peripheral(),
|
||||||
peripheral: peripheral.dma_peripheral(),
|
tx_descriptors,
|
||||||
tx_chain: DescriptorChain::new(tx_descriptors),
|
rx_descriptors,
|
||||||
rx_chain: DescriptorChain::new(rx_descriptors),
|
crate::dma::CHUNK_SIZE,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new Mem2Mem instance with specific chunk size.
|
||||||
|
pub fn new_with_chunk_size(
|
||||||
|
channel: Channel<'d, C, MODE>,
|
||||||
|
peripheral: impl DmaEligible,
|
||||||
|
tx_descriptors: &'static mut [DmaDescriptor],
|
||||||
|
rx_descriptors: &'static mut [DmaDescriptor],
|
||||||
|
chunk_size: usize,
|
||||||
|
) -> Result<Self, DmaError> {
|
||||||
|
unsafe {
|
||||||
|
Self::new_unsafe(
|
||||||
|
channel,
|
||||||
|
peripheral.dma_peripheral(),
|
||||||
|
tx_descriptors,
|
||||||
|
rx_descriptors,
|
||||||
|
chunk_size,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -679,15 +699,22 @@ mod m2m {
|
|||||||
peripheral: DmaPeripheral,
|
peripheral: DmaPeripheral,
|
||||||
tx_descriptors: &'static mut [DmaDescriptor],
|
tx_descriptors: &'static mut [DmaDescriptor],
|
||||||
rx_descriptors: &'static mut [DmaDescriptor],
|
rx_descriptors: &'static mut [DmaDescriptor],
|
||||||
) -> Self {
|
chunk_size: usize,
|
||||||
|
) -> Result<Self, DmaError> {
|
||||||
|
if !(1..=4092).contains(&chunk_size) {
|
||||||
|
return Err(DmaError::InvalidChunkSize);
|
||||||
|
}
|
||||||
|
if tx_descriptors.is_empty() || rx_descriptors.is_empty() {
|
||||||
|
return Err(DmaError::OutOfDescriptors);
|
||||||
|
}
|
||||||
channel.tx.init_channel();
|
channel.tx.init_channel();
|
||||||
channel.rx.init_channel();
|
channel.rx.init_channel();
|
||||||
Mem2Mem {
|
Ok(Mem2Mem {
|
||||||
channel,
|
channel,
|
||||||
peripheral,
|
peripheral,
|
||||||
tx_chain: DescriptorChain::new(tx_descriptors),
|
tx_chain: DescriptorChain::new_with_chunk_size(tx_descriptors, chunk_size),
|
||||||
rx_chain: DescriptorChain::new(rx_descriptors),
|
rx_chain: DescriptorChain::new_with_chunk_size(rx_descriptors, chunk_size),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start a memory to memory transfer.
|
/// Start a memory to memory transfer.
|
||||||
@ -719,16 +746,6 @@ mod m2m {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, C, MODE> Drop for Mem2Mem<'d, C, MODE>
|
|
||||||
where
|
|
||||||
C: ChannelTypes,
|
|
||||||
MODE: crate::Mode,
|
|
||||||
{
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.channel.rx.set_mem2mem_mode(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, C, MODE> DmaSupport for Mem2Mem<'d, C, MODE>
|
impl<'d, C, MODE> DmaSupport for Mem2Mem<'d, C, MODE>
|
||||||
where
|
where
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
|
|||||||
@ -40,8 +40,8 @@
|
|||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! ⚠️ Note: Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`.
|
//! ⚠️ Note: Descriptors should be sized as `(max_transfer_size + CHUNK_SIZE - 1) / CHUNK_SIZE`.
|
||||||
//! I.e., to transfer buffers of size `1..=4092`, you need 1 descriptor.
|
//! I.e., to transfer buffers of size `1..=CHUNK_SIZE`, you need 1 descriptor.
|
||||||
//!
|
//!
|
||||||
//! For convenience you can use the [crate::dma_buffers] macro.
|
//! For convenience you can use the [crate::dma_buffers] macro.
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
@ -142,7 +142,8 @@ pub enum DmaInterrupt {
|
|||||||
RxDone,
|
RxDone,
|
||||||
}
|
}
|
||||||
|
|
||||||
const CHUNK_SIZE: usize = 4092;
|
/// The default CHUNK_SIZE used for DMA transfers
|
||||||
|
pub const CHUNK_SIZE: usize = 4092;
|
||||||
|
|
||||||
/// Convenience macro to create DMA buffers and descriptors
|
/// Convenience macro to create DMA buffers and descriptors
|
||||||
///
|
///
|
||||||
@ -153,39 +154,12 @@ const CHUNK_SIZE: usize = 4092;
|
|||||||
/// ```
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! dma_buffers {
|
macro_rules! dma_buffers {
|
||||||
($tx_size:expr, $rx_size:expr) => {{
|
($tx_size:expr, $rx_size:expr) => {
|
||||||
static mut TX_BUFFER: [u8; $tx_size] = [0u8; $tx_size];
|
$crate::dma_buffers_chunk_size!($tx_size, $rx_size, $crate::dma::CHUNK_SIZE)
|
||||||
static mut RX_BUFFER: [u8; $rx_size] = [0u8; $rx_size];
|
};
|
||||||
static mut TX_DESCRIPTORS: [$crate::dma::DmaDescriptor; ($tx_size + 4091) / 4092] =
|
($size:expr) => {
|
||||||
[$crate::dma::DmaDescriptor::EMPTY; ($tx_size + 4091) / 4092];
|
$crate::dma_buffers_chunk_size!($size, $crate::dma::CHUNK_SIZE)
|
||||||
static mut RX_DESCRIPTORS: [$crate::dma::DmaDescriptor; ($rx_size + 4091) / 4092] =
|
};
|
||||||
[$crate::dma::DmaDescriptor::EMPTY; ($rx_size + 4091) / 4092];
|
|
||||||
unsafe {
|
|
||||||
(
|
|
||||||
&mut TX_BUFFER,
|
|
||||||
&mut TX_DESCRIPTORS,
|
|
||||||
&mut RX_BUFFER,
|
|
||||||
&mut RX_DESCRIPTORS,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
|
|
||||||
($size:expr) => {{
|
|
||||||
static mut TX_BUFFER: [u8; $size] = [0u8; $size];
|
|
||||||
static mut RX_BUFFER: [u8; $size] = [0u8; $size];
|
|
||||||
static mut TX_DESCRIPTORS: [$crate::dma::DmaDescriptor; ($size + 4091) / 4092] =
|
|
||||||
[$crate::dma::DmaDescriptor::EMPTY; ($size + 4091) / 4092];
|
|
||||||
static mut RX_DESCRIPTORS: [$crate::dma::DmaDescriptor; ($size + 4091) / 4092] =
|
|
||||||
[$crate::dma::DmaDescriptor::EMPTY; ($size + 4091) / 4092];
|
|
||||||
unsafe {
|
|
||||||
(
|
|
||||||
&mut TX_BUFFER,
|
|
||||||
&mut TX_DESCRIPTORS,
|
|
||||||
&mut RX_BUFFER,
|
|
||||||
&mut RX_DESCRIPTORS,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience macro to create circular DMA buffers and descriptors
|
/// Convenience macro to create circular DMA buffers and descriptors
|
||||||
@ -198,59 +172,13 @@ macro_rules! dma_buffers {
|
|||||||
/// ```
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! dma_circular_buffers {
|
macro_rules! dma_circular_buffers {
|
||||||
($tx_size:expr, $rx_size:expr) => {{
|
($tx_size:expr, $rx_size:expr) => {
|
||||||
static mut TX_BUFFER: [u8; $tx_size] = [0u8; $tx_size];
|
$crate::dma_circular_buffers_chunk_size!($tx_size, $rx_size, $crate::dma::CHUNK_SIZE)
|
||||||
static mut RX_BUFFER: [u8; $rx_size] = [0u8; $rx_size];
|
};
|
||||||
|
|
||||||
const tx_descriptor_len: usize = if $tx_size > 4092 * 2 {
|
($size:expr) => {
|
||||||
($tx_size + 4091) / 4092
|
$crate::dma_circular_buffers_chunk_size!($size, $size, $crate::dma::CHUNK_SIZE)
|
||||||
} else {
|
};
|
||||||
3
|
|
||||||
};
|
|
||||||
|
|
||||||
const rx_descriptor_len: usize = if $rx_size > 4092 * 2 {
|
|
||||||
($rx_size + 4091) / 4092
|
|
||||||
} else {
|
|
||||||
3
|
|
||||||
};
|
|
||||||
|
|
||||||
static mut TX_DESCRIPTORS: [$crate::dma::DmaDescriptor; tx_descriptor_len] =
|
|
||||||
[$crate::dma::DmaDescriptor::EMPTY; tx_descriptor_len];
|
|
||||||
static mut RX_DESCRIPTORS: [$crate::dma::DmaDescriptor; rx_descriptor_len] =
|
|
||||||
[$crate::dma::DmaDescriptor::EMPTY; rx_descriptor_len];
|
|
||||||
unsafe {
|
|
||||||
(
|
|
||||||
&mut TX_BUFFER,
|
|
||||||
&mut TX_DESCRIPTORS,
|
|
||||||
&mut RX_BUFFER,
|
|
||||||
&mut RX_DESCRIPTORS,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
|
|
||||||
($size:expr) => {{
|
|
||||||
static mut TX_BUFFER: [u8; $size] = [0u8; $size];
|
|
||||||
static mut RX_BUFFER: [u8; $size] = [0u8; $size];
|
|
||||||
|
|
||||||
const descriptor_len: usize = if $size > 4092 * 2 {
|
|
||||||
($size + 4091) / 4092
|
|
||||||
} else {
|
|
||||||
3
|
|
||||||
};
|
|
||||||
|
|
||||||
static mut TX_DESCRIPTORS: [$crate::dma::DmaDescriptor; descriptor_len] =
|
|
||||||
[$crate::dma::DmaDescriptor::EMPTY; descriptor_len];
|
|
||||||
static mut RX_DESCRIPTORS: [$crate::dma::DmaDescriptor; descriptor_len] =
|
|
||||||
[$crate::dma::DmaDescriptor::EMPTY; descriptor_len];
|
|
||||||
unsafe {
|
|
||||||
(
|
|
||||||
&mut TX_BUFFER,
|
|
||||||
&mut TX_DESCRIPTORS,
|
|
||||||
&mut RX_BUFFER,
|
|
||||||
&mut RX_DESCRIPTORS,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience macro to create DMA descriptors
|
/// Convenience macro to create DMA descriptors
|
||||||
@ -262,21 +190,13 @@ macro_rules! dma_circular_buffers {
|
|||||||
/// ```
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! dma_descriptors {
|
macro_rules! dma_descriptors {
|
||||||
($tx_size:expr, $rx_size:expr) => {{
|
($tx_size:expr, $rx_size:expr) => {
|
||||||
static mut TX_DESCRIPTORS: [$crate::dma::DmaDescriptor; ($tx_size + 4091) / 4092] =
|
$crate::dma_descriptors_chunk_size!($tx_size, $rx_size, $crate::dma::CHUNK_SIZE)
|
||||||
[$crate::dma::DmaDescriptor::EMPTY; ($tx_size + 4091) / 4092];
|
};
|
||||||
static mut RX_DESCRIPTORS: [$crate::dma::DmaDescriptor; ($rx_size + 4091) / 4092] =
|
|
||||||
[$crate::dma::DmaDescriptor::EMPTY; ($rx_size + 4091) / 4092];
|
|
||||||
unsafe { (&mut TX_DESCRIPTORS, &mut RX_DESCRIPTORS) }
|
|
||||||
}};
|
|
||||||
|
|
||||||
($size:expr) => {{
|
($size:expr) => {
|
||||||
static mut TX_DESCRIPTORS: [$crate::dma::DmaDescriptor; ($size + 4091) / 4092] =
|
$crate::dma_descriptors_chunk_size!($size, $size, $crate::dma::CHUNK_SIZE)
|
||||||
[$crate::dma::DmaDescriptor::EMPTY; ($size + 4091) / 4092];
|
};
|
||||||
static mut RX_DESCRIPTORS: [$crate::dma::DmaDescriptor; ($size + 4091) / 4092] =
|
|
||||||
[$crate::dma::DmaDescriptor::EMPTY; ($size + 4091) / 4092];
|
|
||||||
unsafe { (&mut TX_DESCRIPTORS, &mut RX_DESCRIPTORS) }
|
|
||||||
}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience macro to create circular DMA descriptors
|
/// Convenience macro to create circular DMA descriptors
|
||||||
@ -288,15 +208,127 @@ macro_rules! dma_descriptors {
|
|||||||
/// ```
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! dma_circular_descriptors {
|
macro_rules! dma_circular_descriptors {
|
||||||
($tx_size:expr, $rx_size:expr) => {{
|
($tx_size:expr, $rx_size:expr) => {
|
||||||
const tx_descriptor_len: usize = if $tx_size > 4092 * 2 {
|
$crate::dma_circular_descriptors_chunk_size!($tx_size, $rx_size, $crate::dma::CHUNK_SIZE)
|
||||||
($tx_size + 4091) / 4092
|
};
|
||||||
|
|
||||||
|
($size:expr) => {
|
||||||
|
$crate::dma_circular_descriptors_chunk_size!($size, $size, $crate::dma::CHUNK_SIZE)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convenience macro to create DMA buffers and descriptors with specific chunk
|
||||||
|
/// size
|
||||||
|
///
|
||||||
|
/// ## Usage
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// // TX and RX buffers are 32000 bytes - passing only one parameter makes TX and RX the same size
|
||||||
|
/// let (tx_buffer, tx_descriptors, rx_buffer, rx_descriptors) = dma_buffers!(32000, 32000, 4032);
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! dma_buffers_chunk_size {
|
||||||
|
($tx_size:expr, $rx_size:expr, $chunk_size:expr) => {{
|
||||||
|
static mut TX_BUFFER: [u8; $tx_size] = [0u8; $tx_size];
|
||||||
|
static mut RX_BUFFER: [u8; $rx_size] = [0u8; $rx_size];
|
||||||
|
let (mut tx_descriptors, mut rx_descriptors) =
|
||||||
|
$crate::dma_descriptors_chunk_size!($tx_size, $rx_size, $chunk_size);
|
||||||
|
unsafe {
|
||||||
|
(
|
||||||
|
&mut TX_BUFFER,
|
||||||
|
tx_descriptors,
|
||||||
|
&mut RX_BUFFER,
|
||||||
|
rx_descriptors,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
|
||||||
|
($size:expr, $chunk_size:expr) => {
|
||||||
|
$crate::dma_buffers_chunk_size!($size, $size, $chunk_size)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convenience macro to create circular DMA buffers and descriptors with
|
||||||
|
/// specific chunk size
|
||||||
|
///
|
||||||
|
/// ## Usage
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// // TX and RX buffers are 32000 bytes - passing only one parameter makes TX and RX the same size
|
||||||
|
/// let (tx_buffer, tx_descriptors, rx_buffer, rx_descriptors) =
|
||||||
|
/// dma_circular_buffers!(32000, 32000, 4032);
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! dma_circular_buffers_chunk_size {
|
||||||
|
($tx_size:expr, $rx_size:expr, $chunk_size:expr) => {{
|
||||||
|
static mut TX_BUFFER: [u8; $tx_size] = [0u8; $tx_size];
|
||||||
|
static mut RX_BUFFER: [u8; $rx_size] = [0u8; $rx_size];
|
||||||
|
let (mut tx_descriptors, mut rx_descriptors) =
|
||||||
|
$crate::dma_circular_descriptors_chunk_size!($tx_size, $rx_size, $chunk_size);
|
||||||
|
unsafe {
|
||||||
|
(
|
||||||
|
&mut TX_BUFFER,
|
||||||
|
tx_descriptors,
|
||||||
|
&mut RX_BUFFER,
|
||||||
|
rx_descriptors,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
|
||||||
|
($size:expr, $chunk_size:expr) => {{
|
||||||
|
$crate::dma_circular_buffers_chunk_size!($size, $size, $chunk_size)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convenience macro to create DMA descriptors with specific chunk size
|
||||||
|
///
|
||||||
|
/// ## Usage
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// // Create TX and RX descriptors for transactions up to 32000 bytes - passing only one parameter assumes TX and RX are the same size
|
||||||
|
/// let (tx_descriptors, rx_descriptors) = dma_descriptors_chunk_size!(32000, 32000, 4032);
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! dma_descriptors_chunk_size {
|
||||||
|
($tx_size:expr, $rx_size:expr, $chunk_size:expr) => {{
|
||||||
|
// these will check for size at compile time
|
||||||
|
const _: () = assert!($chunk_size <= 4092, "chunk size must be <= 4092");
|
||||||
|
const _: () = assert!($chunk_size > 0, "chunk size must be > 0");
|
||||||
|
|
||||||
|
static mut TX_DESCRIPTORS: [$crate::dma::DmaDescriptor;
|
||||||
|
($tx_size + $chunk_size - 1) / $chunk_size] =
|
||||||
|
[$crate::dma::DmaDescriptor::EMPTY; ($tx_size + $chunk_size - 1) / $chunk_size];
|
||||||
|
static mut RX_DESCRIPTORS: [$crate::dma::DmaDescriptor;
|
||||||
|
($rx_size + $chunk_size - 1) / $chunk_size] =
|
||||||
|
[$crate::dma::DmaDescriptor::EMPTY; ($rx_size + $chunk_size - 1) / $chunk_size];
|
||||||
|
unsafe { (&mut TX_DESCRIPTORS, &mut RX_DESCRIPTORS) }
|
||||||
|
}};
|
||||||
|
|
||||||
|
($size:expr, $chunk_size:expr) => {
|
||||||
|
$crate::dma_descriptors_chunk_size!($size, $size, $chunk_size)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convenience macro to create circular DMA descriptors with specific chunk
|
||||||
|
/// size
|
||||||
|
///
|
||||||
|
/// ## Usage
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// // Create TX and RX descriptors for transactions up to 32000 bytes - passing only one parameter assumes TX and RX are the same size
|
||||||
|
/// let (tx_descriptors, rx_descriptors) = dma_circular_descriptors!(32000, 32000, 4032);
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! dma_circular_descriptors_chunk_size {
|
||||||
|
($tx_size:expr, $rx_size:expr, $chunk_size:expr) => {{
|
||||||
|
// these will check for size at compile time
|
||||||
|
const _: () = assert!($chunk_size <= 4092, "chunk size must be <= 4092");
|
||||||
|
const _: () = assert!($chunk_size > 0, "chunk size must be > 0");
|
||||||
|
|
||||||
|
const tx_descriptor_len: usize = if $tx_size > $chunk_size * 2 {
|
||||||
|
($tx_size + $chunk_size - 1) / $chunk_size
|
||||||
} else {
|
} else {
|
||||||
3
|
3
|
||||||
};
|
};
|
||||||
|
|
||||||
const rx_descriptor_len: usize = if $rx_size > 4092 * 2 {
|
const rx_descriptor_len: usize = if $rx_size > $chunk_size * 2 {
|
||||||
($rx_size + 4091) / 4092
|
($rx_size + $chunk_size - 1) / $chunk_size
|
||||||
} else {
|
} else {
|
||||||
3
|
3
|
||||||
};
|
};
|
||||||
@ -308,19 +340,9 @@ macro_rules! dma_circular_descriptors {
|
|||||||
unsafe { (&mut TX_DESCRIPTORS, &mut RX_DESCRIPTORS) }
|
unsafe { (&mut TX_DESCRIPTORS, &mut RX_DESCRIPTORS) }
|
||||||
}};
|
}};
|
||||||
|
|
||||||
($size:expr) => {{
|
($size:expr, $chunk_size:expr) => {
|
||||||
const descriptor_len: usize = if $size > 4092 * 2 {
|
$crate::dma_circular_descriptors_chunk_size!($size, $size, $chunk_size)
|
||||||
($size + 4091) / 4092
|
};
|
||||||
} else {
|
|
||||||
3
|
|
||||||
};
|
|
||||||
|
|
||||||
static mut TX_DESCRIPTORS: [$crate::dma::DmaDescriptor; descriptor_len] =
|
|
||||||
[$crate::dma::DmaDescriptor::EMPTY; descriptor_len];
|
|
||||||
static mut RX_DESCRIPTORS: [$crate::dma::DmaDescriptor; descriptor_len] =
|
|
||||||
[$crate::dma::DmaDescriptor::EMPTY; descriptor_len];
|
|
||||||
unsafe { (&mut TX_DESCRIPTORS, &mut RX_DESCRIPTORS) }
|
|
||||||
}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DMA Errors
|
/// DMA Errors
|
||||||
@ -342,6 +364,8 @@ pub enum DmaError {
|
|||||||
BufferTooSmall,
|
BufferTooSmall,
|
||||||
/// Descriptors or buffers are not located in a supported memory region
|
/// Descriptors or buffers are not located in a supported memory region
|
||||||
UnsupportedMemoryRegion,
|
UnsupportedMemoryRegion,
|
||||||
|
/// Invalid DMA chunk size
|
||||||
|
InvalidChunkSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DMA Priorities
|
/// DMA Priorities
|
||||||
@ -497,11 +521,25 @@ pub trait PeripheralMarker {}
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DescriptorChain {
|
pub struct DescriptorChain {
|
||||||
pub(crate) descriptors: &'static mut [DmaDescriptor],
|
pub(crate) descriptors: &'static mut [DmaDescriptor],
|
||||||
|
chunk_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DescriptorChain {
|
impl DescriptorChain {
|
||||||
pub fn new(descriptors: &'static mut [DmaDescriptor]) -> Self {
|
pub fn new(descriptors: &'static mut [DmaDescriptor]) -> Self {
|
||||||
Self { descriptors }
|
Self {
|
||||||
|
descriptors,
|
||||||
|
chunk_size: CHUNK_SIZE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_with_chunk_size(
|
||||||
|
descriptors: &'static mut [DmaDescriptor],
|
||||||
|
chunk_size: usize,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
descriptors,
|
||||||
|
chunk_size,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn first_mut(&mut self) -> *mut DmaDescriptor {
|
pub fn first_mut(&mut self) -> *mut DmaDescriptor {
|
||||||
@ -535,7 +573,7 @@ impl DescriptorChain {
|
|||||||
return Err(DmaError::UnsupportedMemoryRegion);
|
return Err(DmaError::UnsupportedMemoryRegion);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.descriptors.len() < len.div_ceil(CHUNK_SIZE) {
|
if self.descriptors.len() < len.div_ceil(self.chunk_size) {
|
||||||
return Err(DmaError::OutOfDescriptors);
|
return Err(DmaError::OutOfDescriptors);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,8 +583,8 @@ impl DescriptorChain {
|
|||||||
|
|
||||||
self.descriptors.fill(DmaDescriptor::EMPTY);
|
self.descriptors.fill(DmaDescriptor::EMPTY);
|
||||||
|
|
||||||
let max_chunk_size = if !circular || len > CHUNK_SIZE * 2 {
|
let max_chunk_size = if !circular || len > self.chunk_size * 2 {
|
||||||
CHUNK_SIZE
|
self.chunk_size
|
||||||
} else {
|
} else {
|
||||||
len / 3 + len % 3
|
len / 3 + len % 3
|
||||||
};
|
};
|
||||||
@ -611,14 +649,14 @@ impl DescriptorChain {
|
|||||||
return Err(DmaError::BufferTooSmall);
|
return Err(DmaError::BufferTooSmall);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.descriptors.len() < len.div_ceil(CHUNK_SIZE) {
|
if self.descriptors.len() < len.div_ceil(self.chunk_size) {
|
||||||
return Err(DmaError::OutOfDescriptors);
|
return Err(DmaError::OutOfDescriptors);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.descriptors.fill(DmaDescriptor::EMPTY);
|
self.descriptors.fill(DmaDescriptor::EMPTY);
|
||||||
|
|
||||||
let max_chunk_size = if !circular || len > CHUNK_SIZE * 2 {
|
let max_chunk_size = if !circular || len > self.chunk_size * 2 {
|
||||||
CHUNK_SIZE
|
self.chunk_size
|
||||||
} else {
|
} else {
|
||||||
len / 3 + len % 3
|
len / 3 + len % 3
|
||||||
};
|
};
|
||||||
@ -976,6 +1014,10 @@ where
|
|||||||
fn init(&mut self, burst_mode: bool, priority: DmaPriority) {
|
fn init(&mut self, burst_mode: bool, priority: DmaPriority) {
|
||||||
R::set_in_burstmode(burst_mode);
|
R::set_in_burstmode(burst_mode);
|
||||||
R::set_in_priority(priority);
|
R::set_in_priority(priority);
|
||||||
|
// clear the mem2mem mode to avoid failed DMA if this
|
||||||
|
// channel was previously used for a mem2mem transfer.
|
||||||
|
#[cfg(gdma)]
|
||||||
|
R::set_mem2mem_mode(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn prepare_transfer_without_start(
|
unsafe fn prepare_transfer_without_start(
|
||||||
|
|||||||
@ -38,7 +38,8 @@ fn main() -> ! {
|
|||||||
#[cfg(not(any(feature = "esp32c2", feature = "esp32c3", feature = "esp32s3")))]
|
#[cfg(not(any(feature = "esp32c2", feature = "esp32c3", feature = "esp32s3")))]
|
||||||
let dma_peripheral = peripherals.MEM2MEM1;
|
let dma_peripheral = peripherals.MEM2MEM1;
|
||||||
|
|
||||||
let mut mem2mem = Mem2Mem::new(channel, dma_peripheral, tx_descriptors, rx_descriptors);
|
let mut mem2mem =
|
||||||
|
Mem2Mem::new(channel, dma_peripheral, tx_descriptors, rx_descriptors).unwrap();
|
||||||
|
|
||||||
for i in 0..core::mem::size_of_val(tx_buffer) {
|
for i in 0..core::mem::size_of_val(tx_buffer) {
|
||||||
tx_buffer[i] = (i % 256) as u8;
|
tx_buffer[i] = (i % 256) as u8;
|
||||||
|
|||||||
@ -24,6 +24,10 @@ harness = false
|
|||||||
name = "delay"
|
name = "delay"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "dma_macros"
|
||||||
|
harness = false
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "dma_mem2mem"
|
name = "dma_mem2mem"
|
||||||
harness = false
|
harness = false
|
||||||
|
|||||||
205
hil-test/tests/dma_macros.rs
Normal file
205
hil-test/tests/dma_macros.rs
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
//! DMA Mem2Mem Tests
|
||||||
|
|
||||||
|
//% CHIPS: esp32s3 esp32c2 esp32c3 esp32c6 esp32h2
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use defmt_rtt as _;
|
||||||
|
use esp_backtrace as _;
|
||||||
|
|
||||||
|
const DATA_SIZE: usize = 1024 * 10;
|
||||||
|
|
||||||
|
pub(crate) const fn compute_size(size: usize, chunk_size: usize) -> usize {
|
||||||
|
size.div_ceil(chunk_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) const fn compute_circular_size(size: usize, chunk_size: usize) -> usize {
|
||||||
|
if size > chunk_size * 2 {
|
||||||
|
size.div_ceil(chunk_size)
|
||||||
|
} else {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[embedded_test::tests]
|
||||||
|
mod tests {
|
||||||
|
use defmt::assert_eq;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[init]
|
||||||
|
fn init() {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dma_descriptors_same_size() {
|
||||||
|
use esp_hal::dma::CHUNK_SIZE;
|
||||||
|
let (tx_descriptors, rx_descriptors) = esp_hal::dma_descriptors!(DATA_SIZE);
|
||||||
|
assert_eq!(tx_descriptors.len(), rx_descriptors.len());
|
||||||
|
assert_eq!(tx_descriptors.len(), compute_size(DATA_SIZE, CHUNK_SIZE));
|
||||||
|
assert_eq!(rx_descriptors.len(), compute_size(DATA_SIZE, CHUNK_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dma_descriptors_different_size() {
|
||||||
|
use esp_hal::dma::CHUNK_SIZE;
|
||||||
|
const TX_SIZE: usize = DATA_SIZE;
|
||||||
|
const RX_SIZE: usize = DATA_SIZE / 2;
|
||||||
|
let (tx_descriptors, rx_descriptors) = esp_hal::dma_descriptors!(TX_SIZE, RX_SIZE);
|
||||||
|
assert_eq!(tx_descriptors.len(), compute_size(TX_SIZE, CHUNK_SIZE));
|
||||||
|
assert_eq!(rx_descriptors.len(), compute_size(RX_SIZE, CHUNK_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dma_circular_descriptors_same_size() {
|
||||||
|
use esp_hal::dma::CHUNK_SIZE;
|
||||||
|
let (tx_descriptors, rx_descriptors) = esp_hal::dma_circular_descriptors!(DATA_SIZE);
|
||||||
|
assert_eq!(tx_descriptors.len(), rx_descriptors.len());
|
||||||
|
assert_eq!(
|
||||||
|
tx_descriptors.len(),
|
||||||
|
compute_circular_size(DATA_SIZE, CHUNK_SIZE)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
rx_descriptors.len(),
|
||||||
|
compute_circular_size(DATA_SIZE, CHUNK_SIZE)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dma_circular_descriptors_different_size() {
|
||||||
|
use esp_hal::dma::CHUNK_SIZE;
|
||||||
|
const TX_SIZE: usize = CHUNK_SIZE * 2;
|
||||||
|
const RX_SIZE: usize = DATA_SIZE / 2;
|
||||||
|
let (tx_descriptors, rx_descriptors) = esp_hal::dma_circular_descriptors!(TX_SIZE, RX_SIZE);
|
||||||
|
assert_eq!(
|
||||||
|
tx_descriptors.len(),
|
||||||
|
compute_circular_size(TX_SIZE, CHUNK_SIZE)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
rx_descriptors.len(),
|
||||||
|
compute_circular_size(RX_SIZE, CHUNK_SIZE)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dma_buffers_same_size() {
|
||||||
|
use esp_hal::dma::CHUNK_SIZE;
|
||||||
|
let (tx_buffer, tx_descriptors, rx_buffer, rx_descriptors) =
|
||||||
|
esp_hal::dma_buffers!(DATA_SIZE);
|
||||||
|
assert_eq!(tx_buffer.len(), DATA_SIZE);
|
||||||
|
assert_eq!(rx_buffer.len(), DATA_SIZE);
|
||||||
|
assert_eq!(tx_descriptors.len(), rx_descriptors.len());
|
||||||
|
assert_eq!(tx_descriptors.len(), compute_size(DATA_SIZE, CHUNK_SIZE));
|
||||||
|
assert_eq!(rx_descriptors.len(), compute_size(DATA_SIZE, CHUNK_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dma_buffers_different_size() {
|
||||||
|
use esp_hal::dma::CHUNK_SIZE;
|
||||||
|
const TX_SIZE: usize = DATA_SIZE;
|
||||||
|
const RX_SIZE: usize = DATA_SIZE / 2;
|
||||||
|
|
||||||
|
let (tx_buffer, tx_descriptors, rx_buffer, rx_descriptors) =
|
||||||
|
esp_hal::dma_buffers!(TX_SIZE, RX_SIZE);
|
||||||
|
assert_eq!(tx_buffer.len(), TX_SIZE);
|
||||||
|
assert_eq!(rx_buffer.len(), RX_SIZE);
|
||||||
|
assert_eq!(tx_descriptors.len(), compute_size(TX_SIZE, CHUNK_SIZE));
|
||||||
|
assert_eq!(rx_descriptors.len(), compute_size(RX_SIZE, CHUNK_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dma_circular_buffers_same_size() {
|
||||||
|
use esp_hal::dma::CHUNK_SIZE;
|
||||||
|
let (tx_buffer, tx_descriptors, rx_buffer, rx_descriptors) =
|
||||||
|
esp_hal::dma_circular_buffers!(DATA_SIZE);
|
||||||
|
assert_eq!(tx_buffer.len(), DATA_SIZE);
|
||||||
|
assert_eq!(rx_buffer.len(), DATA_SIZE);
|
||||||
|
assert_eq!(tx_descriptors.len(), rx_descriptors.len());
|
||||||
|
assert_eq!(
|
||||||
|
tx_descriptors.len(),
|
||||||
|
compute_circular_size(DATA_SIZE, CHUNK_SIZE)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
rx_descriptors.len(),
|
||||||
|
compute_circular_size(DATA_SIZE, CHUNK_SIZE)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dma_circular_buffers_different_size() {
|
||||||
|
use esp_hal::dma::CHUNK_SIZE;
|
||||||
|
const TX_SIZE: usize = CHUNK_SIZE * 4;
|
||||||
|
const RX_SIZE: usize = CHUNK_SIZE * 2;
|
||||||
|
let (tx_buffer, tx_descriptors, rx_buffer, rx_descriptors) =
|
||||||
|
esp_hal::dma_circular_buffers!(TX_SIZE, RX_SIZE);
|
||||||
|
assert_eq!(tx_buffer.len(), TX_SIZE);
|
||||||
|
assert_eq!(rx_buffer.len(), RX_SIZE);
|
||||||
|
assert_eq!(
|
||||||
|
tx_descriptors.len(),
|
||||||
|
compute_circular_size(TX_SIZE, CHUNK_SIZE)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
rx_descriptors.len(),
|
||||||
|
compute_circular_size(RX_SIZE, CHUNK_SIZE)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dma_descriptors_chunk_size_same_size() {
|
||||||
|
const CHUNK_SIZE: usize = 2048;
|
||||||
|
let (tx_descriptors, rx_descriptors) =
|
||||||
|
esp_hal::dma_descriptors_chunk_size!(DATA_SIZE, CHUNK_SIZE);
|
||||||
|
assert_eq!(tx_descriptors.len(), rx_descriptors.len());
|
||||||
|
assert_eq!(tx_descriptors.len(), compute_size(DATA_SIZE, CHUNK_SIZE));
|
||||||
|
assert_eq!(rx_descriptors.len(), compute_size(DATA_SIZE, CHUNK_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dma_descriptors_chunk_size_different_size() {
|
||||||
|
const CHUNK_SIZE: usize = 2048;
|
||||||
|
const TX_SIZE: usize = DATA_SIZE;
|
||||||
|
const RX_SIZE: usize = DATA_SIZE / 2;
|
||||||
|
let (tx_descriptors, rx_descriptors) =
|
||||||
|
esp_hal::dma_descriptors_chunk_size!(TX_SIZE, RX_SIZE, CHUNK_SIZE);
|
||||||
|
assert_eq!(tx_descriptors.len(), compute_size(TX_SIZE, CHUNK_SIZE));
|
||||||
|
assert_eq!(rx_descriptors.len(), compute_size(RX_SIZE, CHUNK_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dma_circular_buffers_chunk_size_same_size() {
|
||||||
|
const CHUNK_SIZE: usize = 2048;
|
||||||
|
let (tx_buffer, tx_descriptors, rx_buffer, rx_descriptors) =
|
||||||
|
esp_hal::dma_circular_buffers_chunk_size!(DATA_SIZE, CHUNK_SIZE);
|
||||||
|
assert_eq!(tx_buffer.len(), DATA_SIZE);
|
||||||
|
assert_eq!(rx_buffer.len(), DATA_SIZE);
|
||||||
|
assert_eq!(tx_descriptors.len(), rx_descriptors.len());
|
||||||
|
assert_eq!(
|
||||||
|
tx_descriptors.len(),
|
||||||
|
compute_circular_size(DATA_SIZE, CHUNK_SIZE)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
rx_descriptors.len(),
|
||||||
|
compute_circular_size(DATA_SIZE, CHUNK_SIZE)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dma_circular_buffers_chunk_size_different_size() {
|
||||||
|
const CHUNK_SIZE: usize = 2048;
|
||||||
|
const TX_SIZE: usize = DATA_SIZE;
|
||||||
|
const RX_SIZE: usize = DATA_SIZE / 2;
|
||||||
|
let (tx_buffer, tx_descriptors, rx_buffer, rx_descriptors) =
|
||||||
|
esp_hal::dma_circular_buffers_chunk_size!(TX_SIZE, RX_SIZE, CHUNK_SIZE);
|
||||||
|
assert_eq!(tx_buffer.len(), TX_SIZE);
|
||||||
|
assert_eq!(rx_buffer.len(), RX_SIZE);
|
||||||
|
assert_eq!(
|
||||||
|
tx_descriptors.len(),
|
||||||
|
compute_circular_size(TX_SIZE, CHUNK_SIZE)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
rx_descriptors.len(),
|
||||||
|
compute_circular_size(RX_SIZE, CHUNK_SIZE)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,8 +9,10 @@ use defmt_rtt as _;
|
|||||||
use esp_backtrace as _;
|
use esp_backtrace as _;
|
||||||
use esp_hal::{
|
use esp_hal::{
|
||||||
clock::ClockControl,
|
clock::ClockControl,
|
||||||
dma::{Dma, DmaPriority, Mem2Mem},
|
dma::{Dma, DmaError, DmaPriority, Mem2Mem},
|
||||||
dma_buffers,
|
dma_buffers,
|
||||||
|
dma_buffers_chunk_size,
|
||||||
|
dma_descriptors,
|
||||||
peripherals::Peripherals,
|
peripherals::Peripherals,
|
||||||
system::SystemControl,
|
system::SystemControl,
|
||||||
};
|
};
|
||||||
@ -42,18 +44,160 @@ mod tests {
|
|||||||
#[cfg(not(any(feature = "esp32c2", feature = "esp32c3", feature = "esp32s3")))]
|
#[cfg(not(any(feature = "esp32c2", feature = "esp32c3", feature = "esp32s3")))]
|
||||||
let dma_peripheral = peripherals.MEM2MEM1;
|
let dma_peripheral = peripherals.MEM2MEM1;
|
||||||
|
|
||||||
let mut mem2mem = Mem2Mem::new(channel, dma_peripheral, tx_descriptors, rx_descriptors);
|
let mut mem2mem =
|
||||||
|
Mem2Mem::new(channel, dma_peripheral, tx_descriptors, rx_descriptors).unwrap();
|
||||||
|
|
||||||
for i in 0..core::mem::size_of_val(tx_buffer) {
|
for i in 0..core::mem::size_of_val(tx_buffer) {
|
||||||
tx_buffer[i] = (i % 256) as u8;
|
tx_buffer[i] = (i % 256) as u8;
|
||||||
}
|
}
|
||||||
let dma_wait = mem2mem.start_transfer(&tx_buffer, &mut rx_buffer).unwrap();
|
let dma_wait = mem2mem.start_transfer(&tx_buffer, &mut rx_buffer).unwrap();
|
||||||
dma_wait.wait().unwrap();
|
dma_wait.wait().unwrap();
|
||||||
// explicitly drop to insure the mem2mem bit is not left set as this causes
|
|
||||||
// subsequent dma tests to fail.
|
|
||||||
drop(mem2mem);
|
|
||||||
for i in 0..core::mem::size_of_val(tx_buffer) {
|
for i in 0..core::mem::size_of_val(tx_buffer) {
|
||||||
assert_eq!(rx_buffer[i], tx_buffer[i]);
|
assert_eq!(rx_buffer[i], tx_buffer[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_internal_mem2mem_chunk_size() {
|
||||||
|
const CHUNK_SIZE: usize = 2048;
|
||||||
|
let peripherals = Peripherals::take();
|
||||||
|
let system = SystemControl::new(peripherals.SYSTEM);
|
||||||
|
let _clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||||
|
|
||||||
|
let (tx_buffer, tx_descriptors, mut rx_buffer, rx_descriptors) =
|
||||||
|
dma_buffers_chunk_size!(DATA_SIZE, CHUNK_SIZE);
|
||||||
|
|
||||||
|
let dma = Dma::new(peripherals.DMA);
|
||||||
|
let channel = dma.channel0.configure(false, DmaPriority::Priority0);
|
||||||
|
#[cfg(any(feature = "esp32c2", feature = "esp32c3", feature = "esp32s3"))]
|
||||||
|
let dma_peripheral = peripherals.SPI2;
|
||||||
|
#[cfg(not(any(feature = "esp32c2", feature = "esp32c3", feature = "esp32s3")))]
|
||||||
|
let dma_peripheral = peripherals.MEM2MEM1;
|
||||||
|
|
||||||
|
let mut mem2mem = Mem2Mem::new_with_chunk_size(
|
||||||
|
channel,
|
||||||
|
dma_peripheral,
|
||||||
|
tx_descriptors,
|
||||||
|
rx_descriptors,
|
||||||
|
CHUNK_SIZE,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
for i in 0..core::mem::size_of_val(tx_buffer) {
|
||||||
|
tx_buffer[i] = (i % 256) as u8;
|
||||||
|
}
|
||||||
|
let dma_wait = mem2mem.start_transfer(&tx_buffer, &mut rx_buffer).unwrap();
|
||||||
|
dma_wait.wait().unwrap();
|
||||||
|
for i in 0..core::mem::size_of_val(tx_buffer) {
|
||||||
|
assert_eq!(rx_buffer[i], tx_buffer[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mem2mem_errors_zero_tx() {
|
||||||
|
use esp_hal::dma::CHUNK_SIZE;
|
||||||
|
|
||||||
|
let peripherals = Peripherals::take();
|
||||||
|
let system = SystemControl::new(peripherals.SYSTEM);
|
||||||
|
let _clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||||
|
|
||||||
|
let dma = Dma::new(peripherals.DMA);
|
||||||
|
let channel = dma.channel0.configure(false, DmaPriority::Priority0);
|
||||||
|
#[cfg(any(feature = "esp32c2", feature = "esp32c3", feature = "esp32s3"))]
|
||||||
|
let dma_peripheral = peripherals.SPI2;
|
||||||
|
#[cfg(not(any(feature = "esp32c2", feature = "esp32c3", feature = "esp32s3")))]
|
||||||
|
let dma_peripheral = peripherals.MEM2MEM1;
|
||||||
|
|
||||||
|
let (tx_descriptors, rx_descriptors) = dma_descriptors!(0, 1024);
|
||||||
|
match Mem2Mem::new_with_chunk_size(
|
||||||
|
channel,
|
||||||
|
dma_peripheral,
|
||||||
|
tx_descriptors,
|
||||||
|
rx_descriptors,
|
||||||
|
CHUNK_SIZE,
|
||||||
|
) {
|
||||||
|
Err(DmaError::OutOfDescriptors) => (),
|
||||||
|
_ => panic!("Expected OutOfDescriptors"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mem2mem_errors_zero_rx() {
|
||||||
|
use esp_hal::dma::CHUNK_SIZE;
|
||||||
|
|
||||||
|
let peripherals = Peripherals::take();
|
||||||
|
let system = SystemControl::new(peripherals.SYSTEM);
|
||||||
|
let _clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||||
|
|
||||||
|
let dma = Dma::new(peripherals.DMA);
|
||||||
|
let channel = dma.channel0.configure(false, DmaPriority::Priority0);
|
||||||
|
#[cfg(any(feature = "esp32c2", feature = "esp32c3", feature = "esp32s3"))]
|
||||||
|
let dma_peripheral = peripherals.SPI2;
|
||||||
|
#[cfg(not(any(feature = "esp32c2", feature = "esp32c3", feature = "esp32s3")))]
|
||||||
|
let dma_peripheral = peripherals.MEM2MEM1;
|
||||||
|
|
||||||
|
let (tx_descriptors, rx_descriptors) = dma_descriptors!(1024, 0);
|
||||||
|
match Mem2Mem::new_with_chunk_size(
|
||||||
|
channel,
|
||||||
|
dma_peripheral,
|
||||||
|
tx_descriptors,
|
||||||
|
rx_descriptors,
|
||||||
|
CHUNK_SIZE,
|
||||||
|
) {
|
||||||
|
Err(DmaError::OutOfDescriptors) => (),
|
||||||
|
_ => panic!("Expected OutOfDescriptors"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mem2mem_errors_chunk_size_too_small() {
|
||||||
|
let peripherals = Peripherals::take();
|
||||||
|
let system = SystemControl::new(peripherals.SYSTEM);
|
||||||
|
let _clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||||
|
|
||||||
|
let dma = Dma::new(peripherals.DMA);
|
||||||
|
let channel = dma.channel0.configure(false, DmaPriority::Priority0);
|
||||||
|
#[cfg(any(feature = "esp32c2", feature = "esp32c3", feature = "esp32s3"))]
|
||||||
|
let dma_peripheral = peripherals.SPI2;
|
||||||
|
#[cfg(not(any(feature = "esp32c2", feature = "esp32c3", feature = "esp32s3")))]
|
||||||
|
let dma_peripheral = peripherals.MEM2MEM1;
|
||||||
|
|
||||||
|
let (tx_descriptors, rx_descriptors) = dma_descriptors!(1024, 1024);
|
||||||
|
match Mem2Mem::new_with_chunk_size(
|
||||||
|
channel,
|
||||||
|
dma_peripheral,
|
||||||
|
tx_descriptors,
|
||||||
|
rx_descriptors,
|
||||||
|
0,
|
||||||
|
) {
|
||||||
|
Err(DmaError::InvalidChunkSize) => (),
|
||||||
|
_ => panic!("Expected InvalidChunkSize"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mem2mem_errors_chunk_size_too_big() {
|
||||||
|
let peripherals = Peripherals::take();
|
||||||
|
let system = SystemControl::new(peripherals.SYSTEM);
|
||||||
|
let _clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||||
|
|
||||||
|
let dma = Dma::new(peripherals.DMA);
|
||||||
|
let channel = dma.channel0.configure(false, DmaPriority::Priority0);
|
||||||
|
#[cfg(any(feature = "esp32c2", feature = "esp32c3", feature = "esp32s3"))]
|
||||||
|
let dma_peripheral = peripherals.SPI2;
|
||||||
|
#[cfg(not(any(feature = "esp32c2", feature = "esp32c3", feature = "esp32s3")))]
|
||||||
|
let dma_peripheral = peripherals.MEM2MEM1;
|
||||||
|
|
||||||
|
let (tx_descriptors, rx_descriptors) = dma_descriptors!(1024, 1024);
|
||||||
|
match Mem2Mem::new_with_chunk_size(
|
||||||
|
channel,
|
||||||
|
dma_peripheral,
|
||||||
|
tx_descriptors,
|
||||||
|
rx_descriptors,
|
||||||
|
4093,
|
||||||
|
) {
|
||||||
|
Err(DmaError::InvalidChunkSize) => (),
|
||||||
|
_ => panic!("Expected InvalidChunkSize"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user