diff options
| author | xoviat <[email protected]> | 2023-07-28 01:16:48 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-07-28 01:16:48 +0000 |
| commit | 44c8db2911f0f9d82e6517e31944777454c4e459 (patch) | |
| tree | 603cdf99f82170a34695ee1aeaf799efeae135be | |
| parent | bbd2563e138ce83314ea008547940428617a5798 (diff) | |
| parent | 4883fdd1549e8d43290b39d72c3b311d300010ea (diff) | |
Merge pull request #1681 from alexferro/feature/stm32-dma-read-exact
Add a STM32/DMARingBuffer::read_exact helper
| -rw-r--r-- | embassy-stm32/src/dma/bdma.rs | 44 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/dma.rs | 44 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/ringbuffer.rs | 18 |
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 f14084599..c27ec7bd9 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs | |||
| @@ -711,15 +711,53 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> { | |||
| 711 | self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow())); | 711 | self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow())); |
| 712 | } | 712 | } |
| 713 | 713 | ||
| 714 | /// Read bytes from the ring buffer | 714 | /// Read elements from the ring buffer |
| 715 | /// Return a tuple of the length read and the length remaining in the buffer | 715 | /// Return a tuple of the length read and the length remaining in the buffer |
| 716 | /// If not all of the bytes were read, then there will be some bytes in the buffer remaining | 716 | /// If not all of the elements were read, then there will be some elements in the buffer remaining |
| 717 | /// The length remaining is the capacity, ring_buf.len(), less the bytes remaining after the read | 717 | /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read |
| 718 | /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. | 718 | /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. |
| 719 | pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { | 719 | pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { |
| 720 | self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf) | 720 | self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf) |
| 721 | } | 721 | } |
| 722 | 722 | ||
| 723 | /// Read an exact number of elements from the ringbuffer. | ||
| 724 | /// | ||
| 725 | /// Returns the remaining number of elements available for immediate reading. | ||
| 726 | /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. | ||
| 727 | /// | ||
| 728 | /// Async/Wake Behavior: | ||
| 729 | /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point, | ||
| 730 | /// and when it wraps around. This means that when called with a buffer of length 'M', when this | ||
| 731 | /// ring buffer was created with a buffer of size 'N': | ||
| 732 | /// - 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. | ||
| 733 | /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. | ||
| 734 | pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> { | ||
| 735 | use core::future::poll_fn; | ||
| 736 | use core::sync::atomic::compiler_fence; | ||
| 737 | |||
| 738 | let mut read_data = 0; | ||
| 739 | let buffer_len = buffer.len(); | ||
| 740 | |||
| 741 | poll_fn(|cx| { | ||
| 742 | self.set_waker(cx.waker()); | ||
| 743 | |||
| 744 | compiler_fence(Ordering::SeqCst); | ||
| 745 | |||
| 746 | match self.read(&mut buffer[read_data..buffer_len]) { | ||
| 747 | Ok((len, remaining)) => { | ||
| 748 | read_data += len; | ||
| 749 | if read_data == buffer_len { | ||
| 750 | Poll::Ready(Ok(remaining)) | ||
| 751 | } else { | ||
| 752 | Poll::Pending | ||
| 753 | } | ||
| 754 | } | ||
| 755 | Err(e) => Poll::Ready(Err(e)), | ||
| 756 | } | ||
| 757 | }) | ||
| 758 | .await | ||
| 759 | } | ||
| 760 | |||
| 723 | // The capacity of the ringbuffer | 761 | // The capacity of the ringbuffer |
| 724 | pub fn cap(&self) -> usize { | 762 | pub fn cap(&self) -> usize { |
| 725 | self.ringbuf.cap() | 763 | 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 |
