aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/dma/gpdma/linked_list.rs21
-rw-r--r--embassy-stm32/src/dma/gpdma/mod.rs22
-rw-r--r--embassy-stm32/src/dma/gpdma/ringbuffered.rs112
-rw-r--r--embassy-stm32/src/sai/mod.rs9
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs5
5 files changed, 90 insertions, 79 deletions
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 @@
4use stm32_metapac::gpdma::regs; 4use stm32_metapac::gpdma::regs;
5use stm32_metapac::gpdma::vals::Dreq; 5use stm32_metapac::gpdma::vals::Dreq;
6 6
7use super::RegisterUpdaters;
8use crate::dma::word::{Word, WordSize}; 7use crate::dma::word::{Word, WordSize};
9use crate::dma::{Dir, Request}; 8use crate::dma::{Dir, Request};
10 9
@@ -23,7 +22,6 @@ pub enum RunMode {
23/// 22///
24/// Also works for 2D-capable GPDMA channels, but does not use 2D capabilities. 23/// Also works for 2D-capable GPDMA channels, but does not use 2D capabilities.
25#[derive(Debug, Copy, Clone, Default)] 24#[derive(Debug, Copy, Clone, Default)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
27#[repr(C)] 25#[repr(C)]
28pub struct LinearItem { 26pub struct LinearItem {
29 /// Transfer register 1. 27 /// Transfer register 1.
@@ -42,12 +40,7 @@ pub struct LinearItem {
42 40
43impl LinearItem { 41impl LinearItem {
44 /// Create a new read DMA transfer (peripheral to memory). 42 /// Create a new read DMA transfer (peripheral to memory).
45 pub unsafe fn new_read<'d, W: Word>( 43 pub unsafe fn new_read<'d, W: Word>(request: Request, peri_addr: *mut W, buf: &'d mut [W]) -> Self {
46 request: Request,
47 peri_addr: *mut W,
48 buf: &'d mut [W],
49 register_updaters: &RegisterUpdaters,
50 ) -> Self {
51 Self::new_inner( 44 Self::new_inner(
52 request, 45 request,
53 Dir::PeripheralToMemory, 46 Dir::PeripheralToMemory,
@@ -57,17 +50,11 @@ impl LinearItem {
57 true, 50 true,
58 W::size(), 51 W::size(),
59 W::size(), 52 W::size(),
60 register_updaters,
61 ) 53 )
62 } 54 }
63 55
64 /// Create a new write DMA transfer (memory to peripheral). 56 /// Create a new write DMA transfer (memory to peripheral).
65 pub unsafe fn new_write<'d, MW: Word, PW: Word>( 57 pub unsafe fn new_write<'d, MW: Word, PW: Word>(request: Request, buf: &'d [MW], peri_addr: *mut PW) -> Self {
66 request: Request,
67 buf: &'d [MW],
68 peri_addr: *mut PW,
69 register_updaters: &RegisterUpdaters,
70 ) -> Self {
71 Self::new_inner( 58 Self::new_inner(
72 request, 59 request,
73 Dir::MemoryToPeripheral, 60 Dir::MemoryToPeripheral,
@@ -77,7 +64,6 @@ impl LinearItem {
77 true, 64 true,
78 MW::size(), 65 MW::size(),
79 PW::size(), 66 PW::size(),
80 register_updaters,
81 ) 67 )
82 } 68 }
83 69
@@ -90,7 +76,6 @@ impl LinearItem {
90 incr_mem: bool, 76 incr_mem: bool,
91 data_size: WordSize, 77 data_size: WordSize,
92 dst_size: WordSize, 78 dst_size: WordSize,
93 register_updaters: &RegisterUpdaters,
94 ) -> Self { 79 ) -> Self {
95 // BNDT is specified as bytes, not as number of transfers. 80 // BNDT is specified as bytes, not as number of transfers.
96 let Ok(bndt) = (mem_len * data_size.bytes()).try_into() else { 81 let Ok(bndt) = (mem_len * data_size.bytes()).try_into() else {
@@ -105,7 +90,6 @@ impl LinearItem {
105 tr1.set_ddw(dst_size.into()); 90 tr1.set_ddw(dst_size.into());
106 tr1.set_sinc(dir == Dir::MemoryToPeripheral && incr_mem); 91 tr1.set_sinc(dir == Dir::MemoryToPeripheral && incr_mem);
107 tr1.set_dinc(dir == Dir::PeripheralToMemory && incr_mem); 92 tr1.set_dinc(dir == Dir::PeripheralToMemory && incr_mem);
108 (register_updaters.tr1)(&mut tr1);
109 93
110 let mut tr2 = regs::ChTr2(0); 94 let mut tr2 = regs::ChTr2(0);
111 tr2.set_dreq(match dir { 95 tr2.set_dreq(match dir {
@@ -113,7 +97,6 @@ impl LinearItem {
113 Dir::PeripheralToMemory => Dreq::SOURCE_PERIPHERAL, 97 Dir::PeripheralToMemory => Dreq::SOURCE_PERIPHERAL,
114 }); 98 });
115 tr2.set_reqsel(request); 99 tr2.set_reqsel(request);
116 (register_updaters.tr2)(&mut tr2);
117 100
118 let (sar, dar) = match dir { 101 let (sar, dar) = match dir {
119 Dir::MemoryToPeripheral => (mem_addr as _, peri_addr as _), 102 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 {
73 } 73 }
74} 74}
75 75
76/// GPDMA linked-list item register updater functions.
77#[derive(Debug, Copy, Clone)]
78#[cfg_attr(feature = "defmt", derive(defmt::Format))]
79pub struct RegisterUpdaters {
80 /// Function used to overwrite transfer register 1.
81 pub tr1: fn(&mut pac::gpdma::regs::ChTr1),
82 /// Function used to overwrite transfer register 2.
83 pub tr2: fn(&mut pac::gpdma::regs::ChTr2),
84 /// Function used to overwrite transfer register 3.
85 pub tr3: fn(&mut pac::gpdma::regs::ChTr3),
86}
87
88impl Default for RegisterUpdaters {
89 fn default() -> Self {
90 Self {
91 tr1: |_| {},
92 tr2: |_| {},
93 tr3: |_| {},
94 }
95 }
96}
97
98impl From<WordSize> for vals::Dw { 76impl From<WordSize> for vals::Dw {
99 fn from(raw: WordSize) -> Self { 77 fn from(raw: WordSize) -> Self {
100 match raw { 78 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;
8 8
9use embassy_hal_internal::Peri; 9use embassy_hal_internal::Peri;
10 10
11use super::{AnyChannel, RegisterUpdaters, TransferOptions, STATE}; 11use super::{AnyChannel, TransferOptions, STATE};
12use crate::dma::gpdma::linked_list::{LinearItem, RunMode, Table}; 12use crate::dma::gpdma::linked_list::{LinearItem, RunMode, Table};
13use crate::dma::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; 13use crate::dma::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer};
14use crate::dma::word::Word; 14use crate::dma::word::Word;
@@ -48,14 +48,14 @@ impl<'a> DmaCtrl for DmaCtrlImpl<'a> {
48} 48}
49 49
50/// Ringbuffer for receiving data using GPDMA linked-list mode. 50/// Ringbuffer for receiving data using GPDMA linked-list mode.
51pub struct ReadableRingBuffer<'a, W: Word> { 51pub struct ReadableRingBuffer<'a, W: Word, const L: usize> {
52 channel: Peri<'a, AnyChannel>, 52 channel: Peri<'a, AnyChannel>,
53 ringbuf: ReadableDmaRingBuffer<'a, W>, 53 ringbuf: ReadableDmaRingBuffer<'a, W>,
54 table: Table<2>, 54 table: Table<L>,
55 options: TransferOptions, 55 options: TransferOptions,
56} 56}
57 57
58impl<'a, W: Word> ReadableRingBuffer<'a, W> { 58impl<'a, W: Word> ReadableRingBuffer<'a, W, 2> {
59 /// Create a new ring buffer. 59 /// Create a new ring buffer.
60 /// 60 ///
61 /// Transfer options are applied to the individual linked list items. 61 /// Transfer options are applied to the individual linked list items.
@@ -65,19 +65,30 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
65 peri_addr: *mut W, 65 peri_addr: *mut W,
66 buffer: &'a mut [W], 66 buffer: &'a mut [W],
67 options: TransferOptions, 67 options: TransferOptions,
68 register_updaters: RegisterUpdaters,
69 ) -> Self { 68 ) -> Self {
70 let channel: Peri<'a, AnyChannel> = channel.into(); 69 let channel: Peri<'a, AnyChannel> = channel.into();
70 let table = Self::simple_ring_buffer_table(request, peri_addr, buffer);
71 71
72 // Buffer halves should be the same length. 72 Self {
73 let half_len = buffer.len() / 2; 73 channel,
74 assert_eq!(half_len * 2, buffer.len()); 74 ringbuf: ReadableDmaRingBuffer::new(buffer),
75 table,
76 options,
77 }
78 }
79}
75 80
76 let items = [ 81impl<'a, W: Word, const L: usize> ReadableRingBuffer<'a, W, L> {
77 LinearItem::new_read(request, peri_addr, &mut buffer[..half_len], &register_updaters), 82 /// Create a new ring buffer with a provided linked-list table.
78 LinearItem::new_read(request, peri_addr, &mut buffer[half_len..], &register_updaters), 83 ///
79 ]; 84 /// Transfer options are applied to the individual linked list items.
80 let table = Table::new(items); 85 pub fn new_with_table(
86 channel: Peri<'a, impl Channel>,
87 buffer: &'a mut [W],
88 options: TransferOptions,
89 table: Table<L>,
90 ) -> Self {
91 let channel: Peri<'a, AnyChannel> = channel.into();
81 92
82 Self { 93 Self {
83 channel, 94 channel,
@@ -87,6 +98,21 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
87 } 98 }
88 } 99 }
89 100
101 /// Create a new simple linked-list table.
102 ///
103 /// This uses two linked-list items, one for each half of the buffer.
104 pub unsafe fn simple_ring_buffer_table(request: Request, peri_addr: *mut W, buffer: &mut [W]) -> Table<2> {
105 // Buffer halves should be the same length.
106 let half_len = buffer.len() / 2;
107 assert_eq!(half_len * 2, buffer.len());
108
109 let items = [
110 LinearItem::new_read(request, peri_addr, &mut buffer[..half_len]),
111 LinearItem::new_read(request, peri_addr, &mut buffer[half_len..]),
112 ];
113 Table::new(items)
114 }
115
90 /// Start the ring buffer operation. 116 /// Start the ring buffer operation.
91 pub fn start(&mut self) { 117 pub fn start(&mut self) {
92 // Apply the default configuration to the channel. 118 // Apply the default configuration to the channel.
@@ -190,7 +216,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
190 } 216 }
191} 217}
192 218
193impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> { 219impl<'a, W: Word, const L: usize> Drop for ReadableRingBuffer<'a, W, L> {
194 fn drop(&mut self) { 220 fn drop(&mut self) {
195 self.request_suspend(); 221 self.request_suspend();
196 while self.is_running() {} 222 while self.is_running() {}
@@ -201,43 +227,69 @@ impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> {
201} 227}
202 228
203/// Ringbuffer for writing data using GPDMA linked-list mode. 229/// Ringbuffer for writing data using GPDMA linked-list mode.
204pub struct WritableRingBuffer<'a, W: Word> { 230pub struct WritableRingBuffer<'a, W: Word, const L: usize> {
205 channel: Peri<'a, AnyChannel>, 231 channel: Peri<'a, AnyChannel>,
206 ringbuf: WritableDmaRingBuffer<'a, W>, 232 ringbuf: WritableDmaRingBuffer<'a, W>,
207 table: Table<2>, 233 table: Table<L>,
208 options: TransferOptions, 234 options: TransferOptions,
209} 235}
210 236
211impl<'a, W: Word> WritableRingBuffer<'a, W> { 237impl<'a, W: Word> WritableRingBuffer<'a, W, 2> {
212 /// Create a new ring buffer. 238 /// Create a new ring buffer.
239 ///
240 /// Transfer options are applied to the individual linked list items.
213 pub unsafe fn new( 241 pub unsafe fn new(
214 channel: Peri<'a, impl Channel>, 242 channel: Peri<'a, impl Channel>,
215 request: Request, 243 request: Request,
216 peri_addr: *mut W, 244 peri_addr: *mut W,
217 buffer: &'a mut [W], 245 buffer: &'a mut [W],
218 options: TransferOptions, 246 options: TransferOptions,
219 register_updaters: RegisterUpdaters,
220 ) -> Self { 247 ) -> Self {
221 let channel: Peri<'a, AnyChannel> = channel.into(); 248 let channel: Peri<'a, AnyChannel> = channel.into();
249 let table = Self::simple_ring_buffer_table(request, peri_addr, buffer);
222 250
223 // Buffer halves should be the same length. 251 Self {
224 let half_len = buffer.len() / 2; 252 channel,
225 assert_eq!(half_len * 2, buffer.len()); 253 ringbuf: WritableDmaRingBuffer::new(buffer),
254 table,
255 options,
256 }
257 }
258}
226 259
227 let items = [ 260impl<'a, W: Word, const L: usize> WritableRingBuffer<'a, W, L> {
228 LinearItem::new_write(request, &mut buffer[..half_len], peri_addr, &register_updaters), 261 /// Create a new ring buffer with a provided linked-list table.
229 LinearItem::new_write(request, &mut buffer[half_len..], peri_addr, &register_updaters), 262 ///
230 ]; 263 /// Transfer options are applied to the individual linked list items.
231 let table = Table::new(items); 264 pub fn new_with_table(
265 channel: Peri<'a, impl Channel>,
266 buffer: &'a mut [W],
267 options: TransferOptions,
268 table: Table<L>,
269 ) -> Self {
270 let channel: Peri<'a, AnyChannel> = channel.into();
232 271
233 let this = Self { 272 Self {
234 channel, 273 channel,
235 ringbuf: WritableDmaRingBuffer::new(buffer), 274 ringbuf: WritableDmaRingBuffer::new(buffer),
236 table, 275 table,
237 options, 276 options,
238 }; 277 }
278 }
239 279
240 this 280 /// Create a new simple linked-list table.
281 ///
282 /// This uses two linked-list items, one for each half of the buffer.
283 pub unsafe fn simple_ring_buffer_table(request: Request, peri_addr: *mut W, buffer: &mut [W]) -> Table<2> {
284 // Buffer halves should be the same length.
285 let half_len = buffer.len() / 2;
286 assert_eq!(half_len * 2, buffer.len());
287
288 let items = [
289 LinearItem::new_write(request, &mut buffer[..half_len], peri_addr),
290 LinearItem::new_write(request, &mut buffer[half_len..], peri_addr),
291 ];
292 Table::new(items)
241 } 293 }
242 294
243 /// Start the ring buffer operation. 295 /// Start the ring buffer operation.
@@ -343,7 +395,7 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
343 } 395 }
344} 396}
345 397
346impl<'a, W: Word> Drop for WritableRingBuffer<'a, W> { 398impl<'a, W: Word, const L: usize> Drop for WritableRingBuffer<'a, W, L> {
347 fn drop(&mut self) { 399 fn drop(&mut self) {
348 self.request_suspend(); 400 self.request_suspend();
349 while self.is_running() {} 401 while self.is_running() {}
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs
index ac1ab2505..410b2243c 100644
--- a/embassy-stm32/src/sai/mod.rs
+++ b/embassy-stm32/src/sai/mod.rs
@@ -650,8 +650,8 @@ impl Config {
650} 650}
651 651
652enum RingBuffer<'d, W: word::Word> { 652enum RingBuffer<'d, W: word::Word> {
653 Writable(WritableRingBuffer<'d, W>), 653 Writable(WritableRingBuffer<'d, W, 2>),
654 Readable(ReadableRingBuffer<'d, W>), 654 Readable(ReadableRingBuffer<'d, W, 2>),
655} 655}
656 656
657fn dr<W: word::Word>(w: crate::pac::sai::Sai, sub_block: WhichSubBlock) -> *mut W { 657fn dr<W: word::Word>(w: crate::pac::sai::Sai, sub_block: WhichSubBlock) -> *mut W {
@@ -687,13 +687,12 @@ fn get_ring_buffer<'d, T: Instance, W: word::Word>(
687 //the new_write() and new_read() always use circular mode 687 //the new_write() and new_read() always use circular mode
688 ..Default::default() 688 ..Default::default()
689 }; 689 };
690 let updaters = Default::default();
691 match tx_rx { 690 match tx_rx {
692 TxRx::Transmitter => RingBuffer::Writable(unsafe { 691 TxRx::Transmitter => RingBuffer::Writable(unsafe {
693 WritableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts, updaters) 692 WritableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts)
694 }), 693 }),
695 TxRx::Receiver => RingBuffer::Readable(unsafe { 694 TxRx::Receiver => RingBuffer::Readable(unsafe {
696 ReadableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts, updaters) 695 ReadableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts)
697 }), 696 }),
698 } 697 }
699} 698}
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index 78bf4b72f..8a607a31a 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -83,7 +83,7 @@ pub struct RingBufferedUartRx<'d> {
83 kernel_clock: Hertz, 83 kernel_clock: Hertz,
84 rx: Option<Peri<'d, AnyPin>>, 84 rx: Option<Peri<'d, AnyPin>>,
85 rts: Option<Peri<'d, AnyPin>>, 85 rts: Option<Peri<'d, AnyPin>>,
86 ring_buf: ReadableRingBuffer<'d, u8>, 86 ring_buf: ReadableRingBuffer<'d, u8, 2>,
87} 87}
88 88
89impl<'d> SetConfig for RingBufferedUartRx<'d> { 89impl<'d> SetConfig for RingBufferedUartRx<'d> {
@@ -103,7 +103,6 @@ impl<'d> UartRx<'d, Async> {
103 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); 103 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
104 104
105 let opts = Default::default(); 105 let opts = Default::default();
106 let updaters = Default::default();
107 106
108 // Safety: we forget the struct before this function returns. 107 // Safety: we forget the struct before this function returns.
109 let rx_dma = self.rx_dma.as_mut().unwrap(); 108 let rx_dma = self.rx_dma.as_mut().unwrap();
@@ -113,7 +112,7 @@ impl<'d> UartRx<'d, Async> {
113 let info = self.info; 112 let info = self.info;
114 let state = self.state; 113 let state = self.state;
115 let kernel_clock = self.kernel_clock; 114 let kernel_clock = self.kernel_clock;
116 let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(info.regs), dma_buf, opts, updaters) }; 115 let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(info.regs), dma_buf, opts) };
117 let rx = unsafe { self.rx.as_ref().map(|x| x.clone_unchecked()) }; 116 let rx = unsafe { self.rx.as_ref().map(|x| x.clone_unchecked()) };
118 let rts = unsafe { self.rts.as_ref().map(|x| x.clone_unchecked()) }; 117 let rts = unsafe { self.rts.as_ref().map(|x| x.clone_unchecked()) };
119 118