diff --git a/src/dma/mod.rs b/src/dma/mod.rs index 5d831983..4b39929f 100644 --- a/src/dma/mod.rs +++ b/src/dma/mod.rs @@ -7,7 +7,6 @@ //! transfers, double buffering is supported only for Peripheral To Memory and Memory to Peripheral //! transfers. -use bitflags::bitflags; use core::{ fmt::{self, Debug, Formatter}, marker::PhantomData, @@ -299,17 +298,6 @@ impl Not for CurrentBuffer { } } -bitflags! { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] - /// Type allowing to conveniently listen or unlisten several interrupts at same time. - pub struct DmaCommonInterruptsMask: u8 { - const DIRECT_MODE_ERROR = 1 << 1; - const TRANSFER_ERROR = 1 << 2; - const HALF_TRANSFER = 1 << 3; - const TRANSFER_COMPLETE = 1 << 4; - } -} - /// Structure representing setup of common interrupts. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct DmaCommonInterrupts { @@ -319,6 +307,18 @@ pub struct DmaCommonInterrupts { pub direct_mode_error: bool, } +impl DmaCommonInterrupts { + /// Return a new DmaCommonInterrupts with all fields set to true. + const fn all() -> Self { + Self { + transfer_complete: true, + half_transfer: true, + transfer_error: true, + direct_mode_error: true, + } + } +} + /// Structure returned by Stream or Transfer all_flags() method. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct DmaFlags { @@ -329,6 +329,19 @@ pub struct DmaFlags { pub fifo_error: bool, } +impl DmaFlags { + /// Return a new DmaFlags with all fields set to true. + const fn all() -> Self { + Self { + transfer_complete: true, + half_transfer: true, + transfer_error: true, + direct_mode_error: true, + fifo_error: true, + } + } +} + /// Stream on the DMA controller. pub struct StreamX { _dma: PhantomData, @@ -538,18 +551,22 @@ where } #[inline(always)] - fn listen_common_interrupts(&mut self, mask: DmaCommonInterruptsMask) { - // Note: bitflags doesn't garantee value of unused bit :( - let mask = mask.intersection(DmaCommonInterruptsMask::all()).bits() as u32; + fn listen(&mut self, interrupts: DmaCommonInterrupts) { + let mask = (interrupts.transfer_complete as u32) << 4 + | (interrupts.half_transfer as u32) << 3 + | (interrupts.transfer_error as u32) << 2 + | (interrupts.direct_mode_error as u32) << 1; unsafe { Self::st() } .cr .modify(|r, w| unsafe { w.bits(r.bits() | mask) }); } #[inline(always)] - fn unlisten_common_interrupts(&mut self, mask: DmaCommonInterruptsMask) { - // Note: bitflags doesn't garantee value of unused bit :( - let mask = mask.intersection(DmaCommonInterruptsMask::all()).bits() as u32; + fn unlisten(&mut self, interrupts: DmaCommonInterrupts) { + let mask = (interrupts.transfer_complete as u32) << 4 + | (interrupts.half_transfer as u32) << 3 + | (interrupts.transfer_error as u32) << 2 + | (interrupts.direct_mode_error as u32) << 1; unsafe { Self::st() } .cr .modify(|r, w| unsafe { w.bits(r.bits() & !mask) }); @@ -676,16 +693,16 @@ macro_rules! dma_stream { impl StreamISR for StreamX where Self: crate::Sealed { #[inline(always)] - fn clear_all_flags(&mut self) { + fn clear_flags(&mut self, flag: DmaFlags) { //NOTE(unsafe) Atomic write with no side-effects and we only access the bits // that belongs to the StreamX let dma = unsafe { &*I::ptr() }; dma.$ifcr.write(|w| w - .$tcif().set_bit() //Clear transfer complete interrupt flag - .$htif().set_bit() //Clear half transfer interrupt flag - .$teif().set_bit() //Clear transfer error interrupt flag - .$dmeif().set_bit() //Clear direct mode error interrupt flag - .$feif().set_bit() //Clear fifo error interrupt flag + .$tcif().bit(flag.transfer_complete) //Clear transfer complete interrupt flag + .$htif().bit(flag.half_transfer) //Clear half transfer interrupt flag + .$teif().bit(flag.transfer_error) //Clear transfer error interrupt flag + .$dmeif().bit(flag.direct_mode_error) //Clear direct mode error interrupt flag + .$feif().bit(flag.fifo_error) //Clear fifo error interrupt flag ); } @@ -1045,18 +1062,12 @@ fn stream_disable(stream: &mut T) { if stream.is_enabled() { // Aborting an on-going transfer might cause interrupts to fire, disable let interrupts = stream.common_interrupts(); - stream.unlisten_common_interrupts(DmaCommonInterruptsMask::all()); + stream.unlisten(DmaCommonInterrupts::all()); unsafe { stream.disable() }; while stream.is_enabled() {} - stream.clear_all_flags(); - let mut interrupts_mask = DmaCommonInterruptsMask::empty(); - use DmaCommonInterruptsMask as Mask; - interrupts_mask.set(Mask::TRANSFER_COMPLETE, interrupts.transfer_complete); - interrupts_mask.set(Mask::HALF_TRANSFER, interrupts.half_transfer); - interrupts_mask.set(Mask::TRANSFER_ERROR, interrupts.transfer_error); - interrupts_mask.set(Mask::DIRECT_MODE_ERROR, interrupts.direct_mode_error); - stream.listen_common_interrupts(interrupts_mask); + stream.clear_flags(DmaFlags::all()); + stream.listen(interrupts); } } @@ -1495,7 +1506,7 @@ where pub fn release(mut self) -> (STREAM, PERIPHERAL, BUF, Option) { stream_disable(&mut self.stream); compiler_fence(Ordering::SeqCst); - self.stream.clear_all_flags(); + self.stream.clear_flags(DmaFlags::all()); unsafe { let stream = ptr::read(&self.stream); @@ -1515,7 +1526,7 @@ where /// Clear all interrupts flags for the DMA stream. #[inline(always)] pub fn clear_all_flags(&mut self) { - self.stream.clear_all_flags(); + self.stream.clear_flags(DmaFlags::all()); } /// Clear transfer complete interrupt (tcif) for the DMA stream. @@ -1612,7 +1623,7 @@ where _ => DmaDataSize::Word, }; - stream.clear_all_flags(); + stream.clear_flags(DmaFlags::all()); stream.set_priority(config.priority); // NOTE(unsafe) These values are correct because of the invariants of PeriAddress unsafe { @@ -1622,14 +1633,14 @@ where stream.set_memory_increment(config.memory_increment); stream.set_peripheral_increment(config.peripheral_increment); - use DmaCommonInterruptsMask as Mask; - let mut interrupts_mask = Mask::empty(); - interrupts_mask.set(Mask::TRANSFER_COMPLETE, config.transfer_complete_interrupt); - interrupts_mask.set(Mask::HALF_TRANSFER, config.half_transfer_interrupt); - interrupts_mask.set(Mask::TRANSFER_ERROR, config.transfer_error_interrupt); - interrupts_mask.set(Mask::DIRECT_MODE_ERROR, config.direct_mode_error_interrupt); - stream.unlisten_common_interrupts(Mask::all()); - stream.listen_common_interrupts(interrupts_mask); + let interrupts = DmaCommonInterrupts { + transfer_complete: config.transfer_complete_interrupt, + half_transfer: config.half_transfer_interrupt, + transfer_error: config.transfer_error_interrupt, + direct_mode_error: config.direct_mode_error_interrupt, + }; + stream.unlisten(DmaCommonInterrupts::all()); + stream.listen(interrupts); if config.fifo_error_interrupt { stream.listen_fifo_error(); } else { diff --git a/src/dma/traits.rs b/src/dma/traits.rs index af4ea824..337c6426 100644 --- a/src/dma/traits.rs +++ b/src/dma/traits.rs @@ -20,7 +20,7 @@ pub trait SafePeripheralRead {} /// Trait for DMA stream interrupt handling. pub trait StreamISR: crate::Sealed { /// Clear all interrupts flags for the DMA stream. - fn clear_all_flags(&mut self); + fn clear_flags(&mut self, flags: DmaFlags); /// Clear transfer complete interrupt (tcif) for the DMA stream. fn clear_transfer_complete(&mut self); @@ -149,13 +149,11 @@ pub trait Stream: StreamISR + crate::Sealed { /// Set the flow controller (pfctrl). fn set_flow_controller(&mut self, value: DmaFlowController); - /// Enable several interrupts using a mask. Modify only interrupts with their bits set in the - /// mask - fn listen_common_interrupts(&mut self, mask: DmaCommonInterruptsMask); + /// Enable several interrupts. Modify only interrupts set to `true` in the DmaCommonInterrupts + fn listen(&mut self, interrupts: DmaCommonInterrupts); - /// Disable several interrupts using a mask. Modify only interrupts with their bits set in the - /// mask - fn unlisten_common_interrupts(&mut self, mask: DmaCommonInterruptsMask); + /// Disable several interrupts. Modify only interrupts set to `true` in the DmaCommonInterrupts + fn unlisten(&mut self, interrupts: DmaCommonInterrupts); /// Convenience method to get the value of several interrupts of the DMA stream. The order of the /// returns are: `transfer_complete`, `half_transfer`, `transfer_error` and `direct_mode_error`