mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-22 06:42:32 +00:00
overrun at invalid diffs, rename clear to reset, simplify dma_sync method
This commit is contained in:
parent
8271225216
commit
9c7b296432
@ -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(())
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user