diff options
| author | James Munns <[email protected]> | 2025-12-05 15:22:38 +0100 |
|---|---|---|
| committer | James Munns <[email protected]> | 2025-12-05 15:22:38 +0100 |
| commit | fa54dd5849a083b286b2a3f1928428c8704d3d70 (patch) | |
| tree | 56f6e4f4ad5233d357a7ef5fefb38083f32d0562 | |
| parent | 1ce2083f9a0fcf1cfbb10de0fb3ed44b460a5cc7 (diff) | |
Create separate ring buffered RX receiver to encapsulate unsafe
| -rw-r--r-- | embassy-mcxa/src/dma.rs | 15 | ||||
| -rw-r--r-- | embassy-mcxa/src/lpuart/mod.rs | 40 | ||||
| -rw-r--r-- | examples/mcxa/Cargo.toml | 1 | ||||
| -rw-r--r-- | examples/mcxa/src/bin/lpuart_dma.rs | 2 | ||||
| -rw-r--r-- | examples/mcxa/src/bin/lpuart_ring_buffer.rs | 15 |
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 | ||
| 2197 | impl<'a, W: Word> Drop for RingBuffer<'a, W> { | ||
| 2198 | fn drop(&mut self) { | ||
| 2199 | self.teardown(); | ||
| 2200 | } | ||
| 2201 | } | ||
| 2202 | |||
| 2190 | impl<C: Channel> DmaChannel<C> { | 2203 | impl<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 @@ | |||
| 1 | use core::future::Future; | ||
| 1 | use core::marker::PhantomData; | 2 | use core::marker::PhantomData; |
| 2 | 3 | ||
| 3 | use embassy_hal_internal::{Peri, PeripheralType}; | 4 | use embassy_hal_internal::{Peri, PeripheralType}; |
| 4 | use paste::paste; | 5 | use paste::paste; |
| 5 | 6 | ||
| 6 | use crate::clocks::periph_helpers::{Div4, LpuartClockSel, LpuartConfig}; | 7 | use crate::clocks::periph_helpers::{Div4, LpuartClockSel, LpuartConfig}; |
| 7 | use crate::clocks::{ClockError, Gate, PoweredClock, enable_and_reset}; | 8 | use crate::clocks::{enable_and_reset, ClockError, Gate, PoweredClock}; |
| 8 | use crate::gpio::SealedPin; | 9 | use crate::gpio::SealedPin; |
| 9 | use crate::pac::lpuart0::baud::Sbns as StopBits; | 10 | use crate::pac::lpuart0::baud::Sbns as StopBits; |
| 10 | use crate::pac::lpuart0::ctrl::{Idlecfg as IdleConfig, Ilt as IdleType, M as DataBits, Pt as Parity}; | 11 | use crate::pac::lpuart0::ctrl::{Idlecfg as IdleConfig, Ilt as IdleType, Pt as Parity, M as DataBits}; |
| 11 | use crate::pac::lpuart0::modir::{Txctsc as TxCtsConfig, Txctssrc as TxCtsSource}; | 12 | use crate::pac::lpuart0::modir::{Txctsc as TxCtsConfig, Txctssrc as TxCtsSource}; |
| 12 | use crate::pac::lpuart0::stat::Msbf as MsbFirst; | 13 | use crate::pac::lpuart0::stat::Msbf as MsbFirst; |
| 13 | use crate::{AnyPin, interrupt, pac}; | 14 | use crate::{interrupt, pac, AnyPin}; |
| 14 | 15 | ||
| 15 | pub mod buffered; | 16 | pub 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. | ||
| 725 | pub 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 | ||
| 1483 | impl<'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 | |||
| 1468 | impl<'a, T: Instance, TxC: DmaChannelTrait, RxC: DmaChannelTrait> LpuartDma<'a, T, TxC, RxC> { | 1498 | impl<'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" | |||
| 20 | embedded-io-async = "0.6.1" | 20 | embedded-io-async = "0.6.1" |
| 21 | heapless = "0.9.2" | 21 | heapless = "0.9.2" |
| 22 | panic-probe = { version = "1.0", features = ["print-defmt"] } | 22 | panic-probe = { version = "1.0", features = ["print-defmt"] } |
| 23 | static_cell = "2.1.1" | ||
| 23 | tmp108 = "0.4.0" | 24 | tmp108 = "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; | |||
| 14 | use embassy_mcxa::clocks::config::Div8; | 14 | use embassy_mcxa::clocks::config::Div8; |
| 15 | use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler}; | 15 | use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler}; |
| 16 | use embassy_mcxa::lpuart::{Config, LpuartDma}; | 16 | use embassy_mcxa::lpuart::{Config, LpuartDma}; |
| 17 | use embassy_mcxa::{bind_interrupts, pac}; | 17 | use embassy_mcxa::bind_interrupts; |
| 18 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | 18 | use {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; | |||
| 23 | use embassy_mcxa::clocks::config::Div8; | 23 | use embassy_mcxa::clocks::config::Div8; |
| 24 | use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler}; | 24 | use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler}; |
| 25 | use embassy_mcxa::lpuart::{Config, LpuartDma, LpuartTxDma}; | 25 | use embassy_mcxa::lpuart::{Config, LpuartDma, LpuartTxDma}; |
| 26 | use static_cell::ConstStaticCell; | ||
| 26 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | 27 | use {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 |
| 35 | static mut RX_RING_BUFFER: [u8; 64] = [0; 64]; | 36 | static 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 |
| 38 | fn write_hex<T: embassy_mcxa::lpuart::Instance, C: embassy_mcxa::dma::Channel>( | 39 | fn 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(); |
