Skip to content

Commit 9365f12

Browse files
committed
Manually implement Debug for DMAError
Allow for skipping an ongoing transfer if not using double buffering
1 parent 23c6ec9 commit 9365f12

File tree

2 files changed

+84
-22
lines changed

2 files changed

+84
-22
lines changed

src/dma/mod.rs

Lines changed: 72 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
//! transfers.
99
1010
use core::{
11+
fmt::{self, Debug, Formatter},
1112
marker::PhantomData,
1213
mem,
1314
ops::Not,
@@ -24,7 +25,7 @@ use traits::{
2425
};
2526

2627
/// Errors.
27-
#[derive(Debug, PartialEq)]
28+
#[derive(PartialEq)]
2829
pub enum DMAError<T> {
2930
/// DMA not ready to change buffers.
3031
NotReady(T),
@@ -34,6 +35,19 @@ pub enum DMAError<T> {
3435
Overrun(T),
3536
}
3637

38+
// Manually implement `Debug`, so we can have debug information even with a buffer `T` that doesn't
39+
// implement `Debug`. `T` is always a buffer type chosen by the user, because of that the debug
40+
// information can be helpful even without knowing the inner type
41+
impl<T> Debug for DMAError<T> {
42+
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
43+
match self {
44+
DMAError::NotReady(_) => f.debug_tuple("NotReady").finish(),
45+
DMAError::SmallBuffer(_) => f.debug_tuple("SmalBuffer").finish(),
46+
DMAError::Overrun(_) => f.debug_tuple("Overrun").finish(),
47+
}
48+
}
49+
}
50+
3751
/// Possible DMA's directions.
3852
#[derive(Debug, Clone, Copy, PartialEq)]
3953
pub enum DmaDirection {
@@ -375,6 +389,13 @@ macro_rules! dma_stream {
375389
dma.st[Self::NUMBER].ndtr.write(|w| w.ndt().bits(value));
376390
}
377391

392+
#[inline(always)]
393+
fn get_number_of_transfers() -> u16 {
394+
//NOTE(unsafe) We only access the registers that belongs to the StreamX
395+
let dma = unsafe { &*I::ptr() };
396+
dma.st[Self::NUMBER].ndtr.read().ndt().bits()
397+
}
398+
378399
#[inline(always)]
379400
unsafe fn enable(&mut self) {
380401
//NOTE(unsafe) We only access the registers that belongs to the StreamX
@@ -389,11 +410,23 @@ macro_rules! dma_stream {
389410
dma.st[Self::NUMBER].cr.read().en().bit_is_set()
390411
}
391412

392-
#[inline(always)]
393413
fn disable(&mut self) {
394-
//NOTE(unsafe) We only access the registers that belongs to the StreamX
395-
let dma = unsafe { &*I::ptr() };
396-
dma.st[Self::NUMBER].cr.modify(|_, w| w.en().clear_bit());
414+
if Self::is_enabled() {
415+
//NOTE(unsafe) We only access the registers that belongs to the StreamX
416+
let dma = unsafe { &*I::ptr() };
417+
418+
// Aborting an on-going transfer might cause interrupts to fire, disable
419+
// them
420+
let (tc, ht, te, dm) = Self::get_interrupts_enable();
421+
self
422+
.set_interrupts_enable(false, false, false, false);
423+
424+
dma.st[Self::NUMBER].cr.modify(|_, w| w.en().clear_bit());
425+
while Self::is_enabled() {}
426+
427+
self.clear_interrupts();
428+
self.set_interrupts_enable(tc, ht, te, dm);
429+
}
397430
}
398431

399432
#[inline(always)]
@@ -464,6 +497,15 @@ macro_rules! dma_stream {
464497
);
465498
}
466499

500+
#[inline(always)]
501+
fn get_interrupts_enable() -> (bool, bool, bool, bool) {
502+
//NOTE(unsafe) We only access the registers that belongs to the StreamX
503+
let dma = unsafe { &*I::ptr() };
504+
let cr = dma.st[Self::NUMBER].cr.read();
505+
(cr.tcie().bit_is_set(), cr.htie().bit_is_set(),
506+
cr.teie().bit_is_set(), cr.dmeie().bit_is_set())
507+
}
508+
467509
#[inline(always)]
468510
fn set_transfer_complete_interrupt_enable(&mut self, transfer_complete_interrupt: bool) {
469511
//NOTE(unsafe) We only access the registers that belongs to the StreamX
@@ -969,19 +1011,22 @@ where
9691011
/// Changes the buffer and restarts or continues a double buffer transfer. This must be called
9701012
/// immediately after a transfer complete event. Returns the old buffer together with its
9711013
/// `CurrentBuffer`. If an error occurs, this method will return the new buffer with the error.
1014+
///
9721015
/// This method will clear the transfer complete flag on entry, it will also clear it again if
9731016
/// an overrun occurs during its execution. Moreover, if an overrun occurs, the stream will be
974-
/// disabled and the transfer error flag will be set.
1017+
/// disabled and the transfer error flag will be set. This method can be called before the end
1018+
/// of an ongoing transfer only if not using double buffering, in that case, the current
1019+
/// transfer will be canceled and a new one will be started. A `NotReady` error will be returned
1020+
/// if this method is called before the end of a transfer while double buffering.
9751021
pub fn next_transfer(
9761022
&mut self,
9771023
mut new_buf: BUF,
9781024
) -> Result<(BUF, CurrentBuffer), DMAError<BUF>> {
979-
if !STREAM::get_transfer_complete_flag() {
980-
return Err(DMAError::NotReady(new_buf));
981-
}
982-
self.stream.clear_transfer_complete_interrupt();
983-
9841025
if self.double_buf.is_some() && DIR::direction() != DmaDirection::MemoryToMemory {
1026+
if !STREAM::get_transfer_complete_flag() {
1027+
return Err(DMAError::NotReady(new_buf));
1028+
}
1029+
self.stream.clear_transfer_complete_interrupt();
9851030
// NOTE(unsafe) We now own this buffer and we won't call any &mut methods on it until
9861031
// the end of the DMA transfer
9871032
let (new_buf_ptr, new_buf_len) = unsafe { new_buf.write_buffer() };
@@ -993,7 +1038,7 @@ where
9931038

9941039
if STREAM::current_buffer() == CurrentBuffer::DoubleBuffer {
9951040
self.stream.set_memory_address(new_buf_ptr as u32);
996-
// Check if an overrun occured, the buffer address won't be updated in that case
1041+
// Check if an overrun occurred, the buffer address won't be updated in that case
9971042
if self.stream.get_memory_address() != new_buf_ptr as u32 {
9981043
self.stream.clear_transfer_complete_interrupt();
9991044
return Err(DMAError::Overrun(new_buf));
@@ -1009,7 +1054,7 @@ where
10091054
} else {
10101055
self.stream
10111056
.set_memory_double_buffer_address(new_buf_ptr as u32);
1012-
// Check if an overrun occured, the buffer address won't be updated in that case
1057+
// Check if an overrun occurred, the buffer address won't be updated in that case
10131058
if self.stream.get_memory_double_buffer_address() != new_buf_ptr as u32 {
10141059
self.stream.clear_transfer_complete_interrupt();
10151060
return Err(DMAError::Overrun(new_buf));
@@ -1025,8 +1070,9 @@ where
10251070
}
10261071
}
10271072
self.stream.disable();
1073+
self.stream.clear_transfer_complete_interrupt();
10281074

1029-
// "No re-ordering of reads and writes across this point is allowed"
1075+
// "Subsequent reads and writes cannot be moved ahead of preceding reads."
10301076
compiler_fence(Ordering::SeqCst);
10311077

10321078
// NOTE(unsafe) We now own this buffer and we won't call any &mut methods on it until
@@ -1111,8 +1157,11 @@ where
11111157

11121158
/// Changes the buffer and restarts or continues a double buffer transfer. This must be called
11131159
/// immediately after a transfer complete event. The closure must return `(BUF, T)` where `BUF`
1114-
/// is the new buffer to be used. The closure will not be called if the transfer is not
1115-
/// completed. This method clears the transfer complete flag on entry.
1160+
/// is the new buffer to be used. This method can be called before the end of an ongoing
1161+
/// transfer only if not using double buffering, in that case, the current transfer will be
1162+
/// canceled and a new one will be started. A `NotReady` error will be returned if this method
1163+
/// is called before the end of a transfer while double buffering and the closure won't be
1164+
/// executed.
11161165
///
11171166
/// # Panics
11181167
/// This method will panic when double buffering and one or both of the following conditions
@@ -1133,12 +1182,12 @@ where
11331182
where
11341183
F: FnOnce(BUF, CurrentBuffer) -> (BUF, T),
11351184
{
1136-
if !STREAM::get_transfer_complete_flag() {
1137-
return Err(DMAError::NotReady(()));
1138-
}
1139-
self.stream.clear_transfer_complete_interrupt();
1140-
11411185
if self.double_buf.is_some() && DIR::direction() != DmaDirection::MemoryToMemory {
1186+
if !STREAM::get_transfer_complete_flag() {
1187+
return Err(DMAError::NotReady(()));
1188+
}
1189+
self.stream.clear_transfer_complete_interrupt();
1190+
11421191
let current_buffer = STREAM::current_buffer();
11431192
// double buffering, unwrap can never fail
11441193
let db = if current_buffer == CurrentBuffer::DoubleBuffer {
@@ -1170,7 +1219,7 @@ where
11701219
if current_buffer == CurrentBuffer::DoubleBuffer {
11711220
self.stream.set_memory_address(new_buf_ptr as u32);
11721221

1173-
// Check again if an overrun occured, the buffer address won't be updated in that
1222+
// Check again if an overrun occurred, the buffer address won't be updated in that
11741223
// case
11751224
if self.stream.get_memory_address() != new_buf_ptr as u32 {
11761225
panic!("Overrun");
@@ -1196,6 +1245,7 @@ where
11961245
}
11971246
}
11981247
self.stream.disable();
1248+
self.stream.clear_transfer_complete_interrupt();
11991249

12001250
// "No re-ordering of reads and writes across this point is allowed"
12011251
compiler_fence(Ordering::SeqCst);

src/dma/traits.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ pub trait Stream: Sealed {
6363
/// Set the number of transfers (ndt) for the DMA stream.
6464
fn set_number_of_transfers(&mut self, value: u16);
6565

66+
/// Get the number of transfers (ndt) for the DMA stream.
67+
fn get_number_of_transfers() -> u16;
68+
6669
/// Enable the DMA stream.
6770
///
6871
/// # Safety
@@ -74,6 +77,10 @@ pub trait Stream: Sealed {
7477
fn is_enabled() -> bool;
7578

7679
/// Disable the DMA stream.
80+
///
81+
/// Disabling the stream during an on-going transfer needs to be performed in a certain way to
82+
/// prevent problems if the stream is to be re-enabled shortly after, because of that, this
83+
/// method will also clear all the stream's interrupt flags if the stream is active.
7784
fn disable(&mut self);
7885

7986
/// Set the channel for the (chsel) the DMA stream.
@@ -120,6 +127,11 @@ pub trait Stream: Sealed {
120127
direct_mode_error: bool,
121128
);
122129

130+
/// Convenience method to get the value of the 4 common interrupts for the DMA stream.
131+
/// The order of the returns are: `transfer_complete`, `half_transfer`, `transfer_error` and
132+
/// `direct_mode_error`.
133+
fn get_interrupts_enable() -> (bool, bool, bool, bool);
134+
123135
/// Enable/disable the transfer complete interrupt (tcie) of the DMA stream.
124136
fn set_transfer_complete_interrupt_enable(&mut self, transfer_complete_interrupt: bool);
125137

0 commit comments

Comments
 (0)