aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Ferro <[email protected]>2023-07-22 17:17:01 -0600
committerAlex Ferro <[email protected]>2023-07-22 17:17:01 -0600
commit4883fdd1549e8d43290b39d72c3b311d300010ea (patch)
tree1b15e2b4047129da1c4c510b7233474fc3e70407
parent18b9b6c780b46165ead1de59ce258bd78786bdcb (diff)
Add a STM32/DMARingBuffer::read_exact helper
This provides a helper function with an async implementation, that will only return (or error) when it was able to read that many bytes, sleeping until ready. Additionally, corrected the documentation for Ringbuffer functions to use "elements" instead of "bytes" as the types were already generic over the word/element size.
-rw-r--r--embassy-stm32/src/dma/bdma.rs44
-rw-r--r--embassy-stm32/src/dma/dma.rs44
-rw-r--r--embassy-stm32/src/dma/ringbuffer.rs18
3 files changed, 91 insertions, 15 deletions
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index 5a87888b7..68c78123d 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -466,15 +466,53 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
466 self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow())); 466 self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow()));
467 } 467 }
468 468
469 /// Read bytes from the ring buffer 469 /// Read elements from the ring buffer
470 /// Return a tuple of the length read and the length remaining in the buffer 470 /// Return a tuple of the length read and the length remaining in the buffer
471 /// If not all of the bytes were read, then there will be some bytes in the buffer remaining 471 /// If not all of the elements were read, then there will be some elements in the buffer remaining
472 /// The length remaining is the capacity, ring_buf.len(), less the bytes remaining after the read 472 /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read
473 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. 473 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
474 pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { 474 pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
475 self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf) 475 self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf)
476 } 476 }
477 477
478 /// Read an exact number of elements from the ringbuffer.
479 ///
480 /// Returns the remaining number of elements available for immediate reading.
481 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
482 ///
483 /// Async/Wake Behavior:
484 /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point,
485 /// and when it wraps around. This means that when called with a buffer of length 'M', when this
486 /// ring buffer was created with a buffer of size 'N':
487 /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source.
488 /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning.
489 pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> {
490 use core::future::poll_fn;
491 use core::sync::atomic::compiler_fence;
492
493 let mut read_data = 0;
494 let buffer_len = buffer.len();
495
496 poll_fn(|cx| {
497 self.set_waker(cx.waker());
498
499 compiler_fence(Ordering::SeqCst);
500
501 match self.read(&mut buffer[read_data..buffer_len]) {
502 Ok((len, remaining)) => {
503 read_data += len;
504 if read_data == buffer_len {
505 Poll::Ready(Ok(remaining))
506 } else {
507 Poll::Pending
508 }
509 }
510 Err(e) => Poll::Ready(Err(e)),
511 }
512 })
513 .await
514 }
515
478 /// The capacity of the ringbuffer 516 /// The capacity of the ringbuffer
479 pub fn cap(&self) -> usize { 517 pub fn cap(&self) -> usize {
480 self.ringbuf.cap() 518 self.ringbuf.cap()
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index 58d438af8..9459fb763 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -696,15 +696,53 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
696 self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow())); 696 self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow()));
697 } 697 }
698 698
699 /// Read bytes from the ring buffer 699 /// Read elements from the ring buffer
700 /// Return a tuple of the length read and the length remaining in the buffer 700 /// Return a tuple of the length read and the length remaining in the buffer
701 /// If not all of the bytes were read, then there will be some bytes in the buffer remaining 701 /// If not all of the elements were read, then there will be some elements in the buffer remaining
702 /// The length remaining is the capacity, ring_buf.len(), less the bytes remaining after the read 702 /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read
703 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. 703 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
704 pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { 704 pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
705 self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf) 705 self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf)
706 } 706 }
707 707
708 /// Read an exact number of elements from the ringbuffer.
709 ///
710 /// Returns the remaining number of elements available for immediate reading.
711 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
712 ///
713 /// Async/Wake Behavior:
714 /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point,
715 /// and when it wraps around. This means that when called with a buffer of length 'M', when this
716 /// ring buffer was created with a buffer of size 'N':
717 /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source.
718 /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning.
719 pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> {
720 use core::future::poll_fn;
721 use core::sync::atomic::compiler_fence;
722
723 let mut read_data = 0;
724 let buffer_len = buffer.len();
725
726 poll_fn(|cx| {
727 self.set_waker(cx.waker());
728
729 compiler_fence(Ordering::SeqCst);
730
731 match self.read(&mut buffer[read_data..buffer_len]) {
732 Ok((len, remaining)) => {
733 read_data += len;
734 if read_data == buffer_len {
735 Poll::Ready(Ok(remaining))
736 } else {
737 Poll::Pending
738 }
739 }
740 Err(e) => Poll::Ready(Err(e)),
741 }
742 })
743 .await
744 }
745
708 // The capacity of the ringbuffer 746 // The capacity of the ringbuffer
709 pub fn cap(&self) -> usize { 747 pub fn cap(&self) -> usize {
710 self.ringbuf.cap() 748 self.ringbuf.cap()
diff --git a/embassy-stm32/src/dma/ringbuffer.rs b/embassy-stm32/src/dma/ringbuffer.rs
index a2bde986f..190793974 100644
--- a/embassy-stm32/src/dma/ringbuffer.rs
+++ b/embassy-stm32/src/dma/ringbuffer.rs
@@ -72,10 +72,10 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
72 self.cap() - remaining_transfers 72 self.cap() - remaining_transfers
73 } 73 }
74 74
75 /// Read bytes from the ring buffer 75 /// Read elements from the ring buffer
76 /// Return a tuple of the length read and the length remaining in the buffer 76 /// Return a tuple of the length read and the length remaining in the buffer
77 /// If not all of the bytes were read, then there will be some bytes in the buffer remaining 77 /// If not all of the elements were read, then there will be some elements in the buffer remaining
78 /// The length remaining is the capacity, ring_buf.len(), less the bytes remaining after the read 78 /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read
79 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. 79 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
80 pub fn read(&mut self, mut dma: impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { 80 pub fn read(&mut self, mut dma: impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
81 /* 81 /*
@@ -95,11 +95,11 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
95 */ 95 */
96 let end = self.pos(dma.get_remaining_transfers()); 96 let end = self.pos(dma.get_remaining_transfers());
97 if self.start == end && dma.get_complete_count() == 0 { 97 if self.start == end && dma.get_complete_count() == 0 {
98 // No bytes are available in the buffer 98 // No elements are available in the buffer
99 Ok((0, self.cap())) 99 Ok((0, self.cap()))
100 } else if self.start < end { 100 } else if self.start < end {
101 // The available, unread portion in the ring buffer DOES NOT wrap 101 // The available, unread portion in the ring buffer DOES NOT wrap
102 // Copy out the bytes from the dma buffer 102 // Copy out the elements from the dma buffer
103 let len = self.copy_to(buf, self.start..end); 103 let len = self.copy_to(buf, self.start..end);
104 104
105 compiler_fence(Ordering::SeqCst); 105 compiler_fence(Ordering::SeqCst);
@@ -128,7 +128,7 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
128 // The DMA writer has wrapped since we last read and is currently 128 // The DMA writer has wrapped since we last read and is currently
129 // writing (or the next byte added will be) in the beginning of the ring buffer. 129 // writing (or the next byte added will be) in the beginning of the ring buffer.
130 130
131 // The provided read buffer is not large enough to include all bytes from the tail of the dma buffer. 131 // The provided read buffer is not large enough to include all elements from the tail of the dma buffer.
132 132
133 // Copy out from the dma buffer 133 // Copy out from the dma buffer
134 let len = self.copy_to(buf, self.start..self.cap()); 134 let len = self.copy_to(buf, self.start..self.cap());
@@ -154,8 +154,8 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
154 // The DMA writer has wrapped since we last read and is currently 154 // The DMA writer has wrapped since we last read and is currently
155 // writing (or the next byte added will be) in the beginning of the ring buffer. 155 // writing (or the next byte added will be) in the beginning of the ring buffer.
156 156
157 // The provided read buffer is large enough to include all bytes from the tail of the dma buffer, 157 // The provided read buffer is large enough to include all elements from the tail of the dma buffer,
158 // so the next read will not have any unread tail bytes in the ring buffer. 158 // so the next read will not have any unread tail elements in the ring buffer.
159 159
160 // Copy out from the dma buffer 160 // Copy out from the dma buffer
161 let tail = self.copy_to(buf, self.start..self.cap()); 161 let tail = self.copy_to(buf, self.start..self.cap());
@@ -180,7 +180,7 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
180 } 180 }
181 /// Copy from the dma buffer at `data_range` into `buf` 181 /// Copy from the dma buffer at `data_range` into `buf`
182 fn copy_to(&mut self, buf: &mut [W], data_range: Range<usize>) -> usize { 182 fn copy_to(&mut self, buf: &mut [W], data_range: Range<usize>) -> usize {
183 // Limit the number of bytes that can be copied 183 // Limit the number of elements that can be copied
184 let length = usize::min(data_range.len(), buf.len()); 184 let length = usize::min(data_range.len(), buf.len());
185 185
186 // Copy from dma buffer into read buffer 186 // Copy from dma buffer into read buffer