aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandros Liarokapis <[email protected]>2024-09-23 02:49:05 +0300
committerAlexandros Liarokapis <[email protected]>2024-10-15 12:29:12 +0300
commit85fb890b0025db386459f8b6a573c29f00bf3ed1 (patch)
tree94ec57caad2ab1fb5d73c7bdd6a4bdf98c081b9a
parentf4ec0cb4d4d16bd4e1c242864c5ca828745704c0 (diff)
add auto-clear functionality to ringbuffer
-rw-r--r--embassy-stm32/src/dma/ringbuffer/mod.rs56
-rw-r--r--embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs3
-rw-r--r--embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs3
3 files changed, 40 insertions, 22 deletions
diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs
index d4d119a69..abc01e3cc 100644
--- a/embassy-stm32/src/dma/ringbuffer/mod.rs
+++ b/embassy-stm32/src/dma/ringbuffer/mod.rs
@@ -85,7 +85,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
85 } 85 }
86 } 86 }
87 87
88 /// Reset the ring buffer to its initial state 88 /// Reset the ring buffer to its initial state.
89 pub fn clear(&mut self, dma: &mut impl DmaCtrl) { 89 pub fn clear(&mut self, dma: &mut impl DmaCtrl) {
90 dma.reset_complete_count(); 90 dma.reset_complete_count();
91 self.write_index.reset(); 91 self.write_index.reset();
@@ -113,17 +113,12 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
113 /// Return a tuple of the length read and the length remaining in the buffer 113 /// Return a tuple of the length read and the length remaining in the buffer
114 /// If not all of the elements were read, then there will be some elements in the buffer remaining 114 /// If not all of the elements were read, then there will be some elements in the buffer remaining
115 /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read 115 /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read
116 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. 116 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller,
117 /// in which case the rinbuffer will automatically clear itself.
117 pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { 118 pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
118 self.sync_write_index(dma); 119 self.read_raw(dma, buf).inspect_err(|_e| {
119 let readable = self.len()?.min(buf.len()); 120 self.clear(dma);
120 for i in 0..readable { 121 })
121 buf[i] = self.read_buf(i);
122 }
123 self.sync_write_index(dma);
124 let available = self.len()?;
125 self.read_index.advance(self.cap(), readable);
126 Ok((readable, available - readable))
127 } 122 }
128 123
129 /// Read an exact number of elements from the ringbuffer. 124 /// Read an exact number of elements from the ringbuffer.
@@ -159,6 +154,18 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
159 .await 154 .await
160 } 155 }
161 156
157 fn read_raw(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
158 self.sync_write_index(dma);
159 let readable = self.len()?.min(buf.len());
160 for i in 0..readable {
161 buf[i] = self.read_buf(i);
162 }
163 self.sync_write_index(dma);
164 let available = self.len()?;
165 self.read_index.advance(self.cap(), readable);
166 Ok((readable, available - readable))
167 }
168
162 fn read_buf(&self, offset: usize) -> W { 169 fn read_buf(&self, offset: usize) -> W {
163 unsafe { 170 unsafe {
164 core::ptr::read_volatile( 171 core::ptr::read_volatile(
@@ -222,16 +229,13 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
222 229
223 /// Append data to the ring buffer. 230 /// Append data to the ring buffer.
224 /// Returns a tuple of the data written and the remaining write capacity in the buffer. 231 /// Returns a tuple of the data written and the remaining write capacity in the buffer.
232 /// OverrunError is returned if the portion to be written was previously read by the DMA controller.
233 /// In this case, the ringbuffer will automatically reset itself, giving a full buffer worth of
234 /// leeway between the write index and the DMA.
225 pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { 235 pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> {
226 self.sync_read_index(dma); 236 self.write_raw(dma, buf).inspect_err(|_e| {
227 let writable = self.len()?.min(buf.len()); 237 self.clear(dma);
228 for i in 0..writable { 238 })
229 self.write_buf(i, buf[i]);
230 }
231 self.sync_read_index(dma);
232 let available = self.len()?;
233 self.write_index.advance(self.cap(), writable);
234 Ok((writable, available - writable))
235 } 239 }
236 240
237 /// Write elements directly to the buffer. 241 /// Write elements directly to the buffer.
@@ -266,6 +270,18 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
266 .await 270 .await
267 } 271 }
268 272
273 pub fn write_raw(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> {
274 self.sync_read_index(dma);
275 let writable = self.len()?.min(buf.len());
276 for i in 0..writable {
277 self.write_buf(i, buf[i]);
278 }
279 self.sync_read_index(dma);
280 let available = self.len()?;
281 self.write_index.advance(self.cap(), writable);
282 Ok((writable, available - writable))
283 }
284
269 fn write_buf(&mut self, offset: usize, value: W) { 285 fn write_buf(&mut self, offset: usize, value: W) {
270 unsafe { 286 unsafe {
271 core::ptr::write_volatile( 287 core::ptr::write_volatile(
diff --git a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs
index 6555ebfb0..6e640a813 100644
--- a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs
+++ b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs
@@ -38,8 +38,9 @@ impl ReferenceStateMachine for ReaderSM {
38 Status::Available(x + y) 38 Status::Available(x + y)
39 } 39 }
40 } 40 }
41 (Status::Failed, ReaderTransition::Write(_)) => Status::Failed,
41 (Status::Available(x), ReaderTransition::ReadUpTo(y)) => Status::Available(x.saturating_sub(*y)), 42 (Status::Available(x), ReaderTransition::ReadUpTo(y)) => Status::Available(x.saturating_sub(*y)),
42 (Status::Failed, _) => Status::Failed, 43 (Status::Failed, ReaderTransition::ReadUpTo(_)) => Status::Available(0),
43 } 44 }
44 } 45 }
45} 46}
diff --git a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs
index 15f54c672..c1b3859b2 100644
--- a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs
+++ b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs
@@ -38,8 +38,9 @@ impl ReferenceStateMachine for WriterSM {
38 Status::Available(x - y) 38 Status::Available(x - y)
39 } 39 }
40 } 40 }
41 (Status::Failed, WriterTransition::Read(_)) => Status::Failed,
41 (Status::Available(x), WriterTransition::WriteUpTo(y)) => Status::Available((x + *y).min(CAP)), 42 (Status::Available(x), WriterTransition::WriteUpTo(y)) => Status::Available((x + *y).min(CAP)),
42 (Status::Failed, _) => Status::Failed, 43 (Status::Failed, WriterTransition::WriteUpTo(_)) => Status::Available(CAP),
43 } 44 }
44 } 45 }
45} 46}