aboutsummaryrefslogtreecommitdiff
path: root/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs')
-rw-r--r--examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs55
1 files changed, 15 insertions, 40 deletions
diff --git a/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs b/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs
index 4a64b2498..51a7bc275 100644
--- a/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs
+++ b/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs
@@ -27,12 +27,10 @@
27#![no_std] 27#![no_std]
28#![no_main] 28#![no_main]
29 29
30use core::sync::atomic::{AtomicBool, Ordering};
31
32use embassy_executor::Spawner; 30use embassy_executor::Spawner;
33use embassy_mcxa::clocks::config::Div8; 31use embassy_mcxa::clocks::config::Div8;
34use embassy_mcxa::dma::{self, DmaChannel, Tcd, TransferOptions}; 32use embassy_mcxa::dma::{DmaChannel, Tcd, TransferOptions};
35use embassy_mcxa::{bind_interrupts, pac}; 33use embassy_mcxa::pac;
36use static_cell::ConstStaticCell; 34use static_cell::ConstStaticCell;
37use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 35use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
38 36
@@ -64,32 +62,6 @@ static TCD_POOL: ConstStaticCell<TcdPool> = ConstStaticCell::new(TcdPool(
64 }; 2], 62 }; 2],
65)); 63));
66 64
67// AtomicBool to track scatter/gather completion
68// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads,
69// so we need this flag to detect when each transfer completes
70static TRANSFER_DONE: AtomicBool = AtomicBool::new(false);
71
72// Custom handler for scatter/gather that delegates to HAL's on_interrupt()
73// This follows the "interrupts as threads" pattern - the handler does minimal work
74// (delegates to HAL + sets a flag) and the main task does the actual processing
75pub struct PingPongDmaHandler;
76
77impl embassy_mcxa::interrupt::typelevel::Handler<embassy_mcxa::interrupt::typelevel::DMA_CH0> for PingPongDmaHandler {
78 unsafe fn on_interrupt() {
79 // Delegate to HAL's on_interrupt() which clears INT flag and wakes wakers
80 dma::on_interrupt(0);
81 // Signal completion for polling (needed because ESG clears DONE bit)
82 TRANSFER_DONE.store(true, Ordering::Release);
83 }
84}
85
86// Bind DMA channel interrupts
87// CH0: Custom handler for scatter/gather (delegates to on_interrupt + sets flag)
88// CH1: Standard handler for wait_half() demo
89bind_interrupts!(struct Irqs {
90 DMA_CH0 => PingPongDmaHandler;
91});
92
93#[embassy_executor::main] 65#[embassy_executor::main]
94async fn main(_spawner: Spawner) { 66async fn main(_spawner: Spawner) {
95 // Small delay to allow probe-rs to attach after reset 67 // Small delay to allow probe-rs to attach after reset
@@ -121,12 +93,12 @@ async fn main(_spawner: Spawner) {
121 // This sets up TCD0 and TCD1 in RAM, and loads TCD0 into the channel. 93 // This sets up TCD0 and TCD1 in RAM, and loads TCD0 into the channel.
122 // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), links to TCD1. 94 // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), links to TCD1.
123 // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), links to TCD0. 95 // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), links to TCD0.
124 unsafe { 96 let tcds = &mut TCD_POOL.take().0;
125 let tcds = &mut TCD_POOL.take().0;
126 97
127 let half_len = 4usize; 98 let half_len = 4usize;
128 let half_bytes = (half_len * 4) as u32; 99 let half_bytes = (half_len * 4) as u32;
129 100
101 unsafe {
130 let tcd0_addr = &tcds[0] as *const _ as u32; 102 let tcd0_addr = &tcds[0] as *const _ as u32;
131 let tcd1_addr = &tcds[1] as *const _ as u32; 103 let tcd1_addr = &tcds[1] as *const _ as u32;
132 104
@@ -171,11 +143,13 @@ async fn main(_spawner: Spawner) {
171 dma_ch0.trigger_start(); 143 dma_ch0.trigger_start();
172 } 144 }
173 145
146 let tcd = dma_ch0.tcd();
174 // Wait for first half 147 // Wait for first half
175 while !TRANSFER_DONE.load(Ordering::Acquire) { 148 loop {
176 cortex_m::asm::nop(); 149 if tcd.tcd_saddr().read().bits() != src.as_ptr() as u32 {
150 break;
151 }
177 } 152 }
178 TRANSFER_DONE.store(false, Ordering::Release);
179 153
180 defmt::info!("First half transferred."); 154 defmt::info!("First half transferred.");
181 defmt::info!("Triggering second half transfer..."); 155 defmt::info!("Triggering second half transfer...");
@@ -186,10 +160,11 @@ async fn main(_spawner: Spawner) {
186 } 160 }
187 161
188 // Wait for second half 162 // Wait for second half
189 while !TRANSFER_DONE.load(Ordering::Acquire) { 163 loop {
190 cortex_m::asm::nop(); 164 if tcd.tcd_saddr().read().bits() != unsafe { src.as_ptr().add(half_len) } as u32 {
165 break;
166 }
191 } 167 }
192 TRANSFER_DONE.store(false, Ordering::Release);
193 168
194 defmt::info!("Second half transferred."); 169 defmt::info!("Second half transferred.");
195 170