aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorelagil <[email protected]>2025-08-25 21:10:59 +0200
committerDario Nieuwenhuis <[email protected]>2025-09-05 14:43:29 +0200
commit4155adbf8ad2aa8acbc6e94d059739c9f373323b (patch)
treecb0529a670ddbd22a312f120682ce0b19b341a81
parentcf5b1ea9f593d1d80b718b88330f041b59d071f1 (diff)
feat: ping-pong buffers
-rw-r--r--embassy-stm32/src/dma/gpdma/linked_list.rs22
-rw-r--r--embassy-stm32/src/dma/gpdma/mod.rs49
-rw-r--r--embassy-stm32/src/dma/gpdma/ringbuffered.rs37
3 files changed, 92 insertions, 16 deletions
diff --git a/embassy-stm32/src/dma/gpdma/linked_list.rs b/embassy-stm32/src/dma/gpdma/linked_list.rs
index 7de9a1441..3d2114282 100644
--- a/embassy-stm32/src/dma/gpdma/linked_list.rs
+++ b/embassy-stm32/src/dma/gpdma/linked_list.rs
@@ -156,6 +156,15 @@ impl LinearItem {
156 fn unlink(&mut self) { 156 fn unlink(&mut self) {
157 self.llr = regs::ChLlr(0).0; 157 self.llr = regs::ChLlr(0).0;
158 } 158 }
159
160 /// The item's transfer count in number of words.
161 fn transfer_count(&self) -> usize {
162 let br1 = regs::ChBr1(self.br1);
163 let tr1 = regs::ChTr1(self.tr1);
164 let word_size: WordSize = tr1.ddw().into();
165
166 br1.bndt() as usize / word_size.bytes()
167 }
159} 168}
160 169
161/// A table of linked list items. 170/// A table of linked list items.
@@ -173,6 +182,7 @@ impl<const ITEM_COUNT: usize> Table<ITEM_COUNT> {
173 Self { items } 182 Self { items }
174 } 183 }
175 184
185 /// Link the table as given by the run mode.
176 pub fn link(&mut self, run_mode: RunMode) { 186 pub fn link(&mut self, run_mode: RunMode) {
177 if matches!(run_mode, RunMode::Once | RunMode::Repeat) { 187 if matches!(run_mode, RunMode::Once | RunMode::Repeat) {
178 self.link_sequential(); 188 self.link_sequential();
@@ -183,11 +193,21 @@ impl<const ITEM_COUNT: usize> Table<ITEM_COUNT> {
183 } 193 }
184 } 194 }
185 195
186 /// The number of linked list items.s 196 /// The number of linked list items.
187 pub fn len(&self) -> usize { 197 pub fn len(&self) -> usize {
188 self.items.len() 198 self.items.len()
189 } 199 }
190 200
201 /// The total transfer count of the table in number of words.
202 pub fn transfer_count(&self) -> usize {
203 let mut count = 0;
204 for item in self.items {
205 count += item.transfer_count() as usize
206 }
207
208 count
209 }
210
191 /// Link items of given indices together: first -> second. 211 /// Link items of given indices together: first -> second.
192 pub fn link_indices(&mut self, first: usize, second: usize) { 212 pub fn link_indices(&mut self, first: usize, second: usize) {
193 assert!(first < self.len()); 213 assert!(first < self.len());
diff --git a/embassy-stm32/src/dma/gpdma/mod.rs b/embassy-stm32/src/dma/gpdma/mod.rs
index f65048d1f..1d2811ab4 100644
--- a/embassy-stm32/src/dma/gpdma/mod.rs
+++ b/embassy-stm32/src/dma/gpdma/mod.rs
@@ -94,15 +94,31 @@ impl From<vals::Dw> for WordSize {
94 } 94 }
95} 95}
96 96
97pub(crate) struct LLiState {
98 /// The number of linked-list items.
99 count: AtomicUsize,
100 /// The index of the current linked-list item.
101 index: AtomicUsize,
102 /// The total transfer count of all linked-list items in number of words.
103 transfer_count: AtomicUsize,
104}
105
97pub(crate) struct ChannelState { 106pub(crate) struct ChannelState {
98 waker: AtomicWaker, 107 waker: AtomicWaker,
99 complete_count: AtomicUsize, 108 complete_count: AtomicUsize,
109 lli_state: LLiState,
100} 110}
101 111
102impl ChannelState { 112impl ChannelState {
103 pub(crate) const NEW: Self = Self { 113 pub(crate) const NEW: Self = Self {
104 waker: AtomicWaker::new(), 114 waker: AtomicWaker::new(),
105 complete_count: AtomicUsize::new(0), 115 complete_count: AtomicUsize::new(0),
116
117 lli_state: LLiState {
118 count: AtomicUsize::new(0),
119 index: AtomicUsize::new(0),
120 transfer_count: AtomicUsize::new(0),
121 },
106 }; 122 };
107} 123}
108 124
@@ -161,7 +177,25 @@ impl AnyChannel {
161 177
162 if sr.tcf() { 178 if sr.tcf() {
163 ch.fcr().write(|w| w.set_tcf(true)); 179 ch.fcr().write(|w| w.set_tcf(true));
164 state.complete_count.fetch_add(1, Ordering::Release); 180
181 let lli_count = state.lli_state.count.load(Ordering::Relaxed);
182 let complete = if lli_count > 0 {
183 let next_lli_index = state.lli_state.index.load(Ordering::Relaxed) + 1;
184 let complete = next_lli_index >= lli_count;
185
186 state
187 .lli_state
188 .index
189 .store(if complete { 0 } else { next_lli_index }, Ordering::Relaxed);
190
191 complete
192 } else {
193 true
194 };
195
196 if complete {
197 state.complete_count.fetch_add(1, Ordering::Release);
198 }
165 } 199 }
166 200
167 if sr.suspf() { 201 if sr.suspf() {
@@ -242,6 +276,11 @@ impl AnyChannel {
242 w.set_dteie(true); 276 w.set_dteie(true);
243 w.set_suspie(true); 277 w.set_suspie(true);
244 }); 278 });
279
280 let state = &STATE[self.id as usize];
281 state.lli_state.count.store(0, Ordering::Relaxed);
282 state.lli_state.index.store(0, Ordering::Relaxed);
283 state.lli_state.transfer_count.store(0, Ordering::Relaxed)
245 } 284 }
246 285
247 unsafe fn configure_linked_list<const ITEM_COUNT: usize>( 286 unsafe fn configure_linked_list<const ITEM_COUNT: usize>(
@@ -286,6 +325,14 @@ impl AnyChannel {
286 w.set_dteie(true); 325 w.set_dteie(true);
287 w.set_suspie(true); 326 w.set_suspie(true);
288 }); 327 });
328
329 let state = &STATE[self.id as usize];
330 state.lli_state.count.store(ITEM_COUNT, Ordering::Relaxed);
331 state.lli_state.index.store(0, Ordering::Relaxed);
332 state
333 .lli_state
334 .transfer_count
335 .store(table.transfer_count(), Ordering::Relaxed)
289 } 336 }
290 337
291 fn start(&self) { 338 fn start(&self) {
diff --git a/embassy-stm32/src/dma/gpdma/ringbuffered.rs b/embassy-stm32/src/dma/gpdma/ringbuffered.rs
index fd0a98e23..65ba00b3a 100644
--- a/embassy-stm32/src/dma/gpdma/ringbuffered.rs
+++ b/embassy-stm32/src/dma/gpdma/ringbuffered.rs
@@ -22,7 +22,19 @@ struct DmaCtrlImpl<'a>(PeripheralRef<'a, AnyChannel>);
22 22
23impl<'a> DmaCtrl for DmaCtrlImpl<'a> { 23impl<'a> DmaCtrl for DmaCtrlImpl<'a> {
24 fn get_remaining_transfers(&self) -> usize { 24 fn get_remaining_transfers(&self) -> usize {
25 self.0.get_remaining_transfers() as _ 25 let state = &STATE[self.0.id as usize];
26 let current_remaining = self.0.get_remaining_transfers() as usize;
27
28 let lli_count = state.lli_state.count.load(Ordering::Relaxed);
29
30 if lli_count > 0 {
31 let lli_index = state.lli_state.index.load(Ordering::Relaxed);
32 let single_transfer_count = state.lli_state.transfer_count.load(Ordering::Relaxed) / lli_count;
33
34 (lli_count - lli_index - 1) * single_transfer_count + current_remaining
35 } else {
36 current_remaining
37 }
26 } 38 }
27 39
28 fn reset_complete_count(&mut self) -> usize { 40 fn reset_complete_count(&mut self) -> usize {
@@ -56,7 +68,7 @@ impl BufferHalf {
56pub struct ReadableRingBuffer<'a, W: Word> { 68pub struct ReadableRingBuffer<'a, W: Word> {
57 channel: PeripheralRef<'a, AnyChannel>, 69 channel: PeripheralRef<'a, AnyChannel>,
58 ringbuf: ReadableDmaRingBuffer<'a, W>, 70 ringbuf: ReadableDmaRingBuffer<'a, W>,
59 table: Table<1>, 71 table: Table<2>,
60 user_buffer_half: BufferHalf, 72 user_buffer_half: BufferHalf,
61} 73}
62 74
@@ -78,12 +90,10 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
78 options.half_transfer_ir = true; 90 options.half_transfer_ir = true;
79 options.complete_transfer_ir = true; 91 options.complete_transfer_ir = true;
80 92
81 // let items = [ 93 let items = [
82 // LinearItem::new_read(request, peri_addr, &mut buffer[..half_len], options), 94 LinearItem::new_read(request, peri_addr, &mut buffer[..half_len], options),
83 // LinearItem::new_read(request, peri_addr, &mut buffer[half_len..], options), 95 LinearItem::new_read(request, peri_addr, &mut buffer[half_len..], options),
84 // ]; 96 ];
85 let items = [LinearItem::new_read(request, peri_addr, buffer, options)];
86
87 let table = Table::new(items); 97 let table = Table::new(items);
88 98
89 let this = Self { 99 let this = Self {
@@ -209,7 +219,7 @@ impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> {
209pub struct WritableRingBuffer<'a, W: Word> { 219pub struct WritableRingBuffer<'a, W: Word> {
210 channel: PeripheralRef<'a, AnyChannel>, 220 channel: PeripheralRef<'a, AnyChannel>,
211 ringbuf: WritableDmaRingBuffer<'a, W>, 221 ringbuf: WritableDmaRingBuffer<'a, W>,
212 table: Table<1>, 222 table: Table<2>,
213 user_buffer_half: BufferHalf, 223 user_buffer_half: BufferHalf,
214} 224}
215 225
@@ -231,11 +241,10 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
231 options.half_transfer_ir = true; 241 options.half_transfer_ir = true;
232 options.complete_transfer_ir = true; 242 options.complete_transfer_ir = true;
233 243
234 // let items = [ 244 let items = [
235 // LinearItem::new_write(request, &mut buffer[..half_len], peri_addr, options), 245 LinearItem::new_write(request, &mut buffer[..half_len], peri_addr, options),
236 // LinearItem::new_write(request, &mut buffer[half_len..], peri_addr, options), 246 LinearItem::new_write(request, &mut buffer[half_len..], peri_addr, options),
237 // ]; 247 ];
238 let items = [LinearItem::new_write(request, buffer, peri_addr, options)];
239 let table = Table::new(items); 248 let table = Table::new(items);
240 249
241 let this = Self { 250 let this = Self {