diff --git a/CHANGELOG.md b/CHANGELOG.md index 45969a57..9f1509ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- complete and rework Dma Stream API [#666] + +[#666]: https://github.com/stm32-rs/stm32f4xx-hal/pull/666 + ## [v0.17.1] - 2023-07-24 ### Changed diff --git a/examples/rtic-serial-dma-rx-idle.rs b/examples/rtic-serial-dma-rx-idle.rs index 32e985dd..ebb49a48 100644 --- a/examples/rtic-serial-dma-rx-idle.rs +++ b/examples/rtic-serial-dma-rx-idle.rs @@ -14,10 +14,7 @@ mod app { use hal::{ - dma::{ - config::DmaConfig, traits::Stream, traits::StreamISR, PeripheralToMemory, Stream2, - StreamsTuple, Transfer, - }, + dma::{config::DmaConfig, PeripheralToMemory, Stream2, StreamsTuple, Transfer}, pac::{DMA2, USART1}, prelude::*, rcc::RccExt, @@ -120,7 +117,7 @@ mod app { if transfer.is_idle() { // Calc received bytes count - let bytes_count = BUFFER_SIZE - Stream2::::get_number_of_transfers() as usize; + let bytes_count = BUFFER_SIZE - transfer.number_of_transfers() as usize; // Allocate new buffer let new_buffer = cx.local.rx_buffer.take().unwrap(); @@ -143,11 +140,11 @@ mod app { fn dma2_stream2(mut cx: dma2_stream2::Context) { let transfer = &mut cx.shared.rx_transfer; - if Stream2::::get_fifo_error_flag() { - transfer.clear_fifo_error_interrupt(); + if transfer.is_fifo_error() { + transfer.clear_fifo_error(); } - if Stream2::::get_transfer_complete_flag() { - transfer.clear_transfer_complete_interrupt(); + if transfer.is_transfer_complete() { + transfer.clear_transfer_complete(); // Buffer is full, but no IDLE received! // You can process this data or discard data (ignore transfer complete interrupt and wait IDLE). diff --git a/examples/rtic-spi-slave-dma.rs b/examples/rtic-spi-slave-dma.rs index 53f49e10..32ee5442 100644 --- a/examples/rtic-spi-slave-dma.rs +++ b/examples/rtic-spi-slave-dma.rs @@ -9,8 +9,8 @@ mod app { use embedded_hal::spi::{Mode, Phase, Polarity}; use hal::{ dma::{ - config::DmaConfig, traits::StreamISR, MemoryToPeripheral, PeripheralToMemory, Stream0, - Stream5, StreamsTuple, Transfer, + config::DmaConfig, MemoryToPeripheral, PeripheralToMemory, Stream0, Stream5, + StreamsTuple, Transfer, }, gpio::{gpioc::PC13, GpioExt, Output, PushPull}, pac::{DMA1, SPI3}, @@ -138,50 +138,40 @@ mod app { // The led lights up if the first byte we receive is a 1, it turns off otherwise #[task(binds = DMA1_STREAM0, shared = [rx_transfer, led], local = [rx_buffer])] fn on_receiving(cx: on_receiving::Context) { - let on_receiving::Context { mut shared, local } = cx; - if Stream0::::get_fifo_error_flag() { - shared - .rx_transfer - .lock(|spi_dma| spi_dma.clear_fifo_error_interrupt()); - } - if Stream0::::get_transfer_complete_flag() { - shared - .rx_transfer - .lock(|spi_dma| spi_dma.clear_transfer_complete_interrupt()); - let filled_buffer = shared.rx_transfer.lock(|spi_dma| { - let (result, _) = spi_dma - .next_transfer(local.rx_buffer.take().unwrap()) - .unwrap(); - result - }); - match filled_buffer[0] { - 1 => shared.led.lock(|led| led.set_low()), - _ => shared.led.lock(|led| led.set_high()), + let mut rx_transfer = cx.shared.rx_transfer; + let mut led = cx.shared.led; + let rx_buffer = cx.local.rx_buffer; + rx_transfer.lock(|transfer| { + if transfer.is_fifo_error() { + transfer.clear_fifo_error(); } - *local.rx_buffer = Some(filled_buffer); - } + if transfer.is_transfer_complete() { + transfer.clear_transfer_complete(); + + let (filled_buffer, _) = transfer.next_transfer(rx_buffer.take().unwrap()).unwrap(); + match filled_buffer[0] { + 1 => led.lock(|led| led.set_low()), + _ => led.lock(|led| led.set_high()), + } + *rx_buffer = Some(filled_buffer); + } + }); } // We either send [1,2,3] or [4,5,6] depending on which buffer was loaded - #[task(binds = DMA1_STREAM5, shared = [tx_transfer, led], local = [tx_buffer])] + #[task(binds = DMA1_STREAM5, shared = [tx_transfer], local = [tx_buffer])] fn on_sending(cx: on_sending::Context) { - let on_sending::Context { mut shared, local } = cx; - if Stream5::::get_fifo_error_flag() { - shared - .tx_transfer - .lock(|spi_dma| spi_dma.clear_fifo_error_interrupt()); - } - if Stream5::::get_transfer_complete_flag() { - shared - .tx_transfer - .lock(|spi_dma| spi_dma.clear_transfer_complete_interrupt()); - let filled_buffer = shared.tx_transfer.lock(|spi_dma| { - let (result, _) = spi_dma - .next_transfer(local.tx_buffer.take().unwrap()) - .unwrap(); - result - }); - *local.tx_buffer = Some(filled_buffer); - } + let mut tx_transfer = cx.shared.tx_transfer; + let tx_buffer = cx.local.tx_buffer; + tx_transfer.lock(|transfer| { + if transfer.is_fifo_error() { + transfer.clear_fifo_error(); + } + if transfer.is_transfer_complete() { + transfer.clear_transfer_complete(); + let (filled_buffer, _) = transfer.next_transfer(tx_buffer.take().unwrap()).unwrap(); + *tx_buffer = Some(filled_buffer); + } + }); } } diff --git a/examples/spi-dma.rs b/examples/spi-dma.rs index e99ad1b2..3630fb52 100644 --- a/examples/spi-dma.rs +++ b/examples/spi-dma.rs @@ -10,7 +10,7 @@ use cortex_m_rt::entry; use embedded_hal::spi::{Mode, Phase, Polarity}; use stm32f4xx_hal::pac::interrupt; use stm32f4xx_hal::{ - dma::{config, traits::StreamISR, MemoryToPeripheral, Stream4, StreamsTuple, Transfer}, + dma::{config, MemoryToPeripheral, Stream4, StreamsTuple, Transfer}, gpio::Speed, pac, prelude::*, @@ -101,11 +101,11 @@ fn DMA2_STREAM4() { }); // Its important to clear fifo errors as the transfer is paused until it is cleared - if Stream4::::get_fifo_error_flag() { - transfer.clear_fifo_error_interrupt(); + if transfer.is_fifo_error() { + transfer.clear_fifo_error(); } - if Stream4::::get_transfer_complete_flag() { - transfer.clear_transfer_complete_interrupt(); + if transfer.is_transfer_complete() { + transfer.clear_transfer_complete(); unsafe { static mut BUFFER: [u8; ARRAY_SIZE] = [0; ARRAY_SIZE]; for (i, b) in BUFFER.iter_mut().enumerate() { diff --git a/src/dma/mod.rs b/src/dma/mod.rs index 09a74ff1..4b39929f 100644 --- a/src/dma/mod.rs +++ b/src/dma/mod.rs @@ -50,15 +50,113 @@ impl Debug for DMAError { } } +// most of STM32F4 have 8 DmaChannel +#[cfg(not(feature = "gpio-f413"))] +/// Possible Channel of a DMA Stream. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DmaChannel { + Channel0 = 0, + Channel1 = 1, + Channel2 = 2, + Channel3 = 3, + Channel4 = 4, + Channel5 = 5, + Channel6 = 6, + Channel7 = 7, +} + +// STM32F413 and STM32F423 have 16 DmaChannel +#[cfg(feature = "gpio-f413")] +/// Possible Channel of a DMA Stream. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DmaChannel { + Channel0 = 0, + Channel1 = 1, + Channel2 = 2, + Channel3 = 3, + Channel4 = 4, + Channel5 = 5, + Channel6 = 6, + Channel7 = 7, + Channel8 = 8, + Channel9 = 9, + Channel10 = 10, + Channel11 = 11, + Channel12 = 12, + Channel13 = 13, + Channel14 = 14, + Channel15 = 15, +} + +impl Bits for DmaChannel { + fn bits(self) -> u8 { + self as u8 + } +} + +/// Peripheral increment offset size (pincos) +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PeripheralIncrementOffset { + /// The offset size is linked to the peripheral data size (psize) + PeripheralDataSize = 0, + /// The offset size is fixed to 4 (32 bits alignement) + FixedSize = 1, +} + +impl Bits for PeripheralIncrementOffset { + fn bits(self) -> bool { + match self { + PeripheralIncrementOffset::PeripheralDataSize => false, + PeripheralIncrementOffset::FixedSize => true, + } + } +} + +/// Size of data transfered during a dma stream request +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DmaDataSize { + Byte = 0, + HalfWord = 1, + Word = 2, +} + +impl Bits for DmaDataSize { + fn bits(self) -> u8 { + self as u8 + } +} + /// Possible DMA's directions. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum DmaDirection { /// Memory to Memory transfer. - MemoryToMemory, + MemoryToMemory = 2, /// Peripheral to Memory transfer. - PeripheralToMemory, + PeripheralToMemory = 0, /// Memory to Peripheral transfer. - MemoryToPeripheral, + MemoryToPeripheral = 1, +} + +impl Bits for DmaDirection { + fn bits(self) -> u8 { + self as u8 + } +} + +/// Dma flow controller selection +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DmaFlowController { + Dma = 0, + Peripheral = 1, +} + +impl Bits for DmaFlowController { + fn bits(self) -> bool { + match self { + DmaFlowController::Dma => false, + DmaFlowController::Peripheral => true, + } + } } /// DMA from a peripheral to a memory location. @@ -185,7 +283,7 @@ pub enum CurrentBuffer { /// The first buffer (m0ar) is in use. FirstBuffer, /// The second buffer (m1ar) is in use. - DoubleBuffer, + SecondBuffer, } impl Not for CurrentBuffer { @@ -193,13 +291,57 @@ impl Not for CurrentBuffer { fn not(self) -> Self::Output { if self == CurrentBuffer::FirstBuffer { - CurrentBuffer::DoubleBuffer + CurrentBuffer::SecondBuffer } else { CurrentBuffer::FirstBuffer } } } +/// Structure representing setup of common interrupts. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct DmaCommonInterrupts { + pub transfer_complete: bool, + pub half_transfer: bool, + pub transfer_error: bool, + 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 { + pub transfer_complete: bool, + pub half_transfer: bool, + pub transfer_error: bool, + pub direct_mode_error: bool, + 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, @@ -303,19 +445,19 @@ where } #[inline(always)] - fn get_memory_address(&self) -> u32 { + fn memory_address(&self) -> u32 { unsafe { Self::st() }.m0ar.read().m0a().bits() } #[inline(always)] - fn set_memory_double_buffer_address(&mut self, value: u32) { + fn set_alternate_memory_address(&mut self, value: u32) { unsafe { Self::st() } .m1ar .write(|w| unsafe { w.m1a().bits(value) }); } #[inline(always)] - fn get_memory_double_buffer_address(&self) -> u32 { + fn alternate_memory_address(&self) -> u32 { unsafe { Self::st() }.m1ar.read().m1a().bits() } @@ -325,7 +467,7 @@ where } #[inline(always)] - fn get_number_of_transfers() -> u16 { + fn number_of_transfers(&self) -> u16 { unsafe { Self::st() }.ndtr.read().ndt().bits() } @@ -335,31 +477,20 @@ where } #[inline(always)] - fn is_enabled() -> bool { + fn is_enabled(&self) -> bool { unsafe { Self::st() }.cr.read().en().bit_is_set() } - fn disable(&mut self) { - if Self::is_enabled() { - // Aborting an on-going transfer might cause interrupts to fire, disable - // them - let (tc, ht, te, dm) = Self::get_interrupts_enable(); - self.set_interrupts_enable(false, false, false, false); - - unsafe { Self::st() }.cr.modify(|_, w| w.en().clear_bit()); - while Self::is_enabled() {} - - self.clear_interrupts(); - self.set_interrupts_enable(tc, ht, te, dm); - } + #[inline(always)] + unsafe fn disable(&mut self) { + unsafe { Self::st() }.cr.modify(|_, w| w.en().clear_bit()); } #[inline(always)] - fn set_channel(&mut self) - where - ChannelX: Channel, - { - unsafe { Self::st() }.cr.modify(|_, w| w.chsel().bits(C)); + fn set_channel(&mut self, channel: DmaChannel) { + unsafe { Self::st() } + .cr + .modify(|_, w| w.chsel().bits(channel.bits())); } #[inline(always)] @@ -370,13 +501,20 @@ where } #[inline(always)] - unsafe fn set_memory_size(&mut self, size: u8) { - Self::st().cr.modify(|_, w| w.msize().bits(size)); + fn set_peripheral_increment_offset(&mut self, value: PeripheralIncrementOffset) { + unsafe { Self::st() } + .cr + .modify(|_, w| w.pincos().bit(value.bits())); + } + + #[inline(always)] + unsafe fn set_memory_size(&mut self, size: DmaDataSize) { + Self::st().cr.modify(|_, w| w.msize().bits(size.bits())); } #[inline(always)] - unsafe fn set_peripheral_size(&mut self, size: u8) { - Self::st().cr.modify(|_, w| w.psize().bits(size)); + unsafe fn set_peripheral_size(&mut self, size: DmaDataSize) { + Self::st().cr.modify(|_, w| w.psize().bits(size.bits())); } #[inline(always)] @@ -394,76 +532,105 @@ where } #[inline(always)] - fn set_direction(&mut self, direction: D) { + fn set_circular_mode(&mut self, value: bool) { + unsafe { Self::st() }.cr.modify(|_, w| w.circ().bit(value)); + } + + #[inline(always)] + fn set_direction(&mut self, direction: DmaDirection) { unsafe { Self::st() } .cr .modify(|_, w| unsafe { w.dir().bits(direction.bits()) }); } #[inline(always)] - fn set_interrupts_enable( - &mut self, - transfer_complete: bool, - half_transfer: bool, - transfer_error: bool, - direct_mode_error: bool, - ) { - unsafe { Self::st() }.cr.modify(|_, w| { - w.tcie() - .bit(transfer_complete) - .htie() - .bit(half_transfer) - .teie() - .bit(transfer_error) - .dmeie() - .bit(direct_mode_error) - }); + fn set_flow_controller(&mut self, value: DmaFlowController) { + unsafe { Self::st() } + .cr + .modify(|_, w| w.pfctrl().bit(value.bits())); } #[inline(always)] - fn get_interrupts_enable() -> (bool, bool, bool, bool) { - let cr = unsafe { Self::st() }.cr.read(); - ( - cr.tcie().bit_is_set(), - cr.htie().bit_is_set(), - cr.teie().bit_is_set(), - cr.dmeie().bit_is_set(), - ) + 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 set_transfer_complete_interrupt_enable(&mut self, transfer_complete_interrupt: bool) { + 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(|_, w| w.tcie().bit(transfer_complete_interrupt)); + .modify(|r, w| unsafe { w.bits(r.bits() & !mask) }); } #[inline(always)] - fn set_half_transfer_interrupt_enable(&mut self, half_transfer_interrupt: bool) { - unsafe { Self::st() } - .cr - .modify(|_, w| w.htie().bit(half_transfer_interrupt)); + fn common_interrupts(&self) -> DmaCommonInterrupts { + let cr = unsafe { Self::st() }.cr.read(); + DmaCommonInterrupts { + transfer_complete: cr.tcie().bit_is_set(), + half_transfer: cr.htie().bit_is_set(), + transfer_error: cr.teie().bit_is_set(), + direct_mode_error: cr.dmeie().bit_is_set(), + } } #[inline(always)] - fn set_transfer_error_interrupt_enable(&mut self, transfer_error_interrupt: bool) { - unsafe { Self::st() } - .cr - .modify(|_, w| w.teie().bit(transfer_error_interrupt)); + fn listen_transfer_complete(&mut self) { + unsafe { Self::st() }.cr.modify(|_, w| w.tcie().bit(true)); } #[inline(always)] - fn set_direct_mode_error_interrupt_enable(&mut self, direct_mode_error_interrupt: bool) { - unsafe { Self::st() } - .cr - .modify(|_, w| w.dmeie().bit(direct_mode_error_interrupt)); + fn unlisten_transfer_complete(&mut self) { + unsafe { Self::st() }.cr.modify(|_, w| w.tcie().bit(false)); } #[inline(always)] - fn set_fifo_error_interrupt_enable(&mut self, fifo_error_interrupt: bool) { - unsafe { Self::st() } - .fcr - .modify(|_, w| w.feie().bit(fifo_error_interrupt)); + fn listen_half_transfer(&mut self) { + unsafe { Self::st() }.cr.modify(|_, w| w.htie().bit(true)); + } + + #[inline(always)] + fn unlisten_half_transfer(&mut self) { + unsafe { Self::st() }.cr.modify(|_, w| w.htie().bit(false)); + } + + #[inline(always)] + fn listen_transfer_error(&mut self) { + unsafe { Self::st() }.cr.modify(|_, w| w.teie().bit(true)); + } + + #[inline(always)] + fn unlisten_transfer_error(&mut self) { + unsafe { Self::st() }.cr.modify(|_, w| w.teie().bit(false)); + } + + #[inline(always)] + fn listen_direct_mode_error(&mut self) { + unsafe { Self::st() }.cr.modify(|_, w| w.dmeie().bit(true)); + } + + #[inline(always)] + fn unlisten_direct_mode_error(&mut self) { + unsafe { Self::st() }.cr.modify(|_, w| w.dmeie().bit(false)); + } + + #[inline(always)] + fn listen_fifo_error(&mut self) { + unsafe { Self::st() }.fcr.modify(|_, w| w.feie().bit(true)); + } + + #[inline(always)] + fn unlisten_fifo_error(&mut self) { + unsafe { Self::st() }.fcr.modify(|_, w| w.feie().bit(false)); } #[inline(always)] @@ -503,13 +670,13 @@ where } #[inline(always)] - fn fifo_level() -> FifoLevel { + fn fifo_level(&self) -> FifoLevel { unsafe { Self::st() }.fcr.read().fs().bits().into() } - fn current_buffer() -> CurrentBuffer { + fn current_buffer(&self) -> CurrentBuffer { if unsafe { Self::st() }.cr.read().ct().bit_is_set() { - CurrentBuffer::DoubleBuffer + CurrentBuffer::SecondBuffer } else { CurrentBuffer::FirstBuffer } @@ -526,21 +693,21 @@ macro_rules! dma_stream { impl StreamISR for StreamX where Self: crate::Sealed { #[inline(always)] - fn clear_interrupts(&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 ); } #[inline(always)] - fn clear_transfer_complete_interrupt(&mut self) { + fn clear_transfer_complete(&mut self) { //NOTE(unsafe) Atomic write with no side-effects and we only access the bits // that belongs to the StreamX let dma = unsafe { &*I::ptr() }; @@ -548,7 +715,7 @@ macro_rules! dma_stream { } #[inline(always)] - fn clear_half_transfer_interrupt(&mut self) { + fn clear_half_transfer(&mut self) { //NOTE(unsafe) Atomic write with no side-effects and we only access the bits // that belongs to the StreamX let dma = unsafe { &*I::ptr() }; @@ -556,7 +723,7 @@ macro_rules! dma_stream { } #[inline(always)] - fn clear_transfer_error_interrupt(&mut self) { + fn clear_transfer_error(&mut self) { //NOTE(unsafe) Atomic write with no side-effects and we only access the bits // that belongs to the StreamX let dma = unsafe { &*I::ptr() }; @@ -564,7 +731,7 @@ macro_rules! dma_stream { } #[inline(always)] - fn clear_direct_mode_error_interrupt(&mut self) { + fn clear_direct_mode_error(&mut self) { //NOTE(unsafe) Atomic write with no side-effects and we only access the bits // that belongs to the StreamX let dma = unsafe { &*I::ptr() }; @@ -572,7 +739,7 @@ macro_rules! dma_stream { } #[inline(always)] - fn clear_fifo_error_interrupt(&mut self) { + fn clear_fifo_error(&mut self) { //NOTE(unsafe) Atomic write with no side-effects and we only access the bits // that belongs to the StreamX let dma = unsafe { &*I::ptr() }; @@ -580,39 +747,55 @@ macro_rules! dma_stream { } #[inline(always)] - fn get_transfer_complete_flag() -> bool { + fn all_flags(&self) -> DmaFlags + { + //NOTE(unsafe) Atomic read with no side effects + let dma = unsafe { &*I::ptr() }; + DmaFlags{ + transfer_complete: dma.$isr.read().$tcisr().bit_is_set(), + half_transfer: dma.$isr.read().$htisr().bit_is_set(), + transfer_error: dma.$isr.read().$teisr().bit_is_set(), + direct_mode_error: dma.$isr.read().$dmeisr().bit_is_set(), + fifo_error: dma.$isr.read().$feisr().bit_is_set(), + } + + } + + #[inline(always)] + fn is_transfer_complete(&self) -> bool { //NOTE(unsafe) Atomic read with no side effects let dma = unsafe { &*I::ptr() }; dma.$isr.read().$tcisr().bit_is_set() } #[inline(always)] - fn get_half_transfer_flag() -> bool { + fn is_half_transfer(&self) -> bool { //NOTE(unsafe) Atomic read with no side effects let dma = unsafe { &*I::ptr() }; dma.$isr.read().$htisr().bit_is_set() } #[inline(always)] - fn get_transfer_error_flag() -> bool { + fn is_transfer_error(&self) -> bool { //NOTE(unsafe) Atomic read with no side effects let dma = unsafe { &*I::ptr() }; dma.$isr.read().$teisr().bit_is_set() } #[inline(always)] - fn get_fifo_error_flag() -> bool { + fn is_direct_mode_error(&self) -> bool { //NOTE(unsafe) Atomic read with no side effects let dma = unsafe { &*I::ptr() }; - dma.$isr.read().$feisr().bit_is_set() + dma.$isr.read().$dmeisr().bit_is_set() } #[inline(always)] - fn get_direct_mode_error_flag() -> bool { + fn is_fifo_error(&self) -> bool { //NOTE(unsafe) Atomic read with no side effects let dma = unsafe { &*I::ptr() }; - dma.$isr.read().$dmeisr().bit_is_set() + dma.$isr.read().$feisr().bit_is_set() } + } )+ @@ -635,10 +818,12 @@ dma_stream!( pub struct ChannelX; macro_rules! dma_channel { - ($(($name:ident, $value:literal)),+ $(,)*) => { + ($(($name:ident, $num:literal)),+ $(,)*) => { $( - impl Channel for ChannelX<$value> {} - pub type $name = ChannelX<$value>; + impl Channel for ChannelX<$num> { + const VALUE: DmaChannel = DmaChannel::$name ; + } + pub type $name = ChannelX<$num>; )+ }; } @@ -871,6 +1056,21 @@ where transfer_length: u16, } +// utility function to disable gracefully the stream. It disable stream, wait until stream is +// disabled and prevent during process +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(DmaCommonInterrupts::all()); + unsafe { stream.disable() }; + while stream.is_enabled() {} + + stream.clear_flags(DmaFlags::all()); + stream.listen(interrupts); + } +} + impl Transfer where @@ -961,14 +1161,14 @@ where F: FnOnce(BUF, CurrentBuffer) -> (BUF, T), { if self.double_buf.is_some() { - if !STREAM::get_transfer_complete_flag() { + if !self.stream.is_transfer_complete() { return Err(DMAError::NotReady(())); } - self.stream.clear_transfer_complete_interrupt(); + self.stream.clear_transfer_complete(); - let current_buffer = STREAM::current_buffer(); + let current_buffer = self.stream.current_buffer(); // double buffering, unwrap can never fail - let db = if current_buffer == CurrentBuffer::DoubleBuffer { + let db = if current_buffer == CurrentBuffer::SecondBuffer { self.buf.take().unwrap() } else { self.double_buf.take().unwrap() @@ -982,8 +1182,8 @@ where self.next_transfer_with_common(new_buf, ptr_and_len, true, current_buffer); return Ok(r.1); } - self.stream.disable(); - self.stream.clear_transfer_complete_interrupt(); + stream_disable(&mut self.stream); + self.stream.clear_transfer_complete(); // "No re-ordering of reads and writes across this point is allowed" compiler_fence(Ordering::SeqCst); @@ -1131,14 +1331,14 @@ where F: FnOnce(BUF, CurrentBuffer) -> (BUF, T), { if self.double_buf.is_some() { - if !STREAM::get_transfer_complete_flag() { + if !self.stream.is_transfer_complete() { return Err(DMAError::NotReady(())); } - self.stream.clear_transfer_complete_interrupt(); + self.stream.clear_transfer_complete(); - let current_buffer = STREAM::current_buffer(); + let current_buffer = self.stream.current_buffer(); // double buffering, unwrap can never fail - let db = if current_buffer == CurrentBuffer::DoubleBuffer { + let db = if current_buffer == CurrentBuffer::SecondBuffer { self.buf.take().unwrap() } else { self.double_buf.take().unwrap() @@ -1152,8 +1352,8 @@ where self.next_transfer_with_common(new_buf, ptr_and_len, true, current_buffer); return Ok(r.1); } - self.stream.disable(); - self.stream.clear_transfer_complete_interrupt(); + stream_disable(&mut self.stream); + self.stream.clear_transfer_complete(); // "No re-ordering of reads and writes across this point is allowed" compiler_fence(Ordering::SeqCst); @@ -1248,8 +1448,8 @@ where where F: FnOnce(BUF, CurrentBuffer) -> (BUF, T), { - self.stream.disable(); - self.stream.clear_transfer_complete_interrupt(); + stream_disable(&mut self.stream); + self.stream.clear_transfer_complete(); // "No re-ordering of reads and writes across this point is allowed" compiler_fence(Ordering::SeqCst); @@ -1299,14 +1499,14 @@ where F: FnOnce(&mut PERIPHERAL), { f(&mut self.peripheral); - self.stream.disable() + stream_disable(&mut self.stream) } /// Stops the stream and returns the underlying resources. pub fn release(mut self) -> (STREAM, PERIPHERAL, BUF, Option) { - self.stream.disable(); + stream_disable(&mut self.stream); compiler_fence(Ordering::SeqCst); - self.stream.clear_interrupts(); + self.stream.clear_flags(DmaFlags::all()); unsafe { let stream = ptr::read(&self.stream); @@ -1318,40 +1518,82 @@ where } } - /// Clear all interrupts for the DMA stream. + /// Get the number of remaining transfers (ndt) of the underlying DMA stream. + pub fn number_of_transfers(&self) -> u16 { + self.stream.number_of_transfers() + } + + /// Clear all interrupts flags for the DMA stream. #[inline(always)] - pub fn clear_interrupts(&mut self) { - self.stream.clear_interrupts(); + pub fn clear_all_flags(&mut self) { + self.stream.clear_flags(DmaFlags::all()); } /// Clear transfer complete interrupt (tcif) for the DMA stream. #[inline(always)] - pub fn clear_transfer_complete_interrupt(&mut self) { - self.stream.clear_transfer_complete_interrupt(); + pub fn clear_transfer_complete(&mut self) { + self.stream.clear_transfer_complete(); } /// Clear half transfer interrupt (htif) for the DMA stream. #[inline(always)] - pub fn clear_half_transfer_interrupt(&mut self) { - self.stream.clear_half_transfer_interrupt(); + pub fn clear_half_transfer(&mut self) { + self.stream.clear_half_transfer(); } /// Clear transfer error interrupt (teif) for the DMA stream. #[inline(always)] - pub fn clear_transfer_error_interrupt(&mut self) { - self.stream.clear_transfer_error_interrupt(); + pub fn clear_transfer_error(&mut self) { + self.stream.clear_transfer_error(); } /// Clear direct mode error interrupt (dmeif) for the DMA stream. #[inline(always)] - pub fn clear_direct_mode_error_interrupt(&mut self) { - self.stream.clear_direct_mode_error_interrupt(); + pub fn clear_direct_mode_error(&mut self) { + self.stream.clear_direct_mode_error(); } /// Clear fifo error interrupt (feif) for the DMA stream. #[inline(always)] - pub fn clear_fifo_error_interrupt(&mut self) { - self.stream.clear_fifo_error_interrupt(); + pub fn clear_fifo_error(&mut self) { + self.stream.clear_fifo_error(); + } + + /// Get all interrupts flags a once. + /// + /// The tuple contain in order: + /// - transfer complete flag + /// - half transfer flag + /// - transfer error flag + /// - direct mode error flag + /// - fifo_error flag + pub fn all_flags(&self) -> DmaFlags { + self.stream.all_flags() + } + + /// Get transfer complete flag. + pub fn is_transfer_complete(&self) -> bool { + self.stream.is_transfer_complete() + } + + /// Get half transfer flag. + pub fn is_half_transfer(&self) -> bool { + self.stream.is_half_transfer() + } + + /// Get transfer error flag + pub fn is_transfer_error(&self) -> bool { + self.stream.is_transfer_error() + } + + /// Get direct mode error flag + pub fn is_direct_mode_error(&self) -> bool { + self.stream.is_direct_mode_error() + } + + /// Get fifo error flag + pub fn is_fifo_error(&self) -> bool { + self.stream.is_fifo_error() } /// Get the underlying stream of the transfer. @@ -1361,34 +1603,49 @@ where /// This implementation relies on several configurations points in order to be sound, this /// method can void that. The use of this method is completely discouraged, only use it if you /// know the internals of this API in its entirety. - pub unsafe fn get_stream(&mut self) -> &mut STREAM { + pub unsafe fn stream(&mut self) -> &mut STREAM { &mut self.stream } /// Wait for the transfer to complete. #[inline(always)] pub fn wait(&self) { - while !STREAM::get_transfer_complete_flag() {} + while !self.stream.is_transfer_complete() {} } /// Applies all fields in DmaConfig. fn apply_config(stream: &mut STREAM, config: config::DmaConfig) { - let msize = mem::size_of::<::MemSize>() / 2; + let msize = match mem::size_of::<::MemSize>() { + 1 => DmaDataSize::Byte, + 2 => DmaDataSize::HalfWord, + 4 => DmaDataSize::Word, + //this case can only happen on wrong implemention of PeriAddress::MemSize + _ => DmaDataSize::Word, + }; - stream.clear_interrupts(); + stream.clear_flags(DmaFlags::all()); stream.set_priority(config.priority); // NOTE(unsafe) These values are correct because of the invariants of PeriAddress unsafe { - stream.set_memory_size(msize as u8); - stream.set_peripheral_size(msize as u8); + stream.set_memory_size(msize); + stream.set_peripheral_size(msize); } stream.set_memory_increment(config.memory_increment); stream.set_peripheral_increment(config.peripheral_increment); - stream.set_transfer_complete_interrupt_enable(config.transfer_complete_interrupt); - stream.set_half_transfer_interrupt_enable(config.half_transfer_interrupt); - stream.set_transfer_error_interrupt_enable(config.transfer_error_interrupt); - stream.set_direct_mode_error_interrupt_enable(config.direct_mode_error_interrupt); - stream.set_fifo_error_interrupt_enable(config.fifo_error_interrupt); + + 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 { + stream.unlisten_fifo_error(); + } stream.set_double_buffer(config.double_buffer); stream.set_fifo_threshold(config.fifo_threshold); stream.set_fifo_enable(config.fifo_enable); @@ -1404,13 +1661,13 @@ where buf: (u32, u16), db: Option<(u32, u16)>, ) -> u16 { - stream.disable(); + stream_disable(stream); // Set the channel - stream.set_channel::(); + stream.set_channel(ChannelX::::VALUE); // Set peripheral to memory mode - stream.set_direction(DIR::new()); + stream.set_direction(DIR::direction()); let (buf_ptr, buf_len) = buf; // Set the memory address @@ -1434,7 +1691,7 @@ where // Double buffer is the source in mem2mem mode stream.set_peripheral_address(db_ptr); } else { - stream.set_memory_double_buffer_address(db_ptr); + stream.set_alternate_memory_address(db_ptr); } Some(db_len) } else { @@ -1464,10 +1721,10 @@ where double_buffering: bool, ) -> Result<(BUF, CurrentBuffer), DMAError> { if double_buffering { - if !STREAM::get_transfer_complete_flag() { + if !self.stream.is_transfer_complete() { return Err(DMAError::NotReady(new_buf)); } - self.stream.clear_transfer_complete_interrupt(); + self.stream.clear_transfer_complete(); let (new_buf_ptr, new_buf_len) = ptr_and_len; // We can't change the transfer length while double buffering @@ -1475,14 +1732,14 @@ where return Err(DMAError::SmallBuffer(new_buf)); } - if STREAM::current_buffer() == CurrentBuffer::DoubleBuffer { + if self.stream.current_buffer() == CurrentBuffer::SecondBuffer { // "Preceding reads and writes cannot be moved past subsequent writes" compiler_fence(Ordering::Release); self.stream.set_memory_address(new_buf_ptr); // Check if an overrun occurred, the buffer address won't be updated in that case - if self.stream.get_memory_address() != new_buf_ptr { - self.stream.clear_transfer_complete_interrupt(); + if self.stream.memory_address() != new_buf_ptr { + self.stream.clear_transfer_complete(); return Err(DMAError::Overrun(new_buf)); } @@ -1496,11 +1753,11 @@ where } else { // "Preceding reads and writes cannot be moved past subsequent writes" compiler_fence(Ordering::Release); - self.stream.set_memory_double_buffer_address(new_buf_ptr); + self.stream.set_alternate_memory_address(new_buf_ptr); // Check if an overrun occurred, the buffer address won't be updated in that case - if self.stream.get_memory_double_buffer_address() != new_buf_ptr { - self.stream.clear_transfer_complete_interrupt(); + if self.stream.alternate_memory_address() != new_buf_ptr { + self.stream.clear_transfer_complete(); return Err(DMAError::Overrun(new_buf)); } @@ -1510,11 +1767,11 @@ where let old_buf = self.double_buf.replace(new_buf); // double buffering, unwrap can never fail - return Ok((old_buf.unwrap(), CurrentBuffer::DoubleBuffer)); + return Ok((old_buf.unwrap(), CurrentBuffer::SecondBuffer)); } } - self.stream.disable(); - self.stream.clear_transfer_complete_interrupt(); + stream_disable(&mut self.stream); + self.stream.clear_transfer_complete(); // "No re-ordering of reads and writes across this point is allowed" compiler_fence(Ordering::SeqCst); @@ -1555,7 +1812,7 @@ where // We don't know how long the closure took to complete, we might have changed the // current buffer twice (or any even number of times) and got back to the same buffer // we had in the beginning of the method, check for that - if STREAM::get_transfer_complete_flag() { + if self.stream.is_transfer_complete() { // If this is true, then RAM corruption might have occurred, there's nothing we // can do apart from panicking. // TODO: Is this the best solution ? The closure based approach seems necessary @@ -1563,14 +1820,14 @@ where panic!("Overrun"); } - if current_buffer == CurrentBuffer::DoubleBuffer { + if current_buffer == CurrentBuffer::SecondBuffer { // "Preceding reads and writes cannot be moved past subsequent writes" compiler_fence(Ordering::Release); self.stream.set_memory_address(new_buf_ptr); // Check again if an overrun occurred, the buffer address won't be updated in that // case - if self.stream.get_memory_address() != new_buf_ptr { + if self.stream.memory_address() != new_buf_ptr { panic!("Overrun"); } @@ -1581,9 +1838,9 @@ where } else { // "Preceding reads and writes cannot be moved past subsequent writes" compiler_fence(Ordering::Release); - self.stream.set_memory_double_buffer_address(new_buf_ptr); + self.stream.set_alternate_memory_address(new_buf_ptr); - if self.stream.get_memory_double_buffer_address() != new_buf_ptr { + if self.stream.alternate_memory_address() != new_buf_ptr { panic!("Overrun"); } @@ -1610,7 +1867,7 @@ where PERIPHERAL: PeriAddress, { fn drop(&mut self) { - self.stream.disable(); + stream_disable(&mut self.stream); compiler_fence(Ordering::SeqCst); } } diff --git a/src/dma/traits.rs b/src/dma/traits.rs index b6f40b87..337c6426 100644 --- a/src/dma/traits.rs +++ b/src/dma/traits.rs @@ -19,64 +19,76 @@ pub trait SafePeripheralRead {} /// Trait for DMA stream interrupt handling. pub trait StreamISR: crate::Sealed { - /// Clear all interrupts for the DMA stream. - fn clear_interrupts(&mut self); + /// Clear all interrupts flags for the DMA stream. + fn clear_flags(&mut self, flags: DmaFlags); /// Clear transfer complete interrupt (tcif) for the DMA stream. - fn clear_transfer_complete_interrupt(&mut self); + fn clear_transfer_complete(&mut self); - /// Clear half transfer interrupt (htif) for the DMA stream. - fn clear_half_transfer_interrupt(&mut self); + /// Clear half transfer interrupt flag (htif) for the DMA stream. + fn clear_half_transfer(&mut self); - /// Clear transfer error interrupt (teif) for the DMA stream. - fn clear_transfer_error_interrupt(&mut self); + /// Clear transfer error interrupt flag (teif) for the DMA stream. + fn clear_transfer_error(&mut self); - /// Clear direct mode error interrupt (dmeif) for the DMA stream. - fn clear_direct_mode_error_interrupt(&mut self); + /// Clear direct mode error interrupt flag (dmeif) for the DMA stream. + fn clear_direct_mode_error(&mut self); - /// Clear fifo error interrupt (feif) for the DMA stream. - fn clear_fifo_error_interrupt(&mut self); + /// Clear fifo error interrupt flag (feif) for the DMA stream. + fn clear_fifo_error(&mut self); + + /// Get all interrupts flags a once. + /// + /// The tuple contain in order: + /// - transfer complete flag + /// - half transfer flag + /// - transfer error flag + /// - direct mode error flag + /// - fifo_error flag + fn all_flags(&self) -> DmaFlags; /// Get transfer complete flag. - fn get_transfer_complete_flag() -> bool; + fn is_transfer_complete(&self) -> bool; /// Get half transfer flag. - fn get_half_transfer_flag() -> bool; + fn is_half_transfer(&self) -> bool; /// Get transfer error flag - fn get_transfer_error_flag() -> bool; - - /// Get fifo error flag - fn get_fifo_error_flag() -> bool; + fn is_transfer_error(&self) -> bool; /// Get direct mode error flag - fn get_direct_mode_error_flag() -> bool; + fn is_direct_mode_error(&self) -> bool; + + /// Get fifo error flag + fn is_fifo_error(&self) -> bool; } /// Trait for DMA streams types. pub trait Stream: StreamISR + crate::Sealed { /// Number of the register stream. const NUMBER: usize; - /// Set the peripheral address (par) for the DMA stream. + /// Set the peripheral address (par) of the DMA stream. fn set_peripheral_address(&mut self, value: u32); - /// Set the memory address (m0ar) for the DMA stream. + /// Set the memory address (m0ar) of the DMA stream. fn set_memory_address(&mut self, value: u32); - /// Get the memory address (m0ar) for the DMA stream. - fn get_memory_address(&self) -> u32; + /// Get the memory address (m0ar) of the DMA stream. + fn memory_address(&self) -> u32; - /// Set the double buffer address (m1ar) for the DMA stream. - fn set_memory_double_buffer_address(&mut self, value: u32); + /// Set the second memory address (m1ar) of the DMA stream. Only relevant with double buffer + /// mode. + fn set_alternate_memory_address(&mut self, value: u32); - /// Get the double buffer address (m1ar) for the DMA stream. - fn get_memory_double_buffer_address(&self) -> u32; + /// Get the second memory address (m1ar) of the DMA stream. Only relevant with double buffer + /// mode. + fn alternate_memory_address(&self) -> u32; /// Set the number of transfers (ndt) for the DMA stream. fn set_number_of_transfers(&mut self, value: u16); /// Get the number of transfers (ndt) for the DMA stream. - fn get_number_of_transfers() -> u16; + fn number_of_transfers(&self) -> u16; /// Enable the DMA stream. /// @@ -86,42 +98,41 @@ pub trait Stream: StreamISR + crate::Sealed { unsafe fn enable(&mut self); /// Returns the state of the DMA stream. - fn is_enabled() -> bool; + fn is_enabled(&self) -> bool; /// Disable the DMA stream. /// - /// Disabling the stream during an on-going transfer needs to be performed in a certain way to - /// prevent problems if the stream is to be re-enabled shortly after, because of that, this - /// method will also clear all the stream's interrupt flags if the stream is active. - fn disable(&mut self); + /// Disabling may not immediate, you must check with [`is_enabled()`](Stream::is_enabled) to + /// ensure the stream is correctly disabled. Note that the transfer complete interrupt flag is + /// set when the stream is disabled. You need to delete transfer complete interrupt flag before + /// re-enabling the stream. It's also advisable to clear all interrupt flag before re-enabling + /// the stream. + /// + /// # Safety + /// + /// Disabling the stream before end of transfers may produce invalid data. + unsafe fn disable(&mut self); /// Set the channel for the (chsel) the DMA stream. - fn set_channel(&mut self) - where - ChannelX: Channel; + fn set_channel(&mut self, channel: DmaChannel); /// Set the priority (pl) the DMA stream. fn set_priority(&mut self, priority: config::Priority); + /// Set the peripheral increment offset (pincos) + fn set_peripheral_increment_offset(&mut self, value: PeripheralIncrementOffset); + /// Set the memory size (msize) for the DMA stream. /// /// # Safety /// This must have the same alignment of the buffer used in the transfer. - /// Valid values: - /// * 0 -> byte - /// * 1 -> half word - /// * 2 -> word - unsafe fn set_memory_size(&mut self, size: u8); + unsafe fn set_memory_size(&mut self, size: DmaDataSize); /// Set the peripheral memory size (psize) for the DMA stream. /// /// # Safety /// This must have the same alignment of the peripheral data used in the transfer. - /// Valid values: - /// * 0 -> byte - /// * 1 -> half word - /// * 2 -> word - unsafe fn set_peripheral_size(&mut self, size: u8); + unsafe fn set_peripheral_size(&mut self, size: DmaDataSize); /// Enable/disable memory increment (minc) for the DMA stream. fn set_memory_increment(&mut self, increment: bool); @@ -129,37 +140,56 @@ pub trait Stream: StreamISR + crate::Sealed { /// Enable/disable peripheral increment (pinc) for the DMA stream. fn set_peripheral_increment(&mut self, increment: bool); + /// Enable/disable circular mode (circ) for the DMA stream. + fn set_circular_mode(&mut self, value: bool); + /// Set the direction (dir) of the DMA stream. - fn set_direction(&mut self, direction: D); + fn set_direction(&mut self, direction: DmaDirection); + + /// Set the flow controller (pfctrl). + fn set_flow_controller(&mut self, value: DmaFlowController); + + /// Enable several interrupts. Modify only interrupts set to `true` in the DmaCommonInterrupts + fn listen(&mut self, interrupts: DmaCommonInterrupts); + + /// 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` + /// + /// Note: fifo_error interrupt is not returned because it's in a different register + fn common_interrupts(&self) -> DmaCommonInterrupts; + + /// Enable transfer complete interrupt (tcie) of the DMA stream. + fn listen_transfer_complete(&mut self); + + /// Disable the transfer complete interrupt (tcie) of the DMA stream. + fn unlisten_transfer_complete(&mut self); - /// Convenience method to configure the 4 common interrupts for the DMA stream. - fn set_interrupts_enable( - &mut self, - transfer_complete: bool, - half_transfer: bool, - transfer_error: bool, - direct_mode_error: bool, - ); + /// Enable the half transfer interrupt (htie) of the DMA stream. + fn listen_half_transfer(&mut self); - /// Convenience method to get the value of the 4 common interrupts for the DMA stream. - /// The order of the returns are: `transfer_complete`, `half_transfer`, `transfer_error` and - /// `direct_mode_error`. - fn get_interrupts_enable() -> (bool, bool, bool, bool); + /// Disable the half transfer interrupt (htie) of the DMA stream. + fn unlisten_half_transfer(&mut self); - /// Enable/disable the transfer complete interrupt (tcie) of the DMA stream. - fn set_transfer_complete_interrupt_enable(&mut self, transfer_complete_interrupt: bool); + /// Enable the transfer error interrupt (teie) of the DMA stream. + fn listen_transfer_error(&mut self); - /// Enable/disable the half transfer interrupt (htie) of the DMA stream. - fn set_half_transfer_interrupt_enable(&mut self, half_transfer_interrupt: bool); + /// Disable the transfer error interrupt (teie) of the DMA stream. + fn unlisten_transfer_error(&mut self); - /// Enable/disable the transfer error interrupt (teie) of the DMA stream. - fn set_transfer_error_interrupt_enable(&mut self, transfer_error_interrupt: bool); + /// Enable the direct mode error interrupt (dmeie) of the DMA stream. + fn listen_direct_mode_error(&mut self); - /// Enable/disable the direct mode error interrupt (dmeie) of the DMA stream. - fn set_direct_mode_error_interrupt_enable(&mut self, direct_mode_error_interrupt: bool); + /// Disable the direct mode error interrupt (dmeie) of the DMA stream. + fn unlisten_direct_mode_error(&mut self); - /// Enable/disable the fifo error interrupt (feie) of the DMA stream. - fn set_fifo_error_interrupt_enable(&mut self, fifo_error_interrupt: bool); + /// Enable the fifo error interrupt (feie) of the DMA stream. + fn listen_fifo_error(&mut self); + + /// Disable the fifo error interrupt (feie) of the DMA stream. + fn unlisten_fifo_error(&mut self); /// Enable/disable the double buffer (dbm) of the DMA stream. fn set_double_buffer(&mut self, double_buffer: bool); @@ -177,10 +207,10 @@ pub trait Stream: StreamISR + crate::Sealed { fn set_peripheral_burst(&mut self, peripheral_burst: config::BurstMode); /// Get the current fifo level (fs) of the DMA stream. - fn fifo_level() -> FifoLevel; + fn fifo_level(&self) -> FifoLevel; /// Get which buffer is currently in use by the DMA. - fn current_buffer() -> CurrentBuffer; + fn current_buffer(&self) -> CurrentBuffer; } /// DMA direction. @@ -246,8 +276,10 @@ impl Instance for DMA2 { } } -/// A channel that can be configured on a DMA stream. -pub trait Channel {} +/// A trait for marker tha represent Channel of a DMA stream. +pub trait Channel { + const VALUE: DmaChannel; +} /// Trait to mark a set of Stream, Channel and Direction for a Peripheral as correct together. /// diff --git a/src/i2c/dma.rs b/src/i2c/dma.rs index 339292e8..c22e8de6 100644 --- a/src/i2c/dma.rs +++ b/src/i2c/dma.rs @@ -597,23 +597,19 @@ where { fn handle_dma_interrupt(&mut self) { if let Some(tx_t) = &mut self.tx.tx_transfer { - if TX_STREAM::get_fifo_error_flag() { - tx_t.clear_fifo_error_interrupt(); - + let flags = tx_t.all_flags(); + tx_t.clear_fifo_error(); + tx_t.clear_transfer_error(); + tx_t.clear_transfer_complete(); + if flags.fifo_error { return; } - - if TX_STREAM::get_transfer_error_flag() { - tx_t.clear_transfer_error_interrupt(); - + if flags.transfer_error { self.finish_transfer_with_result(Err(Error::TransferError)); - return; } - if TX_STREAM::get_transfer_complete_flag() { - tx_t.clear_transfer_complete_interrupt(); - + if flags.transfer_complete { self.finish_transfer_with_result(Ok(())); // Wait for BTF @@ -644,22 +640,22 @@ where { fn handle_dma_interrupt(&mut self) { if let Some(rx_t) = &mut self.rx.rx_transfer { - if RX_STREAM::get_fifo_error_flag() { - rx_t.clear_fifo_error_interrupt(); + if rx_t.is_fifo_error() { + rx_t.clear_fifo_error(); return; } - if RX_STREAM::get_transfer_error_flag() { - rx_t.clear_transfer_error_interrupt(); + if rx_t.is_transfer_error() { + rx_t.clear_transfer_error(); self.finish_transfer_with_result(Err(Error::TransferError)); return; } - if RX_STREAM::get_transfer_complete_flag() { - rx_t.clear_transfer_complete_interrupt(); + if rx_t.is_transfer_complete() { + rx_t.clear_transfer_complete(); self.finish_transfer_with_result(Ok(())); @@ -695,22 +691,22 @@ where fn handle_dma_interrupt(&mut self) { // Handle Transmit if let Some(tx_t) = &mut self.tx.tx_transfer { - if TX_STREAM::get_fifo_error_flag() { - tx_t.clear_fifo_error_interrupt(); + if tx_t.is_fifo_error() { + tx_t.clear_fifo_error(); return; } - if TX_STREAM::get_transfer_error_flag() { - tx_t.clear_transfer_error_interrupt(); + if tx_t.is_transfer_error() { + tx_t.clear_transfer_error(); self.finish_transfer_with_result(Err(Error::TransferError)); return; } - if TX_STREAM::get_transfer_complete_flag() { - tx_t.clear_transfer_complete_interrupt(); + if tx_t.is_transfer_complete() { + tx_t.clear_transfer_complete(); // If we have prepared Rx Transfer, there are write_read command, generate restart signal and do not disable DMA requests // Indicate that we have read after this transmit @@ -746,22 +742,22 @@ where } if let Some(rx_t) = &mut self.rx.rx_transfer { - if RX_STREAM::get_fifo_error_flag() { - rx_t.clear_fifo_error_interrupt(); + if rx_t.is_fifo_error() { + rx_t.clear_fifo_error(); return; } - if RX_STREAM::get_transfer_error_flag() { - rx_t.clear_transfer_error_interrupt(); + if rx_t.is_transfer_error() { + rx_t.clear_transfer_error(); self.finish_transfer_with_result(Err(Error::TransferError)); return; } - if RX_STREAM::get_transfer_complete_flag() { - rx_t.clear_transfer_complete_interrupt(); + if rx_t.is_transfer_complete() { + rx_t.clear_transfer_complete(); self.finish_transfer_with_result(Ok(()));