aboutsummaryrefslogtreecommitdiff
path: root/examples/mcxa/src
diff options
context:
space:
mode:
authorJames Munns <[email protected]>2025-12-09 15:52:12 +0100
committerJames Munns <[email protected]>2025-12-09 15:52:12 +0100
commite962f5568a9f6433dcd6ad3e41d3faabb8b7c552 (patch)
tree0bcf67cbd0d53039580042b856e1b9dd58a528aa /examples/mcxa/src
parent4386b39e2516c453966d894b4fd265fae9d82c1a (diff)
Clean up remaining examples, move some to "raw" examples
Diffstat (limited to 'examples/mcxa/src')
-rw-r--r--examples/mcxa/src/bin/dma_scatter_gather_builder.rs6
-rw-r--r--examples/mcxa/src/bin/raw_dma_channel_link.rs (renamed from examples/mcxa/src/bin/dma_channel_link.rs)124
-rw-r--r--examples/mcxa/src/bin/raw_dma_interleave_transfer.rs (renamed from examples/mcxa/src/bin/dma_interleave_transfer.rs)50
-rw-r--r--examples/mcxa/src/bin/raw_dma_memset.rs (renamed from examples/mcxa/src/bin/dma_memset.rs)4
-rw-r--r--examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs (renamed from examples/mcxa/src/bin/dma_ping_pong_transfer.rs)176
-rw-r--r--examples/mcxa/src/bin/raw_dma_scatter_gather.rs (renamed from examples/mcxa/src/bin/dma_scatter_gather.rs)98
6 files changed, 127 insertions, 331 deletions
diff --git a/examples/mcxa/src/bin/dma_scatter_gather_builder.rs b/examples/mcxa/src/bin/dma_scatter_gather_builder.rs
index 1691129f6..30ce20c96 100644
--- a/examples/mcxa/src/bin/dma_scatter_gather_builder.rs
+++ b/examples/mcxa/src/bin/dma_scatter_gather_builder.rs
@@ -112,11 +112,7 @@ async fn main(_spawner: Spawner) {
112 defmt::info!(" DST2: {=[?]}", dst2.as_slice()); 112 defmt::info!(" DST2: {=[?]}", dst2.as_slice());
113 defmt::info!(" DST3: {=[?]}", dst3.as_slice()); 113 defmt::info!(" DST3: {=[?]}", dst3.as_slice());
114 114
115 let comps = [ 115 let comps = [(src1, dst1), (src2, dst2), (src3, dst3)];
116 (src1, dst1),
117 (src2, dst2),
118 (src3, dst3),
119 ];
120 116
121 // Verify all three segments 117 // Verify all three segments
122 let mut all_ok = true; 118 let mut all_ok = true;
diff --git a/examples/mcxa/src/bin/dma_channel_link.rs b/examples/mcxa/src/bin/raw_dma_channel_link.rs
index 2d757a636..987f1ba43 100644
--- a/examples/mcxa/src/bin/dma_channel_link.rs
+++ b/examples/mcxa/src/bin/raw_dma_channel_link.rs
@@ -1,5 +1,9 @@
1//! DMA channel linking example for MCXA276. 1//! DMA channel linking example for MCXA276.
2//! 2//!
3//! NOTE: this is a "raw dma" example! It exists as a proof of concept, as we don't have
4//! a high-level and safe API for. It should not be taken as typical, recommended, or
5//! stable usage!
6//!
3//! This example demonstrates DMA channel linking (minor and major loop linking): 7//! This example demonstrates DMA channel linking (minor and major loop linking):
4//! - Channel 0: Transfers SRC_BUFFER to DEST_BUFFER0, with: 8//! - Channel 0: Transfers SRC_BUFFER to DEST_BUFFER0, with:
5//! - Minor Link to Channel 1 (triggers CH1 after each minor loop) 9//! - Minor Link to Channel 1 (triggers CH1 after each minor loop)
@@ -16,25 +20,18 @@
16#![no_std] 20#![no_std]
17#![no_main] 21#![no_main]
18 22
19use core::fmt::Write as _;
20
21use embassy_executor::Spawner; 23use embassy_executor::Spawner;
22use embassy_mcxa::clocks::config::Div8; 24use embassy_mcxa::clocks::config::Div8;
23use embassy_mcxa::dma::DmaChannel; 25use embassy_mcxa::dma::DmaChannel;
24use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
25use embassy_mcxa::pac; 26use embassy_mcxa::pac;
27use static_cell::ConstStaticCell;
26use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 28use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
27 29
28// Buffers 30// Buffers
29static mut SRC_BUFFER: [u32; 4] = [1, 2, 3, 4]; 31static SRC_BUFFER: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([1, 2, 3, 4]);
30static mut DEST_BUFFER0: [u32; 4] = [0; 4]; 32static DEST_BUFFER0: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0; 4]);
31static mut DEST_BUFFER1: [u32; 4] = [0; 4]; 33static DEST_BUFFER1: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0; 4]);
32static mut DEST_BUFFER2: [u32; 4] = [0; 4]; 34static DEST_BUFFER2: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0; 4]);
33
34/// Helper to print a buffer to UART
35fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) {
36 write!(tx, "{:?}", unsafe { core::slice::from_raw_parts(buf_ptr, len) }).ok();
37}
38 35
39#[embassy_executor::main] 36#[embassy_executor::main]
40async fn main(_spawner: Spawner) { 37async fn main(_spawner: Spawner) {
@@ -77,42 +74,20 @@ async fn main(_spawner: Spawner) {
77 .normal_operation() 74 .normal_operation()
78 }); 75 });
79 76
80 let config = Config { 77 defmt::info!("EDMA channel link example begin.");
81 baudrate_bps: 115_200,
82 ..Default::default()
83 };
84
85 let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap();
86 let (mut tx, _rx) = lpuart.split();
87
88 tx.blocking_write(b"EDMA channel link example begin.\r\n\r\n").unwrap();
89 78
90 // Initialize buffers 79 // Initialize buffers
91 unsafe { 80 let src = SRC_BUFFER.take();
92 SRC_BUFFER = [1, 2, 3, 4]; 81 let dst0 = DEST_BUFFER0.take();
93 DEST_BUFFER0 = [0; 4]; 82 let dst1 = DEST_BUFFER1.take();
94 DEST_BUFFER1 = [0; 4]; 83 let dst2 = DEST_BUFFER2.take();
95 DEST_BUFFER2 = [0; 4];
96 }
97 84
98 tx.blocking_write(b"Source Buffer: ").unwrap(); 85 defmt::info!("Source Buffer: {=[?]}", src.as_slice());
99 print_buffer(&mut tx, core::ptr::addr_of!(SRC_BUFFER) as *const u32, 4); 86 defmt::info!("DEST0 (before): {=[?]}", dst0.as_slice());
100 tx.blocking_write(b"\r\n").unwrap(); 87 defmt::info!("DEST1 (before): {=[?]}", dst1.as_slice());
88 defmt::info!("DEST2 (before): {=[?]}", dst2.as_slice());
101 89
102 tx.blocking_write(b"DEST0 (before): ").unwrap(); 90 defmt::info!("Configuring DMA channels with Embassy-style API...");
103 print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER0) as *const u32, 4);
104 tx.blocking_write(b"\r\n").unwrap();
105
106 tx.blocking_write(b"DEST1 (before): ").unwrap();
107 print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER1) as *const u32, 4);
108 tx.blocking_write(b"\r\n").unwrap();
109
110 tx.blocking_write(b"DEST2 (before): ").unwrap();
111 print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER2) as *const u32, 4);
112 tx.blocking_write(b"\r\n\r\n").unwrap();
113
114 tx.blocking_write(b"Configuring DMA channels with Embassy-style API...\r\n")
115 .unwrap();
116 91
117 let ch0 = DmaChannel::new(p.DMA_CH0); 92 let ch0 = DmaChannel::new(p.DMA_CH0);
118 let ch1 = DmaChannel::new(p.DMA_CH1); 93 let ch1 = DmaChannel::new(p.DMA_CH1);
@@ -200,8 +175,8 @@ async fn main(_spawner: Spawner) {
200 configure_tcd( 175 configure_tcd(
201 edma, 176 edma,
202 0, 177 0,
203 core::ptr::addr_of!(SRC_BUFFER) as u32, 178 src.as_ptr() as u32,
204 core::ptr::addr_of_mut!(DEST_BUFFER0) as u32, 179 dst0.as_mut_ptr() as u32,
205 4, // src width 180 4, // src width
206 8, // nbytes (minor loop = 2 words) 181 8, // nbytes (minor loop = 2 words)
207 2, // count (major loop = 2 iterations) 182 2, // count (major loop = 2 iterations)
@@ -214,8 +189,8 @@ async fn main(_spawner: Spawner) {
214 configure_tcd( 189 configure_tcd(
215 edma, 190 edma,
216 1, 191 1,
217 core::ptr::addr_of!(SRC_BUFFER) as u32, 192 src.as_ptr() as u32,
218 core::ptr::addr_of_mut!(DEST_BUFFER1) as u32, 193 dst1.as_mut_ptr() as u32,
219 4, 194 4,
220 16, // full buffer in one minor loop 195 16, // full buffer in one minor loop
221 1, // 1 major iteration 196 1, // 1 major iteration
@@ -226,8 +201,8 @@ async fn main(_spawner: Spawner) {
226 configure_tcd( 201 configure_tcd(
227 edma, 202 edma,
228 2, 203 2,
229 core::ptr::addr_of!(SRC_BUFFER) as u32, 204 src.as_ptr() as u32,
230 core::ptr::addr_of_mut!(DEST_BUFFER2) as u32, 205 dst2.as_mut_ptr() as u32,
231 4, 206 4,
232 16, // full buffer in one minor loop 207 16, // full buffer in one minor loop
233 1, // 1 major iteration 208 1, // 1 major iteration
@@ -235,8 +210,7 @@ async fn main(_spawner: Spawner) {
235 ); 210 );
236 } 211 }
237 212
238 tx.blocking_write(b"Triggering Channel 0 (1st minor loop)...\r\n") 213 defmt::info!("Triggering Channel 0 (1st minor loop)...");
239 .unwrap();
240 214
241 // Trigger first minor loop of CH0 215 // Trigger first minor loop of CH0
242 unsafe { 216 unsafe {
@@ -251,9 +225,8 @@ async fn main(_spawner: Spawner) {
251 ch1.clear_done(); 225 ch1.clear_done();
252 } 226 }
253 227
254 tx.blocking_write(b"CH1 done (via minor link).\r\n").unwrap(); 228 defmt::info!("CH1 done (via minor link).");
255 tx.blocking_write(b"Triggering Channel 0 (2nd minor loop)...\r\n") 229 defmt::info!("Triggering Channel 0 (2nd minor loop)...");
256 .unwrap();
257 230
258 // Trigger second minor loop of CH0 231 // Trigger second minor loop of CH0
259 unsafe { 232 unsafe {
@@ -268,7 +241,7 @@ async fn main(_spawner: Spawner) {
268 ch0.clear_done(); 241 ch0.clear_done();
269 } 242 }
270 243
271 tx.blocking_write(b"CH0 major loop done.\r\n").unwrap(); 244 defmt::info!("CH0 major loop done.");
272 245
273 // Wait for CH2 to complete (triggered by CH0 major link) 246 // Wait for CH2 to complete (triggered by CH0 major link)
274 // Using is_done() instead of AtomicBool - the standard interrupt handler 247 // Using is_done() instead of AtomicBool - the standard interrupt handler
@@ -280,48 +253,23 @@ async fn main(_spawner: Spawner) {
280 ch2.clear_done(); 253 ch2.clear_done();
281 } 254 }
282 255
283 tx.blocking_write(b"CH2 done (via major link).\r\n\r\n").unwrap(); 256 defmt::info!("CH2 done (via major link).");
284
285 tx.blocking_write(b"EDMA channel link example finish.\r\n\r\n").unwrap();
286 257
287 tx.blocking_write(b"DEST0 (after): ").unwrap(); 258 defmt::info!("EDMA channel link example finish.");
288 print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER0) as *const u32, 4);
289 tx.blocking_write(b"\r\n").unwrap();
290 259
291 tx.blocking_write(b"DEST1 (after): ").unwrap(); 260 defmt::info!("DEST0 (after): {=[?]}", dst0.as_slice());
292 print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER1) as *const u32, 4); 261 defmt::info!("DEST1 (after): {=[?]}", dst1.as_slice());
293 tx.blocking_write(b"\r\n").unwrap(); 262 defmt::info!("DEST2 (after): {=[?]}", dst2.as_slice());
294
295 tx.blocking_write(b"DEST2 (after): ").unwrap();
296 print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER2) as *const u32, 4);
297 tx.blocking_write(b"\r\n\r\n").unwrap();
298 263
299 // Verify all buffers match source 264 // Verify all buffers match source
300 let mut success = true; 265 let mut success = true;
301 unsafe { 266 for sli in [dst0, dst1, dst2] {
302 let src_ptr = core::ptr::addr_of!(SRC_BUFFER) as *const u32; 267 success &= sli == src;
303 let dst0_ptr = core::ptr::addr_of!(DEST_BUFFER0) as *const u32;
304 let dst1_ptr = core::ptr::addr_of!(DEST_BUFFER1) as *const u32;
305 let dst2_ptr = core::ptr::addr_of!(DEST_BUFFER2) as *const u32;
306
307 for i in 0..4 {
308 if *dst0_ptr.add(i) != *src_ptr.add(i) {
309 success = false;
310 }
311 if *dst1_ptr.add(i) != *src_ptr.add(i) {
312 success = false;
313 }
314 if *dst2_ptr.add(i) != *src_ptr.add(i) {
315 success = false;
316 }
317 }
318 } 268 }
319 269
320 if success { 270 if success {
321 tx.blocking_write(b"PASS: Data verified.\r\n").unwrap();
322 defmt::info!("PASS: Data verified."); 271 defmt::info!("PASS: Data verified.");
323 } else { 272 } else {
324 tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap();
325 defmt::error!("FAIL: Mismatch detected!"); 273 defmt::error!("FAIL: Mismatch detected!");
326 } 274 }
327 275
diff --git a/examples/mcxa/src/bin/dma_interleave_transfer.rs b/examples/mcxa/src/bin/raw_dma_interleave_transfer.rs
index 03441fc32..a383b6cf4 100644
--- a/examples/mcxa/src/bin/dma_interleave_transfer.rs
+++ b/examples/mcxa/src/bin/raw_dma_interleave_transfer.rs
@@ -1,5 +1,9 @@
1//! DMA interleaved transfer example for MCXA276. 1//! DMA interleaved transfer example for MCXA276.
2//! 2//!
3//! NOTE: this is a "raw dma" example! It exists as a proof of concept, as we don't have
4//! a high-level and safe API for. It should not be taken as typical, recommended, or
5//! stable usage!
6//!
3//! This example demonstrates using DMA with custom source/destination offsets 7//! This example demonstrates using DMA with custom source/destination offsets
4//! to interleave data during transfer. 8//! to interleave data during transfer.
5//! 9//!
@@ -10,12 +14,9 @@
10#![no_std] 14#![no_std]
11#![no_main] 15#![no_main]
12 16
13use core::fmt::Write as _;
14
15use embassy_executor::Spawner; 17use embassy_executor::Spawner;
16use embassy_mcxa::clocks::config::Div8; 18use embassy_mcxa::clocks::config::Div8;
17use embassy_mcxa::dma::DmaChannel; 19use embassy_mcxa::dma::DmaChannel;
18use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
19use static_cell::ConstStaticCell; 20use static_cell::ConstStaticCell;
20use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 21use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
21 22
@@ -26,11 +27,6 @@ const HALF_BUFF_LENGTH: usize = BUFFER_LENGTH / 2;
26static SRC_BUFFER: ConstStaticCell<[u32; HALF_BUFF_LENGTH]> = ConstStaticCell::new([0; HALF_BUFF_LENGTH]); 27static SRC_BUFFER: ConstStaticCell<[u32; HALF_BUFF_LENGTH]> = ConstStaticCell::new([0; HALF_BUFF_LENGTH]);
27static DEST_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new([0; BUFFER_LENGTH]); 28static DEST_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new([0; BUFFER_LENGTH]);
28 29
29/// Helper to print a buffer to UART
30fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf: &[u32]) {
31 write!(tx, "{:?}", buf).ok();
32}
33
34#[embassy_executor::main] 30#[embassy_executor::main]
35async fn main(_spawner: Spawner) { 31async fn main(_spawner: Spawner) {
36 // Small delay to allow probe-rs to attach after reset 32 // Small delay to allow probe-rs to attach after reset
@@ -45,32 +41,17 @@ async fn main(_spawner: Spawner) {
45 41
46 defmt::info!("DMA interleave transfer example starting..."); 42 defmt::info!("DMA interleave transfer example starting...");
47 43
48 let config = Config { 44 defmt::info!("EDMA interleave transfer example begin.");
49 baudrate_bps: 115_200,
50 ..Default::default()
51 };
52
53 let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap();
54 let (mut tx, _rx) = lpuart.split();
55
56 tx.blocking_write(b"EDMA interleave transfer example begin.\r\n\r\n")
57 .unwrap();
58 45
59 // Initialize buffers 46 // Initialize buffers
60 let src = SRC_BUFFER.take(); 47 let src = SRC_BUFFER.take();
61 *src = [1, 2, 3, 4, 5, 6, 7, 8]; 48 *src = [1, 2, 3, 4, 5, 6, 7, 8];
62 let dst = DEST_BUFFER.take(); 49 let dst = DEST_BUFFER.take();
63 50
64 tx.blocking_write(b"Source Buffer: ").unwrap(); 51 defmt::info!("Source Buffer: {=[?]}", src.as_slice());
65 print_buffer(&mut tx, src); 52 defmt::info!("Destination Buffer (before): {=[?]}", dst.as_slice());
66 tx.blocking_write(b"\r\n").unwrap();
67
68 tx.blocking_write(b"Destination Buffer (before): ").unwrap();
69 print_buffer(&mut tx, dst);
70 tx.blocking_write(b"\r\n").unwrap();
71 53
72 tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n") 54 defmt::info!("Configuring DMA with Embassy-style API...");
73 .unwrap();
74 55
75 // Create DMA channel using Embassy-style API 56 // Create DMA channel using Embassy-style API
76 let dma_ch0 = DmaChannel::new(p.DMA_CH0); 57 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
@@ -129,7 +110,7 @@ async fn main(_spawner: Spawner) {
129 110
130 cortex_m::asm::dsb(); 111 cortex_m::asm::dsb();
131 112
132 tx.blocking_write(b"Triggering transfer...\r\n").unwrap(); 113 defmt::info!("Triggering transfer...");
133 dma_ch0.trigger_start(); 114 dma_ch0.trigger_start();
134 } 115 }
135 116
@@ -141,11 +122,8 @@ async fn main(_spawner: Spawner) {
141 dma_ch0.clear_done(); 122 dma_ch0.clear_done();
142 } 123 }
143 124
144 tx.blocking_write(b"\r\nEDMA interleave transfer example finish.\r\n\r\n") 125 defmt::info!("EDMA interleave transfer example finish.");
145 .unwrap(); 126 defmt::info!("Destination Buffer (after): {=[?]}", dst.as_slice());
146 tx.blocking_write(b"Destination Buffer (after): ").unwrap();
147 print_buffer(&mut tx, dst);
148 tx.blocking_write(b"\r\n\r\n").unwrap();
149 127
150 // Verify: Even indices should match SRC_BUFFER[i/2], odd indices should be 0 128 // Verify: Even indices should match SRC_BUFFER[i/2], odd indices should be 0
151 let mut mismatch = false; 129 let mut mismatch = false;
@@ -156,14 +134,8 @@ async fn main(_spawner: Spawner) {
156 } 134 }
157 135
158 if mismatch { 136 if mismatch {
159 tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap();
160 defmt::error!("FAIL: Mismatch detected!"); 137 defmt::error!("FAIL: Mismatch detected!");
161 } else { 138 } else {
162 tx.blocking_write(b"PASS: Data verified.\r\n").unwrap();
163 defmt::info!("PASS: Data verified."); 139 defmt::info!("PASS: Data verified.");
164 } 140 }
165
166 loop {
167 cortex_m::asm::wfe();
168 }
169} 141}
diff --git a/examples/mcxa/src/bin/dma_memset.rs b/examples/mcxa/src/bin/raw_dma_memset.rs
index d7b03e91b..7b3c06ffa 100644
--- a/examples/mcxa/src/bin/dma_memset.rs
+++ b/examples/mcxa/src/bin/raw_dma_memset.rs
@@ -1,5 +1,9 @@
1//! DMA memset example for MCXA276. 1//! DMA memset example for MCXA276.
2//! 2//!
3//! NOTE: this is a "raw dma" example! It exists as a proof of concept, as we don't have
4//! a high-level and safe API for. It should not be taken as typical, recommended, or
5//! stable usage!
6//!
3//! This example demonstrates using DMA to fill a buffer with a repeated pattern. 7//! This example demonstrates using DMA to fill a buffer with a repeated pattern.
4//! The source address stays fixed while the destination increments. 8//! The source address stays fixed while the destination increments.
5//! 9//!
diff --git a/examples/mcxa/src/bin/dma_ping_pong_transfer.rs b/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs
index 58f643b80..4a64b2498 100644
--- a/examples/mcxa/src/bin/dma_ping_pong_transfer.rs
+++ b/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs
@@ -1,5 +1,9 @@
1//! DMA ping-pong/double-buffer transfer example for MCXA276. 1//! DMA ping-pong/double-buffer transfer example for MCXA276.
2//! 2//!
3//! NOTE: this is a "raw dma" example! It exists as a proof of concept, as we don't have
4//! a high-level and safe API for. It should not be taken as typical, recommended, or
5//! stable usage!
6//!
3//! This example demonstrates two approaches for ping-pong/double-buffering: 7//! This example demonstrates two approaches for ping-pong/double-buffering:
4//! 8//!
5//! ## Approach 1: Scatter/Gather with linked TCDs (manual) 9//! ## Approach 1: Scatter/Gather with linked TCDs (manual)
@@ -23,29 +27,28 @@
23#![no_std] 27#![no_std]
24#![no_main] 28#![no_main]
25 29
26use core::fmt::Write as _;
27use core::sync::atomic::{AtomicBool, Ordering}; 30use core::sync::atomic::{AtomicBool, Ordering};
28 31
29use embassy_executor::Spawner; 32use embassy_executor::Spawner;
30use embassy_mcxa::clocks::config::Div8; 33use embassy_mcxa::clocks::config::Div8;
31use embassy_mcxa::dma::{self, DmaChannel, Tcd, TransferOptions}; 34use embassy_mcxa::dma::{self, DmaChannel, Tcd, TransferOptions};
32use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
33use embassy_mcxa::{bind_interrupts, pac}; 35use embassy_mcxa::{bind_interrupts, pac};
36use static_cell::ConstStaticCell;
34use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 37use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
35 38
36// Source and destination buffers for Approach 1 (scatter/gather) 39// Source and destination buffers for Approach 1 (scatter/gather)
37static mut SRC: [u32; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; 40static SRC: ConstStaticCell<[u32; 8]> = ConstStaticCell::new([1, 2, 3, 4, 5, 6, 7, 8]);
38static mut DST: [u32; 8] = [0; 8]; 41static DST: ConstStaticCell<[u32; 8]> = ConstStaticCell::new([0; 8]);
39 42
40// Source and destination buffers for Approach 2 (wait_half) 43// Source and destination buffers for Approach 2 (wait_half)
41static mut SRC2: [u32; 8] = [0xA1, 0xA2, 0xA3, 0xA4, 0xB1, 0xB2, 0xB3, 0xB4]; 44static SRC2: ConstStaticCell<[u32; 8]> = ConstStaticCell::new([0xA1, 0xA2, 0xA3, 0xA4, 0xB1, 0xB2, 0xB3, 0xB4]);
42static mut DST2: [u32; 8] = [0; 8]; 45static DST2: ConstStaticCell<[u32; 8]> = ConstStaticCell::new([0; 8]);
43 46
44// TCD pool for scatter/gather - must be 32-byte aligned 47// TCD pool for scatter/gather - must be 32-byte aligned
45#[repr(C, align(32))] 48#[repr(C, align(32))]
46struct TcdPool([Tcd; 2]); 49struct TcdPool([Tcd; 2]);
47 50
48static mut TCD_POOL: TcdPool = TcdPool( 51static TCD_POOL: ConstStaticCell<TcdPool> = ConstStaticCell::new(TcdPool(
49 [Tcd { 52 [Tcd {
50 saddr: 0, 53 saddr: 0,
51 soff: 0, 54 soff: 0,
@@ -59,7 +62,7 @@ static mut TCD_POOL: TcdPool = TcdPool(
59 csr: 0, 62 csr: 0,
60 biter: 0, 63 biter: 0,
61 }; 2], 64 }; 2],
62); 65));
63 66
64// AtomicBool to track scatter/gather completion 67// AtomicBool to track scatter/gather completion
65// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, 68// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads,
@@ -87,11 +90,6 @@ bind_interrupts!(struct Irqs {
87 DMA_CH0 => PingPongDmaHandler; 90 DMA_CH0 => PingPongDmaHandler;
88}); 91});
89 92
90/// Helper to print a buffer to UART
91fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) {
92 write!(tx, "{:?}", unsafe { core::slice::from_raw_parts(buf_ptr, len) }).ok();
93}
94
95#[embassy_executor::main] 93#[embassy_executor::main]
96async fn main(_spawner: Spawner) { 94async fn main(_spawner: Spawner) {
97 // Small delay to allow probe-rs to attach after reset 95 // Small delay to allow probe-rs to attach after reset
@@ -106,38 +104,16 @@ async fn main(_spawner: Spawner) {
106 104
107 defmt::info!("DMA ping-pong transfer example starting..."); 105 defmt::info!("DMA ping-pong transfer example starting...");
108 106
109 // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) 107 defmt::info!("EDMA ping-pong transfer example begin.");
110 unsafe {
111 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
112 }
113
114 let config = Config {
115 baudrate_bps: 115_200,
116 ..Default::default()
117 };
118
119 let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap();
120 let (mut tx, _rx) = lpuart.split();
121
122 tx.blocking_write(b"EDMA ping-pong transfer example begin.\r\n\r\n")
123 .unwrap();
124 108
125 // Initialize buffers 109 // Initialize buffers
126 unsafe { 110 let src = SRC.take();
127 SRC = [1, 2, 3, 4, 5, 6, 7, 8]; 111 let dst = DST.take();
128 DST = [0; 8];
129 }
130
131 tx.blocking_write(b"Source Buffer: ").unwrap();
132 print_buffer(&mut tx, core::ptr::addr_of!(SRC) as *const u32, 8);
133 tx.blocking_write(b"\r\n").unwrap();
134 112
135 tx.blocking_write(b"Destination Buffer (before): ").unwrap(); 113 defmt::info!("Source Buffer: {=[?]}", src.as_slice());
136 print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); 114 defmt::info!("Destination Buffer (before): {=[?]}", dst.as_slice());
137 tx.blocking_write(b"\r\n").unwrap();
138 115
139 tx.blocking_write(b"Configuring ping-pong DMA with Embassy-style API...\r\n") 116 defmt::info!("Configuring ping-pong DMA with Embassy-style API...");
140 .unwrap();
141 117
142 let dma_ch0 = DmaChannel::new(p.DMA_CH0); 118 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
143 119
@@ -146,9 +122,7 @@ async fn main(_spawner: Spawner) {
146 // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), links to TCD1. 122 // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), links to TCD1.
147 // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), links to TCD0. 123 // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), links to TCD0.
148 unsafe { 124 unsafe {
149 let tcds = &mut *core::ptr::addr_of_mut!(TCD_POOL.0); 125 let tcds = &mut TCD_POOL.take().0;
150 let src_ptr = core::ptr::addr_of!(SRC) as *const u32;
151 let dst_ptr = core::ptr::addr_of_mut!(DST) as *mut u32;
152 126
153 let half_len = 4usize; 127 let half_len = 4usize;
154 let half_bytes = (half_len * 4) as u32; 128 let half_bytes = (half_len * 4) as u32;
@@ -158,12 +132,12 @@ async fn main(_spawner: Spawner) {
158 132
159 // TCD0: First half -> Links to TCD1 133 // TCD0: First half -> Links to TCD1
160 tcds[0] = Tcd { 134 tcds[0] = Tcd {
161 saddr: src_ptr as u32, 135 saddr: src.as_ptr() as u32,
162 soff: 4, 136 soff: 4,
163 attr: 0x0202, // 32-bit src/dst 137 attr: 0x0202, // 32-bit src/dst
164 nbytes: half_bytes, 138 nbytes: half_bytes,
165 slast: 0, 139 slast: 0,
166 daddr: dst_ptr as u32, 140 daddr: dst.as_mut_ptr() as u32,
167 doff: 4, 141 doff: 4,
168 citer: 1, 142 citer: 1,
169 dlast_sga: tcd1_addr as i32, 143 dlast_sga: tcd1_addr as i32,
@@ -173,12 +147,12 @@ async fn main(_spawner: Spawner) {
173 147
174 // TCD1: Second half -> Links to TCD0 148 // TCD1: Second half -> Links to TCD0
175 tcds[1] = Tcd { 149 tcds[1] = Tcd {
176 saddr: src_ptr.add(half_len) as u32, 150 saddr: src.as_ptr().add(half_len) as u32,
177 soff: 4, 151 soff: 4,
178 attr: 0x0202, 152 attr: 0x0202,
179 nbytes: half_bytes, 153 nbytes: half_bytes,
180 slast: 0, 154 slast: 0,
181 daddr: dst_ptr.add(half_len) as u32, 155 daddr: dst.as_mut_ptr().add(half_len) as u32,
182 doff: 4, 156 doff: 4,
183 citer: 1, 157 citer: 1,
184 dlast_sga: tcd0_addr as i32, 158 dlast_sga: tcd0_addr as i32,
@@ -190,7 +164,7 @@ async fn main(_spawner: Spawner) {
190 dma_ch0.load_tcd(&tcds[0]); 164 dma_ch0.load_tcd(&tcds[0]);
191 } 165 }
192 166
193 tx.blocking_write(b"Triggering first half transfer...\r\n").unwrap(); 167 defmt::info!("Triggering first half transfer...");
194 168
195 // Trigger first transfer (first half: SRC[0..4] -> DST[0..4]) 169 // Trigger first transfer (first half: SRC[0..4] -> DST[0..4])
196 unsafe { 170 unsafe {
@@ -203,8 +177,8 @@ async fn main(_spawner: Spawner) {
203 } 177 }
204 TRANSFER_DONE.store(false, Ordering::Release); 178 TRANSFER_DONE.store(false, Ordering::Release);
205 179
206 tx.blocking_write(b"First half transferred.\r\n").unwrap(); 180 defmt::info!("First half transferred.");
207 tx.blocking_write(b"Triggering second half transfer...\r\n").unwrap(); 181 defmt::info!("Triggering second half transfer...");
208 182
209 // Trigger second transfer (second half: SRC[4..8] -> DST[4..8]) 183 // Trigger second transfer (second half: SRC[4..8] -> DST[4..8])
210 unsafe { 184 unsafe {
@@ -217,32 +191,17 @@ async fn main(_spawner: Spawner) {
217 } 191 }
218 TRANSFER_DONE.store(false, Ordering::Release); 192 TRANSFER_DONE.store(false, Ordering::Release);
219 193
220 tx.blocking_write(b"Second half transferred.\r\n\r\n").unwrap(); 194 defmt::info!("Second half transferred.");
221 195
222 tx.blocking_write(b"EDMA ping-pong transfer example finish.\r\n\r\n") 196 defmt::info!("EDMA ping-pong transfer example finish.");
223 .unwrap(); 197 defmt::info!("Destination Buffer (after): {=[?]}", dst.as_slice());
224 tx.blocking_write(b"Destination Buffer (after): ").unwrap();
225 print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8);
226 tx.blocking_write(b"\r\n\r\n").unwrap();
227 198
228 // Verify: DST should match SRC 199 // Verify: DST should match SRC
229 let mut mismatch = false; 200 let mismatch = src != dst;
230 unsafe {
231 let src_ptr = core::ptr::addr_of!(SRC) as *const u32;
232 let dst_ptr = core::ptr::addr_of!(DST) as *const u32;
233 for i in 0..8 {
234 if *src_ptr.add(i) != *dst_ptr.add(i) {
235 mismatch = true;
236 break;
237 }
238 }
239 }
240 201
241 if mismatch { 202 if mismatch {
242 tx.blocking_write(b"FAIL: Approach 1 mismatch detected!\r\n").unwrap();
243 defmt::error!("FAIL: Approach 1 mismatch detected!"); 203 defmt::error!("FAIL: Approach 1 mismatch detected!");
244 } else { 204 } else {
245 tx.blocking_write(b"PASS: Approach 1 data verified.\r\n\r\n").unwrap();
246 defmt::info!("PASS: Approach 1 data verified."); 205 defmt::info!("PASS: Approach 1 data verified.");
247 } 206 }
248 207
@@ -260,8 +219,7 @@ async fn main(_spawner: Spawner) {
260 // - True async/await support 219 // - True async/await support
261 // - Good for streaming data processing 220 // - Good for streaming data processing
262 221
263 tx.blocking_write(b"--- Approach 2: wait_half() demo ---\r\n\r\n") 222 defmt::info!("--- Approach 2: wait_half() demo ---");
264 .unwrap();
265 223
266 // Enable DMA CH1 interrupt 224 // Enable DMA CH1 interrupt
267 unsafe { 225 unsafe {
@@ -269,14 +227,10 @@ async fn main(_spawner: Spawner) {
269 } 227 }
270 228
271 // Initialize approach 2 buffers 229 // Initialize approach 2 buffers
272 unsafe { 230 let src2 = SRC2.take();
273 SRC2 = [0xA1, 0xA2, 0xA3, 0xA4, 0xB1, 0xB2, 0xB3, 0xB4]; 231 let dst2 = DST2.take();
274 DST2 = [0; 8];
275 }
276 232
277 tx.blocking_write(b"SRC2: ").unwrap(); 233 defmt::info!("SRC2: {=[?]}", src2.as_slice());
278 print_buffer(&mut tx, core::ptr::addr_of!(SRC2) as *const u32, 8);
279 tx.blocking_write(b"\r\n").unwrap();
280 234
281 let dma_ch1 = DmaChannel::new(p.DMA_CH1); 235 let dma_ch1 = DmaChannel::new(p.DMA_CH1);
282 236
@@ -285,63 +239,31 @@ async fn main(_spawner: Spawner) {
285 options.half_transfer_interrupt = true; // Enable half-transfer interrupt 239 options.half_transfer_interrupt = true; // Enable half-transfer interrupt
286 options.complete_transfer_interrupt = true; 240 options.complete_transfer_interrupt = true;
287 241
288 tx.blocking_write(b"Starting transfer with half_transfer_interrupt...\r\n") 242 defmt::info!("Starting transfer with half_transfer_interrupt...");
289 .unwrap();
290 243
291 unsafe { 244 // Create the transfer
292 let src = &*core::ptr::addr_of!(SRC2); 245 let mut transfer = dma_ch1.mem_to_mem(src2, dst2, options);
293 let dst = &mut *core::ptr::addr_of_mut!(DST2); 246
294 247 // Wait for half-transfer (first 4 elements)
295 // Create the transfer 248 defmt::info!("Waiting for first half...");
296 let mut transfer = dma_ch1.mem_to_mem(src, dst, options); 249 let _ok = transfer.wait_half().await;
297
298 // Wait for half-transfer (first 4 elements)
299 tx.blocking_write(b"Waiting for first half...\r\n").unwrap();
300 let half_ok = transfer.wait_half().await;
301
302 if half_ok {
303 tx.blocking_write(b"Half-transfer complete! First half of DST2: ")
304 .unwrap();
305 print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 4);
306 tx.blocking_write(b"\r\n").unwrap();
307 tx.blocking_write(b"(Processing first half while second half transfers...)\r\n")
308 .unwrap();
309 }
310
311 // Wait for complete transfer
312 tx.blocking_write(b"Waiting for second half...\r\n").unwrap();
313 transfer.await;
314 }
315 250
316 tx.blocking_write(b"Transfer complete! Full DST2: ").unwrap(); 251 defmt::info!("Half-transfer complete!");
317 print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 8); 252
318 tx.blocking_write(b"\r\n\r\n").unwrap(); 253 // Wait for complete transfer
254 defmt::info!("Waiting for second half...");
255 transfer.await;
256
257 defmt::info!("Transfer complete! Full DST2: {=[?]}", dst2.as_slice());
319 258
320 // Verify approach 2 259 // Verify approach 2
321 let mut mismatch2 = false; 260 let mismatch2 = src2 != dst2;
322 unsafe {
323 let src_ptr = core::ptr::addr_of!(SRC2) as *const u32;
324 let dst_ptr = core::ptr::addr_of!(DST2) as *const u32;
325 for i in 0..8 {
326 if *src_ptr.add(i) != *dst_ptr.add(i) {
327 mismatch2 = true;
328 break;
329 }
330 }
331 }
332 261
333 if mismatch2 { 262 if mismatch2 {
334 tx.blocking_write(b"FAIL: Approach 2 mismatch!\r\n").unwrap();
335 defmt::error!("FAIL: Approach 2 mismatch!"); 263 defmt::error!("FAIL: Approach 2 mismatch!");
336 } else { 264 } else {
337 tx.blocking_write(b"PASS: Approach 2 verified.\r\n").unwrap();
338 defmt::info!("PASS: Approach 2 verified."); 265 defmt::info!("PASS: Approach 2 verified.");
339 } 266 }
340 267
341 tx.blocking_write(b"\r\n=== All ping-pong demos complete ===\r\n") 268 defmt::info!("=== All ping-pong demos complete ===");
342 .unwrap();
343
344 loop {
345 cortex_m::asm::wfe();
346 }
347} 269}
diff --git a/examples/mcxa/src/bin/dma_scatter_gather.rs b/examples/mcxa/src/bin/raw_dma_scatter_gather.rs
index 3e34e95b1..057e56826 100644
--- a/examples/mcxa/src/bin/dma_scatter_gather.rs
+++ b/examples/mcxa/src/bin/raw_dma_scatter_gather.rs
@@ -1,5 +1,9 @@
1//! DMA scatter-gather transfer example for MCXA276. 1//! DMA scatter-gather transfer example for MCXA276.
2//! 2//!
3//! NOTE: this is a "raw dma" example! It exists as a proof of concept, as we don't have
4//! a high-level and safe API for. It should not be taken as typical, recommended, or
5//! stable usage!
6//!
3//! This example demonstrates using DMA with scatter/gather to chain multiple 7//! This example demonstrates using DMA with scatter/gather to chain multiple
4//! transfer descriptors. The first TCD transfers the first half of the buffer, 8//! transfer descriptors. The first TCD transfers the first half of the buffer,
5//! then automatically loads the second TCD to transfer the second half. 9//! then automatically loads the second TCD to transfer the second half.
@@ -12,25 +16,24 @@
12#![no_std] 16#![no_std]
13#![no_main] 17#![no_main]
14 18
15use core::fmt::Write as _;
16use core::sync::atomic::{AtomicBool, Ordering}; 19use core::sync::atomic::{AtomicBool, Ordering};
17 20
18use embassy_executor::Spawner; 21use embassy_executor::Spawner;
22use embassy_mcxa::bind_interrupts;
19use embassy_mcxa::clocks::config::Div8; 23use embassy_mcxa::clocks::config::Div8;
20use embassy_mcxa::dma::{self, DmaChannel, Tcd}; 24use embassy_mcxa::dma::{self, DmaChannel, Tcd};
21use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; 25use static_cell::ConstStaticCell;
22use embassy_mcxa::{bind_interrupts, pac};
23use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 26use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
24 27
25// Source and destination buffers 28// Source and destination buffers
26static mut SRC: [u32; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; 29static SRC: ConstStaticCell<[u32; 8]> = ConstStaticCell::new([1, 2, 3, 4, 5, 6, 7, 8]);
27static mut DST: [u32; 8] = [0; 8]; 30static DST: ConstStaticCell<[u32; 8]> = ConstStaticCell::new([0; 8]);
28 31
29// TCD pool for scatter/gather - must be 32-byte aligned 32// TCD pool for scatter/gather - must be 32-byte aligned
30#[repr(C, align(32))] 33#[repr(C, align(32))]
31struct TcdPool([Tcd; 2]); 34struct TcdPool([Tcd; 2]);
32 35
33static mut TCD_POOL: TcdPool = TcdPool( 36static TCD_POOL: ConstStaticCell<TcdPool> = ConstStaticCell::new(TcdPool(
34 [Tcd { 37 [Tcd {
35 saddr: 0, 38 saddr: 0,
36 soff: 0, 39 soff: 0,
@@ -44,7 +47,7 @@ static mut TCD_POOL: TcdPool = TcdPool(
44 csr: 0, 47 csr: 0,
45 biter: 0, 48 biter: 0,
46 }; 2], 49 }; 2],
47); 50));
48 51
49// AtomicBool to track scatter/gather completion 52// AtomicBool to track scatter/gather completion
50// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, 53// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads,
@@ -73,11 +76,6 @@ bind_interrupts!(struct Irqs {
73 DMA_CH0 => ScatterGatherDmaHandler; 76 DMA_CH0 => ScatterGatherDmaHandler;
74}); 77});
75 78
76/// Helper to print a buffer to UART
77fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) {
78 write!(tx, "{:?}", unsafe { core::slice::from_raw_parts(buf_ptr, len) }).ok();
79}
80
81#[embassy_executor::main] 79#[embassy_executor::main]
82async fn main(_spawner: Spawner) { 80async fn main(_spawner: Spawner) {
83 // Small delay to allow probe-rs to attach after reset 81 // Small delay to allow probe-rs to attach after reset
@@ -92,40 +90,15 @@ async fn main(_spawner: Spawner) {
92 90
93 defmt::info!("DMA scatter-gather transfer example starting..."); 91 defmt::info!("DMA scatter-gather transfer example starting...");
94 92
95 // DMA is initialized during hal::init() - no need to call ensure_init() 93 defmt::info!("EDMA scatter-gather transfer example begin.");
96
97 // Enable DMA interrupt
98 unsafe {
99 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
100 }
101
102 let config = Config {
103 baudrate_bps: 115_200,
104 ..Default::default()
105 };
106
107 let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap();
108 let (mut tx, _rx) = lpuart.split();
109
110 tx.blocking_write(b"EDMA scatter-gather transfer example begin.\r\n\r\n")
111 .unwrap();
112 94
113 // Initialize buffers 95 // Initialize buffers
114 unsafe { 96 let src = SRC.take();
115 SRC = [1, 2, 3, 4, 5, 6, 7, 8]; 97 let dst = DST.take();
116 DST = [0; 8];
117 }
118
119 tx.blocking_write(b"Source Buffer: ").unwrap();
120 print_buffer(&mut tx, core::ptr::addr_of!(SRC) as *const u32, 8);
121 tx.blocking_write(b"\r\n").unwrap();
122 98
123 tx.blocking_write(b"Destination Buffer (before): ").unwrap(); 99 defmt::info!("Source Buffer: {=[?]}", src.as_slice());
124 print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); 100 defmt::info!("Destination Buffer (before): {=[?]}", dst.as_slice());
125 tx.blocking_write(b"\r\n").unwrap(); 101 defmt::info!("Configuring scatter-gather DMA with Embassy-style API...");
126
127 tx.blocking_write(b"Configuring scatter-gather DMA with Embassy-style API...\r\n")
128 .unwrap();
129 102
130 let dma_ch0 = DmaChannel::new(p.DMA_CH0); 103 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
131 104
@@ -134,9 +107,9 @@ async fn main(_spawner: Spawner) {
134 // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), then loads TCD1. 107 // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), then loads TCD1.
135 // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), last TCD. 108 // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), last TCD.
136 unsafe { 109 unsafe {
137 let tcds = core::slice::from_raw_parts_mut(core::ptr::addr_of_mut!(TCD_POOL.0) as *mut Tcd, 2); 110 let tcds = &mut TCD_POOL.take().0;
138 let src_ptr = core::ptr::addr_of!(SRC) as *const u32; 111 let src_ptr = src.as_ptr();
139 let dst_ptr = core::ptr::addr_of_mut!(DST) as *mut u32; 112 let dst_ptr = dst.as_mut_ptr();
140 113
141 let num_tcds = 2usize; 114 let num_tcds = 2usize;
142 let chunk_len = 4usize; // 8 / 2 115 let chunk_len = 4usize; // 8 / 2
@@ -170,7 +143,7 @@ async fn main(_spawner: Spawner) {
170 dma_ch0.load_tcd(&tcds[0]); 143 dma_ch0.load_tcd(&tcds[0]);
171 } 144 }
172 145
173 tx.blocking_write(b"Triggering first half transfer...\r\n").unwrap(); 146 defmt::info!("Triggering first half transfer...");
174 147
175 // Trigger first transfer (first half: SRC[0..4] -> DST[0..4]) 148 // Trigger first transfer (first half: SRC[0..4] -> DST[0..4])
176 // TCD0 is currently loaded. 149 // TCD0 is currently loaded.
@@ -184,8 +157,8 @@ async fn main(_spawner: Spawner) {
184 } 157 }
185 TRANSFER_DONE.store(false, Ordering::Release); 158 TRANSFER_DONE.store(false, Ordering::Release);
186 159
187 tx.blocking_write(b"First half transferred.\r\n").unwrap(); 160 defmt::info!("First half transferred.");
188 tx.blocking_write(b"Triggering second half transfer...\r\n").unwrap(); 161 defmt::info!("Triggering second half transfer...");
189 162
190 // Trigger second transfer (second half: SRC[4..8] -> DST[4..8]) 163 // Trigger second transfer (second half: SRC[4..8] -> DST[4..8])
191 // TCD1 should have been loaded by the scatter/gather engine. 164 // TCD1 should have been loaded by the scatter/gather engine.
@@ -199,36 +172,17 @@ async fn main(_spawner: Spawner) {
199 } 172 }
200 TRANSFER_DONE.store(false, Ordering::Release); 173 TRANSFER_DONE.store(false, Ordering::Release);
201 174
202 tx.blocking_write(b"Second half transferred.\r\n\r\n").unwrap(); 175 defmt::info!("Second half transferred.");
203 176
204 tx.blocking_write(b"EDMA scatter-gather transfer example finish.\r\n\r\n") 177 defmt::info!("EDMA scatter-gather transfer example finish.");
205 .unwrap(); 178 defmt::info!("Destination Buffer (after): {=[?]}", dst.as_slice());
206 tx.blocking_write(b"Destination Buffer (after): ").unwrap();
207 print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8);
208 tx.blocking_write(b"\r\n\r\n").unwrap();
209 179
210 // Verify: DST should match SRC 180 // Verify: DST should match SRC
211 let mut mismatch = false; 181 let mismatch = src != dst;
212 unsafe {
213 let src_ptr = core::ptr::addr_of!(SRC) as *const u32;
214 let dst_ptr = core::ptr::addr_of!(DST) as *const u32;
215 for i in 0..8 {
216 if *src_ptr.add(i) != *dst_ptr.add(i) {
217 mismatch = true;
218 break;
219 }
220 }
221 }
222 182
223 if mismatch { 183 if mismatch {
224 tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap();
225 defmt::error!("FAIL: Mismatch detected!"); 184 defmt::error!("FAIL: Mismatch detected!");
226 } else { 185 } else {
227 tx.blocking_write(b"PASS: Data verified.\r\n").unwrap();
228 defmt::info!("PASS: Data verified."); 186 defmt::info!("PASS: Data verified.");
229 } 187 }
230
231 loop {
232 cortex_m::asm::wfe();
233 }
234} 188}