diff options
| author | James Munns <[email protected]> | 2025-12-05 14:28:47 +0100 |
|---|---|---|
| committer | James Munns <[email protected]> | 2025-12-05 14:28:47 +0100 |
| commit | b252db845e19603faf528cf93fe0c44757a27430 (patch) | |
| tree | 99e646d17bed747df244dd607a15f5a67baa530a /examples/mcxa/src/bin/lpuart_ring_buffer.rs | |
| parent | 6a1eed83b9df8ffa81b93860f530f5bb3252d996 (diff) | |
Move
Diffstat (limited to 'examples/mcxa/src/bin/lpuart_ring_buffer.rs')
| -rw-r--r-- | examples/mcxa/src/bin/lpuart_ring_buffer.rs | 130 |
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 | |||
| 21 | use embassy_executor::Spawner; | ||
| 22 | use embassy_mcxa::bind_interrupts; | ||
| 23 | use embassy_mcxa::clocks::config::Div8; | ||
| 24 | use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler}; | ||
| 25 | use embassy_mcxa::lpuart::{Config, LpuartDma, LpuartTxDma}; | ||
| 26 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | ||
| 27 | |||
| 28 | // Bind DMA channel interrupts | ||
| 29 | bind_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 | ||
| 35 | static mut RX_RING_BUFFER: [u8; 64] = [0; 64]; | ||
| 36 | |||
| 37 | /// Helper to write a byte as hex to UART | ||
| 38 | fn 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] | ||
| 48 | async 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 | } | ||
