aboutsummaryrefslogtreecommitdiff
path: root/examples/src/bin/dma_scatter_gather_builder.rs
diff options
context:
space:
mode:
Diffstat (limited to 'examples/src/bin/dma_scatter_gather_builder.rs')
-rw-r--r--examples/src/bin/dma_scatter_gather_builder.rs244
1 files changed, 244 insertions, 0 deletions
diff --git a/examples/src/bin/dma_scatter_gather_builder.rs b/examples/src/bin/dma_scatter_gather_builder.rs
new file mode 100644
index 000000000..078e26c60
--- /dev/null
+++ b/examples/src/bin/dma_scatter_gather_builder.rs
@@ -0,0 +1,244 @@
1//! DMA Scatter-Gather Builder example for MCXA276.
2//!
3//! This example demonstrates using the new `ScatterGatherBuilder` API for
4//! chaining multiple DMA transfers with a type-safe builder pattern.
5//!
6//! # Features demonstrated:
7//! - `ScatterGatherBuilder::new()` for creating a builder
8//! - `add_transfer()` for adding memory-to-memory segments
9//! - `build()` to start the chained transfer
10//! - Automatic TCD linking and ESG bit management
11//!
12//! # Comparison with manual scatter-gather:
13//! The manual approach (see `dma_scatter_gather.rs`) requires:
14//! - Manual TCD pool allocation and alignment
15//! - Manual CSR/ESG/INTMAJOR bit manipulation
16//! - Manual dlast_sga address calculations
17//!
18//! The builder approach handles all of this automatically!
19
20#![no_std]
21#![no_main]
22
23use embassy_executor::Spawner;
24use embassy_mcxa::clocks::config::Div8;
25use embassy_mcxa::clocks::Gate;
26use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler, ScatterGatherBuilder};
27use embassy_mcxa::{bind_interrupts, dma};
28use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
29use embassy_mcxa::pac;
30use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
31
32// Bind DMA channel 0 interrupt
33bind_interrupts!(struct Irqs {
34 DMA_CH0 => DmaCh0InterruptHandler;
35});
36
37// Source buffers (multiple segments)
38static mut SRC1: [u32; 4] = [0x11111111, 0x22222222, 0x33333333, 0x44444444];
39static mut SRC2: [u32; 4] = [0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC, 0xDDDDDDDD];
40static mut SRC3: [u32; 4] = [0x12345678, 0x9ABCDEF0, 0xFEDCBA98, 0x76543210];
41
42// Destination buffers (one per segment)
43static mut DST1: [u32; 4] = [0; 4];
44static mut DST2: [u32; 4] = [0; 4];
45static mut DST3: [u32; 4] = [0; 4];
46
47/// Helper to write a u32 as hex to UART
48fn write_hex(tx: &mut LpuartTx<'_, Blocking>, val: u32) {
49 const HEX: &[u8; 16] = b"0123456789ABCDEF";
50 for i in (0..8).rev() {
51 let nibble = ((val >> (i * 4)) & 0xF) as usize;
52 tx.blocking_write(&[HEX[nibble]]).ok();
53 }
54}
55
56/// Helper to print a buffer to UART
57fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) {
58 tx.blocking_write(b"[").ok();
59 unsafe {
60 for i in 0..len {
61 write_hex(tx, *buf_ptr.add(i));
62 if i < len - 1 {
63 tx.blocking_write(b", ").ok();
64 }
65 }
66 }
67 tx.blocking_write(b"]").ok();
68}
69
70#[embassy_executor::main]
71async fn main(_spawner: Spawner) {
72 // Small delay to allow probe-rs to attach after reset
73 for _ in 0..100_000 {
74 cortex_m::asm::nop();
75 }
76
77 let mut cfg = hal::config::Config::default();
78 cfg.clock_cfg.sirc.fro_12m_enabled = true;
79 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
80 let p = hal::init(cfg);
81
82 defmt::info!("DMA Scatter-Gather Builder example starting...");
83
84 // Enable DMA0 clock and release reset
85 unsafe {
86 hal::peripherals::DMA0::enable_clock();
87 hal::peripherals::DMA0::release_reset();
88 }
89
90 let pac_periphs = unsafe { pac::Peripherals::steal() };
91
92 // Initialize DMA
93 unsafe {
94 dma::init(&pac_periphs);
95 }
96
97 // Enable DMA interrupt
98 unsafe {
99 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
100 }
101
102 // Create UART for debug output
103 let config = Config {
104 baudrate_bps: 115_200,
105 enable_tx: true,
106 enable_rx: false,
107 ..Default::default()
108 };
109
110 let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap();
111 let (mut tx, _rx) = lpuart.split();
112
113 tx.blocking_write(b"DMA Scatter-Gather Builder Example\r\n").unwrap();
114 tx.blocking_write(b"===================================\r\n\r\n").unwrap();
115
116 // Show source buffers
117 tx.blocking_write(b"Source buffers:\r\n").unwrap();
118 tx.blocking_write(b" SRC1: ").unwrap();
119 print_buffer(&mut tx, core::ptr::addr_of!(SRC1) as *const u32, 4);
120 tx.blocking_write(b"\r\n").unwrap();
121 tx.blocking_write(b" SRC2: ").unwrap();
122 print_buffer(&mut tx, core::ptr::addr_of!(SRC2) as *const u32, 4);
123 tx.blocking_write(b"\r\n").unwrap();
124 tx.blocking_write(b" SRC3: ").unwrap();
125 print_buffer(&mut tx, core::ptr::addr_of!(SRC3) as *const u32, 4);
126 tx.blocking_write(b"\r\n\r\n").unwrap();
127
128 tx.blocking_write(b"Destination buffers (before):\r\n").unwrap();
129 tx.blocking_write(b" DST1: ").unwrap();
130 print_buffer(&mut tx, core::ptr::addr_of!(DST1) as *const u32, 4);
131 tx.blocking_write(b"\r\n").unwrap();
132 tx.blocking_write(b" DST2: ").unwrap();
133 print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 4);
134 tx.blocking_write(b"\r\n").unwrap();
135 tx.blocking_write(b" DST3: ").unwrap();
136 print_buffer(&mut tx, core::ptr::addr_of!(DST3) as *const u32, 4);
137 tx.blocking_write(b"\r\n\r\n").unwrap();
138
139 // Create DMA channel
140 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
141
142 tx.blocking_write(b"Building scatter-gather chain with builder API...\r\n").unwrap();
143
144 // =========================================================================
145 // ScatterGatherBuilder API demonstration
146 // =========================================================================
147 //
148 // The builder pattern makes scatter-gather transfers much easier:
149 // 1. Create a builder
150 // 2. Add transfer segments with add_transfer()
151 // 3. Call build() to start the entire chain
152 // No manual TCD manipulation required!
153
154 let mut builder = ScatterGatherBuilder::<u32>::new();
155
156 // Add three transfer segments - the builder handles TCD linking automatically
157 unsafe {
158 let src1 = &*core::ptr::addr_of!(SRC1);
159 let dst1 = &mut *core::ptr::addr_of_mut!(DST1);
160 builder.add_transfer(src1, dst1);
161 }
162
163 unsafe {
164 let src2 = &*core::ptr::addr_of!(SRC2);
165 let dst2 = &mut *core::ptr::addr_of_mut!(DST2);
166 builder.add_transfer(src2, dst2);
167 }
168
169 unsafe {
170 let src3 = &*core::ptr::addr_of!(SRC3);
171 let dst3 = &mut *core::ptr::addr_of_mut!(DST3);
172 builder.add_transfer(src3, dst3);
173 }
174
175 tx.blocking_write(b"Added 3 transfer segments to chain.\r\n").unwrap();
176 tx.blocking_write(b"Starting scatter-gather transfer with .await...\r\n\r\n").unwrap();
177
178 // Build and execute the scatter-gather chain
179 // The build() method:
180 // - Links all TCDs together with ESG bit
181 // - Sets INTMAJOR on all TCDs
182 // - Loads the first TCD into hardware
183 // - Returns a Transfer future
184 unsafe {
185 let transfer = builder.build(&dma_ch0).expect("Failed to build scatter-gather");
186 transfer.blocking_wait();
187 }
188
189 tx.blocking_write(b"Scatter-gather transfer complete!\r\n\r\n").unwrap();
190
191 // Show results
192 tx.blocking_write(b"Destination buffers (after):\r\n").unwrap();
193 tx.blocking_write(b" DST1: ").unwrap();
194 print_buffer(&mut tx, core::ptr::addr_of!(DST1) as *const u32, 4);
195 tx.blocking_write(b"\r\n").unwrap();
196 tx.blocking_write(b" DST2: ").unwrap();
197 print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 4);
198 tx.blocking_write(b"\r\n").unwrap();
199 tx.blocking_write(b" DST3: ").unwrap();
200 print_buffer(&mut tx, core::ptr::addr_of!(DST3) as *const u32, 4);
201 tx.blocking_write(b"\r\n\r\n").unwrap();
202
203 // Verify all three segments
204 let mut all_ok = true;
205 unsafe {
206 let src1 = core::ptr::addr_of!(SRC1) as *const u32;
207 let dst1 = core::ptr::addr_of!(DST1) as *const u32;
208 for i in 0..4 {
209 if *src1.add(i) != *dst1.add(i) {
210 all_ok = false;
211 }
212 }
213
214 let src2 = core::ptr::addr_of!(SRC2) as *const u32;
215 let dst2 = core::ptr::addr_of!(DST2) as *const u32;
216 for i in 0..4 {
217 if *src2.add(i) != *dst2.add(i) {
218 all_ok = false;
219 }
220 }
221
222 let src3 = core::ptr::addr_of!(SRC3) as *const u32;
223 let dst3 = core::ptr::addr_of!(DST3) as *const u32;
224 for i in 0..4 {
225 if *src3.add(i) != *dst3.add(i) {
226 all_ok = false;
227 }
228 }
229 }
230
231 if all_ok {
232 tx.blocking_write(b"PASS: All segments verified!\r\n").unwrap();
233 defmt::info!("PASS: All segments verified!");
234 } else {
235 tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap();
236 defmt::error!("FAIL: Mismatch detected!");
237 }
238
239 tx.blocking_write(b"\r\n=== Scatter-Gather Builder example complete ===\r\n").unwrap();
240
241 loop {
242 cortex_m::asm::wfe();
243 }
244}