From 50e2e2ec60ca32a2da53b91f4a30c3a71d4e9f30 Mon Sep 17 00:00:00 2001 From: etiennecollin Date: Mon, 25 Aug 2025 21:10:59 +0200 Subject: feat: add new_with_table() initializer for ring-buffers and removal of RegisterUpdaters - It is now possible to pass a linked-list table to the ring-buffer with the `new_with_table()` function or use the `new()` function for a basic ring-buffer setup. - A `simple_ring_buffer_table()` function was added to the read and write ring-buffers to generate the same table as the one created by `new()` in case the user only wants to customize the default table options. - RegisterUpdaters have been removed as the user now has direct access to the table and its items if needed. See: https://github.com/elagil/embassy/pull/1#issuecomment-2891997294 --- embassy-stm32/src/dma/gpdma/linked_list.rs | 21 +----- embassy-stm32/src/dma/gpdma/mod.rs | 22 ------ embassy-stm32/src/dma/gpdma/ringbuffered.rs | 112 ++++++++++++++++++++-------- 3 files changed, 84 insertions(+), 71 deletions(-) (limited to 'embassy-stm32/src/dma') diff --git a/embassy-stm32/src/dma/gpdma/linked_list.rs b/embassy-stm32/src/dma/gpdma/linked_list.rs index 76381def3..ca2d4fb7f 100644 --- a/embassy-stm32/src/dma/gpdma/linked_list.rs +++ b/embassy-stm32/src/dma/gpdma/linked_list.rs @@ -4,7 +4,6 @@ use stm32_metapac::gpdma::regs; use stm32_metapac::gpdma::vals::Dreq; -use super::RegisterUpdaters; use crate::dma::word::{Word, WordSize}; use crate::dma::{Dir, Request}; @@ -23,7 +22,6 @@ pub enum RunMode { /// /// Also works for 2D-capable GPDMA channels, but does not use 2D capabilities. #[derive(Debug, Copy, Clone, Default)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(C)] pub struct LinearItem { /// Transfer register 1. @@ -42,12 +40,7 @@ pub struct LinearItem { impl LinearItem { /// Create a new read DMA transfer (peripheral to memory). - pub unsafe fn new_read<'d, W: Word>( - request: Request, - peri_addr: *mut W, - buf: &'d mut [W], - register_updaters: &RegisterUpdaters, - ) -> Self { + pub unsafe fn new_read<'d, W: Word>(request: Request, peri_addr: *mut W, buf: &'d mut [W]) -> Self { Self::new_inner( request, Dir::PeripheralToMemory, @@ -57,17 +50,11 @@ impl LinearItem { true, W::size(), W::size(), - register_updaters, ) } /// Create a new write DMA transfer (memory to peripheral). - pub unsafe fn new_write<'d, MW: Word, PW: Word>( - request: Request, - buf: &'d [MW], - peri_addr: *mut PW, - register_updaters: &RegisterUpdaters, - ) -> Self { + pub unsafe fn new_write<'d, MW: Word, PW: Word>(request: Request, buf: &'d [MW], peri_addr: *mut PW) -> Self { Self::new_inner( request, Dir::MemoryToPeripheral, @@ -77,7 +64,6 @@ impl LinearItem { true, MW::size(), PW::size(), - register_updaters, ) } @@ -90,7 +76,6 @@ impl LinearItem { incr_mem: bool, data_size: WordSize, dst_size: WordSize, - register_updaters: &RegisterUpdaters, ) -> Self { // BNDT is specified as bytes, not as number of transfers. let Ok(bndt) = (mem_len * data_size.bytes()).try_into() else { @@ -105,7 +90,6 @@ impl LinearItem { tr1.set_ddw(dst_size.into()); tr1.set_sinc(dir == Dir::MemoryToPeripheral && incr_mem); tr1.set_dinc(dir == Dir::PeripheralToMemory && incr_mem); - (register_updaters.tr1)(&mut tr1); let mut tr2 = regs::ChTr2(0); tr2.set_dreq(match dir { @@ -113,7 +97,6 @@ impl LinearItem { Dir::PeripheralToMemory => Dreq::SOURCE_PERIPHERAL, }); tr2.set_reqsel(request); - (register_updaters.tr2)(&mut tr2); let (sar, dar) = match dir { Dir::MemoryToPeripheral => (mem_addr as _, peri_addr as _), diff --git a/embassy-stm32/src/dma/gpdma/mod.rs b/embassy-stm32/src/dma/gpdma/mod.rs index 4893fed94..074447148 100644 --- a/embassy-stm32/src/dma/gpdma/mod.rs +++ b/embassy-stm32/src/dma/gpdma/mod.rs @@ -73,28 +73,6 @@ impl Default for TransferOptions { } } -/// GPDMA linked-list item register updater functions. -#[derive(Debug, Copy, Clone)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct RegisterUpdaters { - /// Function used to overwrite transfer register 1. - pub tr1: fn(&mut pac::gpdma::regs::ChTr1), - /// Function used to overwrite transfer register 2. - pub tr2: fn(&mut pac::gpdma::regs::ChTr2), - /// Function used to overwrite transfer register 3. - pub tr3: fn(&mut pac::gpdma::regs::ChTr3), -} - -impl Default for RegisterUpdaters { - fn default() -> Self { - Self { - tr1: |_| {}, - tr2: |_| {}, - tr3: |_| {}, - } - } -} - impl From for vals::Dw { fn from(raw: WordSize) -> Self { match raw { diff --git a/embassy-stm32/src/dma/gpdma/ringbuffered.rs b/embassy-stm32/src/dma/gpdma/ringbuffered.rs index 359bc83b3..d7451285e 100644 --- a/embassy-stm32/src/dma/gpdma/ringbuffered.rs +++ b/embassy-stm32/src/dma/gpdma/ringbuffered.rs @@ -8,7 +8,7 @@ use core::task::Waker; use embassy_hal_internal::Peri; -use super::{AnyChannel, RegisterUpdaters, TransferOptions, STATE}; +use super::{AnyChannel, TransferOptions, STATE}; use crate::dma::gpdma::linked_list::{LinearItem, RunMode, Table}; use crate::dma::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; use crate::dma::word::Word; @@ -48,14 +48,14 @@ impl<'a> DmaCtrl for DmaCtrlImpl<'a> { } /// Ringbuffer for receiving data using GPDMA linked-list mode. -pub struct ReadableRingBuffer<'a, W: Word> { +pub struct ReadableRingBuffer<'a, W: Word, const L: usize> { channel: Peri<'a, AnyChannel>, ringbuf: ReadableDmaRingBuffer<'a, W>, - table: Table<2>, + table: Table, options: TransferOptions, } -impl<'a, W: Word> ReadableRingBuffer<'a, W> { +impl<'a, W: Word> ReadableRingBuffer<'a, W, 2> { /// Create a new ring buffer. /// /// Transfer options are applied to the individual linked list items. @@ -65,19 +65,30 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { peri_addr: *mut W, buffer: &'a mut [W], options: TransferOptions, - register_updaters: RegisterUpdaters, ) -> Self { let channel: Peri<'a, AnyChannel> = channel.into(); + let table = Self::simple_ring_buffer_table(request, peri_addr, buffer); - // Buffer halves should be the same length. - let half_len = buffer.len() / 2; - assert_eq!(half_len * 2, buffer.len()); + Self { + channel, + ringbuf: ReadableDmaRingBuffer::new(buffer), + table, + options, + } + } +} - let items = [ - LinearItem::new_read(request, peri_addr, &mut buffer[..half_len], ®ister_updaters), - LinearItem::new_read(request, peri_addr, &mut buffer[half_len..], ®ister_updaters), - ]; - let table = Table::new(items); +impl<'a, W: Word, const L: usize> ReadableRingBuffer<'a, W, L> { + /// Create a new ring buffer with a provided linked-list table. + /// + /// Transfer options are applied to the individual linked list items. + pub fn new_with_table( + channel: Peri<'a, impl Channel>, + buffer: &'a mut [W], + options: TransferOptions, + table: Table, + ) -> Self { + let channel: Peri<'a, AnyChannel> = channel.into(); Self { channel, @@ -87,6 +98,21 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { } } + /// Create a new simple linked-list table. + /// + /// This uses two linked-list items, one for each half of the buffer. + pub unsafe fn simple_ring_buffer_table(request: Request, peri_addr: *mut W, buffer: &mut [W]) -> Table<2> { + // Buffer halves should be the same length. + let half_len = buffer.len() / 2; + assert_eq!(half_len * 2, buffer.len()); + + let items = [ + LinearItem::new_read(request, peri_addr, &mut buffer[..half_len]), + LinearItem::new_read(request, peri_addr, &mut buffer[half_len..]), + ]; + Table::new(items) + } + /// Start the ring buffer operation. pub fn start(&mut self) { // Apply the default configuration to the channel. @@ -190,7 +216,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { } } -impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> { +impl<'a, W: Word, const L: usize> Drop for ReadableRingBuffer<'a, W, L> { fn drop(&mut self) { self.request_suspend(); while self.is_running() {} @@ -201,43 +227,69 @@ impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> { } /// Ringbuffer for writing data using GPDMA linked-list mode. -pub struct WritableRingBuffer<'a, W: Word> { +pub struct WritableRingBuffer<'a, W: Word, const L: usize> { channel: Peri<'a, AnyChannel>, ringbuf: WritableDmaRingBuffer<'a, W>, - table: Table<2>, + table: Table, options: TransferOptions, } -impl<'a, W: Word> WritableRingBuffer<'a, W> { +impl<'a, W: Word> WritableRingBuffer<'a, W, 2> { /// Create a new ring buffer. + /// + /// Transfer options are applied to the individual linked list items. pub unsafe fn new( channel: Peri<'a, impl Channel>, request: Request, peri_addr: *mut W, buffer: &'a mut [W], options: TransferOptions, - register_updaters: RegisterUpdaters, ) -> Self { let channel: Peri<'a, AnyChannel> = channel.into(); + let table = Self::simple_ring_buffer_table(request, peri_addr, buffer); - // Buffer halves should be the same length. - let half_len = buffer.len() / 2; - assert_eq!(half_len * 2, buffer.len()); + Self { + channel, + ringbuf: WritableDmaRingBuffer::new(buffer), + table, + options, + } + } +} - let items = [ - LinearItem::new_write(request, &mut buffer[..half_len], peri_addr, ®ister_updaters), - LinearItem::new_write(request, &mut buffer[half_len..], peri_addr, ®ister_updaters), - ]; - let table = Table::new(items); +impl<'a, W: Word, const L: usize> WritableRingBuffer<'a, W, L> { + /// Create a new ring buffer with a provided linked-list table. + /// + /// Transfer options are applied to the individual linked list items. + pub fn new_with_table( + channel: Peri<'a, impl Channel>, + buffer: &'a mut [W], + options: TransferOptions, + table: Table, + ) -> Self { + let channel: Peri<'a, AnyChannel> = channel.into(); - let this = Self { + Self { channel, ringbuf: WritableDmaRingBuffer::new(buffer), table, options, - }; + } + } - this + /// Create a new simple linked-list table. + /// + /// This uses two linked-list items, one for each half of the buffer. + pub unsafe fn simple_ring_buffer_table(request: Request, peri_addr: *mut W, buffer: &mut [W]) -> Table<2> { + // Buffer halves should be the same length. + let half_len = buffer.len() / 2; + assert_eq!(half_len * 2, buffer.len()); + + let items = [ + LinearItem::new_write(request, &mut buffer[..half_len], peri_addr), + LinearItem::new_write(request, &mut buffer[half_len..], peri_addr), + ]; + Table::new(items) } /// Start the ring buffer operation. @@ -343,7 +395,7 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { } } -impl<'a, W: Word> Drop for WritableRingBuffer<'a, W> { +impl<'a, W: Word, const L: usize> Drop for WritableRingBuffer<'a, W, L> { fn drop(&mut self) { self.request_suspend(); while self.is_running() {} -- cgit