diff options
| author | elagil <[email protected]> | 2025-08-25 21:10:59 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2025-09-05 14:43:29 +0200 |
| commit | 4155adbf8ad2aa8acbc6e94d059739c9f373323b (patch) | |
| tree | cb0529a670ddbd22a312f120682ce0b19b341a81 | |
| parent | cf5b1ea9f593d1d80b718b88330f041b59d071f1 (diff) | |
feat: ping-pong buffers
| -rw-r--r-- | embassy-stm32/src/dma/gpdma/linked_list.rs | 22 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/gpdma/mod.rs | 49 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/gpdma/ringbuffered.rs | 37 |
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 | ||
| 97 | pub(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 | |||
| 97 | pub(crate) struct ChannelState { | 106 | pub(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 | ||
| 102 | impl ChannelState { | 112 | impl 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 | ||
| 23 | impl<'a> DmaCtrl for DmaCtrlImpl<'a> { | 23 | impl<'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 { | |||
| 56 | pub struct ReadableRingBuffer<'a, W: Word> { | 68 | pub 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> { | |||
| 209 | pub struct WritableRingBuffer<'a, W: Word> { | 219 | pub 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 { |
