aboutsummaryrefslogtreecommitdiff
path: root/examples/src/bin/dma_memset.rs
diff options
context:
space:
mode:
Diffstat (limited to 'examples/src/bin/dma_memset.rs')
-rw-r--r--examples/src/bin/dma_memset.rs232
1 files changed, 232 insertions, 0 deletions
diff --git a/examples/src/bin/dma_memset.rs b/examples/src/bin/dma_memset.rs
new file mode 100644
index 000000000..b76ba988d
--- /dev/null
+++ b/examples/src/bin/dma_memset.rs
@@ -0,0 +1,232 @@
1//! DMA memset example for MCXA276.
2//!
3//! This example demonstrates using DMA to fill a buffer with a repeated pattern.
4//! The source address stays fixed while the destination increments.
5//!
6//! # Embassy-style features demonstrated:
7//! - `dma::edma_tcd()` accessor for simplified register access
8//! - `DmaChannel::is_done()` and `clear_done()` helper methods
9//! - No need to pass register block around
10
11#![no_std]
12#![no_main]
13
14use embassy_executor::Spawner;
15use embassy_mcxa::clocks::config::Div8;
16use embassy_mcxa::clocks::Gate;
17use embassy_mcxa::dma::{edma_tcd, DmaChannel, DmaCh0InterruptHandler};
18use embassy_mcxa::{bind_interrupts, dma};
19use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
20use embassy_mcxa::pac;
21use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
22
23// Bind DMA channel 0 interrupt using Embassy-style macro
24bind_interrupts!(struct Irqs {
25 DMA_CH0 => DmaCh0InterruptHandler;
26});
27
28const BUFFER_LENGTH: usize = 4;
29
30// Buffers in RAM
31static mut PATTERN: u32 = 0;
32static mut DEST_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH];
33
34/// Helper to write a u32 as decimal ASCII to UART
35fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) {
36 let mut buf = [0u8; 10];
37 let mut n = val;
38 let mut i = buf.len();
39
40 if n == 0 {
41 tx.blocking_write(b"0").ok();
42 return;
43 }
44
45 while n > 0 {
46 i -= 1;
47 buf[i] = b'0' + (n % 10) as u8;
48 n /= 10;
49 }
50
51 tx.blocking_write(&buf[i..]).ok();
52}
53
54/// Helper to print a buffer to UART
55fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) {
56 tx.blocking_write(b"[").ok();
57 unsafe {
58 for i in 0..len {
59 write_u32(tx, *buf_ptr.add(i));
60 if i < len - 1 {
61 tx.blocking_write(b", ").ok();
62 }
63 }
64 }
65 tx.blocking_write(b"]").ok();
66}
67
68#[embassy_executor::main]
69async fn main(_spawner: Spawner) {
70 // Small delay to allow probe-rs to attach after reset
71 for _ in 0..100_000 {
72 cortex_m::asm::nop();
73 }
74
75 let mut cfg = hal::config::Config::default();
76 cfg.clock_cfg.sirc.fro_12m_enabled = true;
77 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
78 let p = hal::init(cfg);
79
80 defmt::info!("DMA memset example starting...");
81
82 // Enable DMA0 clock and release reset
83 unsafe {
84 hal::peripherals::DMA0::enable_clock();
85 hal::peripherals::DMA0::release_reset();
86 }
87
88 let pac_periphs = unsafe { pac::Peripherals::steal() };
89
90 unsafe {
91 dma::init(&pac_periphs);
92 }
93
94 // Enable DMA interrupt
95 unsafe {
96 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
97 }
98
99 let config = Config {
100 baudrate_bps: 115_200,
101 enable_tx: true,
102 enable_rx: false,
103 ..Default::default()
104 };
105
106 let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap();
107 let (mut tx, _rx) = lpuart.split();
108
109 tx.blocking_write(b"EDMA memset example begin.\r\n\r\n")
110 .unwrap();
111
112 // Initialize buffers
113 unsafe {
114 PATTERN = 0xDEADBEEF;
115 DEST_BUFFER = [0; BUFFER_LENGTH];
116 }
117
118 tx.blocking_write(b"Pattern value: 0x").unwrap();
119 // Print pattern in hex
120 unsafe {
121 let hex_chars = b"0123456789ABCDEF";
122 let mut hex_buf = [0u8; 8];
123 let mut val = PATTERN;
124 for i in (0..8).rev() {
125 hex_buf[i] = hex_chars[(val & 0xF) as usize];
126 val >>= 4;
127 }
128 tx.blocking_write(&hex_buf).ok();
129 }
130 tx.blocking_write(b"\r\n").unwrap();
131
132 tx.blocking_write(b"Destination Buffer (before): ").unwrap();
133 print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH);
134 tx.blocking_write(b"\r\n").unwrap();
135
136 tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n")
137 .unwrap();
138
139 // Create DMA channel using Embassy-style API
140 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
141
142 // Use edma_tcd() accessor instead of passing register block around
143 let edma = edma_tcd();
144
145 // Configure memset transfer using direct TCD access:
146 // Source stays fixed (soff = 0, reads same pattern repeatedly)
147 // Destination increments (doff = 4)
148 unsafe {
149 let t = edma.tcd(0);
150
151 // Reset channel state
152 t.ch_csr().write(|w| {
153 w.erq().disable()
154 .earq().disable()
155 .eei().no_error()
156 .ebw().disable()
157 .done().clear_bit_by_one()
158 });
159 t.ch_es().write(|w| w.bits(0));
160 t.ch_int().write(|w| w.int().clear_bit_by_one());
161
162 // Source address (pattern) - fixed
163 t.tcd_saddr().write(|w| w.saddr().bits(core::ptr::addr_of_mut!(PATTERN) as u32));
164 // Destination address - increments
165 t.tcd_daddr().write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DEST_BUFFER) as u32));
166
167 // Source offset = 0 (stays fixed), Dest offset = 4 (increments)
168 t.tcd_soff().write(|w| w.soff().bits(0));
169 t.tcd_doff().write(|w| w.doff().bits(4));
170
171 // Attributes: 32-bit transfers (size = 2)
172 t.tcd_attr().write(|w| w.ssize().bits(2).dsize().bits(2));
173
174 // Transfer entire buffer in one minor loop
175 let nbytes = (BUFFER_LENGTH * 4) as u32;
176 t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes));
177
178 // Source doesn't need adjustment (stays fixed)
179 t.tcd_slast_sda().write(|w| w.slast_sda().bits(0));
180 // Reset dest address after major loop
181 t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(-(nbytes as i32) as u32));
182
183 // Major loop count = 1
184 t.tcd_biter_elinkno().write(|w| w.biter().bits(1));
185 t.tcd_citer_elinkno().write(|w| w.citer().bits(1));
186
187 // Enable interrupt on major loop completion
188 t.tcd_csr().write(|w| w.intmajor().set_bit());
189
190 cortex_m::asm::dsb();
191
192 tx.blocking_write(b"Triggering transfer...\r\n").unwrap();
193 dma_ch0.trigger_start(edma);
194 }
195
196 // Wait for completion using channel helper method
197 while !dma_ch0.is_done(edma) {
198 cortex_m::asm::nop();
199 }
200 unsafe { dma_ch0.clear_done(edma); }
201
202 tx.blocking_write(b"\r\nEDMA memset example finish.\r\n\r\n")
203 .unwrap();
204 tx.blocking_write(b"Destination Buffer (after): ").unwrap();
205 print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH);
206 tx.blocking_write(b"\r\n\r\n").unwrap();
207
208 // Verify: All elements should equal PATTERN
209 let mut mismatch = false;
210 unsafe {
211 #[allow(clippy::needless_range_loop)]
212 for i in 0..BUFFER_LENGTH {
213 if DEST_BUFFER[i] != PATTERN {
214 mismatch = true;
215 break;
216 }
217 }
218 }
219
220 if mismatch {
221 tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap();
222 defmt::error!("FAIL: Mismatch detected!");
223 } else {
224 tx.blocking_write(b"PASS: Data verified.\r\n").unwrap();
225 defmt::info!("PASS: Data verified.");
226 }
227
228 loop {
229 cortex_m::asm::wfe();
230 }
231}
232