aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Munns <[email protected]>2025-12-05 15:22:38 +0100
committerJames Munns <[email protected]>2025-12-05 15:22:38 +0100
commitfa54dd5849a083b286b2a3f1928428c8704d3d70 (patch)
tree56f6e4f4ad5233d357a7ef5fefb38083f32d0562
parent1ce2083f9a0fcf1cfbb10de0fb3ed44b460a5cc7 (diff)
Create separate ring buffered RX receiver to encapsulate unsafe
-rw-r--r--embassy-mcxa/src/dma.rs15
-rw-r--r--embassy-mcxa/src/lpuart/mod.rs40
-rw-r--r--examples/mcxa/Cargo.toml1
-rw-r--r--examples/mcxa/src/bin/lpuart_dma.rs2
-rw-r--r--examples/mcxa/src/bin/lpuart_ring_buffer.rs15
5 files changed, 55 insertions, 18 deletions
diff --git a/embassy-mcxa/src/dma.rs b/embassy-mcxa/src/dma.rs
index 7d1588516..d563c2e29 100644
--- a/embassy-mcxa/src/dma.rs
+++ b/embassy-mcxa/src/dma.rs
@@ -2170,7 +2170,14 @@ impl<'a, W: Word> RingBuffer<'a, W> {
2170 /// Stop the DMA transfer and consume the ring buffer. 2170 /// Stop the DMA transfer and consume the ring buffer.
2171 /// 2171 ///
2172 /// Returns any remaining unread data count. 2172 /// Returns any remaining unread data count.
2173 pub fn stop(self) -> usize { 2173 pub fn stop(mut self) -> usize {
2174 let res = self.teardown();
2175 drop(self);
2176 res
2177 }
2178
2179 /// Stop the DMA transfer. Intended to be called by `stop()` or `Drop`.
2180 fn teardown(&mut self) -> usize {
2174 let available = self.available(); 2181 let available = self.available();
2175 2182
2176 // Disable the channel 2183 // Disable the channel
@@ -2187,6 +2194,12 @@ impl<'a, W: Word> RingBuffer<'a, W> {
2187 } 2194 }
2188} 2195}
2189 2196
2197impl<'a, W: Word> Drop for RingBuffer<'a, W> {
2198 fn drop(&mut self) {
2199 self.teardown();
2200 }
2201}
2202
2190impl<C: Channel> DmaChannel<C> { 2203impl<C: Channel> DmaChannel<C> {
2191 /// Set up a circular DMA transfer for continuous peripheral-to-memory reception. 2204 /// Set up a circular DMA transfer for continuous peripheral-to-memory reception.
2192 /// 2205 ///
diff --git a/embassy-mcxa/src/lpuart/mod.rs b/embassy-mcxa/src/lpuart/mod.rs
index 39fecb413..a176c7032 100644
--- a/embassy-mcxa/src/lpuart/mod.rs
+++ b/embassy-mcxa/src/lpuart/mod.rs
@@ -1,16 +1,17 @@
1use core::future::Future;
1use core::marker::PhantomData; 2use core::marker::PhantomData;
2 3
3use embassy_hal_internal::{Peri, PeripheralType}; 4use embassy_hal_internal::{Peri, PeripheralType};
4use paste::paste; 5use paste::paste;
5 6
6use crate::clocks::periph_helpers::{Div4, LpuartClockSel, LpuartConfig}; 7use crate::clocks::periph_helpers::{Div4, LpuartClockSel, LpuartConfig};
7use crate::clocks::{ClockError, Gate, PoweredClock, enable_and_reset}; 8use crate::clocks::{enable_and_reset, ClockError, Gate, PoweredClock};
8use crate::gpio::SealedPin; 9use crate::gpio::SealedPin;
9use crate::pac::lpuart0::baud::Sbns as StopBits; 10use crate::pac::lpuart0::baud::Sbns as StopBits;
10use crate::pac::lpuart0::ctrl::{Idlecfg as IdleConfig, Ilt as IdleType, M as DataBits, Pt as Parity}; 11use crate::pac::lpuart0::ctrl::{Idlecfg as IdleConfig, Ilt as IdleType, Pt as Parity, M as DataBits};
11use crate::pac::lpuart0::modir::{Txctsc as TxCtsConfig, Txctssrc as TxCtsSource}; 12use crate::pac::lpuart0::modir::{Txctsc as TxCtsConfig, Txctssrc as TxCtsSource};
12use crate::pac::lpuart0::stat::Msbf as MsbFirst; 13use crate::pac::lpuart0::stat::Msbf as MsbFirst;
13use crate::{AnyPin, interrupt, pac}; 14use crate::{interrupt, pac, AnyPin};
14 15
15pub mod buffered; 16pub mod buffered;
16 17
@@ -720,6 +721,12 @@ pub struct LpuartDma<'a, T: Instance, TxC: DmaChannelTrait, RxC: DmaChannelTrait
720 rx: LpuartRxDma<'a, T, RxC>, 721 rx: LpuartRxDma<'a, T, RxC>,
721} 722}
722 723
724/// Lpuart RX driver with ring-buffered DMA support.
725pub struct LpuartRxRingDma<'peri, 'ring, T: Instance, C: DmaChannelTrait> {
726 _inner: LpuartRxDma<'peri, T, C>,
727 ring: RingBuffer<'ring, u8>,
728}
729
723// ============================================================================ 730// ============================================================================
724// LPUART CORE IMPLEMENTATION 731// LPUART CORE IMPLEMENTATION
725// ============================================================================ 732// ============================================================================
@@ -1402,6 +1409,14 @@ impl<'a, T: Instance, C: DmaChannelTrait> LpuartRxDma<'a, T, C> {
1402 Ok(()) 1409 Ok(())
1403 } 1410 }
1404 1411
1412 pub fn into_ring_dma_rx<'buf>(self, buf: &'buf mut [u8]) -> LpuartRxRingDma<'a, 'buf, T, C> {
1413 unsafe {
1414 let ring = self.setup_ring_buffer(buf);
1415 self.enable_dma_request();
1416 LpuartRxRingDma { _inner: self, ring }
1417 }
1418 }
1419
1405 /// Set up a ring buffer for continuous DMA reception. 1420 /// Set up a ring buffer for continuous DMA reception.
1406 /// 1421 ///
1407 /// This configures the DMA channel for circular operation, enabling continuous 1422 /// This configures the DMA channel for circular operation, enabling continuous
@@ -1441,7 +1456,7 @@ impl<'a, T: Instance, C: DmaChannelTrait> LpuartRxDma<'a, T, C> {
1441 /// - Only one RingBuffer should exist per LPUART RX channel at a time. 1456 /// - Only one RingBuffer should exist per LPUART RX channel at a time.
1442 /// - The caller must ensure the static buffer is not accessed elsewhere while 1457 /// - The caller must ensure the static buffer is not accessed elsewhere while
1443 /// the ring buffer is active. 1458 /// the ring buffer is active.
1444 pub unsafe fn setup_ring_buffer<'b>(&self, buf: &'b mut [u8]) -> RingBuffer<'b, u8> { 1459 unsafe fn setup_ring_buffer<'b>(&self, buf: &'b mut [u8]) -> RingBuffer<'b, u8> {
1445 // Get the peripheral data register address 1460 // Get the peripheral data register address
1446 let peri_addr = self.info.regs.data().as_ptr() as *const u8; 1461 let peri_addr = self.info.regs.data().as_ptr() as *const u8;
1447 1462
@@ -1460,11 +1475,26 @@ impl<'a, T: Instance, C: DmaChannelTrait> LpuartRxDma<'a, T, C> {
1460 /// Call this after `setup_ring_buffer()` to start continuous reception. 1475 /// Call this after `setup_ring_buffer()` to start continuous reception.
1461 /// This is separated from setup to allow for any additional configuration 1476 /// This is separated from setup to allow for any additional configuration
1462 /// before starting the transfer. 1477 /// before starting the transfer.
1463 pub unsafe fn enable_dma_request(&self) { 1478 unsafe fn enable_dma_request(&self) {
1464 self.rx_dma.enable_request(); 1479 self.rx_dma.enable_request();
1465 } 1480 }
1466} 1481}
1467 1482
1483impl<'peri, 'buf, T: Instance, C: DmaChannelTrait> LpuartRxRingDma<'peri, 'buf, T, C> {
1484 /// Read from the ring buffer
1485 pub fn read<'d>(
1486 &mut self,
1487 dst: &'d mut [u8],
1488 ) -> impl Future<Output = core::result::Result<usize, crate::dma::Error>> + use<'_, 'buf, 'd, T, C> {
1489 self.ring.read(dst)
1490 }
1491
1492 /// Clear the current contents of the ring buffer
1493 pub fn clear(&mut self) {
1494 self.ring.clear();
1495 }
1496}
1497
1468impl<'a, T: Instance, TxC: DmaChannelTrait, RxC: DmaChannelTrait> LpuartDma<'a, T, TxC, RxC> { 1498impl<'a, T: Instance, TxC: DmaChannelTrait, RxC: DmaChannelTrait> LpuartDma<'a, T, TxC, RxC> {
1469 /// Create a new LPUART driver with DMA support for both TX and RX. 1499 /// Create a new LPUART driver with DMA support for both TX and RX.
1470 pub fn new( 1500 pub fn new(
diff --git a/examples/mcxa/Cargo.toml b/examples/mcxa/Cargo.toml
index 4d0459f41..1ac8eac53 100644
--- a/examples/mcxa/Cargo.toml
+++ b/examples/mcxa/Cargo.toml
@@ -20,6 +20,7 @@ embassy-time-driver = "0.2.1"
20embedded-io-async = "0.6.1" 20embedded-io-async = "0.6.1"
21heapless = "0.9.2" 21heapless = "0.9.2"
22panic-probe = { version = "1.0", features = ["print-defmt"] } 22panic-probe = { version = "1.0", features = ["print-defmt"] }
23static_cell = "2.1.1"
23tmp108 = "0.4.0" 24tmp108 = "0.4.0"
24 25
25[profile.release] 26[profile.release]
diff --git a/examples/mcxa/src/bin/lpuart_dma.rs b/examples/mcxa/src/bin/lpuart_dma.rs
index 1fc6595e6..34d343452 100644
--- a/examples/mcxa/src/bin/lpuart_dma.rs
+++ b/examples/mcxa/src/bin/lpuart_dma.rs
@@ -14,7 +14,7 @@ use embassy_executor::Spawner;
14use embassy_mcxa::clocks::config::Div8; 14use embassy_mcxa::clocks::config::Div8;
15use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler}; 15use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler};
16use embassy_mcxa::lpuart::{Config, LpuartDma}; 16use embassy_mcxa::lpuart::{Config, LpuartDma};
17use embassy_mcxa::{bind_interrupts, pac}; 17use embassy_mcxa::bind_interrupts;
18use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 18use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
19 19
20// Bind DMA channel interrupts using Embassy-style macro 20// Bind DMA channel interrupts using Embassy-style macro
diff --git a/examples/mcxa/src/bin/lpuart_ring_buffer.rs b/examples/mcxa/src/bin/lpuart_ring_buffer.rs
index 1d1a51970..b707e20f8 100644
--- a/examples/mcxa/src/bin/lpuart_ring_buffer.rs
+++ b/examples/mcxa/src/bin/lpuart_ring_buffer.rs
@@ -23,6 +23,7 @@ use embassy_mcxa::bind_interrupts;
23use embassy_mcxa::clocks::config::Div8; 23use embassy_mcxa::clocks::config::Div8;
24use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler}; 24use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler};
25use embassy_mcxa::lpuart::{Config, LpuartDma, LpuartTxDma}; 25use embassy_mcxa::lpuart::{Config, LpuartDma, LpuartTxDma};
26use static_cell::ConstStaticCell;
26use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 27use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
27 28
28// Bind DMA channel interrupts 29// Bind DMA channel interrupts
@@ -32,7 +33,7 @@ bind_interrupts!(struct Irqs {
32}); 33});
33 34
34// Ring buffer for RX - power of 2 is ideal for modulo efficiency 35// Ring buffer for RX - power of 2 is ideal for modulo efficiency
35static mut RX_RING_BUFFER: [u8; 64] = [0; 64]; 36static RX_RING_BUFFER: ConstStaticCell<[u8; 64]> = ConstStaticCell::new([0; 64]);
36 37
37/// Helper to write a byte as hex to UART 38/// Helper to write a byte as hex to UART
38fn write_hex<T: embassy_mcxa::lpuart::Instance, C: embassy_mcxa::dma::Channel>( 39fn write_hex<T: embassy_mcxa::lpuart::Instance, C: embassy_mcxa::dma::Channel>(
@@ -75,17 +76,9 @@ async fn main(_spawner: Spawner) {
75 tx.blocking_write(b"Setting up circular DMA for UART RX...\r\n") 76 tx.blocking_write(b"Setting up circular DMA for UART RX...\r\n")
76 .unwrap(); 77 .unwrap();
77 78
79 let buf = RX_RING_BUFFER.take();
78 // Set up the ring buffer with circular DMA 80 // Set up the ring buffer with circular DMA
79 // The HAL handles: DMA request source, RDMAE enable, circular transfer config, NVIC enable 81 let mut ring_buf = rx.into_ring_dma_rx(buf);
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 82
90 tx.blocking_write(b"Ring buffer ready! Type characters to see them echoed.\r\n") 83 tx.blocking_write(b"Ring buffer ready! Type characters to see them echoed.\r\n")
91 .unwrap(); 84 .unwrap();