overrun at invalid diffs, rename clear to reset, simplify dma_sync method

This commit is contained in:
Alexandros Liarokapis 2024-09-24 00:59:34 +03:00
parent 8271225216
commit 9c7b296432
6 changed files with 49 additions and 53 deletions

View File

@ -226,9 +226,8 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
/// Turns on ADC if it is not already turned on and starts continuous DMA transfer. /// Turns on ADC if it is not already turned on and starts continuous DMA transfer.
pub fn start(&mut self) -> Result<(), OverrunError> { pub fn start(&mut self) -> Result<(), OverrunError> {
self.ring_buf.clear();
self.setup_adc(); self.setup_adc();
self.ring_buf.clear();
Ok(()) Ok(())
} }

View File

@ -833,7 +833,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
/// Clear all data in the ring buffer. /// Clear all data in the ring buffer.
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); self.ringbuf.reset(&mut DmaCtrlImpl(self.channel.reborrow()));
} }
/// Read elements from the ring buffer /// Read elements from the ring buffer
@ -980,7 +980,7 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
/// Clear all data in the ring buffer. /// Clear all data in the ring buffer.
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); self.ringbuf.reset(&mut DmaCtrlImpl(self.channel.reborrow()));
} }
/// Write elements directly to the raw buffer. /// Write elements directly to the raw buffer.

View File

@ -23,14 +23,14 @@ pub struct OverrunError;
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
struct DmaIndex { struct DmaIndex {
completion_count: usize, complete_count: usize,
pos: usize, pos: usize,
} }
impl DmaIndex { impl DmaIndex {
fn reset(&mut self) { fn reset(&mut self) {
self.pos = 0; self.pos = 0;
self.completion_count = 0; self.complete_count = 0;
} }
fn as_index(&self, cap: usize, offset: usize) -> usize { fn as_index(&self, cap: usize, offset: usize) -> usize {
@ -38,34 +38,31 @@ impl DmaIndex {
} }
fn dma_sync(&mut self, cap: usize, dma: &mut impl DmaCtrl) { fn dma_sync(&mut self, cap: usize, dma: &mut impl DmaCtrl) {
let fst_pos = cap - dma.get_remaining_transfers(); let first_pos = cap - dma.get_remaining_transfers();
let fst_count = dma.reset_complete_count(); self.complete_count += dma.reset_complete_count();
let pos = cap - dma.get_remaining_transfers(); self.pos = cap - dma.get_remaining_transfers();
let wrap_count = if pos >= fst_pos { // If the latter call to get_remaining_transfers() returned a smaller value than the first, the dma
fst_count // has wrapped around between calls and we must check if the complete count also incremented.
} else { if self.pos < first_pos {
fst_count + dma.reset_complete_count() self.complete_count += dma.reset_complete_count();
}; }
self.pos = pos;
self.completion_count += wrap_count;
} }
fn advance(&mut self, cap: usize, steps: usize) { fn advance(&mut self, cap: usize, steps: usize) {
let next = self.pos + steps; let next = self.pos + steps;
self.completion_count += next / cap; self.complete_count += next / cap;
self.pos = next % cap; self.pos = next % cap;
} }
fn normalize(lhs: &mut DmaIndex, rhs: &mut DmaIndex) { fn normalize(lhs: &mut DmaIndex, rhs: &mut DmaIndex) {
let min_count = lhs.completion_count.min(rhs.completion_count); let min_count = lhs.complete_count.min(rhs.complete_count);
lhs.completion_count -= min_count; lhs.complete_count -= min_count;
rhs.completion_count -= min_count; rhs.complete_count -= min_count;
} }
fn diff(&self, cap: usize, rhs: &DmaIndex) -> isize { fn diff(&self, cap: usize, rhs: &DmaIndex) -> isize {
(self.completion_count * cap + self.pos) as isize - (rhs.completion_count * cap + rhs.pos) as isize (self.complete_count * cap + self.pos) as isize - (rhs.complete_count * cap + rhs.pos) as isize
} }
} }
@ -86,7 +83,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
} }
/// Reset the ring buffer to its initial state. /// Reset the ring buffer to its initial state.
pub fn clear(&mut self, dma: &mut impl DmaCtrl) { pub fn reset(&mut self, dma: &mut impl DmaCtrl) {
dma.reset_complete_count(); dma.reset_complete_count();
self.write_index.reset(); self.write_index.reset();
self.write_index.dma_sync(self.cap(), dma); self.write_index.dma_sync(self.cap(), dma);
@ -103,12 +100,12 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
self.write_index.dma_sync(self.cap(), dma); self.write_index.dma_sync(self.cap(), dma);
DmaIndex::normalize(&mut self.write_index, &mut self.read_index); DmaIndex::normalize(&mut self.write_index, &mut self.read_index);
let diff: usize = self.write_index.diff(self.cap(), &self.read_index).try_into().unwrap(); let diff = self.write_index.diff(self.cap(), &self.read_index);
if diff > self.cap() { if diff < 0 || diff > self.cap() as isize {
Err(OverrunError) Err(OverrunError)
} else { } else {
Ok(diff) Ok(diff as usize)
} }
} }
@ -117,10 +114,10 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
/// If not all of the elements were read, then there will be some elements in the buffer remaining /// If not all of the elements were read, then there will be some elements in the buffer remaining
/// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read
/// OverrunError is returned if the portion to be read was overwritten by the DMA controller, /// OverrunError is returned if the portion to be read was overwritten by the DMA controller,
/// in which case the rinbuffer will automatically clear itself. /// in which case the rinbuffer will automatically reset itself.
pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
self.read_raw(dma, buf).inspect_err(|_e| { self.read_raw(dma, buf).inspect_err(|_e| {
self.clear(dma); self.reset(dma);
}) })
} }
@ -192,14 +189,14 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
dma_buf, dma_buf,
read_index: Default::default(), read_index: Default::default(),
write_index: DmaIndex { write_index: DmaIndex {
completion_count: 0, complete_count: 0,
pos: len, pos: len,
}, },
} }
} }
/// Reset the ring buffer to its initial state. The buffer after the reset will be full. /// Reset the ring buffer to its initial state. The buffer after the reset will be full.
pub fn clear(&mut self, dma: &mut impl DmaCtrl) { pub fn reset(&mut self, dma: &mut impl DmaCtrl) {
dma.reset_complete_count(); dma.reset_complete_count();
self.read_index.reset(); self.read_index.reset();
self.read_index.dma_sync(self.cap(), dma); self.read_index.dma_sync(self.cap(), dma);
@ -214,7 +211,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
let diff = self.write_index.diff(self.cap(), &self.read_index); let diff = self.write_index.diff(self.cap(), &self.read_index);
if diff < 0 { if diff < 0 || diff > self.cap() as isize {
Err(OverrunError) Err(OverrunError)
} else { } else {
Ok(self.cap().saturating_sub(diff as usize)) Ok(self.cap().saturating_sub(diff as usize))
@ -233,7 +230,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
/// leeway between the write index and the DMA. /// leeway between the write index and the DMA.
pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> {
self.write_raw(dma, buf).inspect_err(|_e| { self.write_raw(dma, buf).inspect_err(|_e| {
self.clear(dma); self.reset(dma);
}) })
} }

View File

@ -64,12 +64,12 @@ fn dma_index_dma_sync_syncs_position_to_last_read_if_sync_takes_place_on_same_dm
]); ]);
let mut index = DmaIndex::default(); let mut index = DmaIndex::default();
index.dma_sync(CAP, &mut dma); index.dma_sync(CAP, &mut dma);
assert_eq!(index.completion_count, 0); assert_eq!(index.complete_count, 0);
assert_eq!(index.pos, 7); assert_eq!(index.pos, 7);
} }
#[test] #[test]
fn dma_index_dma_sync_updates_completion_count_properly_if_sync_takes_place_on_same_dma_cycle() { fn dma_index_dma_sync_updates_complete_count_properly_if_sync_takes_place_on_same_dma_cycle() {
let mut dma = TestCircularTransfer::new(CAP); let mut dma = TestCircularTransfer::new(CAP);
dma.setup(vec![ dma.setup(vec![
TestCircularTransferRequest::PositionRequest(4), TestCircularTransferRequest::PositionRequest(4),
@ -77,9 +77,9 @@ fn dma_index_dma_sync_updates_completion_count_properly_if_sync_takes_place_on_s
TestCircularTransferRequest::PositionRequest(7), TestCircularTransferRequest::PositionRequest(7),
]); ]);
let mut index = DmaIndex::default(); let mut index = DmaIndex::default();
index.completion_count = 1; index.complete_count = 1;
index.dma_sync(CAP, &mut dma); index.dma_sync(CAP, &mut dma);
assert_eq!(index.completion_count, 3); assert_eq!(index.complete_count, 3);
assert_eq!(index.pos, 7); assert_eq!(index.pos, 7);
} }
@ -94,12 +94,12 @@ fn dma_index_dma_sync_syncs_to_last_position_if_reads_occur_on_different_dma_cyc
]); ]);
let mut index = DmaIndex::default(); let mut index = DmaIndex::default();
index.dma_sync(CAP, &mut dma); index.dma_sync(CAP, &mut dma);
assert_eq!(index.completion_count, 1); assert_eq!(index.complete_count, 1);
assert_eq!(index.pos, 5); assert_eq!(index.pos, 5);
} }
#[test] #[test]
fn dma_index_dma_sync_detects_new_cycle_if_later_position_is_less_than_first_and_first_completion_count_occurs_on_first_cycle( fn dma_index_dma_sync_detects_new_cycle_if_later_position_is_less_than_first_and_first_complete_count_occurs_on_first_cycle(
) { ) {
let mut dma = TestCircularTransfer::new(CAP); let mut dma = TestCircularTransfer::new(CAP);
dma.setup(vec![ dma.setup(vec![
@ -109,14 +109,14 @@ fn dma_index_dma_sync_detects_new_cycle_if_later_position_is_less_than_first_and
TestCircularTransferRequest::ResetCompleteCount(1), TestCircularTransferRequest::ResetCompleteCount(1),
]); ]);
let mut index = DmaIndex::default(); let mut index = DmaIndex::default();
index.completion_count = 1; index.complete_count = 1;
index.dma_sync(CAP, &mut dma); index.dma_sync(CAP, &mut dma);
assert_eq!(index.completion_count, 3); assert_eq!(index.complete_count, 3);
assert_eq!(index.pos, 5); assert_eq!(index.pos, 5);
} }
#[test] #[test]
fn dma_index_dma_sync_detects_new_cycle_if_later_position_is_less_than_first_and_first_completion_count_occurs_on_later_cycle( fn dma_index_dma_sync_detects_new_cycle_if_later_position_is_less_than_first_and_first_complete_count_occurs_on_later_cycle(
) { ) {
let mut dma = TestCircularTransfer::new(CAP); let mut dma = TestCircularTransfer::new(CAP);
dma.setup(vec![ dma.setup(vec![
@ -126,9 +126,9 @@ fn dma_index_dma_sync_detects_new_cycle_if_later_position_is_less_than_first_and
TestCircularTransferRequest::ResetCompleteCount(0), TestCircularTransferRequest::ResetCompleteCount(0),
]); ]);
let mut index = DmaIndex::default(); let mut index = DmaIndex::default();
index.completion_count = 1; index.complete_count = 1;
index.dma_sync(CAP, &mut dma); index.dma_sync(CAP, &mut dma);
assert_eq!(index.completion_count, 3); assert_eq!(index.complete_count, 3);
assert_eq!(index.pos, 5); assert_eq!(index.pos, 5);
} }

View File

@ -5,7 +5,7 @@ use super::*;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
enum ReaderTransition { enum ReaderTransition {
Write(usize), Write(usize),
Clear, Reset,
ReadUpTo(usize), ReadUpTo(usize),
} }
@ -23,14 +23,14 @@ impl ReferenceStateMachine for ReaderSM {
prop_oneof![ prop_oneof![
(1..50_usize).prop_map(ReaderTransition::Write), (1..50_usize).prop_map(ReaderTransition::Write),
(1..50_usize).prop_map(ReaderTransition::ReadUpTo), (1..50_usize).prop_map(ReaderTransition::ReadUpTo),
strategy::Just(ReaderTransition::Clear), strategy::Just(ReaderTransition::Reset),
] ]
.boxed() .boxed()
} }
fn apply(status: Self::State, transition: &Self::Transition) -> Self::State { fn apply(status: Self::State, transition: &Self::Transition) -> Self::State {
match (status, transition) { match (status, transition) {
(_, ReaderTransition::Clear) => Status::Available(0), (_, ReaderTransition::Reset) => Status::Available(0),
(Status::Available(x), ReaderTransition::Write(y)) => { (Status::Available(x), ReaderTransition::Write(y)) => {
if x + y > CAP { if x + y > CAP {
Status::Failed Status::Failed
@ -87,8 +87,8 @@ impl StateMachineTest for ReaderTest {
) -> Self::SystemUnderTest { ) -> Self::SystemUnderTest {
match transition { match transition {
ReaderTransition::Write(x) => sut.producer.advance(x), ReaderTransition::Write(x) => sut.producer.advance(x),
ReaderTransition::Clear => { ReaderTransition::Reset => {
sut.consumer.clear(&mut sut.producer); sut.consumer.reset(&mut sut.producer);
} }
ReaderTransition::ReadUpTo(x) => { ReaderTransition::ReadUpTo(x) => {
let status = sut.status; let status = sut.status;

View File

@ -6,7 +6,7 @@ use super::*;
enum WriterTransition { enum WriterTransition {
Read(usize), Read(usize),
WriteUpTo(usize), WriteUpTo(usize),
Clear, Reset,
} }
struct WriterSM; struct WriterSM;
@ -23,14 +23,14 @@ impl ReferenceStateMachine for WriterSM {
prop_oneof![ prop_oneof![
(1..50_usize).prop_map(WriterTransition::Read), (1..50_usize).prop_map(WriterTransition::Read),
(1..50_usize).prop_map(WriterTransition::WriteUpTo), (1..50_usize).prop_map(WriterTransition::WriteUpTo),
strategy::Just(WriterTransition::Clear), strategy::Just(WriterTransition::Reset),
] ]
.boxed() .boxed()
} }
fn apply(status: Self::State, transition: &Self::Transition) -> Self::State { fn apply(status: Self::State, transition: &Self::Transition) -> Self::State {
match (status, transition) { match (status, transition) {
(_, WriterTransition::Clear) => Status::Available(CAP), (_, WriterTransition::Reset) => Status::Available(CAP),
(Status::Available(x), WriterTransition::Read(y)) => { (Status::Available(x), WriterTransition::Read(y)) => {
if x < *y { if x < *y {
Status::Failed Status::Failed
@ -87,8 +87,8 @@ impl StateMachineTest for WriterTest {
) -> Self::SystemUnderTest { ) -> Self::SystemUnderTest {
match transition { match transition {
WriterTransition::Read(x) => sut.consumer.advance(x), WriterTransition::Read(x) => sut.consumer.advance(x),
WriterTransition::Clear => { WriterTransition::Reset => {
sut.producer.clear(&mut sut.consumer); sut.producer.reset(&mut sut.consumer);
} }
WriterTransition::WriteUpTo(x) => { WriterTransition::WriteUpTo(x) => {
let status = sut.status; let status = sut.status;