aboutsummaryrefslogtreecommitdiff
path: root/examples/mcxa/src/bin/lpuart_ring_buffer.rs
diff options
context:
space:
mode:
authorJames Munns <[email protected]>2025-12-05 14:28:47 +0100
committerJames Munns <[email protected]>2025-12-05 14:28:47 +0100
commitb252db845e19603faf528cf93fe0c44757a27430 (patch)
tree99e646d17bed747df244dd607a15f5a67baa530a /examples/mcxa/src/bin/lpuart_ring_buffer.rs
parent6a1eed83b9df8ffa81b93860f530f5bb3252d996 (diff)
Move
Diffstat (limited to 'examples/mcxa/src/bin/lpuart_ring_buffer.rs')
-rw-r--r--examples/mcxa/src/bin/lpuart_ring_buffer.rs130
1 files changed, 130 insertions, 0 deletions
diff --git a/examples/mcxa/src/bin/lpuart_ring_buffer.rs b/examples/mcxa/src/bin/lpuart_ring_buffer.rs
new file mode 100644
index 000000000..1d1a51970
--- /dev/null
+++ b/examples/mcxa/src/bin/lpuart_ring_buffer.rs
@@ -0,0 +1,130 @@
1//! LPUART Ring Buffer DMA example for MCXA276.
2//!
3//! This example demonstrates using the high-level `LpuartRxDma::setup_ring_buffer()`
4//! API for continuous circular DMA reception from a UART peripheral.
5//!
6//! # Features demonstrated:
7//! - `LpuartRxDma::setup_ring_buffer()` for continuous peripheral-to-memory DMA
8//! - `RingBuffer` for async reading of received data
9//! - Handling of potential overrun conditions
10//! - Half-transfer and complete-transfer interrupts for timely wakeups
11//!
12//! # How it works:
13//! 1. Create an `LpuartRxDma` driver with a DMA channel
14//! 2. Call `setup_ring_buffer()` which handles all low-level DMA configuration
15//! 3. Application asynchronously reads data as it arrives via `ring_buf.read()`
16//! 4. Both half-transfer and complete-transfer interrupts wake the reader
17
18#![no_std]
19#![no_main]
20
21use embassy_executor::Spawner;
22use embassy_mcxa::bind_interrupts;
23use embassy_mcxa::clocks::config::Div8;
24use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler};
25use embassy_mcxa::lpuart::{Config, LpuartDma, LpuartTxDma};
26use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
27
28// Bind DMA channel interrupts
29bind_interrupts!(struct Irqs {
30 DMA_CH0 => DmaCh0InterruptHandler;
31 DMA_CH1 => DmaCh1InterruptHandler;
32});
33
34// Ring buffer for RX - power of 2 is ideal for modulo efficiency
35static mut RX_RING_BUFFER: [u8; 64] = [0; 64];
36
37/// Helper to write a byte as hex to UART
38fn write_hex<T: embassy_mcxa::lpuart::Instance, C: embassy_mcxa::dma::Channel>(
39 tx: &mut LpuartTxDma<'_, T, C>,
40 byte: u8,
41) {
42 const HEX: &[u8; 16] = b"0123456789ABCDEF";
43 let buf = [HEX[(byte >> 4) as usize], HEX[(byte & 0x0F) as usize]];
44 tx.blocking_write(&buf).ok();
45}
46
47#[embassy_executor::main]
48async fn main(_spawner: Spawner) {
49 // Small delay to allow probe-rs to attach after reset
50 for _ in 0..100_000 {
51 cortex_m::asm::nop();
52 }
53
54 let mut cfg = hal::config::Config::default();
55 cfg.clock_cfg.sirc.fro_12m_enabled = true;
56 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
57 let p = hal::init(cfg);
58
59 defmt::info!("LPUART Ring Buffer DMA example starting...");
60
61 // Create UART configuration
62 let config = Config {
63 baudrate_bps: 115_200,
64 ..Default::default()
65 };
66
67 // Create LPUART with DMA support for both TX and RX, then split
68 // This is the proper Embassy pattern - create once, split into TX and RX
69 let lpuart = LpuartDma::new(p.LPUART2, p.P2_2, p.P2_3, p.DMA_CH1, p.DMA_CH0, config).unwrap();
70 let (mut tx, rx) = lpuart.split();
71
72 tx.blocking_write(b"LPUART Ring Buffer DMA Example\r\n").unwrap();
73 tx.blocking_write(b"==============================\r\n\r\n").unwrap();
74
75 tx.blocking_write(b"Setting up circular DMA for UART RX...\r\n")
76 .unwrap();
77
78 // Set up the ring buffer with circular DMA
79 // The HAL handles: DMA request source, RDMAE enable, circular transfer config, NVIC enable
80 let ring_buf = unsafe {
81 let buf = &mut *core::ptr::addr_of_mut!(RX_RING_BUFFER);
82 rx.setup_ring_buffer(buf)
83 };
84
85 // Enable DMA requests to start continuous reception
86 unsafe {
87 rx.enable_dma_request();
88 }
89
90 tx.blocking_write(b"Ring buffer ready! Type characters to see them echoed.\r\n")
91 .unwrap();
92 tx.blocking_write(b"The DMA continuously receives in the background.\r\n\r\n")
93 .unwrap();
94
95 // Main loop: read from ring buffer and echo back
96 let mut read_buf = [0u8; 16];
97 let mut total_received: usize = 0;
98
99 loop {
100 // Async read - waits until data is available
101 match ring_buf.read(&mut read_buf).await {
102 Ok(n) if n > 0 => {
103 total_received += n;
104
105 // Echo back what we received
106 tx.blocking_write(b"RX[").unwrap();
107 for (i, &byte) in read_buf.iter().enumerate().take(n) {
108 write_hex(&mut tx, byte);
109 if i < n - 1 {
110 tx.blocking_write(b" ").unwrap();
111 }
112 }
113 tx.blocking_write(b"]: ").unwrap();
114 tx.blocking_write(&read_buf[..n]).unwrap();
115 tx.blocking_write(b"\r\n").unwrap();
116
117 defmt::info!("Received {} bytes, total: {}", n, total_received);
118 }
119 Ok(_) => {
120 // No data, shouldn't happen with async read
121 }
122 Err(_) => {
123 // Overrun detected
124 tx.blocking_write(b"ERROR: Ring buffer overrun!\r\n").unwrap();
125 defmt::error!("Ring buffer overrun!");
126 ring_buf.clear();
127 }
128 }
129 }
130}