aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorBogdan Petru Chircu Mare <[email protected]>2025-11-27 21:39:31 -0800
committerBogdan Petru Chircu Mare <[email protected]>2025-11-28 12:34:37 -0800
commit5a6394666e23555e4f329f7b1bd470d0728434a1 (patch)
treecf4d3f68d30224051707ff1a74769ff3588e1702 /examples
parent03356a261801d7ee234490809eef3eac3c27cc52 (diff)
Updated per PR #52 feedback
Diffstat (limited to 'examples')
-rw-r--r--examples/src/bin/dma_channel_link.rs93
-rw-r--r--examples/src/bin/dma_interleave_transfer.rs31
-rw-r--r--examples/src/bin/dma_mem_to_mem.rs19
-rw-r--r--examples/src/bin/dma_memset.rs31
-rw-r--r--examples/src/bin/dma_ping_pong_transfer.rs60
-rw-r--r--examples/src/bin/dma_scatter_gather.rs54
-rw-r--r--examples/src/bin/dma_scatter_gather_builder.rs18
-rw-r--r--examples/src/bin/dma_wrap_transfer.rs31
-rw-r--r--examples/src/bin/lpuart_dma.rs78
-rw-r--r--examples/src/bin/lpuart_ring_buffer.rs23
10 files changed, 114 insertions, 324 deletions
diff --git a/examples/src/bin/dma_channel_link.rs b/examples/src/bin/dma_channel_link.rs
index d585f8e3a..d541dc7f4 100644
--- a/examples/src/bin/dma_channel_link.rs
+++ b/examples/src/bin/dma_channel_link.rs
@@ -8,20 +8,18 @@
8//! - Channel 2: Transfers SRC_BUFFER to DEST_BUFFER2 (triggered by CH0 major link) 8//! - Channel 2: Transfers SRC_BUFFER to DEST_BUFFER2 (triggered by CH0 major link)
9//! 9//!
10//! # Embassy-style features demonstrated: 10//! # Embassy-style features demonstrated:
11//! - `dma::edma_tcd()` accessor for simplified register access
12//! - `DmaChannel::new()` for channel creation 11//! - `DmaChannel::new()` for channel creation
13//! - `DmaChannel::is_done()` and `clear_done()` helper methods 12//! - `DmaChannel::is_done()` and `clear_done()` helper methods
14//! - Channel linking with `set_minor_link()` and `set_major_link()` 13//! - Channel linking with `set_minor_link()` and `set_major_link()`
14//! - Standard `DmaCh*InterruptHandler` with `bind_interrupts!` macro
15 15
16#![no_std] 16#![no_std]
17#![no_main] 17#![no_main]
18 18
19use core::sync::atomic::{AtomicBool, Ordering};
20use embassy_executor::Spawner; 19use embassy_executor::Spawner;
21use embassy_mcxa::clocks::config::Div8; 20use embassy_mcxa::clocks::config::Div8;
22use embassy_mcxa::clocks::Gate; 21use embassy_mcxa::dma::{self, DmaChannel, DmaCh0InterruptHandler, DmaCh1InterruptHandler, DmaCh2InterruptHandler};
23use embassy_mcxa::dma::{edma_tcd, DmaChannel}; 22use embassy_mcxa::bind_interrupts;
24use embassy_mcxa::{bind_interrupts, dma};
25use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; 23use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
26use embassy_mcxa::pac; 24use embassy_mcxa::pac;
27use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 25use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
@@ -32,49 +30,12 @@ static mut DEST_BUFFER0: [u32; 4] = [0; 4];
32static mut DEST_BUFFER1: [u32; 4] = [0; 4]; 30static mut DEST_BUFFER1: [u32; 4] = [0; 4];
33static mut DEST_BUFFER2: [u32; 4] = [0; 4]; 31static mut DEST_BUFFER2: [u32; 4] = [0; 4];
34 32
35static DMA_CH2_DONE: AtomicBool = AtomicBool::new(false); 33// Bind DMA channel interrupts using Embassy-style macro
36 34// The standard handlers call on_interrupt() which wakes wakers and clears flags
37// Custom DMA interrupt handlers for channel linking
38// CH0 and CH1 just clear flags, CH2 signals completion
39
40pub struct Ch0Handler;
41impl embassy_mcxa::interrupt::typelevel::Handler<embassy_mcxa::interrupt::typelevel::DMA_CH0> for Ch0Handler {
42 unsafe fn on_interrupt() {
43 let edma = edma_tcd();
44 edma.tcd(0).ch_int().write(|w| w.int().clear_bit_by_one());
45 if edma.tcd(0).ch_csr().read().done().bit_is_set() {
46 edma.tcd(0).ch_csr().write(|w| w.done().clear_bit_by_one());
47 }
48 }
49}
50
51pub struct Ch1Handler;
52impl embassy_mcxa::interrupt::typelevel::Handler<embassy_mcxa::interrupt::typelevel::DMA_CH1> for Ch1Handler {
53 unsafe fn on_interrupt() {
54 let edma = edma_tcd();
55 edma.tcd(1).ch_int().write(|w| w.int().clear_bit_by_one());
56 if edma.tcd(1).ch_csr().read().done().bit_is_set() {
57 edma.tcd(1).ch_csr().write(|w| w.done().clear_bit_by_one());
58 }
59 }
60}
61
62pub struct Ch2Handler;
63impl embassy_mcxa::interrupt::typelevel::Handler<embassy_mcxa::interrupt::typelevel::DMA_CH2> for Ch2Handler {
64 unsafe fn on_interrupt() {
65 let edma = edma_tcd();
66 edma.tcd(2).ch_int().write(|w| w.int().clear_bit_by_one());
67 if edma.tcd(2).ch_csr().read().done().bit_is_set() {
68 edma.tcd(2).ch_csr().write(|w| w.done().clear_bit_by_one());
69 }
70 DMA_CH2_DONE.store(true, Ordering::Release);
71 }
72}
73
74bind_interrupts!(struct Irqs { 35bind_interrupts!(struct Irqs {
75 DMA_CH0 => Ch0Handler; 36 DMA_CH0 => DmaCh0InterruptHandler;
76 DMA_CH1 => Ch1Handler; 37 DMA_CH1 => DmaCh1InterruptHandler;
77 DMA_CH2 => Ch2Handler; 38 DMA_CH2 => DmaCh2InterruptHandler;
78}); 39});
79 40
80/// Helper to write a u32 as decimal ASCII to UART 41/// Helper to write a u32 as decimal ASCII to UART
@@ -125,21 +86,12 @@ async fn main(_spawner: Spawner) {
125 86
126 defmt::info!("DMA channel link example starting..."); 87 defmt::info!("DMA channel link example starting...");
127 88
128 // Enable DMA0 clock and release reset 89 // Ensure DMA is initialized (clock/reset/init handled automatically by HAL)
129 unsafe { 90 dma::ensure_init();
130 hal::peripherals::DMA0::enable_clock();
131 hal::peripherals::DMA0::release_reset();
132 }
133 91
134 let pac_periphs = unsafe { pac::Peripherals::steal() }; 92 let pac_periphs = unsafe { pac::Peripherals::steal() };
135
136 unsafe {
137 dma::init(&pac_periphs);
138 }
139
140 // Use edma_tcd() accessor instead of passing register block around
141 let edma = edma_tcd();
142 let dma0 = &pac_periphs.dma0; 93 let dma0 = &pac_periphs.dma0;
94 let edma = unsafe { &*pac::Edma0Tcd0::ptr() };
143 95
144 // Clear any residual state 96 // Clear any residual state
145 for i in 0..3 { 97 for i in 0..3 {
@@ -206,7 +158,7 @@ async fn main(_spawner: Spawner) {
206 158
207 let ch0 = DmaChannel::new(p.DMA_CH0); 159 let ch0 = DmaChannel::new(p.DMA_CH0);
208 let ch1 = DmaChannel::new(p.DMA_CH1); 160 let ch1 = DmaChannel::new(p.DMA_CH1);
209 let _ch2 = DmaChannel::new(p.DMA_CH2); 161 let ch2 = DmaChannel::new(p.DMA_CH2);
210 162
211 // Configure channels using direct TCD access (advanced feature demo) 163 // Configure channels using direct TCD access (advanced feature demo)
212 // This example demonstrates channel linking which requires direct TCD manipulation 164 // This example demonstrates channel linking which requires direct TCD manipulation
@@ -291,8 +243,8 @@ async fn main(_spawner: Spawner) {
291 2, // count (major loop = 2 iterations) 243 2, // count (major loop = 2 iterations)
292 false, // no interrupt 244 false, // no interrupt
293 ); 245 );
294 ch0.set_minor_link(edma, 1); // Link to CH1 after each minor loop 246 ch0.set_minor_link(1); // Link to CH1 after each minor loop
295 ch0.set_major_link(edma, 2); // Link to CH2 after major loop 247 ch0.set_major_link(2); // Link to CH2 after major loop
296 248
297 // Channel 1: Transfer 16 bytes (triggered by CH0 minor link) 249 // Channel 1: Transfer 16 bytes (triggered by CH0 minor link)
298 configure_tcd( 250 configure_tcd(
@@ -322,32 +274,35 @@ async fn main(_spawner: Spawner) {
322 tx.blocking_write(b"Triggering Channel 0 (1st minor loop)...\r\n").unwrap(); 274 tx.blocking_write(b"Triggering Channel 0 (1st minor loop)...\r\n").unwrap();
323 275
324 // Trigger first minor loop of CH0 276 // Trigger first minor loop of CH0
325 unsafe { ch0.trigger_start(edma); } 277 unsafe { ch0.trigger_start(); }
326 278
327 // Wait for CH1 to complete (triggered by CH0 minor link) 279 // Wait for CH1 to complete (triggered by CH0 minor link)
328 while !ch1.is_done(edma) { 280 while !ch1.is_done() {
329 cortex_m::asm::nop(); 281 cortex_m::asm::nop();
330 } 282 }
331 unsafe { ch1.clear_done(edma); } 283 unsafe { ch1.clear_done(); }
332 284
333 tx.blocking_write(b"CH1 done (via minor link).\r\n").unwrap(); 285 tx.blocking_write(b"CH1 done (via minor link).\r\n").unwrap();
334 tx.blocking_write(b"Triggering Channel 0 (2nd minor loop)...\r\n").unwrap(); 286 tx.blocking_write(b"Triggering Channel 0 (2nd minor loop)...\r\n").unwrap();
335 287
336 // Trigger second minor loop of CH0 288 // Trigger second minor loop of CH0
337 unsafe { ch0.trigger_start(edma); } 289 unsafe { ch0.trigger_start(); }
338 290
339 // Wait for CH0 major loop to complete 291 // Wait for CH0 major loop to complete
340 while !ch0.is_done(edma) { 292 while !ch0.is_done() {
341 cortex_m::asm::nop(); 293 cortex_m::asm::nop();
342 } 294 }
343 unsafe { ch0.clear_done(edma); } 295 unsafe { ch0.clear_done(); }
344 296
345 tx.blocking_write(b"CH0 major loop done.\r\n").unwrap(); 297 tx.blocking_write(b"CH0 major loop done.\r\n").unwrap();
346 298
347 // Wait for CH2 to complete (triggered by CH0 major link) 299 // Wait for CH2 to complete (triggered by CH0 major link)
348 while !DMA_CH2_DONE.load(Ordering::Acquire) { 300 // Using is_done() instead of AtomicBool - the standard interrupt handler
301 // clears the interrupt flag and wakes wakers, but DONE bit remains set
302 while !ch2.is_done() {
349 cortex_m::asm::nop(); 303 cortex_m::asm::nop();
350 } 304 }
305 unsafe { ch2.clear_done(); }
351 306
352 tx.blocking_write(b"CH2 done (via major link).\r\n\r\n").unwrap(); 307 tx.blocking_write(b"CH2 done (via major link).\r\n\r\n").unwrap();
353 308
diff --git a/examples/src/bin/dma_interleave_transfer.rs b/examples/src/bin/dma_interleave_transfer.rs
index 710f18de3..949ea0605 100644
--- a/examples/src/bin/dma_interleave_transfer.rs
+++ b/examples/src/bin/dma_interleave_transfer.rs
@@ -4,7 +4,6 @@
4//! to interleave data during transfer. 4//! to interleave data during transfer.
5//! 5//!
6//! # Embassy-style features demonstrated: 6//! # Embassy-style features demonstrated:
7//! - `dma::edma_tcd()` accessor for simplified register access
8//! - `TransferOptions::default()` for configuration (used internally) 7//! - `TransferOptions::default()` for configuration (used internally)
9//! - DMA channel with `DmaChannel::new()` 8//! - DMA channel with `DmaChannel::new()`
10 9
@@ -13,9 +12,8 @@
13 12
14use embassy_executor::Spawner; 13use embassy_executor::Spawner;
15use embassy_mcxa::clocks::config::Div8; 14use embassy_mcxa::clocks::config::Div8;
16use embassy_mcxa::clocks::Gate; 15use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler};
17use embassy_mcxa::dma::{edma_tcd, DmaChannel, DmaCh0InterruptHandler}; 16use embassy_mcxa::bind_interrupts;
18use embassy_mcxa::{bind_interrupts, dma};
19use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; 17use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
20use embassy_mcxa::pac; 18use embassy_mcxa::pac;
21use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 19use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
@@ -80,19 +78,7 @@ async fn main(_spawner: Spawner) {
80 78
81 defmt::info!("DMA interleave transfer example starting..."); 79 defmt::info!("DMA interleave transfer example starting...");
82 80
83 // Enable DMA0 clock and release reset 81 // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL)
84 unsafe {
85 hal::peripherals::DMA0::enable_clock();
86 hal::peripherals::DMA0::release_reset();
87 }
88
89 let pac_periphs = unsafe { pac::Peripherals::steal() };
90
91 unsafe {
92 dma::init(&pac_periphs);
93 }
94
95 // Enable DMA interrupt
96 unsafe { 82 unsafe {
97 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); 83 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
98 } 84 }
@@ -130,15 +116,12 @@ async fn main(_spawner: Spawner) {
130 // Create DMA channel using Embassy-style API 116 // Create DMA channel using Embassy-style API
131 let dma_ch0 = DmaChannel::new(p.DMA_CH0); 117 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
132 118
133 // Use edma_tcd() accessor instead of passing register block around
134 let edma = edma_tcd();
135
136 // Configure interleaved transfer using direct TCD access: 119 // Configure interleaved transfer using direct TCD access:
137 // - src_offset = 4: advance source by 4 bytes after each read 120 // - src_offset = 4: advance source by 4 bytes after each read
138 // - dst_offset = 8: advance dest by 8 bytes after each write 121 // - dst_offset = 8: advance dest by 8 bytes after each write
139 // This spreads source data across every other word in destination 122 // This spreads source data across every other word in destination
140 unsafe { 123 unsafe {
141 let t = edma.tcd(0); 124 let t = dma_ch0.tcd();
142 125
143 // Reset channel state 126 // Reset channel state
144 t.ch_csr().write(|w| { 127 t.ch_csr().write(|w| {
@@ -182,14 +165,14 @@ async fn main(_spawner: Spawner) {
182 cortex_m::asm::dsb(); 165 cortex_m::asm::dsb();
183 166
184 tx.blocking_write(b"Triggering transfer...\r\n").unwrap(); 167 tx.blocking_write(b"Triggering transfer...\r\n").unwrap();
185 dma_ch0.trigger_start(edma); 168 dma_ch0.trigger_start();
186 } 169 }
187 170
188 // Wait for completion using channel helper method 171 // Wait for completion using channel helper method
189 while !dma_ch0.is_done(edma) { 172 while !dma_ch0.is_done() {
190 cortex_m::asm::nop(); 173 cortex_m::asm::nop();
191 } 174 }
192 unsafe { dma_ch0.clear_done(edma); } 175 unsafe { dma_ch0.clear_done(); }
193 176
194 tx.blocking_write(b"\r\nEDMA interleave transfer example finish.\r\n\r\n") 177 tx.blocking_write(b"\r\nEDMA interleave transfer example finish.\r\n\r\n")
195 .unwrap(); 178 .unwrap();
diff --git a/examples/src/bin/dma_mem_to_mem.rs b/examples/src/bin/dma_mem_to_mem.rs
index e193e8c6a..01e5edb1e 100644
--- a/examples/src/bin/dma_mem_to_mem.rs
+++ b/examples/src/bin/dma_mem_to_mem.rs
@@ -15,9 +15,8 @@
15 15
16use embassy_executor::Spawner; 16use embassy_executor::Spawner;
17use embassy_mcxa::clocks::config::Div8; 17use embassy_mcxa::clocks::config::Div8;
18use embassy_mcxa::clocks::Gate;
19use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler, TransferOptions}; 18use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler, TransferOptions};
20use embassy_mcxa::{bind_interrupts, dma}; 19use embassy_mcxa::bind_interrupts;
21use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; 20use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
22use embassy_mcxa::pac; 21use embassy_mcxa::pac;
23use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 22use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
@@ -84,21 +83,7 @@ async fn main(_spawner: Spawner) {
84 83
85 defmt::info!("DMA memory-to-memory example starting..."); 84 defmt::info!("DMA memory-to-memory example starting...");
86 85
87 // Enable DMA0 clock and release reset 86 // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL)
88 unsafe {
89 hal::peripherals::DMA0::enable_clock();
90 hal::peripherals::DMA0::release_reset();
91 }
92
93 // Get PAC peripherals for DMA init
94 let pac_periphs = unsafe { pac::Peripherals::steal() };
95
96 // Initialize DMA
97 unsafe {
98 dma::init(&pac_periphs);
99 }
100
101 // Enable DMA interrupt
102 unsafe { 87 unsafe {
103 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); 88 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
104 } 89 }
diff --git a/examples/src/bin/dma_memset.rs b/examples/src/bin/dma_memset.rs
index b76ba988d..8a1636e57 100644
--- a/examples/src/bin/dma_memset.rs
+++ b/examples/src/bin/dma_memset.rs
@@ -4,7 +4,6 @@
4//! The source address stays fixed while the destination increments. 4//! The source address stays fixed while the destination increments.
5//! 5//!
6//! # Embassy-style features demonstrated: 6//! # Embassy-style features demonstrated:
7//! - `dma::edma_tcd()` accessor for simplified register access
8//! - `DmaChannel::is_done()` and `clear_done()` helper methods 7//! - `DmaChannel::is_done()` and `clear_done()` helper methods
9//! - No need to pass register block around 8//! - No need to pass register block around
10 9
@@ -13,9 +12,8 @@
13 12
14use embassy_executor::Spawner; 13use embassy_executor::Spawner;
15use embassy_mcxa::clocks::config::Div8; 14use embassy_mcxa::clocks::config::Div8;
16use embassy_mcxa::clocks::Gate; 15use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler};
17use embassy_mcxa::dma::{edma_tcd, DmaChannel, DmaCh0InterruptHandler}; 16use embassy_mcxa::bind_interrupts;
18use embassy_mcxa::{bind_interrupts, dma};
19use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; 17use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
20use embassy_mcxa::pac; 18use embassy_mcxa::pac;
21use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 19use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
@@ -79,19 +77,7 @@ async fn main(_spawner: Spawner) {
79 77
80 defmt::info!("DMA memset example starting..."); 78 defmt::info!("DMA memset example starting...");
81 79
82 // Enable DMA0 clock and release reset 80 // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL)
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 { 81 unsafe {
96 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); 82 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
97 } 83 }
@@ -139,14 +125,11 @@ async fn main(_spawner: Spawner) {
139 // Create DMA channel using Embassy-style API 125 // Create DMA channel using Embassy-style API
140 let dma_ch0 = DmaChannel::new(p.DMA_CH0); 126 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
141 127
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: 128 // Configure memset transfer using direct TCD access:
146 // Source stays fixed (soff = 0, reads same pattern repeatedly) 129 // Source stays fixed (soff = 0, reads same pattern repeatedly)
147 // Destination increments (doff = 4) 130 // Destination increments (doff = 4)
148 unsafe { 131 unsafe {
149 let t = edma.tcd(0); 132 let t = dma_ch0.tcd();
150 133
151 // Reset channel state 134 // Reset channel state
152 t.ch_csr().write(|w| { 135 t.ch_csr().write(|w| {
@@ -190,14 +173,14 @@ async fn main(_spawner: Spawner) {
190 cortex_m::asm::dsb(); 173 cortex_m::asm::dsb();
191 174
192 tx.blocking_write(b"Triggering transfer...\r\n").unwrap(); 175 tx.blocking_write(b"Triggering transfer...\r\n").unwrap();
193 dma_ch0.trigger_start(edma); 176 dma_ch0.trigger_start();
194 } 177 }
195 178
196 // Wait for completion using channel helper method 179 // Wait for completion using channel helper method
197 while !dma_ch0.is_done(edma) { 180 while !dma_ch0.is_done() {
198 cortex_m::asm::nop(); 181 cortex_m::asm::nop();
199 } 182 }
200 unsafe { dma_ch0.clear_done(edma); } 183 unsafe { dma_ch0.clear_done(); }
201 184
202 tx.blocking_write(b"\r\nEDMA memset example finish.\r\n\r\n") 185 tx.blocking_write(b"\r\nEDMA memset example finish.\r\n\r\n")
203 .unwrap(); 186 .unwrap();
diff --git a/examples/src/bin/dma_ping_pong_transfer.rs b/examples/src/bin/dma_ping_pong_transfer.rs
index 13ad9782d..d765ea575 100644
--- a/examples/src/bin/dma_ping_pong_transfer.rs
+++ b/examples/src/bin/dma_ping_pong_transfer.rs
@@ -4,7 +4,9 @@
4//! 4//!
5//! ## Approach 1: Scatter/Gather with linked TCDs (manual) 5//! ## Approach 1: Scatter/Gather with linked TCDs (manual)
6//! - Two TCDs link to each other for alternating transfers 6//! - Two TCDs link to each other for alternating transfers
7//! - Uses custom interrupt handler with AtomicBool flag 7//! - Uses custom handler that delegates to on_interrupt() then signals completion
8//! - Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads,
9//! so we need an AtomicBool to track completion
8//! 10//!
9//! ## Approach 2: Half-transfer interrupt with wait_half() (NEW!) 11//! ## Approach 2: Half-transfer interrupt with wait_half() (NEW!)
10//! - Single continuous transfer over entire buffer 12//! - Single continuous transfer over entire buffer
@@ -12,9 +14,10 @@
12//! - Application can process first half while second half is being filled 14//! - Application can process first half while second half is being filled
13//! 15//!
14//! # Embassy-style features demonstrated: 16//! # Embassy-style features demonstrated:
15//! - `dma::edma_tcd()` accessor for simplified register access
16//! - `DmaChannel::new()` for channel creation 17//! - `DmaChannel::new()` for channel creation
17//! - Scatter/gather with linked TCDs 18//! - Scatter/gather with linked TCDs
19//! - Custom handler that delegates to HAL's `on_interrupt()` (best practice)
20//! - Standard `DmaCh1InterruptHandler` with `bind_interrupts!` macro
18//! - NEW: `wait_half()` for half-transfer interrupt handling 21//! - NEW: `wait_half()` for half-transfer interrupt handling
19 22
20#![no_std] 23#![no_std]
@@ -23,9 +26,8 @@
23use core::sync::atomic::{AtomicBool, Ordering}; 26use core::sync::atomic::{AtomicBool, Ordering};
24use embassy_executor::Spawner; 27use embassy_executor::Spawner;
25use embassy_mcxa::clocks::config::Div8; 28use embassy_mcxa::clocks::config::Div8;
26use embassy_mcxa::clocks::Gate; 29use embassy_mcxa::dma::{self, DmaChannel, DmaCh1InterruptHandler, Tcd, TransferOptions};
27use embassy_mcxa::dma::{edma_tcd, DmaChannel, DmaCh1InterruptHandler, Tcd, TransferOptions}; 30use embassy_mcxa::bind_interrupts;
28use embassy_mcxa::{bind_interrupts, dma};
29use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; 31use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
30use embassy_mcxa::pac; 32use embassy_mcxa::pac;
31use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 33use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
@@ -56,30 +58,31 @@ static mut TCD_POOL: TcdPool = TcdPool([Tcd {
56 biter: 0, 58 biter: 0,
57}; 2]); 59}; 2]);
58 60
61// AtomicBool to track scatter/gather completion
62// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads,
63// so we need this flag to detect when each transfer completes
59static TRANSFER_DONE: AtomicBool = AtomicBool::new(false); 64static TRANSFER_DONE: AtomicBool = AtomicBool::new(false);
60 65
61// Custom DMA interrupt handler for ping-pong transfer 66// Custom handler for scatter/gather that delegates to HAL's on_interrupt()
62// We need a custom handler because we signal completion via TRANSFER_DONE flag 67// This follows the "interrupts as threads" pattern - the handler does minimal work
63// and don't clear DONE bit when using Scatter/Gather (ESG=1) 68// (delegates to HAL + sets a flag) and the main task does the actual processing
64pub struct PingPongDmaHandler; 69pub struct PingPongDmaHandler;
65 70
66impl embassy_mcxa::interrupt::typelevel::Handler<embassy_mcxa::interrupt::typelevel::DMA_CH0> for PingPongDmaHandler { 71impl embassy_mcxa::interrupt::typelevel::Handler<embassy_mcxa::interrupt::typelevel::DMA_CH0> for PingPongDmaHandler {
67 unsafe fn on_interrupt() { 72 unsafe fn on_interrupt() {
68 let edma = edma_tcd(); 73 // Delegate to HAL's on_interrupt() which clears INT flag and wakes wakers
69 74 dma::on_interrupt(0);
70 // Clear interrupt flag 75 // Signal completion for polling (needed because ESG clears DONE bit)
71 edma.tcd(0).ch_int().write(|w| w.int().clear_bit_by_one());
72
73 // Do NOT clear DONE bit when using Scatter/Gather (ESG=1),
74 // as the hardware loads the next TCD which resets the status.
75
76 TRANSFER_DONE.store(true, Ordering::Release); 76 TRANSFER_DONE.store(true, Ordering::Release);
77 } 77 }
78} 78}
79 79
80// Bind DMA channel interrupts
81// CH0: Custom handler for scatter/gather (delegates to on_interrupt + sets flag)
82// CH1: Standard handler for wait_half() demo
80bind_interrupts!(struct Irqs { 83bind_interrupts!(struct Irqs {
81 DMA_CH0 => PingPongDmaHandler; 84 DMA_CH0 => PingPongDmaHandler;
82 DMA_CH1 => DmaCh1InterruptHandler; // For wait_half() demo 85 DMA_CH1 => DmaCh1InterruptHandler;
83}); 86});
84 87
85/// Helper to write a u32 as decimal ASCII to UART 88/// Helper to write a u32 as decimal ASCII to UART
@@ -130,22 +133,7 @@ async fn main(_spawner: Spawner) {
130 133
131 defmt::info!("DMA ping-pong transfer example starting..."); 134 defmt::info!("DMA ping-pong transfer example starting...");
132 135
133 // Enable DMA0 clock and release reset 136 // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL)
134 unsafe {
135 hal::peripherals::DMA0::enable_clock();
136 hal::peripherals::DMA0::release_reset();
137 }
138
139 let pac_periphs = unsafe { pac::Peripherals::steal() };
140
141 unsafe {
142 dma::init(&pac_periphs);
143 }
144
145 // Use edma_tcd() accessor instead of passing register block around
146 let edma = edma_tcd();
147
148 // Enable DMA interrupt
149 unsafe { 137 unsafe {
150 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); 138 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
151 } 139 }
@@ -228,14 +216,14 @@ async fn main(_spawner: Spawner) {
228 }; 216 };
229 217
230 // Load TCD0 into hardware registers 218 // Load TCD0 into hardware registers
231 dma_ch0.load_tcd(edma, &tcds[0]); 219 dma_ch0.load_tcd(&tcds[0]);
232 } 220 }
233 221
234 tx.blocking_write(b"Triggering first half transfer...\r\n").unwrap(); 222 tx.blocking_write(b"Triggering first half transfer...\r\n").unwrap();
235 223
236 // Trigger first transfer (first half: SRC[0..4] -> DST[0..4]) 224 // Trigger first transfer (first half: SRC[0..4] -> DST[0..4])
237 unsafe { 225 unsafe {
238 dma_ch0.trigger_start(edma); 226 dma_ch0.trigger_start();
239 } 227 }
240 228
241 // Wait for first half 229 // Wait for first half
@@ -249,7 +237,7 @@ async fn main(_spawner: Spawner) {
249 237
250 // Trigger second transfer (second half: SRC[4..8] -> DST[4..8]) 238 // Trigger second transfer (second half: SRC[4..8] -> DST[4..8])
251 unsafe { 239 unsafe {
252 dma_ch0.trigger_start(edma); 240 dma_ch0.trigger_start();
253 } 241 }
254 242
255 // Wait for second half 243 // Wait for second half
diff --git a/examples/src/bin/dma_scatter_gather.rs b/examples/src/bin/dma_scatter_gather.rs
index 86dd881cd..d78605acc 100644
--- a/examples/src/bin/dma_scatter_gather.rs
+++ b/examples/src/bin/dma_scatter_gather.rs
@@ -5,9 +5,9 @@
5//! then automatically loads the second TCD to transfer the second half. 5//! then automatically loads the second TCD to transfer the second half.
6//! 6//!
7//! # Embassy-style features demonstrated: 7//! # Embassy-style features demonstrated:
8//! - `dma::edma_tcd()` accessor for simplified register access
9//! - `DmaChannel::new()` for channel creation 8//! - `DmaChannel::new()` for channel creation
10//! - Scatter/gather with chained TCDs 9//! - Scatter/gather with chained TCDs
10//! - Custom handler that delegates to HAL's `on_interrupt()` (best practice)
11 11
12#![no_std] 12#![no_std]
13#![no_main] 13#![no_main]
@@ -15,9 +15,8 @@
15use core::sync::atomic::{AtomicBool, Ordering}; 15use core::sync::atomic::{AtomicBool, Ordering};
16use embassy_executor::Spawner; 16use embassy_executor::Spawner;
17use embassy_mcxa::clocks::config::Div8; 17use embassy_mcxa::clocks::config::Div8;
18use embassy_mcxa::clocks::Gate; 18use embassy_mcxa::dma::{self, DmaChannel, Tcd};
19use embassy_mcxa::dma::{edma_tcd, DmaChannel, Tcd}; 19use embassy_mcxa::bind_interrupts;
20use embassy_mcxa::{bind_interrupts, dma};
21use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; 20use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
22use embassy_mcxa::pac; 21use embassy_mcxa::pac;
23use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 22use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
@@ -44,30 +43,27 @@ static mut TCD_POOL: TcdPool = TcdPool([Tcd {
44 biter: 0, 43 biter: 0,
45}; 2]); 44}; 2]);
46 45
46// AtomicBool to track scatter/gather completion
47// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads,
48// so we need this flag to detect when each transfer completes
47static TRANSFER_DONE: AtomicBool = AtomicBool::new(false); 49static TRANSFER_DONE: AtomicBool = AtomicBool::new(false);
48 50
49// Custom DMA interrupt handler for scatter-gather transfer 51// Custom handler for scatter/gather that delegates to HAL's on_interrupt()
50// We need a custom handler because we signal completion via TRANSFER_DONE flag 52// This follows the "interrupts as threads" pattern - the handler does minimal work
51// and need to conditionally clear DONE bit based on ESG status 53// (delegates to HAL + sets a flag) and the main task does the actual processing
52pub struct ScatterGatherDmaHandler; 54pub struct ScatterGatherDmaHandler;
53 55
54impl embassy_mcxa::interrupt::typelevel::Handler<embassy_mcxa::interrupt::typelevel::DMA_CH0> for ScatterGatherDmaHandler { 56impl embassy_mcxa::interrupt::typelevel::Handler<embassy_mcxa::interrupt::typelevel::DMA_CH0> for ScatterGatherDmaHandler {
55 unsafe fn on_interrupt() { 57 unsafe fn on_interrupt() {
56 let edma = edma_tcd(); 58 // Delegate to HAL's on_interrupt() which clears INT flag and wakes wakers
57 59 dma::on_interrupt(0);
58 // Clear interrupt flag 60 // Signal completion for polling (needed because ESG clears DONE bit)
59 edma.tcd(0).ch_int().write(|w| w.int().clear_bit_by_one());
60
61 // If ESG=1 (Scatter/Gather), the hardware loads the next TCD and clears DONE.
62 // If ESG=0 (Last TCD), DONE remains set and must be cleared.
63 if edma.tcd(0).ch_csr().read().done().bit_is_set() {
64 edma.tcd(0).ch_csr().write(|w| w.done().clear_bit_by_one());
65 }
66
67 TRANSFER_DONE.store(true, Ordering::Release); 61 TRANSFER_DONE.store(true, Ordering::Release);
68 } 62 }
69} 63}
70 64
65// Bind DMA channel interrupt
66// Custom handler for scatter/gather (delegates to on_interrupt + sets flag)
71bind_interrupts!(struct Irqs { 67bind_interrupts!(struct Irqs {
72 DMA_CH0 => ScatterGatherDmaHandler; 68 DMA_CH0 => ScatterGatherDmaHandler;
73}); 69});
@@ -120,20 +116,8 @@ async fn main(_spawner: Spawner) {
120 116
121 defmt::info!("DMA scatter-gather transfer example starting..."); 117 defmt::info!("DMA scatter-gather transfer example starting...");
122 118
123 // Enable DMA0 clock and release reset 119 // Ensure DMA is initialized (clock/reset/init handled automatically by HAL)
124 unsafe { 120 dma::ensure_init();
125 hal::peripherals::DMA0::enable_clock();
126 hal::peripherals::DMA0::release_reset();
127 }
128
129 let pac_periphs = unsafe { pac::Peripherals::steal() };
130
131 unsafe {
132 dma::init(&pac_periphs);
133 }
134
135 // Use edma_tcd() accessor instead of passing register block around
136 let edma = edma_tcd();
137 121
138 // Enable DMA interrupt 122 // Enable DMA interrupt
139 unsafe { 123 unsafe {
@@ -213,7 +197,7 @@ async fn main(_spawner: Spawner) {
213 } 197 }
214 198
215 // Load TCD0 into hardware registers 199 // Load TCD0 into hardware registers
216 dma_ch0.load_tcd(edma, &tcds[0]); 200 dma_ch0.load_tcd(&tcds[0]);
217 } 201 }
218 202
219 tx.blocking_write(b"Triggering first half transfer...\r\n").unwrap(); 203 tx.blocking_write(b"Triggering first half transfer...\r\n").unwrap();
@@ -221,7 +205,7 @@ async fn main(_spawner: Spawner) {
221 // Trigger first transfer (first half: SRC[0..4] -> DST[0..4]) 205 // Trigger first transfer (first half: SRC[0..4] -> DST[0..4])
222 // TCD0 is currently loaded. 206 // TCD0 is currently loaded.
223 unsafe { 207 unsafe {
224 dma_ch0.trigger_start(edma); 208 dma_ch0.trigger_start();
225 } 209 }
226 210
227 // Wait for first half 211 // Wait for first half
@@ -236,7 +220,7 @@ async fn main(_spawner: Spawner) {
236 // Trigger second transfer (second half: SRC[4..8] -> DST[4..8]) 220 // Trigger second transfer (second half: SRC[4..8] -> DST[4..8])
237 // TCD1 should have been loaded by the scatter/gather engine. 221 // TCD1 should have been loaded by the scatter/gather engine.
238 unsafe { 222 unsafe {
239 dma_ch0.trigger_start(edma); 223 dma_ch0.trigger_start();
240 } 224 }
241 225
242 // Wait for second half 226 // Wait for second half
diff --git a/examples/src/bin/dma_scatter_gather_builder.rs b/examples/src/bin/dma_scatter_gather_builder.rs
index 078e26c60..51bfbeb67 100644
--- a/examples/src/bin/dma_scatter_gather_builder.rs
+++ b/examples/src/bin/dma_scatter_gather_builder.rs
@@ -22,9 +22,8 @@
22 22
23use embassy_executor::Spawner; 23use embassy_executor::Spawner;
24use embassy_mcxa::clocks::config::Div8; 24use embassy_mcxa::clocks::config::Div8;
25use embassy_mcxa::clocks::Gate;
26use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler, ScatterGatherBuilder}; 25use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler, ScatterGatherBuilder};
27use embassy_mcxa::{bind_interrupts, dma}; 26use embassy_mcxa::bind_interrupts;
28use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; 27use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
29use embassy_mcxa::pac; 28use embassy_mcxa::pac;
30use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 29use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
@@ -81,20 +80,7 @@ async fn main(_spawner: Spawner) {
81 80
82 defmt::info!("DMA Scatter-Gather Builder example starting..."); 81 defmt::info!("DMA Scatter-Gather Builder example starting...");
83 82
84 // Enable DMA0 clock and release reset 83 // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL)
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 { 84 unsafe {
99 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); 85 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
100 } 86 }
diff --git a/examples/src/bin/dma_wrap_transfer.rs b/examples/src/bin/dma_wrap_transfer.rs
index b115a2c19..8e9aedbfb 100644
--- a/examples/src/bin/dma_wrap_transfer.rs
+++ b/examples/src/bin/dma_wrap_transfer.rs
@@ -4,7 +4,6 @@
4//! a source buffer, effectively repeating the source data in the destination. 4//! a source buffer, effectively repeating the source data in the destination.
5//! 5//!
6//! # Embassy-style features demonstrated: 6//! # Embassy-style features demonstrated:
7//! - `dma::edma_tcd()` accessor for simplified register access
8//! - `DmaChannel::is_done()` and `clear_done()` helper methods 7//! - `DmaChannel::is_done()` and `clear_done()` helper methods
9//! - No need to pass register block around 8//! - No need to pass register block around
10 9
@@ -13,9 +12,8 @@
13 12
14use embassy_executor::Spawner; 13use embassy_executor::Spawner;
15use embassy_mcxa::clocks::config::Div8; 14use embassy_mcxa::clocks::config::Div8;
16use embassy_mcxa::clocks::Gate; 15use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler};
17use embassy_mcxa::dma::{edma_tcd, DmaChannel, DmaCh0InterruptHandler}; 16use embassy_mcxa::bind_interrupts;
18use embassy_mcxa::{bind_interrupts, dma};
19use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; 17use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
20use embassy_mcxa::pac; 18use embassy_mcxa::pac;
21use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 19use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
@@ -80,19 +78,7 @@ async fn main(_spawner: Spawner) {
80 78
81 defmt::info!("DMA wrap transfer example starting..."); 79 defmt::info!("DMA wrap transfer example starting...");
82 80
83 // Enable DMA0 clock and release reset 81 // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL)
84 unsafe {
85 hal::peripherals::DMA0::enable_clock();
86 hal::peripherals::DMA0::release_reset();
87 }
88
89 let pac_periphs = unsafe { pac::Peripherals::steal() };
90
91 unsafe {
92 dma::init(&pac_periphs);
93 }
94
95 // Enable DMA interrupt
96 unsafe { 82 unsafe {
97 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); 83 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
98 } 84 }
@@ -130,9 +116,6 @@ async fn main(_spawner: Spawner) {
130 // Create DMA channel using Embassy-style API 116 // Create DMA channel using Embassy-style API
131 let dma_ch0 = DmaChannel::new(p.DMA_CH0); 117 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
132 118
133 // Use edma_tcd() accessor instead of passing register block around
134 let edma = edma_tcd();
135
136 // Configure wrap transfer using direct TCD access: 119 // Configure wrap transfer using direct TCD access:
137 // SRC is 16 bytes (4 * u32). We want to transfer 32 bytes (8 * u32). 120 // SRC is 16 bytes (4 * u32). We want to transfer 32 bytes (8 * u32).
138 // SRC modulo is 16 bytes (2^4 = 16) - wraps source address. 121 // SRC modulo is 16 bytes (2^4 = 16) - wraps source address.
@@ -140,7 +123,7 @@ async fn main(_spawner: Spawner) {
140 // This causes the source address to wrap around after 16 bytes, 123 // This causes the source address to wrap around after 16 bytes,
141 // effectively repeating the source data. 124 // effectively repeating the source data.
142 unsafe { 125 unsafe {
143 let t = edma.tcd(0); 126 let t = dma_ch0.tcd();
144 127
145 // Reset channel state 128 // Reset channel state
146 t.ch_csr().write(|w| { 129 t.ch_csr().write(|w| {
@@ -189,14 +172,14 @@ async fn main(_spawner: Spawner) {
189 cortex_m::asm::dsb(); 172 cortex_m::asm::dsb();
190 173
191 tx.blocking_write(b"Triggering transfer...\r\n").unwrap(); 174 tx.blocking_write(b"Triggering transfer...\r\n").unwrap();
192 dma_ch0.trigger_start(edma); 175 dma_ch0.trigger_start();
193 } 176 }
194 177
195 // Wait for completion using channel helper method 178 // Wait for completion using channel helper method
196 while !dma_ch0.is_done(edma) { 179 while !dma_ch0.is_done() {
197 cortex_m::asm::nop(); 180 cortex_m::asm::nop();
198 } 181 }
199 unsafe { dma_ch0.clear_done(edma); } 182 unsafe { dma_ch0.clear_done(); }
200 183
201 tx.blocking_write(b"\r\nEDMA wrap transfer example finish.\r\n\r\n") 184 tx.blocking_write(b"\r\nEDMA wrap transfer example finish.\r\n\r\n")
202 .unwrap(); 185 .unwrap();
diff --git a/examples/src/bin/lpuart_dma.rs b/examples/src/bin/lpuart_dma.rs
index 5ccf97ecc..4e321b111 100644
--- a/examples/src/bin/lpuart_dma.rs
+++ b/examples/src/bin/lpuart_dma.rs
@@ -3,28 +3,25 @@
3//! This example demonstrates using DMA for UART TX and RX operations. 3//! This example demonstrates using DMA for UART TX and RX operations.
4//! It sends a message using DMA, then waits for 16 characters to be received 4//! It sends a message using DMA, then waits for 16 characters to be received
5//! via DMA and echoes them back. 5//! via DMA and echoes them back.
6//!
7//! The DMA request sources are automatically derived from the LPUART instance type.
8//! DMA clock/reset/init is handled automatically by the HAL.
6 9
7#![no_std] 10#![no_std]
8#![no_main] 11#![no_main]
9 12
10use embassy_executor::Spawner; 13use embassy_executor::Spawner;
11use embassy_mcxa::clocks::config::Div8; 14use embassy_mcxa::clocks::config::Div8;
12use embassy_mcxa::clocks::Gate; 15use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler};
13use embassy_mcxa::dma::{self, DMA_REQ_LPUART2_RX, DMA_REQ_LPUART2_TX};
14use embassy_mcxa::lpuart::{Config, LpuartDma}; 16use embassy_mcxa::lpuart::{Config, LpuartDma};
15use embassy_mcxa::pac; 17use embassy_mcxa::{bind_interrupts, pac};
16use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 18use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
17 19
18// DMA interrupt handlers 20// Bind DMA channel interrupts using Embassy-style macro
19#[no_mangle] 21bind_interrupts!(struct Irqs {
20pub extern "C" fn DMA_CH0() { 22 DMA_CH0 => DmaCh0InterruptHandler;
21 unsafe { dma::on_interrupt(0) }; 23 DMA_CH1 => DmaCh1InterruptHandler;
22} 24});
23
24#[no_mangle]
25pub extern "C" fn DMA_CH1() {
26 unsafe { dma::on_interrupt(1) };
27}
28 25
29#[embassy_executor::main] 26#[embassy_executor::main]
30async fn main(_spawner: Spawner) { 27async fn main(_spawner: Spawner) {
@@ -35,24 +32,7 @@ async fn main(_spawner: Spawner) {
35 32
36 defmt::info!("LPUART DMA example starting..."); 33 defmt::info!("LPUART DMA example starting...");
37 34
38 // Enable DMA0 clock and release reset 35 // Enable DMA interrupts (per-channel, as needed)
39 unsafe {
40 hal::peripherals::DMA0::enable_clock();
41 hal::peripherals::DMA0::release_reset();
42 }
43
44 // Get PAC peripherals for DMA init
45 let pac_periphs = unsafe { pac::Peripherals::steal() };
46
47 // Initialize DMA
48 unsafe {
49 dma::init(&pac_periphs);
50 }
51
52 // Get EDMA TCD register block for transfers
53 let edma = &pac_periphs.edma_0_tcd0;
54
55 // Enable DMA interrupts
56 unsafe { 36 unsafe {
57 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); 37 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
58 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1); 38 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1);
@@ -77,51 +57,29 @@ async fn main(_spawner: Spawner) {
77 ) 57 )
78 .unwrap(); 58 .unwrap();
79 59
80 // Send a message using DMA 60 // Send a message using DMA (DMA request source is automatically derived from LPUART2)
81 let tx_msg = b"Hello from LPUART2 DMA TX!\r\n"; 61 let tx_msg = b"Hello from LPUART2 DMA TX!\r\n";
82 lpuart 62 lpuart.write_dma(tx_msg).await.unwrap();
83 .write_dma(edma, DMA_REQ_LPUART2_TX, tx_msg)
84 .await
85 .unwrap();
86 63
87 defmt::info!("TX DMA complete"); 64 defmt::info!("TX DMA complete");
88 65
89 // Send prompt 66 // Send prompt
90 let prompt = b"Type 16 characters to echo via DMA:\r\n"; 67 let prompt = b"Type 16 characters to echo via DMA:\r\n";
91 lpuart 68 lpuart.write_dma(prompt).await.unwrap();
92 .write_dma(edma, DMA_REQ_LPUART2_TX, prompt)
93 .await
94 .unwrap();
95 69
96 // Receive 16 characters using DMA 70 // Receive 16 characters using DMA
97 let mut rx_buf = [0u8; 16]; 71 let mut rx_buf = [0u8; 16];
98 lpuart 72 lpuart.read_dma(&mut rx_buf).await.unwrap();
99 .read_dma(edma, DMA_REQ_LPUART2_RX, &mut rx_buf)
100 .await
101 .unwrap();
102 73
103 defmt::info!("RX DMA complete"); 74 defmt::info!("RX DMA complete");
104 75
105 // Echo back the received data 76 // Echo back the received data
106 let echo_prefix = b"\r\nReceived: "; 77 let echo_prefix = b"\r\nReceived: ";
107 lpuart 78 lpuart.write_dma(echo_prefix).await.unwrap();
108 .write_dma(edma, DMA_REQ_LPUART2_TX, echo_prefix) 79 lpuart.write_dma(&rx_buf).await.unwrap();
109 .await
110 .unwrap();
111 lpuart
112 .write_dma(edma, DMA_REQ_LPUART2_TX, &rx_buf)
113 .await
114 .unwrap();
115 let done_msg = b"\r\nDone!\r\n"; 80 let done_msg = b"\r\nDone!\r\n";
116 lpuart 81 lpuart.write_dma(done_msg).await.unwrap();
117 .write_dma(edma, DMA_REQ_LPUART2_TX, done_msg)
118 .await
119 .unwrap();
120 82
121 defmt::info!("Example complete"); 83 defmt::info!("Example complete");
122
123 loop {
124 cortex_m::asm::wfe();
125 }
126} 84}
127 85
diff --git a/examples/src/bin/lpuart_ring_buffer.rs b/examples/src/bin/lpuart_ring_buffer.rs
index bc666560c..d71876ade 100644
--- a/examples/src/bin/lpuart_ring_buffer.rs
+++ b/examples/src/bin/lpuart_ring_buffer.rs
@@ -20,8 +20,7 @@
20 20
21use embassy_executor::Spawner; 21use embassy_executor::Spawner;
22use embassy_mcxa::clocks::config::Div8; 22use embassy_mcxa::clocks::config::Div8;
23use embassy_mcxa::clocks::Gate; 23use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler, DmaCh1InterruptHandler, DMA_REQ_LPUART2_RX};
24use embassy_mcxa::dma::{self, DmaChannel, DmaCh0InterruptHandler, DmaCh1InterruptHandler, DMA_REQ_LPUART2_RX};
25use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; 24use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
26use embassy_mcxa::{bind_interrupts, pac}; 25use embassy_mcxa::{bind_interrupts, pac};
27use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 26use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
@@ -56,20 +55,7 @@ async fn main(_spawner: Spawner) {
56 55
57 defmt::info!("LPUART Ring Buffer DMA example starting..."); 56 defmt::info!("LPUART Ring Buffer DMA example starting...");
58 57
59 // Enable DMA0 clock and release reset 58 // Enable DMA interrupts (DMA clock/reset/init is handled automatically by HAL)
60 unsafe {
61 hal::peripherals::DMA0::enable_clock();
62 hal::peripherals::DMA0::release_reset();
63 }
64
65 let pac_periphs = unsafe { pac::Peripherals::steal() };
66
67 // Initialize DMA
68 unsafe {
69 dma::init(&pac_periphs);
70 }
71
72 // Enable DMA interrupts
73 unsafe { 59 unsafe {
74 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); 60 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
75 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1); 61 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1);
@@ -99,11 +85,10 @@ async fn main(_spawner: Spawner) {
99 85
100 // Create DMA channel for RX 86 // Create DMA channel for RX
101 let dma_ch_rx = DmaChannel::new(p.DMA_CH0); 87 let dma_ch_rx = DmaChannel::new(p.DMA_CH0);
102 let edma = dma::edma_tcd();
103 88
104 // Configure the DMA mux for LPUART2 RX 89 // Configure the DMA mux for LPUART2 RX
105 unsafe { 90 unsafe {
106 dma_ch_rx.set_request_source(edma, DMA_REQ_LPUART2_RX); 91 dma_ch_rx.set_request_source(DMA_REQ_LPUART2_RX);
107 } 92 }
108 93
109 tx.blocking_write(b"Setting up circular DMA for UART RX...\r\n").unwrap(); 94 tx.blocking_write(b"Setting up circular DMA for UART RX...\r\n").unwrap();
@@ -117,7 +102,7 @@ async fn main(_spawner: Spawner) {
117 102
118 // Enable DMA requests to start continuous reception 103 // Enable DMA requests to start continuous reception
119 unsafe { 104 unsafe {
120 dma_ch_rx.enable_request(edma); 105 dma_ch_rx.enable_request();
121 } 106 }
122 107
123 tx.blocking_write(b"Ring buffer ready! Type characters to see them echoed.\r\n").unwrap(); 108 tx.blocking_write(b"Ring buffer ready! Type characters to see them echoed.\r\n").unwrap();