diff options
| author | Alexandros Liarokapis <[email protected]> | 2024-10-01 17:59:04 +0300 |
|---|---|---|
| committer | Alexandros Liarokapis <[email protected]> | 2024-10-15 12:29:12 +0300 |
| commit | f0d2ebdc7ead41307155b083790b8450ca2b7eac (patch) | |
| tree | 3f976a73e34f81818126476b2dc896c750000a6b /embassy-stm32/src/dma | |
| parent | c991ddb76662cc7da5e847f33c1a446f17822887 (diff) | |
stm32: fix ringbugger overrun errors due to bad dma wrap-around behavior
Diffstat (limited to 'embassy-stm32/src/dma')
| -rw-r--r-- | embassy-stm32/src/dma/dma_bdma.rs | 30 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/ringbuffer/mod.rs | 67 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/ringbuffer/tests/mod.rs | 83 |
3 files changed, 65 insertions, 115 deletions
diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 59ad4d988..3f047a9a4 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs | |||
| @@ -6,7 +6,7 @@ use core::task::{Context, Poll, Waker}; | |||
| 6 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; | 6 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; |
| 7 | use embassy_sync::waitqueue::AtomicWaker; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | 8 | ||
| 9 | use super::ringbuffer::{DmaCtrl, OverrunError, ReadableDmaRingBuffer, WritableDmaRingBuffer}; | 9 | use super::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; |
| 10 | use super::word::{Word, WordSize}; | 10 | use super::word::{Word, WordSize}; |
| 11 | use super::{AnyChannel, Channel, Dir, Request, STATE}; | 11 | use super::{AnyChannel, Channel, Dir, Request, STATE}; |
| 12 | use crate::interrupt::typelevel::Interrupt; | 12 | use crate::interrupt::typelevel::Interrupt; |
| @@ -299,7 +299,6 @@ impl AnyChannel { | |||
| 299 | } else { | 299 | } else { |
| 300 | return; | 300 | return; |
| 301 | } | 301 | } |
| 302 | |||
| 303 | state.waker.wake(); | 302 | state.waker.wake(); |
| 304 | } | 303 | } |
| 305 | #[cfg(bdma)] | 304 | #[cfg(bdma)] |
| @@ -828,7 +827,8 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { | |||
| 828 | /// | 827 | /// |
| 829 | /// You must call this after creating it for it to work. | 828 | /// You must call this after creating it for it to work. |
| 830 | pub fn start(&mut self) { | 829 | pub fn start(&mut self) { |
| 831 | self.channel.start() | 830 | self.channel.start(); |
| 831 | self.clear(); | ||
| 832 | } | 832 | } |
| 833 | 833 | ||
| 834 | /// Clear all data in the ring buffer. | 834 | /// Clear all data in the ring buffer. |
| @@ -840,15 +840,15 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { | |||
| 840 | /// Return a tuple of the length read and the length remaining in the buffer | 840 | /// Return a tuple of the length read and the length remaining in the buffer |
| 841 | /// If not all of the elements were read, then there will be some elements in the buffer remaining | 841 | /// If not all of the elements were read, then there will be some elements in the buffer remaining |
| 842 | /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read | 842 | /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read |
| 843 | /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. | 843 | /// Error is returned if the portion to be read was overwritten by the DMA controller. |
| 844 | pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { | 844 | pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), Error> { |
| 845 | self.ringbuf.read(&mut DmaCtrlImpl(self.channel.reborrow()), buf) | 845 | self.ringbuf.read(&mut DmaCtrlImpl(self.channel.reborrow()), buf) |
| 846 | } | 846 | } |
| 847 | 847 | ||
| 848 | /// Read an exact number of elements from the ringbuffer. | 848 | /// Read an exact number of elements from the ringbuffer. |
| 849 | /// | 849 | /// |
| 850 | /// Returns the remaining number of elements available for immediate reading. | 850 | /// Returns the remaining number of elements available for immediate reading. |
| 851 | /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. | 851 | /// Error is returned if the portion to be read was overwritten by the DMA controller. |
| 852 | /// | 852 | /// |
| 853 | /// Async/Wake Behavior: | 853 | /// Async/Wake Behavior: |
| 854 | /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point, | 854 | /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point, |
| @@ -856,12 +856,17 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { | |||
| 856 | /// ring buffer was created with a buffer of size 'N': | 856 | /// ring buffer was created with a buffer of size 'N': |
| 857 | /// - 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. | 857 | /// - 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. |
| 858 | /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. | 858 | /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. |
| 859 | pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> { | 859 | pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, Error> { |
| 860 | self.ringbuf | 860 | self.ringbuf |
| 861 | .read_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer) | 861 | .read_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer) |
| 862 | .await | 862 | .await |
| 863 | } | 863 | } |
| 864 | 864 | ||
| 865 | /// The current length of the ringbuffer | ||
| 866 | pub fn len(&mut self) -> Result<usize, Error> { | ||
| 867 | Ok(self.ringbuf.len(&mut DmaCtrlImpl(self.channel.reborrow()))?) | ||
| 868 | } | ||
| 869 | |||
| 865 | /// The capacity of the ringbuffer | 870 | /// The capacity of the ringbuffer |
| 866 | pub const fn capacity(&self) -> usize { | 871 | pub const fn capacity(&self) -> usize { |
| 867 | self.ringbuf.cap() | 872 | self.ringbuf.cap() |
| @@ -986,23 +991,28 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { | |||
| 986 | /// Write elements directly to the raw buffer. | 991 | /// Write elements directly to the raw buffer. |
| 987 | /// This can be used to fill the buffer before starting the DMA transfer. | 992 | /// This can be used to fill the buffer before starting the DMA transfer. |
| 988 | #[allow(dead_code)] | 993 | #[allow(dead_code)] |
| 989 | pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { | 994 | pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), Error> { |
| 990 | self.ringbuf.write_immediate(buf) | 995 | self.ringbuf.write_immediate(buf) |
| 991 | } | 996 | } |
| 992 | 997 | ||
| 993 | /// Write elements from the ring buffer | 998 | /// Write elements from the ring buffer |
| 994 | /// Return a tuple of the length written and the length remaining in the buffer | 999 | /// Return a tuple of the length written and the length remaining in the buffer |
| 995 | pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { | 1000 | pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), Error> { |
| 996 | self.ringbuf.write(&mut DmaCtrlImpl(self.channel.reborrow()), buf) | 1001 | self.ringbuf.write(&mut DmaCtrlImpl(self.channel.reborrow()), buf) |
| 997 | } | 1002 | } |
| 998 | 1003 | ||
| 999 | /// Write an exact number of elements to the ringbuffer. | 1004 | /// Write an exact number of elements to the ringbuffer. |
| 1000 | pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> { | 1005 | pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, Error> { |
| 1001 | self.ringbuf | 1006 | self.ringbuf |
| 1002 | .write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer) | 1007 | .write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer) |
| 1003 | .await | 1008 | .await |
| 1004 | } | 1009 | } |
| 1005 | 1010 | ||
| 1011 | /// The current length of the ringbuffer | ||
| 1012 | pub fn len(&mut self) -> Result<usize, Error> { | ||
| 1013 | Ok(self.ringbuf.len(&mut DmaCtrlImpl(self.channel.reborrow()))?) | ||
| 1014 | } | ||
| 1015 | |||
| 1006 | /// The capacity of the ringbuffer | 1016 | /// The capacity of the ringbuffer |
| 1007 | pub const fn capacity(&self) -> usize { | 1017 | pub const fn capacity(&self) -> usize { |
| 1008 | self.ringbuf.cap() | 1018 | self.ringbuf.cap() |
diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs index eb64ad016..a257faa5b 100644 --- a/embassy-stm32/src/dma/ringbuffer/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/mod.rs | |||
| @@ -19,9 +19,13 @@ pub trait DmaCtrl { | |||
| 19 | 19 | ||
| 20 | #[derive(Debug, PartialEq)] | 20 | #[derive(Debug, PartialEq)] |
| 21 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 21 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 22 | pub struct OverrunError; | 22 | pub enum Error { |
| 23 | Overrun, | ||
| 24 | DmaUnsynced, | ||
| 25 | } | ||
| 23 | 26 | ||
| 24 | #[derive(Debug, Clone, Copy, Default)] | 27 | #[derive(Debug, Clone, Copy, Default)] |
| 28 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 25 | struct DmaIndex { | 29 | struct DmaIndex { |
| 26 | complete_count: usize, | 30 | complete_count: usize, |
| 27 | pos: usize, | 31 | pos: usize, |
| @@ -38,15 +42,19 @@ impl DmaIndex { | |||
| 38 | } | 42 | } |
| 39 | 43 | ||
| 40 | fn dma_sync(&mut self, cap: usize, dma: &mut impl DmaCtrl) { | 44 | fn dma_sync(&mut self, cap: usize, dma: &mut impl DmaCtrl) { |
| 41 | let first_pos = cap - dma.get_remaining_transfers(); | 45 | // Important! |
| 42 | self.complete_count += dma.reset_complete_count(); | 46 | // The ordering of the first two lines matters! |
| 43 | self.pos = cap - dma.get_remaining_transfers(); | 47 | // If changed, the code will detect a wrong +capacity |
| 44 | 48 | // jump at wrap-around. | |
| 45 | // If the latter call to get_remaining_transfers() returned a smaller value than the first, the dma | 49 | let count_diff = dma.reset_complete_count(); |
| 46 | // has wrapped around between calls and we must check if the complete count also incremented. | 50 | let pos = cap - dma.get_remaining_transfers(); |
| 47 | if self.pos < first_pos { | 51 | self.pos = if pos < self.pos && count_diff == 0 { |
| 48 | self.complete_count += dma.reset_complete_count(); | 52 | cap - 1 |
| 49 | } | 53 | } else { |
| 54 | pos | ||
| 55 | }; | ||
| 56 | |||
| 57 | self.complete_count += count_diff; | ||
| 50 | } | 58 | } |
| 51 | 59 | ||
| 52 | fn advance(&mut self, cap: usize, steps: usize) { | 60 | fn advance(&mut self, cap: usize, steps: usize) { |
| @@ -96,14 +104,18 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { | |||
| 96 | } | 104 | } |
| 97 | 105 | ||
| 98 | /// Get the available readable dma samples. | 106 | /// Get the available readable dma samples. |
| 99 | pub fn len(&mut self, dma: &mut impl DmaCtrl) -> Result<usize, OverrunError> { | 107 | pub fn len(&mut self, dma: &mut impl DmaCtrl) -> Result<usize, Error> { |
| 100 | self.write_index.dma_sync(self.cap(), dma); | 108 | self.write_index.dma_sync(self.cap(), dma); |
| 101 | DmaIndex::normalize(&mut self.write_index, &mut self.read_index); | 109 | DmaIndex::normalize(&mut self.write_index, &mut self.read_index); |
| 102 | 110 | ||
| 103 | let diff = self.write_index.diff(self.cap(), &self.read_index); | 111 | let diff = self.write_index.diff(self.cap(), &self.read_index); |
| 104 | 112 | ||
| 105 | if diff < 0 || diff > self.cap() as isize { | 113 | if diff < 0 { |
| 106 | Err(OverrunError) | 114 | return Err(Error::DmaUnsynced); |
| 115 | } | ||
| 116 | |||
| 117 | if diff > self.cap() as isize { | ||
| 118 | Err(Error::Overrun) | ||
| 107 | } else { | 119 | } else { |
| 108 | Ok(diff as usize) | 120 | Ok(diff as usize) |
| 109 | } | 121 | } |
| @@ -113,9 +125,9 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { | |||
| 113 | /// Return a tuple of the length read and the length remaining in the buffer | 125 | /// 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 | 126 | /// 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 | 127 | /// 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, | 128 | /// Error is returned if the portion to be read was overwritten by the DMA controller, |
| 117 | /// in which case the rinbuffer will automatically reset itself. | 129 | /// in which case the rinbuffer will automatically reset itself. |
| 118 | pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { | 130 | pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), Error> { |
| 119 | self.read_raw(dma, buf).inspect_err(|_e| { | 131 | self.read_raw(dma, buf).inspect_err(|_e| { |
| 120 | self.reset(dma); | 132 | self.reset(dma); |
| 121 | }) | 133 | }) |
| @@ -124,7 +136,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { | |||
| 124 | /// Read an exact number of elements from the ringbuffer. | 136 | /// Read an exact number of elements from the ringbuffer. |
| 125 | /// | 137 | /// |
| 126 | /// Returns the remaining number of elements available for immediate reading. | 138 | /// Returns the remaining number of elements available for immediate reading. |
| 127 | /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. | 139 | /// Error is returned if the portion to be read was overwritten by the DMA controller. |
| 128 | /// | 140 | /// |
| 129 | /// Async/Wake Behavior: | 141 | /// Async/Wake Behavior: |
| 130 | /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point, | 142 | /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point, |
| @@ -132,7 +144,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { | |||
| 132 | /// ring buffer was created with a buffer of size 'N': | 144 | /// ring buffer was created with a buffer of size 'N': |
| 133 | /// - 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. | 145 | /// - 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. |
| 134 | /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. | 146 | /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. |
| 135 | pub async fn read_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &mut [W]) -> Result<usize, OverrunError> { | 147 | pub async fn read_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &mut [W]) -> Result<usize, Error> { |
| 136 | let mut read_data = 0; | 148 | let mut read_data = 0; |
| 137 | let buffer_len = buffer.len(); | 149 | let buffer_len = buffer.len(); |
| 138 | 150 | ||
| @@ -154,7 +166,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { | |||
| 154 | .await | 166 | .await |
| 155 | } | 167 | } |
| 156 | 168 | ||
| 157 | fn read_raw(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { | 169 | fn read_raw(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), Error> { |
| 158 | let readable = self.len(dma)?.min(buf.len()); | 170 | let readable = self.len(dma)?.min(buf.len()); |
| 159 | for i in 0..readable { | 171 | for i in 0..readable { |
| 160 | buf[i] = self.read_buf(i); | 172 | buf[i] = self.read_buf(i); |
| @@ -205,14 +217,17 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { | |||
| 205 | } | 217 | } |
| 206 | 218 | ||
| 207 | /// Get the remaining writable dma samples. | 219 | /// Get the remaining writable dma samples. |
| 208 | pub fn len(&mut self, dma: &mut impl DmaCtrl) -> Result<usize, OverrunError> { | 220 | pub fn len(&mut self, dma: &mut impl DmaCtrl) -> Result<usize, Error> { |
| 209 | self.read_index.dma_sync(self.cap(), dma); | 221 | self.read_index.dma_sync(self.cap(), dma); |
| 210 | DmaIndex::normalize(&mut self.read_index, &mut self.write_index); | 222 | DmaIndex::normalize(&mut self.read_index, &mut self.write_index); |
| 211 | 223 | ||
| 212 | let diff = self.write_index.diff(self.cap(), &self.read_index); | 224 | let diff = self.write_index.diff(self.cap(), &self.read_index); |
| 213 | 225 | ||
| 214 | if diff < 0 || diff > self.cap() as isize { | 226 | if diff > self.cap() as isize { |
| 215 | Err(OverrunError) | 227 | return Err(Error::DmaUnsynced); |
| 228 | } | ||
| 229 | if diff < 0 { | ||
| 230 | Err(Error::Overrun) | ||
| 216 | } else { | 231 | } else { |
| 217 | Ok(self.cap().saturating_sub(diff as usize)) | 232 | Ok(self.cap().saturating_sub(diff as usize)) |
| 218 | } | 233 | } |
| @@ -225,17 +240,17 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { | |||
| 225 | 240 | ||
| 226 | /// Append data to the ring buffer. | 241 | /// Append data to the ring buffer. |
| 227 | /// Returns a tuple of the data written and the remaining write capacity in the buffer. | 242 | /// Returns a tuple of the data written and the remaining write capacity in the buffer. |
| 228 | /// OverrunError is returned if the portion to be written was previously read by the DMA controller. | 243 | /// Error is returned if the portion to be written was previously read by the DMA controller. |
| 229 | /// In this case, the ringbuffer will automatically reset itself, giving a full buffer worth of | 244 | /// In this case, the ringbuffer will automatically reset itself, giving a full buffer worth of |
| 230 | /// leeway between the write index and the DMA. | 245 | /// leeway between the write index and the DMA. |
| 231 | pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { | 246 | pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), Error> { |
| 232 | self.write_raw(dma, buf).inspect_err(|_e| { | 247 | self.write_raw(dma, buf).inspect_err(|_e| { |
| 233 | self.reset(dma); | 248 | self.reset(dma); |
| 234 | }) | 249 | }) |
| 235 | } | 250 | } |
| 236 | 251 | ||
| 237 | /// Write elements directly to the buffer. | 252 | /// Write elements directly to the buffer. |
| 238 | pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { | 253 | pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), Error> { |
| 239 | for (i, data) in buf.iter().enumerate() { | 254 | for (i, data) in buf.iter().enumerate() { |
| 240 | self.write_buf(i, *data) | 255 | self.write_buf(i, *data) |
| 241 | } | 256 | } |
| @@ -244,7 +259,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { | |||
| 244 | } | 259 | } |
| 245 | 260 | ||
| 246 | /// Write an exact number of elements to the ringbuffer. | 261 | /// Write an exact number of elements to the ringbuffer. |
| 247 | pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result<usize, OverrunError> { | 262 | pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result<usize, Error> { |
| 248 | let mut written_data = 0; | 263 | let mut written_data = 0; |
| 249 | let buffer_len = buffer.len(); | 264 | let buffer_len = buffer.len(); |
| 250 | 265 | ||
| @@ -266,7 +281,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { | |||
| 266 | .await | 281 | .await |
| 267 | } | 282 | } |
| 268 | 283 | ||
| 269 | pub fn write_raw(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { | 284 | fn write_raw(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), Error> { |
| 270 | let writable = self.len(dma)?.min(buf.len()); | 285 | let writable = self.len(dma)?.min(buf.len()); |
| 271 | for i in 0..writable { | 286 | for i in 0..writable { |
| 272 | self.write_buf(i, buf[i]); | 287 | self.write_buf(i, buf[i]); |
diff --git a/embassy-stm32/src/dma/ringbuffer/tests/mod.rs b/embassy-stm32/src/dma/ringbuffer/tests/mod.rs index 1800eae69..6fabedb83 100644 --- a/embassy-stm32/src/dma/ringbuffer/tests/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/tests/mod.rs | |||
| @@ -2,13 +2,14 @@ use std::{cell, vec}; | |||
| 2 | 2 | ||
| 3 | use super::*; | 3 | use super::*; |
| 4 | 4 | ||
| 5 | #[allow(dead_code)] | 5 | #[allow(unused)] |
| 6 | #[derive(PartialEq, Debug)] | 6 | #[derive(PartialEq, Debug)] |
| 7 | enum TestCircularTransferRequest { | 7 | enum TestCircularTransferRequest { |
| 8 | ResetCompleteCount(usize), | 8 | ResetCompleteCount(usize), |
| 9 | PositionRequest(usize), | 9 | PositionRequest(usize), |
| 10 | } | 10 | } |
| 11 | 11 | ||
| 12 | #[allow(unused)] | ||
| 12 | struct TestCircularTransfer { | 13 | struct TestCircularTransfer { |
| 13 | len: usize, | 14 | len: usize, |
| 14 | requests: cell::RefCell<vec::Vec<TestCircularTransferRequest>>, | 15 | requests: cell::RefCell<vec::Vec<TestCircularTransferRequest>>, |
| @@ -39,6 +40,7 @@ impl DmaCtrl for TestCircularTransfer { | |||
| 39 | } | 40 | } |
| 40 | 41 | ||
| 41 | impl TestCircularTransfer { | 42 | impl TestCircularTransfer { |
| 43 | #[allow(unused)] | ||
| 42 | pub fn new(len: usize) -> Self { | 44 | pub fn new(len: usize) -> Self { |
| 43 | Self { | 45 | Self { |
| 44 | requests: cell::RefCell::new(vec![]), | 46 | requests: cell::RefCell::new(vec![]), |
| @@ -46,6 +48,7 @@ impl TestCircularTransfer { | |||
| 46 | } | 48 | } |
| 47 | } | 49 | } |
| 48 | 50 | ||
| 51 | #[allow(unused)] | ||
| 49 | pub fn setup(&self, mut requests: vec::Vec<TestCircularTransferRequest>) { | 52 | pub fn setup(&self, mut requests: vec::Vec<TestCircularTransferRequest>) { |
| 50 | requests.reverse(); | 53 | requests.reverse(); |
| 51 | self.requests.replace(requests); | 54 | self.requests.replace(requests); |
| @@ -55,84 +58,6 @@ impl TestCircularTransfer { | |||
| 55 | const CAP: usize = 16; | 58 | const CAP: usize = 16; |
| 56 | 59 | ||
| 57 | #[test] | 60 | #[test] |
| 58 | fn dma_index_dma_sync_syncs_position_to_last_read_if_sync_takes_place_on_same_dma_cycle() { | ||
| 59 | let mut dma = TestCircularTransfer::new(CAP); | ||
| 60 | dma.setup(vec![ | ||
| 61 | TestCircularTransferRequest::PositionRequest(4), | ||
| 62 | TestCircularTransferRequest::ResetCompleteCount(0), | ||
| 63 | TestCircularTransferRequest::PositionRequest(7), | ||
| 64 | ]); | ||
| 65 | let mut index = DmaIndex::default(); | ||
| 66 | index.dma_sync(CAP, &mut dma); | ||
| 67 | assert_eq!(index.complete_count, 0); | ||
| 68 | assert_eq!(index.pos, 7); | ||
| 69 | } | ||
| 70 | |||
| 71 | #[test] | ||
| 72 | fn dma_index_dma_sync_updates_complete_count_properly_if_sync_takes_place_on_same_dma_cycle() { | ||
| 73 | let mut dma = TestCircularTransfer::new(CAP); | ||
| 74 | dma.setup(vec![ | ||
| 75 | TestCircularTransferRequest::PositionRequest(4), | ||
| 76 | TestCircularTransferRequest::ResetCompleteCount(2), | ||
| 77 | TestCircularTransferRequest::PositionRequest(7), | ||
| 78 | ]); | ||
| 79 | let mut index = DmaIndex::default(); | ||
| 80 | index.complete_count = 1; | ||
| 81 | index.dma_sync(CAP, &mut dma); | ||
| 82 | assert_eq!(index.complete_count, 3); | ||
| 83 | assert_eq!(index.pos, 7); | ||
| 84 | } | ||
| 85 | |||
| 86 | #[test] | ||
| 87 | fn dma_index_dma_sync_syncs_to_last_position_if_reads_occur_on_different_dma_cycles() { | ||
| 88 | let mut dma = TestCircularTransfer::new(CAP); | ||
| 89 | dma.setup(vec![ | ||
| 90 | TestCircularTransferRequest::PositionRequest(10), | ||
| 91 | TestCircularTransferRequest::ResetCompleteCount(1), | ||
| 92 | TestCircularTransferRequest::PositionRequest(5), | ||
| 93 | TestCircularTransferRequest::ResetCompleteCount(0), | ||
| 94 | ]); | ||
| 95 | let mut index = DmaIndex::default(); | ||
| 96 | index.dma_sync(CAP, &mut dma); | ||
| 97 | assert_eq!(index.complete_count, 1); | ||
| 98 | assert_eq!(index.pos, 5); | ||
| 99 | } | ||
| 100 | |||
| 101 | #[test] | ||
| 102 | fn dma_index_dma_sync_detects_new_cycle_if_later_position_is_less_than_first_and_first_complete_count_occurs_on_first_cycle( | ||
| 103 | ) { | ||
| 104 | let mut dma = TestCircularTransfer::new(CAP); | ||
| 105 | dma.setup(vec![ | ||
| 106 | TestCircularTransferRequest::PositionRequest(10), | ||
| 107 | TestCircularTransferRequest::ResetCompleteCount(1), | ||
| 108 | TestCircularTransferRequest::PositionRequest(5), | ||
| 109 | TestCircularTransferRequest::ResetCompleteCount(1), | ||
| 110 | ]); | ||
| 111 | let mut index = DmaIndex::default(); | ||
| 112 | index.complete_count = 1; | ||
| 113 | index.dma_sync(CAP, &mut dma); | ||
| 114 | assert_eq!(index.complete_count, 3); | ||
| 115 | assert_eq!(index.pos, 5); | ||
| 116 | } | ||
| 117 | |||
| 118 | #[test] | ||
| 119 | fn dma_index_dma_sync_detects_new_cycle_if_later_position_is_less_than_first_and_first_complete_count_occurs_on_later_cycle( | ||
| 120 | ) { | ||
| 121 | let mut dma = TestCircularTransfer::new(CAP); | ||
| 122 | dma.setup(vec![ | ||
| 123 | TestCircularTransferRequest::PositionRequest(10), | ||
| 124 | TestCircularTransferRequest::ResetCompleteCount(2), | ||
| 125 | TestCircularTransferRequest::PositionRequest(5), | ||
| 126 | TestCircularTransferRequest::ResetCompleteCount(0), | ||
| 127 | ]); | ||
| 128 | let mut index = DmaIndex::default(); | ||
| 129 | index.complete_count = 1; | ||
| 130 | index.dma_sync(CAP, &mut dma); | ||
| 131 | assert_eq!(index.complete_count, 3); | ||
| 132 | assert_eq!(index.pos, 5); | ||
| 133 | } | ||
| 134 | |||
| 135 | #[test] | ||
| 136 | fn dma_index_as_index_returns_index_mod_cap_by_default() { | 61 | fn dma_index_as_index_returns_index_mod_cap_by_default() { |
| 137 | let index = DmaIndex::default(); | 62 | let index = DmaIndex::default(); |
| 138 | assert_eq!(index.as_index(CAP, 0), 0); | 63 | assert_eq!(index.as_index(CAP, 0), 0); |
