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
commita4d3b4b6ae3f3265ea372e446a6e7b5d3685ea3a (patch)
tree979b06f9ea1261a2fcb3a5b5c840796a5cf59998
parent78364b966eb76c071d5450c2a13cc788d7e5be80 (diff)
feat: wip, write buffer in halves
-rw-r--r--embassy-stm32/src/dma/gpdma/ringbuffered.rs84
-rw-r--r--embassy-stm32/src/dma/ringbuffer/mod.rs76
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs2
3 files changed, 54 insertions, 108 deletions
diff --git a/embassy-stm32/src/dma/gpdma/ringbuffered.rs b/embassy-stm32/src/dma/gpdma/ringbuffered.rs
index 99c85a221..a5d2c700c 100644
--- a/embassy-stm32/src/dma/gpdma/ringbuffered.rs
+++ b/embassy-stm32/src/dma/gpdma/ringbuffered.rs
@@ -46,29 +46,11 @@ impl<'a> DmaCtrl for DmaCtrlImpl<'a> {
46 } 46 }
47} 47}
48 48
49/// The current buffer half (e.g. for DMA or the user application).
50#[derive(Debug, PartialEq, PartialOrd)]
51#[cfg_attr(feature = "defmt", derive(defmt::Format))]
52enum BufferHalf {
53 First,
54 Second,
55}
56
57impl BufferHalf {
58 fn toggle(&mut self) {
59 *self = match *self {
60 Self::First => Self::Second,
61 Self::Second => Self::First,
62 };
63 }
64}
65
66/// Ringbuffer for receiving data using GPDMA linked-list mode. 49/// Ringbuffer for receiving data using GPDMA linked-list mode.
67pub struct ReadableRingBuffer<'a, W: Word> { 50pub struct ReadableRingBuffer<'a, W: Word> {
68 channel: PeripheralRef<'a, AnyChannel>, 51 channel: PeripheralRef<'a, AnyChannel>,
69 ringbuf: ReadableDmaRingBuffer<'a, W>, 52 ringbuf: ReadableDmaRingBuffer<'a, W>,
70 table: Table<2>, 53 table: Table<2>,
71 user_buffer_half: BufferHalf,
72} 54}
73 55
74impl<'a, W: Word> ReadableRingBuffer<'a, W> { 56impl<'a, W: Word> ReadableRingBuffer<'a, W> {
@@ -99,7 +81,6 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
99 channel, 81 channel,
100 ringbuf: ReadableDmaRingBuffer::new(buffer), 82 ringbuf: ReadableDmaRingBuffer::new(buffer),
101 table, 83 table,
102 user_buffer_half: BufferHalf::First,
103 } 84 }
104 } 85 }
105 86
@@ -217,7 +198,6 @@ pub struct WritableRingBuffer<'a, W: Word> {
217 channel: PeripheralRef<'a, AnyChannel>, 198 channel: PeripheralRef<'a, AnyChannel>,
218 ringbuf: WritableDmaRingBuffer<'a, W>, 199 ringbuf: WritableDmaRingBuffer<'a, W>,
219 table: Table<2>, 200 table: Table<2>,
220 user_buffer_half: BufferHalf,
221} 201}
222 202
223impl<'a, W: Word> WritableRingBuffer<'a, W> { 203impl<'a, W: Word> WritableRingBuffer<'a, W> {
@@ -246,7 +226,6 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
246 channel, 226 channel,
247 ringbuf: WritableDmaRingBuffer::new(buffer), 227 ringbuf: WritableDmaRingBuffer::new(buffer),
248 table, 228 table,
249 user_buffer_half: BufferHalf::First,
250 }; 229 };
251 230
252 this 231 this
@@ -280,62 +259,21 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
280 259
281 /// Write an exact number of elements to the ringbuffer. 260 /// Write an exact number of elements to the ringbuffer.
282 pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, Error> { 261 pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, Error> {
283 return self 262 // return self
284 .ringbuf 263 // .ringbuf
285 .write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer) 264 // .write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
286 .await; 265 // .await;
287 266
267 let mut remaining_cap = 0;
288 let mut written_len = 0; 268 let mut written_len = 0;
289 let len = buffer.len();
290 269
291 let mut remaining_cap = 0; 270 while written_len < buffer.len() {
292 let cap = self.ringbuf.cap(); 271 (written_len, remaining_cap) = self
293 272 .ringbuf
294 let dma = &mut DmaCtrlImpl(self.channel.reborrow()); 273 .write_half(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
295 let user_buffer_half = &mut self.user_buffer_half; 274 .await?;
296 let ringbuf = &mut self.ringbuf; 275 // info!("Written: {}/{}", written_len, buffer.len());
297 let table = &mut self.table;
298
299 while written_len != len {
300 // info!(
301 // "read {}, write {}, cap {}",
302 // ringbuf.read_index(0),
303 // ringbuf.write_index(0),
304 // ringbuf.cap()
305 // );
306
307 let dma_buffer_half = if ringbuf.read_index(0) < ringbuf.cap() / 2 {
308 BufferHalf::First
309 } else {
310 BufferHalf::Second
311 };
312
313 // if dma_buffer_half == *user_buffer_half {
314 // info!("swap user from {}", user_buffer_half);
315 // table.unlink();
316
317 // match user_buffer_half {
318 // BufferHalf::First => table.link_indices(1, 0),
319 // BufferHalf::Second => table.link_indices(0, 1),
320 // }
321
322 // user_buffer_half.toggle();
323 // }
324
325 let index = match dma_buffer_half {
326 BufferHalf::First => {
327 // Fill up second buffer half when DMA reads the first.
328 cap - 1
329 }
330 BufferHalf::Second => {
331 // Fill up first buffer half when DMA reads the second.
332 cap / 2 - 1
333 }
334 };
335
336 (written_len, remaining_cap) = ringbuf.write_until(dma, &buffer, index).await?;
337 } 276 }
338 info!("done");
339 277
340 Ok(remaining_cap) 278 Ok(remaining_cap)
341 } 279 }
diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs
index c4bf4dd60..8d00d822d 100644
--- a/embassy-stm32/src/dma/ringbuffer/mod.rs
+++ b/embassy-stm32/src/dma/ringbuffer/mod.rs
@@ -3,6 +3,14 @@ use core::task::{Poll, Waker};
3 3
4use crate::dma::word::Word; 4use crate::dma::word::Word;
5 5
6/// The current buffer half (e.g. for DMA or the user application).
7#[derive(Debug, PartialEq, PartialOrd)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9enum BufferHalf {
10 First,
11 Second,
12}
13
6pub trait DmaCtrl { 14pub trait DmaCtrl {
7 /// Get the NDTR register value, i.e. the space left in the underlying 15 /// Get the NDTR register value, i.e. the space left in the underlying
8 /// buffer until the dma writer wraps. 16 /// buffer until the dma writer wraps.
@@ -92,16 +100,6 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
92 } 100 }
93 } 101 }
94 102
95 /// The current ring-buffer read index.
96 pub fn read_index(&self, offset: usize) -> usize {
97 self.read_index.as_index(self.cap(), offset)
98 }
99
100 /// The current ring-buffer write index.
101 pub fn write_index(&self, offset: usize) -> usize {
102 self.write_index.as_index(self.cap(), offset)
103 }
104
105 /// Reset the ring buffer to its initial state. 103 /// Reset the ring buffer to its initial state.
106 pub fn reset(&mut self, dma: &mut impl DmaCtrl) { 104 pub fn reset(&mut self, dma: &mut impl DmaCtrl) {
107 dma.reset_complete_count(); 105 dma.reset_complete_count();
@@ -218,14 +216,13 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
218 } 216 }
219 } 217 }
220 218
221 /// The current ring-buffer read index. 219 /// The buffer half that is in use by the DMA.
222 pub fn read_index(&self, offset: usize) -> usize { 220 fn dma_half(&self) -> BufferHalf {
223 self.read_index.as_index(self.cap(), offset) 221 if self.read_index.as_index(self.cap(), 0) < self.cap() / 2 {
224 } 222 BufferHalf::First
225 223 } else {
226 /// The current ring-buffer write index. 224 BufferHalf::Second
227 pub fn write_index(&self, offset: usize) -> usize { 225 }
228 self.write_index.as_index(self.cap(), offset)
229 } 226 }
230 227
231 /// Reset the ring buffer to its initial state. The buffer after the reset will be full. 228 /// Reset the ring buffer to its initial state. The buffer after the reset will be full.
@@ -305,6 +302,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
305 /// Write an exact number of elements to the ringbuffer. 302 /// Write an exact number of elements to the ringbuffer.
306 /// 303 ///
307 /// Returns the remaining write capacity in the buffer. 304 /// Returns the remaining write capacity in the buffer.
305 #[allow(dead_code)]
308 pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result<usize, Error> { 306 pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result<usize, Error> {
309 let mut written_len = 0; 307 let mut written_len = 0;
310 let buffer_len = buffer.len(); 308 let buffer_len = buffer.len();
@@ -327,31 +325,41 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
327 .await 325 .await
328 } 326 }
329 327
330 /// Write until a given write index. 328 /// Write the user's current buffer half - not used by the DMA.
331 /// 329 ///
332 /// Returns a tuple of the written length, and the remaining write capacity in the buffer. 330 /// Returns a tuple of the written length, and the remaining write capacity in the buffer.
333 pub async fn write_until( 331 #[allow(dead_code)]
334 &mut self, 332 pub async fn write_half(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result<(usize, usize), Error> {
335 dma: &mut impl DmaCtrl,
336 buffer: &[W],
337 index: usize,
338 ) -> Result<(usize, usize), Error> {
339 let mut written_len = 0; 333 let mut written_len = 0;
340 let write_len = index 334 let buffer_len = buffer.len();
341 .saturating_sub(self.write_index.as_index(self.cap(), 0))
342 .min(buffer.len());
343
344 if write_len == 0 {
345 return Err(Error::Overrun);
346 }
347 335
348 poll_fn(|cx| { 336 poll_fn(|cx| {
349 dma.set_waker(cx.waker()); 337 dma.set_waker(cx.waker());
350 338
351 match self.write(dma, &buffer[written_len..write_len]) { 339 let dma_half = self.dma_half();
340 // let user_half = self.user_half();
341
342 // if dma_half == user_half {
343 // info!("ups");
344 // return Poll::Ready(Err(Error::Overrun));
345 // }
346
347 let write_index = self.write_index.as_index(self.cap(), 0);
348 let target_write_len = match dma_half {
349 BufferHalf::First => self.cap().saturating_sub(write_index),
350 BufferHalf::Second => (self.cap() / 2).saturating_sub(write_index),
351 };
352 let write_end_index = (target_write_len + written_len).min(buffer_len);
353
354 // info!(
355 // "buf_len: {}, write_len: {}, write_index: {}",
356 // buffer_len, target_write_len, write_index
357 // );
358
359 match self.write(dma, &buffer[written_len..write_end_index]) {
352 Ok((len, remaining)) => { 360 Ok((len, remaining)) => {
353 written_len += len; 361 written_len += len;
354 if written_len == write_len { 362 if written_len == write_end_index {
355 Poll::Ready(Ok((written_len, remaining))) 363 Poll::Ready(Ok((written_len, remaining)))
356 } else { 364 } else {
357 Poll::Pending 365 Poll::Pending
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index 1d4a44896..5f4e87834 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -381,7 +381,7 @@ impl ReadReady for RingBufferedUartRx<'_> {
381 crate::dma::ringbuffer::Error::Overrun => Self::Error::Overrun, 381 crate::dma::ringbuffer::Error::Overrun => Self::Error::Overrun,
382 crate::dma::ringbuffer::Error::DmaUnsynced => { 382 crate::dma::ringbuffer::Error::DmaUnsynced => {
383 error!( 383 error!(
384 "Ringbuffer error: DmaUNsynced, driver implementation is 384 "Ringbuffer error: DmaUNsynced, driver implementation is
385 probably bugged please open an issue" 385 probably bugged please open an issue"
386 ); 386 );
387 // we report this as overrun since its recoverable in the same way 387 // we report this as overrun since its recoverable in the same way