diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 2ed4b7542..2219acd6d 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -58,6 +58,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed an issue with DMA transfers potentially not waking up the correct async task (#2065) - Fixed an issue with LCD_CAM i8080 where it would send double the clocks in 16bit mode (#2085) - Fix i2c embedded-hal transaction (#2028) +- Fix some inconsistencies in DMA interrupt bits (#2169) - Fix SPI DMA alternating `write` and `read` for ESP32 and ESP32-S2 (#2131) - Fix I2C ending up in a state when only re-creating the peripheral makes it useable again (#2141) - Fix `SpiBus::transfer` transferring data twice in some cases (#2159) diff --git a/esp-hal/src/dma/gdma.rs b/esp-hal/src/dma/gdma.rs index 4c0989077..14afac470 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -139,10 +139,6 @@ impl RegisterAccess for Channel { .modify(|_, w| unsafe { w.outlink_addr().bits(address) }); } - fn has_out_descriptor_error() -> bool { - Self::out_int().raw().read().out_dscr_err().bit() - } - fn set_out_peripheral(peripheral: u8) { Self::ch() .out_peri_sel() @@ -155,34 +151,6 @@ impl RegisterAccess for Channel { .modify(|_, w| w.outlink_start().set_bit()); } - fn clear_ch_out_done() { - Self::out_int() - .clr() - .write(|w| w.out_done().clear_bit_by_one()); - } - - fn is_ch_out_done_set() -> bool { - Self::out_int().raw().read().out_done().bit() - } - - fn listen_ch_out_done() { - Self::out_int().ena().modify(|_, w| w.out_done().set_bit()) - } - - fn unlisten_ch_out_done() { - Self::out_int() - .ena() - .modify(|_, w| w.out_done().clear_bit()) - } - - fn is_listening_ch_out_done() -> bool { - Self::out_int().ena().read().out_done().bit() - } - - fn is_out_done() -> bool { - Self::out_int().raw().read().out_total_eof().bit() - } - fn last_out_dscr_address() -> usize { Self::ch() .out_eof_des_addr() @@ -191,16 +159,6 @@ impl RegisterAccess for Channel { .bits() as _ } - fn is_out_eof_interrupt_set() -> bool { - Self::out_int().raw().read().out_eof().bit() - } - - fn reset_out_eof_interrupt() { - Self::out_int() - .clr() - .write(|w| w.out_eof().clear_bit_by_one()); - } - #[cfg(esp32s3)] fn set_in_ext_mem_block_size(size: DmaExtMemBKSize) { Self::ch() @@ -259,18 +217,6 @@ impl RegisterAccess for Channel { .modify(|_, w| unsafe { w.inlink_addr().bits(address) }); } - fn has_in_descriptor_error() -> bool { - Self::in_int().raw().read().in_dscr_err().bit() - } - - fn has_in_descriptor_error_dscr_empty() -> bool { - Self::in_int().raw().read().in_dscr_empty().bit() - } - - fn has_in_descriptor_error_err_eof() -> bool { - Self::in_int().raw().read().in_err_eof().bit() - } - fn set_in_peripheral(peripheral: u8) { Self::ch() .in_peri_sel() @@ -283,122 +229,177 @@ impl RegisterAccess for Channel { .modify(|_, w| w.inlink_start().set_bit()); } - fn is_in_done() -> bool { - Self::in_int().raw().read().in_suc_eof().bit() + fn listen_out(interrupts: impl Into>) { + Self::out_int().ena().modify(|_, w| { + for interrupt in interrupts.into() { + match interrupt { + DmaTxInterrupt::TotalEof => w.out_total_eof().set_bit(), + DmaTxInterrupt::DescriptorError => w.out_dscr_err().set_bit(), + DmaTxInterrupt::Eof => w.out_eof().set_bit(), + DmaTxInterrupt::Done => w.out_done().set_bit(), + }; + } + w + }) } - fn is_listening_in_eof() -> bool { - Self::in_int().ena().read().in_suc_eof().bit_is_set() + fn unlisten_out(interrupts: impl Into>) { + Self::out_int().ena().modify(|_, w| { + for interrupt in interrupts.into() { + match interrupt { + DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit(), + DmaTxInterrupt::DescriptorError => w.out_dscr_err().clear_bit(), + DmaTxInterrupt::Eof => w.out_eof().clear_bit(), + DmaTxInterrupt::Done => w.out_done().clear_bit(), + }; + } + w + }) } - fn is_listening_out_eof() -> bool { - Self::out_int().ena().read().out_total_eof().bit_is_set() + fn is_listening_out() -> EnumSet { + let mut result = EnumSet::new(); + + let int_ena = Self::out_int().ena().read(); + if int_ena.out_total_eof().bit_is_set() { + result |= DmaTxInterrupt::TotalEof; + } + if int_ena.out_dscr_err().bit_is_set() { + result |= DmaTxInterrupt::DescriptorError; + } + if int_ena.out_eof().bit_is_set() { + result |= DmaTxInterrupt::Eof; + } + if int_ena.out_done().bit_is_set() { + result |= DmaTxInterrupt::Done; + } + + result } - fn listen_in_eof() { - Self::in_int().ena().modify(|_, w| w.in_suc_eof().set_bit()); + fn pending_out_interrupts() -> EnumSet { + let mut result = EnumSet::new(); + + let int_raw = Self::out_int().raw().read(); + if int_raw.out_total_eof().bit_is_set() { + result |= DmaTxInterrupt::TotalEof; + } + if int_raw.out_dscr_err().bit_is_set() { + result |= DmaTxInterrupt::DescriptorError; + } + if int_raw.out_eof().bit_is_set() { + result |= DmaTxInterrupt::Eof; + } + if int_raw.out_done().bit_is_set() { + result |= DmaTxInterrupt::Done; + } + + result } - fn listen_out_eof() { - Self::out_int() - .ena() - .modify(|_, w| w.out_total_eof().set_bit()); + fn clear_out(interrupts: impl Into>) { + Self::out_int().clr().write(|w| { + for interrupt in interrupts.into() { + match interrupt { + DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit_by_one(), + DmaTxInterrupt::DescriptorError => w.out_dscr_err().clear_bit_by_one(), + DmaTxInterrupt::Eof => w.out_eof().clear_bit_by_one(), + DmaTxInterrupt::Done => w.out_done().clear_bit_by_one(), + }; + } + w + }) } - fn unlisten_in_eof() { - Self::in_int() - .ena() - .modify(|_, w| w.in_suc_eof().clear_bit()); + fn listen_in(interrupts: impl Into>) { + Self::in_int().ena().modify(|_, w| { + for interrupt in interrupts.into() { + match interrupt { + DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().set_bit(), + DmaRxInterrupt::ErrorEof => w.in_err_eof().set_bit(), + DmaRxInterrupt::DescriptorError => w.in_dscr_err().set_bit(), + DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().set_bit(), + DmaRxInterrupt::Done => w.in_done().set_bit(), + }; + } + w + }) } - fn unlisten_out_eof() { - Self::out_int() - .ena() - .modify(|_, w| w.out_total_eof().clear_bit()); + fn unlisten_in(interrupts: impl Into>) { + Self::in_int().ena().modify(|_, w| { + for interrupt in interrupts.into() { + match interrupt { + DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit(), + DmaRxInterrupt::ErrorEof => w.in_err_eof().clear_bit(), + DmaRxInterrupt::DescriptorError => w.in_dscr_err().clear_bit(), + DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().clear_bit(), + DmaRxInterrupt::Done => w.in_done().clear_bit(), + }; + } + w + }) } - fn listen_ch_in_done() { - Self::in_int().ena().modify(|_, w| w.in_done().set_bit()) + fn is_listening_in() -> EnumSet { + let mut result = EnumSet::new(); + + let int_ena = Self::in_int().ena().read(); + if int_ena.in_dscr_err().bit_is_set() { + result |= DmaRxInterrupt::DescriptorError; + } + if int_ena.in_dscr_empty().bit_is_set() { + result |= DmaRxInterrupt::DescriptorEmpty; + } + if int_ena.in_suc_eof().bit_is_set() { + result |= DmaRxInterrupt::SuccessfulEof; + } + if int_ena.in_err_eof().bit_is_set() { + result |= DmaRxInterrupt::ErrorEof; + } + if int_ena.in_done().bit_is_set() { + result |= DmaRxInterrupt::Done; + } + + result } - fn clear_ch_in_done() { - Self::in_int() - .clr() - .write(|w| w.in_done().clear_bit_by_one()); + fn pending_in_interrupts() -> EnumSet { + let mut result = EnumSet::new(); + + let int_raw = Self::in_int().raw().read(); + if int_raw.in_dscr_err().bit_is_set() { + result |= DmaRxInterrupt::DescriptorError; + } + if int_raw.in_dscr_empty().bit_is_set() { + result |= DmaRxInterrupt::DescriptorEmpty; + } + if int_raw.in_suc_eof().bit_is_set() { + result |= DmaRxInterrupt::SuccessfulEof; + } + if int_raw.in_err_eof().bit_is_set() { + result |= DmaRxInterrupt::ErrorEof; + } + if int_raw.in_done().bit_is_set() { + result |= DmaRxInterrupt::Done; + } + + result } - fn is_ch_in_done_set() -> bool { - Self::in_int().raw().read().in_done().bit() - } - - fn unlisten_ch_in_done() { - Self::in_int().ena().modify(|_, w| w.in_done().clear_bit()); - } - - fn is_listening_ch_in_done() -> bool { - Self::in_int().ena().read().in_done().bit() - } - - fn listen_in_descriptor_error() { - Self::in_int() - .ena() - .modify(|_, w| w.in_dscr_err().set_bit()) - } - - fn unlisten_in_descriptor_error() { - Self::in_int() - .ena() - .modify(|_, w| w.in_dscr_err().clear_bit()) - } - - fn is_listening_in_descriptor_error() -> bool { - Self::in_int().ena().read().in_dscr_err().bit() - } - - fn listen_in_descriptor_error_dscr_empty() { - Self::in_int() - .ena() - .modify(|_, w| w.in_dscr_empty().set_bit()) - } - - fn unlisten_in_descriptor_error_dscr_empty() { - Self::in_int() - .ena() - .modify(|_, w| w.in_dscr_empty().clear_bit()) - } - - fn is_listening_in_descriptor_error_dscr_empty() -> bool { - Self::in_int().ena().read().in_dscr_empty().bit() - } - - fn listen_in_descriptor_error_err_eof() { - Self::in_int().ena().modify(|_, w| w.in_err_eof().set_bit()) - } - - fn unlisten_in_descriptor_error_err_eof() { - Self::in_int() - .ena() - .modify(|_, w| w.in_err_eof().clear_bit()) - } - - fn is_listening_in_descriptor_error_err_eof() -> bool { - Self::in_int().ena().read().in_err_eof().bit() - } - - fn listen_out_descriptor_error() { - Self::out_int() - .ena() - .modify(|_, w| w.out_dscr_err().set_bit()) - } - - fn unlisten_out_descriptor_error() { - Self::out_int() - .ena() - .modify(|_, w| w.out_dscr_err().clear_bit()) - } - - fn is_listening_out_descriptor_error() -> bool { - Self::out_int().ena().read().out_dscr_err().bit() + fn clear_in(interrupts: impl Into>) { + Self::in_int().clr().write(|w| { + for interrupt in interrupts.into() { + match interrupt { + DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit_by_one(), + DmaRxInterrupt::ErrorEof => w.in_err_eof().clear_bit_by_one(), + DmaRxInterrupt::DescriptorError => w.in_dscr_err().clear_bit_by_one(), + DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().clear_bit_by_one(), + DmaRxInterrupt::Done => w.in_done().clear_bit_by_one(), + }; + } + w + }) } } diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index 799033bdd..8375b85d8 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -302,6 +302,53 @@ pub enum DmaInterrupt { TxDone, } +/// Types of interrupts emitted by the TX channel. +#[derive(EnumSetType)] +pub enum DmaTxInterrupt { + /// Triggered when all data corresponding to a linked list (including + /// multiple descriptors) have been sent via transmit channel. + TotalEof, + + /// Triggered when an error is detected in a transmit descriptor on transmit + /// channel. + DescriptorError, + + /// Triggered when EOF in a transmit descriptor is true and data + /// corresponding to this descriptor have been sent via transmit + /// channel. + Eof, + + /// Triggered when all data corresponding to a transmit descriptor have been + /// sent via transmit channel. + Done, +} + +/// Types of interrupts emitted by the RX channel. +#[derive(EnumSetType)] +pub enum DmaRxInterrupt { + /// Triggered when the size of the buffer pointed by receive descriptors + /// is smaller than the length of data to be received via receive channel. + DescriptorEmpty, + + /// Triggered when an error is detected in a receive descriptor on receive + /// channel. + DescriptorError, + + /// Triggered when an error is detected in the data segment corresponding to + /// a descriptor received via receive channel n. + /// This interrupt is used only for UHCI0 peripheral (UART0 or UART1). + ErrorEof, + + /// Triggered when the suc_eof bit in a receive descriptor is 1 and the data + /// corresponding to this receive descriptor has been received via receive + /// channel. + SuccessfulEof, + + /// Triggered when all data corresponding to a receive descriptor have been + /// received via receive channel. + Done, +} + /// The default chunk size used for DMA transfers. pub const CHUNK_SIZE: usize = 4092; @@ -983,8 +1030,12 @@ impl TxCircularState { where T: TxPrivate, { - if channel.descriptors_handled() { - channel.reset_descriptors_handled(); + if channel + .pending_out_interrupts() + .contains(DmaTxInterrupt::Eof) + { + channel.clear_out(DmaTxInterrupt::Eof); + let descr_address = channel.last_out_dscr_address() as *mut DmaDescriptor; let mut ptr = self.last_seen_handled_descriptor_ptr; @@ -1226,50 +1277,32 @@ pub trait RxPrivate: crate::private::Sealed { #[cfg(gdma)] fn set_mem2mem_mode(&mut self, value: bool); - fn listen_ch_in_done(&self); + fn listen_in(&self, interrupts: impl Into>); - fn clear_ch_in_done(&self); + fn unlisten_in(&self, interrupts: impl Into>); - fn is_ch_in_done_set(&self) -> bool; + fn is_listening_in(&self) -> EnumSet; - fn unlisten_ch_in_done(&self); + fn clear_in(&self, interrupts: impl Into>); - fn is_listening_ch_in_done(&self) -> bool; + fn pending_in_interrupts(&self) -> EnumSet; fn is_done(&self) -> bool; - fn is_listening_eof(&self) -> bool; + fn has_error(&self) -> bool { + self.pending_in_interrupts() + .contains(DmaRxInterrupt::DescriptorError) + } - fn listen_eof(&self); + fn has_dscr_empty_error(&self) -> bool { + self.pending_in_interrupts() + .contains(DmaRxInterrupt::DescriptorEmpty) + } - fn unlisten_eof(&self); - - /// Descriptor error detected - fn has_error(&self) -> bool; - - /// ERR_DSCR_EMPTY error detected - fn has_dscr_empty_error(&self) -> bool; - - /// ERR_EOF error detected - fn has_eof_error(&self) -> bool; - - fn is_listening_in_descriptor_error(&self) -> bool; - - fn listen_in_descriptor_error(&self); - - fn unlisten_in_descriptor_error(&self); - - fn is_listening_in_descriptor_error_dscr_empty(&self) -> bool; - - fn listen_in_descriptor_error_dscr_empty(&self); - - fn unlisten_in_descriptor_error_dscr_empty(&self); - - fn is_listening_in_descriptor_error_err_eof(&self) -> bool; - - fn listen_in_descriptor_error_err_eof(&self); - - fn unlisten_in_descriptor_error_err_eof(&self); + fn has_eof_error(&self) -> bool { + self.pending_in_interrupts() + .contains(DmaRxInterrupt::ErrorEof) + } fn clear_interrupts(&self); @@ -1308,17 +1341,13 @@ where fn start_transfer(&mut self) -> Result<(), DmaError> { R::start_in(); - if R::has_in_descriptor_error() { + if R::pending_in_interrupts().contains(DmaRxInterrupt::DescriptorError) { Err(DmaError::DescriptorError) } else { Ok(()) } } - fn is_done(&self) -> bool { - R::is_in_done() - } - fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker; } @@ -1426,94 +1455,35 @@ where CH::Channel::set_mem2mem_mode(value); } - fn listen_ch_in_done(&self) { - CH::Channel::listen_ch_in_done(); + fn listen_in(&self, interrupts: impl Into>) { + CH::Channel::listen_in(interrupts); } - fn clear_ch_in_done(&self) { - CH::Channel::clear_ch_in_done(); + fn unlisten_in(&self, interrupts: impl Into>) { + CH::Channel::unlisten_in(interrupts); } - fn is_ch_in_done_set(&self) -> bool { - CH::Channel::is_ch_in_done_set() + fn is_listening_in(&self) -> EnumSet { + CH::Channel::is_listening_in() } - fn unlisten_ch_in_done(&self) { - CH::Channel::unlisten_ch_in_done(); + fn clear_in(&self, interrupts: impl Into>) { + CH::Channel::clear_in(interrupts); } - fn is_listening_ch_in_done(&self) -> bool { - CH::Channel::is_listening_ch_in_done() + fn pending_in_interrupts(&self) -> EnumSet { + CH::Channel::pending_in_interrupts() } fn is_done(&self) -> bool { - self.rx_impl.is_done() + self.pending_in_interrupts() + .contains(DmaRxInterrupt::SuccessfulEof) } fn init_channel(&mut self) { CH::Channel::init_channel(); } - fn is_listening_eof(&self) -> bool { - CH::Channel::is_listening_in_eof() - } - - fn listen_eof(&self) { - CH::Channel::listen_in_eof() - } - - fn unlisten_eof(&self) { - CH::Channel::unlisten_in_eof() - } - - fn has_error(&self) -> bool { - CH::Channel::has_in_descriptor_error() - } - - fn has_dscr_empty_error(&self) -> bool { - CH::Channel::has_in_descriptor_error_dscr_empty() - } - - fn has_eof_error(&self) -> bool { - CH::Channel::has_in_descriptor_error_err_eof() - } - - fn is_listening_in_descriptor_error(&self) -> bool { - CH::Channel::is_listening_in_descriptor_error() - } - - fn listen_in_descriptor_error(&self) { - CH::Channel::listen_in_descriptor_error(); - } - - fn unlisten_in_descriptor_error(&self) { - CH::Channel::unlisten_in_descriptor_error(); - } - - fn is_listening_in_descriptor_error_dscr_empty(&self) -> bool { - CH::Channel::is_listening_in_descriptor_error_dscr_empty() - } - - fn listen_in_descriptor_error_dscr_empty(&self) { - CH::Channel::listen_in_descriptor_error_dscr_empty(); - } - - fn unlisten_in_descriptor_error_dscr_empty(&self) { - CH::Channel::unlisten_in_descriptor_error_dscr_empty(); - } - - fn is_listening_in_descriptor_error_err_eof(&self) -> bool { - CH::Channel::is_listening_in_descriptor_error_err_eof() - } - - fn listen_in_descriptor_error_err_eof(&self) { - CH::Channel::listen_in_descriptor_error_err_eof(); - } - - fn unlisten_in_descriptor_error_err_eof(&self) { - CH::Channel::unlisten_in_descriptor_error_err_eof(); - } - fn clear_interrupts(&self) { CH::Channel::clear_in_interrupts(); } @@ -1542,45 +1512,35 @@ pub trait TxPrivate: crate::private::Sealed { buffer: &mut BUF, ) -> Result<(), DmaError>; + fn listen_out(&self, interrupts: impl Into>); + + fn unlisten_out(&self, interrupts: impl Into>); + + fn is_listening_out(&self) -> EnumSet; + + fn clear_out(&self, interrupts: impl Into>); + + fn pending_out_interrupts(&self) -> EnumSet; + fn start_transfer(&mut self) -> Result<(), DmaError>; #[cfg(esp32s3)] fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize); - fn clear_ch_out_done(&self); + fn is_done(&self) -> bool { + self.pending_out_interrupts() + .contains(DmaTxInterrupt::TotalEof) + } - fn is_ch_out_done_set(&self) -> bool; - - fn listen_ch_out_done(&self); - - fn unlisten_ch_out_done(&self); - - fn is_listening_ch_out_done(&self) -> bool; - - fn is_done(&self) -> bool; - - fn is_listening_eof(&self) -> bool; - - fn listen_eof(&self); - - fn unlisten_eof(&self); - - fn is_listening_out_descriptor_error(&self) -> bool; - - fn listen_out_descriptor_error(&self); - - fn unlisten_out_descriptor_error(&self); - - fn has_error(&self) -> bool; + fn has_error(&self) -> bool { + self.pending_out_interrupts() + .contains(DmaTxInterrupt::DescriptorError) + } fn clear_interrupts(&self); fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker; - fn descriptors_handled(&self) -> bool; - - fn reset_descriptors_handled(&self); - fn last_out_dscr_address(&self) -> usize; } @@ -1612,47 +1572,27 @@ where fn start_transfer(&mut self) -> Result<(), DmaError> { R::start_out(); - if R::has_out_descriptor_error() { + if R::pending_out_interrupts().contains(DmaTxInterrupt::DescriptorError) { Err(DmaError::DescriptorError) } else { Ok(()) } } - fn clear_ch_out_done(&self) { - R::clear_ch_out_done(); + fn listen_out(&self, interrupts: impl Into>) { + R::listen_out(interrupts) } - - fn is_ch_out_done_set(&self) -> bool { - R::is_ch_out_done_set() + fn unlisten_out(&self, interrupts: impl Into>) { + R::unlisten_out(interrupts) } - - fn listen_ch_out_done(&self) { - R::listen_ch_out_done(); + fn is_listening_out(&self) -> EnumSet { + R::is_listening_out() } - - fn unlisten_ch_out_done(&self) { - R::unlisten_ch_out_done(); + fn clear_out(&self, interrupts: impl Into>) { + R::clear_out(interrupts) } - - fn is_listening_ch_out_done(&self) -> bool { - R::is_listening_ch_out_done() - } - - fn is_done(&self) -> bool { - R::is_out_done() - } - - fn descriptors_handled(&self) -> bool { - R::is_out_eof_interrupt_set() - } - - fn reset_descriptors_handled(&self) { - R::reset_out_eof_interrupt(); - } - - fn last_out_dscr_address(&self) -> usize { - R::last_out_dscr_address() + fn pending_out_interrupts(&self) -> EnumSet { + R::pending_out_interrupts() } fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker; @@ -1743,76 +1683,36 @@ where CH::Channel::set_out_ext_mem_block_size(size); } - fn clear_ch_out_done(&self) { - self.tx_impl.clear_ch_out_done(); + fn listen_out(&self, interrupts: impl Into>) { + CH::Channel::listen_out(interrupts); } - fn is_ch_out_done_set(&self) -> bool { - self.tx_impl.is_ch_out_done_set() + fn unlisten_out(&self, interrupts: impl Into>) { + CH::Channel::unlisten_out(interrupts); } - fn listen_ch_out_done(&self) { - self.tx_impl.listen_ch_out_done(); + fn is_listening_out(&self) -> EnumSet { + CH::Channel::is_listening_out() } - fn unlisten_ch_out_done(&self) { - self.tx_impl.unlisten_ch_out_done(); + fn clear_out(&self, interrupts: impl Into>) { + CH::Channel::clear_out(interrupts); } - fn is_listening_ch_out_done(&self) -> bool { - self.tx_impl.is_listening_ch_out_done() - } - - fn is_done(&self) -> bool { - self.tx_impl.is_done() - } - - fn is_listening_eof(&self) -> bool { - CH::Channel::is_listening_out_eof() - } - - fn listen_eof(&self) { - CH::Channel::listen_out_eof() - } - - fn unlisten_eof(&self) { - CH::Channel::unlisten_out_eof() - } - - fn has_error(&self) -> bool { - CH::Channel::has_out_descriptor_error() + fn pending_out_interrupts(&self) -> EnumSet { + CH::Channel::pending_out_interrupts() } fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker { CH::Tx::waker() } - fn is_listening_out_descriptor_error(&self) -> bool { - CH::Channel::is_listening_out_descriptor_error() - } - - fn listen_out_descriptor_error(&self) { - CH::Channel::listen_out_descriptor_error(); - } - - fn unlisten_out_descriptor_error(&self) { - CH::Channel::unlisten_out_descriptor_error(); - } - fn clear_interrupts(&self) { CH::Channel::clear_out_interrupts(); } - fn descriptors_handled(&self) -> bool { - self.tx_impl.descriptors_handled() - } - - fn reset_descriptors_handled(&self) { - self.tx_impl.reset_descriptors_handled() - } - fn last_out_dscr_address(&self) -> usize { - self.tx_impl.last_out_dscr_address() + CH::Channel::last_out_dscr_address() } } @@ -1828,17 +1728,21 @@ pub trait RegisterAccess: crate::private::Sealed { fn clear_out_interrupts(); fn reset_out(); fn set_out_descriptors(address: u32); - fn has_out_descriptor_error() -> bool; fn set_out_peripheral(peripheral: u8); fn start_out(); - fn clear_ch_out_done(); - fn is_ch_out_done_set() -> bool; - fn listen_ch_out_done(); - fn unlisten_ch_out_done(); - fn is_listening_ch_out_done() -> bool; - fn is_out_done() -> bool; - fn is_out_eof_interrupt_set() -> bool; - fn reset_out_eof_interrupt(); + + fn listen_out(interrupts: impl Into>); + fn unlisten_out(interrupts: impl Into>); + fn is_listening_out() -> EnumSet; + fn clear_out(interrupts: impl Into>); + fn pending_out_interrupts() -> EnumSet; + + fn listen_in(interrupts: impl Into>); + fn unlisten_in(interrupts: impl Into>); + fn is_listening_in() -> EnumSet; + fn clear_in(interrupts: impl Into>); + fn pending_in_interrupts() -> EnumSet; + fn last_out_dscr_address() -> usize; #[cfg(esp32s3)] @@ -1848,42 +1752,8 @@ pub trait RegisterAccess: crate::private::Sealed { fn clear_in_interrupts(); fn reset_in(); fn set_in_descriptors(address: u32); - fn has_in_descriptor_error() -> bool; - fn has_in_descriptor_error_dscr_empty() -> bool; - fn has_in_descriptor_error_err_eof() -> bool; fn set_in_peripheral(peripheral: u8); fn start_in(); - fn is_in_done() -> bool; - - fn is_listening_in_eof() -> bool; - fn is_listening_out_eof() -> bool; - - fn listen_in_eof(); - fn listen_out_eof(); - fn unlisten_in_eof(); - fn unlisten_out_eof(); - - fn listen_in_descriptor_error(); - fn unlisten_in_descriptor_error(); - fn is_listening_in_descriptor_error() -> bool; - - fn listen_in_descriptor_error_dscr_empty(); - fn unlisten_in_descriptor_error_dscr_empty(); - fn is_listening_in_descriptor_error_dscr_empty() -> bool; - - fn listen_in_descriptor_error_err_eof(); - fn unlisten_in_descriptor_error_err_eof(); - fn is_listening_in_descriptor_error_err_eof() -> bool; - - fn listen_out_descriptor_error(); - fn unlisten_out_descriptor_error(); - fn is_listening_out_descriptor_error() -> bool; - - fn listen_ch_in_done(); - fn clear_ch_in_done(); - fn is_ch_in_done_set() -> bool; - fn unlisten_ch_in_done(); - fn is_listening_ch_in_done() -> bool; } #[doc(hidden)] @@ -1920,8 +1790,8 @@ where pub fn listen(&mut self, interrupts: EnumSet) { for interrupt in interrupts { match interrupt { - DmaInterrupt::RxDone => self.rx.listen_ch_in_done(), - DmaInterrupt::TxDone => self.tx.listen_ch_out_done(), + DmaInterrupt::RxDone => self.rx.listen_in(DmaRxInterrupt::Done), + DmaInterrupt::TxDone => self.tx.listen_out(DmaTxInterrupt::Done), } } } @@ -1930,8 +1800,8 @@ where pub fn unlisten(&mut self, interrupts: EnumSet) { for interrupt in interrupts { match interrupt { - DmaInterrupt::RxDone => self.rx.unlisten_ch_in_done(), - DmaInterrupt::TxDone => self.tx.unlisten_ch_out_done(), + DmaInterrupt::RxDone => self.rx.unlisten_in(DmaRxInterrupt::Done), + DmaInterrupt::TxDone => self.tx.unlisten_out(DmaTxInterrupt::Done), } } } @@ -1952,8 +1822,8 @@ where pub fn clear_interrupts(&mut self, interrupts: EnumSet) { for interrupt in interrupts { match interrupt { - DmaInterrupt::RxDone => self.rx.clear_ch_in_done(), - DmaInterrupt::TxDone => self.tx.clear_ch_out_done(), + DmaInterrupt::RxDone => self.rx.clear_in(DmaRxInterrupt::Done), + DmaInterrupt::TxDone => self.tx.clear_out(DmaTxInterrupt::Done), } } } @@ -2684,7 +2554,12 @@ where pub fn wait(self) -> Result<(), DmaError> { self.instance.peripheral_wait_dma(false, true); - if self.instance.tx().has_error() { + if self + .instance + .tx() + .pending_out_interrupts() + .contains(DmaTxInterrupt::DescriptorError) + { Err(DmaError::DescriptorError) } else { Ok(()) @@ -2732,7 +2607,12 @@ where pub fn wait(self) -> Result<(), DmaError> { self.instance.peripheral_wait_dma(true, false); - if self.instance.rx().has_error() { + if self + .instance + .rx() + .pending_in_interrupts() + .contains(DmaRxInterrupt::DescriptorError) + { Err(DmaError::DescriptorError) } else { Ok(()) @@ -2781,7 +2661,17 @@ where pub fn wait(self) -> Result<(), DmaError> { self.instance.peripheral_wait_dma(true, true); - if self.instance.tx().has_error() || self.instance.rx().has_error() { + if self + .instance + .tx() + .pending_out_interrupts() + .contains(DmaTxInterrupt::DescriptorError) + || self + .instance + .rx() + .pending_in_interrupts() + .contains(DmaRxInterrupt::DescriptorError) + { Err(DmaError::DescriptorError) } else { Ok(()) @@ -2854,7 +2744,12 @@ where pub fn stop(self) -> Result<(), DmaError> { self.instance.peripheral_dma_stop(); - if self.instance.tx().has_error() { + if self + .instance + .tx() + .pending_out_interrupts() + .contains(DmaTxInterrupt::DescriptorError) + { Err(DmaError::DescriptorError) } else { Ok(()) @@ -2964,12 +2859,16 @@ pub(crate) mod asynch { if self.tx.is_done() { self.tx.clear_interrupts(); Poll::Ready(Ok(())) - } else if self.tx.has_error() { + } else if self + .tx + .pending_out_interrupts() + .contains(DmaTxInterrupt::DescriptorError) + { self.tx.clear_interrupts(); Poll::Ready(Err(DmaError::DescriptorError)) } else { - self.tx.listen_eof(); - self.tx.listen_out_descriptor_error(); + self.tx + .listen_out(DmaTxInterrupt::TotalEof | DmaTxInterrupt::DescriptorError); Poll::Pending } } @@ -2980,8 +2879,8 @@ pub(crate) mod asynch { TX: Tx, { fn drop(&mut self) { - self.tx.unlisten_eof(); - self.tx.unlisten_out_descriptor_error(); + self.tx + .unlisten_out(DmaTxInterrupt::TotalEof | DmaTxInterrupt::DescriptorError); } } @@ -3016,17 +2915,20 @@ pub(crate) mod asynch { if self.rx.is_done() { self.rx.clear_interrupts(); Poll::Ready(Ok(())) - } else if self.rx.has_error() - || self.rx.has_dscr_empty_error() - || self.rx.has_eof_error() - { + } else if !self.rx.pending_in_interrupts().is_disjoint( + DmaRxInterrupt::DescriptorError + | DmaRxInterrupt::DescriptorEmpty + | DmaRxInterrupt::ErrorEof, + ) { self.rx.clear_interrupts(); Poll::Ready(Err(DmaError::DescriptorError)) } else { - self.rx.listen_eof(); - self.rx.listen_in_descriptor_error(); - self.rx.listen_in_descriptor_error_dscr_empty(); - self.rx.listen_in_descriptor_error_err_eof(); + self.rx.listen_in( + DmaRxInterrupt::SuccessfulEof + | DmaRxInterrupt::DescriptorError + | DmaRxInterrupt::DescriptorEmpty + | DmaRxInterrupt::ErrorEof, + ); Poll::Pending } } @@ -3037,10 +2939,11 @@ pub(crate) mod asynch { RX: Rx, { fn drop(&mut self) { - self.rx.unlisten_eof(); - self.rx.unlisten_in_descriptor_error(); - self.rx.unlisten_in_descriptor_error_dscr_empty(); - self.rx.unlisten_in_descriptor_error_err_eof(); + self.rx.unlisten_in( + DmaRxInterrupt::DescriptorError + | DmaRxInterrupt::DescriptorEmpty + | DmaRxInterrupt::ErrorEof, + ); } } @@ -3075,15 +2978,23 @@ pub(crate) mod asynch { cx: &mut core::task::Context<'_>, ) -> Poll { TX::waker().register(cx.waker()); - if self.tx.is_ch_out_done_set() { - self.tx.clear_ch_out_done(); + if self + .tx + .pending_out_interrupts() + .contains(DmaTxInterrupt::Done) + { + self.tx.clear_out(DmaTxInterrupt::Done); Poll::Ready(Ok(())) - } else if self.tx.has_error() { + } else if self + .tx + .pending_out_interrupts() + .contains(DmaTxInterrupt::DescriptorError) + { self.tx.clear_interrupts(); Poll::Ready(Err(DmaError::DescriptorError)) } else { - self.tx.listen_ch_out_done(); - self.tx.listen_out_descriptor_error(); + self.tx + .listen_out(DmaTxInterrupt::Done | DmaTxInterrupt::DescriptorError); Poll::Pending } } @@ -3095,8 +3006,8 @@ pub(crate) mod asynch { TX: Tx, { fn drop(&mut self) { - self.tx.unlisten_ch_out_done(); - self.tx.unlisten_out_descriptor_error(); + self.tx + .unlisten_out(DmaTxInterrupt::Done | DmaTxInterrupt::DescriptorError); } } @@ -3131,20 +3042,27 @@ pub(crate) mod asynch { cx: &mut core::task::Context<'_>, ) -> Poll { RX::waker().register(cx.waker()); - if self.rx.is_ch_in_done_set() { - self.rx.clear_ch_in_done(); - Poll::Ready(Ok(())) - } else if self.rx.has_error() - || self.rx.has_dscr_empty_error() - || self.rx.has_eof_error() + if self + .rx + .pending_in_interrupts() + .contains(DmaRxInterrupt::Done) { + self.rx.clear_in(DmaRxInterrupt::Done); + Poll::Ready(Ok(())) + } else if !self.rx.pending_in_interrupts().is_disjoint( + DmaRxInterrupt::DescriptorError + | DmaRxInterrupt::DescriptorEmpty + | DmaRxInterrupt::ErrorEof, + ) { self.rx.clear_interrupts(); Poll::Ready(Err(DmaError::DescriptorError)) } else { - self.rx.listen_ch_in_done(); - self.rx.listen_in_descriptor_error(); - self.rx.listen_in_descriptor_error_dscr_empty(); - self.rx.listen_in_descriptor_error_err_eof(); + self.rx.listen_in( + DmaRxInterrupt::Done + | DmaRxInterrupt::DescriptorError + | DmaRxInterrupt::DescriptorEmpty + | DmaRxInterrupt::ErrorEof, + ); Poll::Pending } } @@ -3156,50 +3074,57 @@ pub(crate) mod asynch { RX: Rx, { fn drop(&mut self) { - self.rx.unlisten_ch_in_done(); - self.rx.unlisten_in_descriptor_error(); - self.rx.unlisten_in_descriptor_error_dscr_empty(); - self.rx.unlisten_in_descriptor_error_err_eof(); + self.rx.unlisten_in( + DmaRxInterrupt::Done + | DmaRxInterrupt::DescriptorError + | DmaRxInterrupt::DescriptorEmpty + | DmaRxInterrupt::ErrorEof, + ); } } fn handle_interrupt, Tx: TxChannel>() { - if Channel::has_in_descriptor_error() - || Channel::has_in_descriptor_error_dscr_empty() - || Channel::has_in_descriptor_error_err_eof() + if Channel::pending_in_interrupts().is_disjoint( + DmaRxInterrupt::DescriptorError + | DmaRxInterrupt::DescriptorEmpty + | DmaRxInterrupt::ErrorEof, + ) { + Channel::unlisten_in( + DmaRxInterrupt::DescriptorError + | DmaRxInterrupt::DescriptorEmpty + | DmaRxInterrupt::ErrorEof + | DmaRxInterrupt::SuccessfulEof + | DmaRxInterrupt::Done, + ); + Rx::waker().wake() + } + + if Channel::pending_out_interrupts().contains(DmaTxInterrupt::DescriptorError) { + Channel::unlisten_out( + DmaTxInterrupt::DescriptorError | DmaTxInterrupt::TotalEof | DmaTxInterrupt::Done, + ); + Tx::waker().wake() + } + + if Channel::pending_in_interrupts().contains(DmaRxInterrupt::SuccessfulEof) { + Channel::unlisten_in(DmaRxInterrupt::SuccessfulEof); + Rx::waker().wake() + } + + if Channel::pending_in_interrupts().contains(DmaRxInterrupt::Done) { + Channel::unlisten_in(DmaRxInterrupt::Done); + Rx::waker().wake() + } + + if Channel::pending_out_interrupts().contains(DmaTxInterrupt::TotalEof) + && Channel::is_listening_out().contains(DmaTxInterrupt::TotalEof) { - Channel::unlisten_in_descriptor_error(); - Channel::unlisten_in_descriptor_error_dscr_empty(); - Channel::unlisten_in_descriptor_error_err_eof(); - Channel::unlisten_in_eof(); - Channel::unlisten_ch_in_done(); - Rx::waker().wake() - } - - if Channel::has_out_descriptor_error() { - Channel::unlisten_out_descriptor_error(); - Channel::unlisten_out_eof(); - Channel::unlisten_ch_out_done(); + Channel::unlisten_out(DmaTxInterrupt::TotalEof); Tx::waker().wake() } - if Channel::is_in_done() && Channel::is_listening_in_eof() { - Channel::unlisten_in_eof(); - Rx::waker().wake() - } - - if Channel::is_ch_in_done_set() { - Channel::unlisten_ch_in_done(); - Rx::waker().wake() - } - - if Channel::is_out_done() && Channel::is_listening_out_eof() { - Channel::unlisten_out_eof(); - Tx::waker().wake() - } - - if Channel::is_ch_out_done_set() { - Channel::unlisten_ch_out_done(); + if Channel::pending_out_interrupts().contains(DmaTxInterrupt::Done) { + Channel::unlisten_out(DmaTxInterrupt::Done); Tx::waker().wake() } } diff --git a/esp-hal/src/dma/pdma.rs b/esp-hal/src/dma/pdma.rs index 875209893..f53c1c44e 100644 --- a/esp-hal/src/dma/pdma.rs +++ b/esp-hal/src/dma/pdma.rs @@ -83,11 +83,6 @@ macro_rules! ImplSpiChannel { .modify(|_, w| unsafe { w.outlink_addr().bits(address) }); } - fn has_out_descriptor_error() -> bool { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_raw().read().outlink_dscr_error().bit() - } - fn set_out_peripheral(_peripheral: u8) { // no-op } @@ -97,53 +92,11 @@ macro_rules! ImplSpiChannel { spi.dma_out_link().modify(|_, w| w.outlink_start().set_bit()); } - fn clear_ch_out_done() { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_clr().write(|w| w.out_done().clear_bit_by_one()); - } - - fn is_ch_out_done_set() -> bool { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_raw().read().out_done().bit() - } - - fn listen_ch_out_done() { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().modify(|_, w| w.out_done().set_bit()); - } - - fn unlisten_ch_out_done() { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().modify(|_, w| w.out_done().clear_bit()); - } - - fn is_listening_ch_out_done() -> bool { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().read().out_done().bit() - } - - fn is_out_done() -> bool { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_raw().read().out_total_eof().bit() - } - fn last_out_dscr_address() -> usize { let spi = unsafe { &*crate::peripherals::[]::PTR }; spi.out_eof_des_addr().read().dma_out_eof_des_addr().bits() as usize } - fn is_out_eof_interrupt_set() -> bool { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_raw().read().out_eof().bit() - } - - fn reset_out_eof_interrupt() { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_clr().write(|w| { - w.out_eof().clear_bit_by_one() - }); - } - fn set_in_burstmode(burst_mode: bool) { let spi = unsafe { &*crate::peripherals::[]::PTR }; spi.dma_conf() @@ -174,21 +127,6 @@ macro_rules! ImplSpiChannel { .modify(|_, w| unsafe { w.inlink_addr().bits(address) }); } - fn has_in_descriptor_error() -> bool { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_raw().read().inlink_dscr_error().bit() - } - - fn has_in_descriptor_error_dscr_empty() -> bool { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_raw().read().inlink_dscr_empty().bit() - } - - fn has_in_descriptor_error_err_eof() -> bool { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_raw().read().in_err_eof().bit() - } - fn set_in_peripheral(_peripheral: u8) { // no-op } @@ -198,124 +136,187 @@ macro_rules! ImplSpiChannel { spi.dma_in_link().modify(|_, w| w.inlink_start().set_bit()); } - fn is_in_done() -> bool { + fn listen_out(interrupts: impl Into>) { let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_raw().read().in_done().bit() + spi.dma_int_ena().modify(|_, w| { + for interrupt in interrupts.into() { + match interrupt { + DmaTxInterrupt::TotalEof => w.out_total_eof().set_bit(), + DmaTxInterrupt::DescriptorError => w.outlink_dscr_error().set_bit(), + DmaTxInterrupt::Eof => w.out_eof().set_bit(), + DmaTxInterrupt::Done => w.out_done().set_bit(), + }; + } + w + }) } - fn is_listening_in_eof() -> bool { + fn unlisten_out(interrupts: impl Into>) { let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().read().in_suc_eof().bit_is_set() + spi.dma_int_ena().modify(|_, w| { + for interrupt in interrupts.into() { + match interrupt { + DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit(), + DmaTxInterrupt::DescriptorError => w.outlink_dscr_error().clear_bit(), + DmaTxInterrupt::Eof => w.out_eof().clear_bit(), + DmaTxInterrupt::Done => w.out_done().clear_bit(), + }; + } + w + }) } - fn is_listening_out_eof() -> bool { + fn is_listening_out() -> EnumSet { + let mut result = EnumSet::new(); + let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().read().out_total_eof().bit_is_set() + let int_ena = spi.dma_int_ena().read(); + if int_ena.out_total_eof().bit_is_set() { + result |= DmaTxInterrupt::TotalEof; + } + if int_ena.outlink_dscr_error().bit_is_set() { + result |= DmaTxInterrupt::DescriptorError; + } + if int_ena.out_eof().bit_is_set() { + result |= DmaTxInterrupt::Eof; + } + if int_ena.out_done().bit_is_set() { + result |= DmaTxInterrupt::Done; + } + + result } - fn listen_in_eof() { + fn pending_out_interrupts() -> EnumSet { + let mut result = EnumSet::new(); + let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().modify(|_, w| w.in_suc_eof().set_bit()); + let int_raw = spi.dma_int_raw().read(); + if int_raw.out_total_eof().bit_is_set() { + result |= DmaTxInterrupt::TotalEof; + } + if int_raw.outlink_dscr_error().bit_is_set() { + result |= DmaTxInterrupt::DescriptorError; + } + if int_raw.out_eof().bit_is_set() { + result |= DmaTxInterrupt::Eof; + } + if int_raw.out_done().bit_is_set() { + result |= DmaTxInterrupt::Done; + } + + result } - fn listen_out_eof() { + fn clear_out(interrupts: impl Into>) { let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().modify(|_, w| w.out_total_eof().set_bit()); + spi.dma_int_clr().write(|w| { + for interrupt in interrupts.into() { + match interrupt { + DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit_by_one(), + DmaTxInterrupt::DescriptorError => w.outlink_dscr_error().clear_bit_by_one(), + DmaTxInterrupt::Eof => w.out_eof().clear_bit_by_one(), + DmaTxInterrupt::Done => w.out_done().clear_bit_by_one(), + }; + } + w + }) } - fn unlisten_in_eof() { + fn listen_in(interrupts: impl Into>) { let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().modify(|_, w| w.in_suc_eof().clear_bit()); + spi.dma_int_ena().modify(|_, w| { + for interrupt in interrupts.into() { + match interrupt { + DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().set_bit(), + DmaRxInterrupt::ErrorEof => w.in_err_eof().set_bit(), + DmaRxInterrupt::DescriptorError => w.inlink_dscr_error().set_bit(), + DmaRxInterrupt::DescriptorEmpty => w.inlink_dscr_empty().set_bit(), + DmaRxInterrupt::Done => w.in_done().set_bit(), + }; + } + w + }) } - fn unlisten_out_eof() { + fn unlisten_in(interrupts: impl Into>) { let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().modify(|_, w| w.out_total_eof().clear_bit()); + spi.dma_int_ena().modify(|_, w| { + for interrupt in interrupts.into() { + match interrupt { + DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit(), + DmaRxInterrupt::ErrorEof => w.in_err_eof().clear_bit(), + DmaRxInterrupt::DescriptorError => w.inlink_dscr_error().clear_bit(), + DmaRxInterrupt::DescriptorEmpty => w.inlink_dscr_empty().clear_bit(), + DmaRxInterrupt::Done => w.in_done().clear_bit(), + }; + } + w + }) } - fn listen_ch_in_done(){ + fn is_listening_in() -> EnumSet { + let mut result = EnumSet::new(); + let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().modify(|_, w| w.in_done().set_bit()); + let int_ena = spi.dma_int_ena().read(); + if int_ena.inlink_dscr_error().bit_is_set() { + result |= DmaRxInterrupt::DescriptorError; + } + if int_ena.inlink_dscr_empty().bit_is_set() { + result |= DmaRxInterrupt::DescriptorEmpty; + } + if int_ena.in_suc_eof().bit_is_set() { + result |= DmaRxInterrupt::SuccessfulEof; + } + if int_ena.in_err_eof().bit_is_set() { + result |= DmaRxInterrupt::ErrorEof; + } + if int_ena.in_done().bit_is_set() { + result |= DmaRxInterrupt::Done; + } + + result } - fn clear_ch_in_done(){ + fn pending_in_interrupts() -> EnumSet { + let mut result = EnumSet::new(); + let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_clr().write(|w| w.in_done().clear_bit_by_one()); + let int_raw = spi.dma_int_raw().read(); + if int_raw.inlink_dscr_error().bit_is_set() { + result |= DmaRxInterrupt::DescriptorError; + } + if int_raw.inlink_dscr_empty().bit_is_set() { + result |= DmaRxInterrupt::DescriptorEmpty; + } + if int_raw.in_suc_eof().bit_is_set() { + result |= DmaRxInterrupt::SuccessfulEof; + } + if int_raw.in_err_eof().bit_is_set() { + result |= DmaRxInterrupt::ErrorEof; + } + if int_raw.in_done().bit_is_set() { + result |= DmaRxInterrupt::Done; + } + + result } - fn is_ch_in_done_set() -> bool { + fn clear_in(interrupts: impl Into>) { let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_raw().read().in_done().bit() - } - - fn unlisten_ch_in_done() { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().modify(|_, w| w.in_done().clear_bit()); - } - - fn is_listening_ch_in_done() -> bool { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().read().in_done().bit() - } - - fn listen_in_descriptor_error() { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().modify(|_,w| w.inlink_dscr_error().set_bit()) - } - - fn unlisten_in_descriptor_error() { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().modify(|_,w| w.inlink_dscr_error().clear_bit()) - } - - fn is_listening_in_descriptor_error() -> bool { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().read().inlink_dscr_error().bit() - } - - fn listen_in_descriptor_error_dscr_empty() { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().modify(|_,w| w.inlink_dscr_empty().set_bit()) - } - - fn unlisten_in_descriptor_error_dscr_empty() { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().modify(|_,w| w.inlink_dscr_empty().clear_bit()) - } - - fn is_listening_in_descriptor_error_dscr_empty() -> bool { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().read().inlink_dscr_empty().bit() - } - - fn listen_in_descriptor_error_err_eof() { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().modify(|_,w| w.in_err_eof().set_bit()) - } - - fn unlisten_in_descriptor_error_err_eof() { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().modify(|_,w| w.in_err_eof().clear_bit()) - } - - fn is_listening_in_descriptor_error_err_eof() -> bool{ - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().read().in_err_eof().bit() - } - - fn listen_out_descriptor_error() { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().modify(|_,w| w.outlink_dscr_error().set_bit()) - } - - fn unlisten_out_descriptor_error() { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().modify(|_,w| w.outlink_dscr_error().clear_bit()) - } - - fn is_listening_out_descriptor_error() -> bool { - let spi = unsafe { &*crate::peripherals::[]::PTR }; - spi.dma_int_ena().read().outlink_dscr_error().bit() + spi.dma_int_clr().modify(|_, w| { + for interrupt in interrupts.into() { + match interrupt { + DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit_by_one(), + DmaRxInterrupt::ErrorEof => w.in_err_eof().clear_bit_by_one(), + DmaRxInterrupt::DescriptorError => w.inlink_dscr_error().clear_bit_by_one(), + DmaRxInterrupt::DescriptorEmpty => w.inlink_dscr_empty().clear_bit_by_one(), + DmaRxInterrupt::Done => w.in_done().clear_bit_by_one(), + }; + } + w + }) } } @@ -462,11 +463,6 @@ macro_rules! ImplI2sChannel { .modify(|_, w| unsafe { w.outlink_addr().bits(address) }); } - fn has_out_descriptor_error() -> bool { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_raw().read().out_dscr_err().bit() - } - fn set_out_peripheral(_peripheral: u8) { // no-op } @@ -476,54 +472,11 @@ macro_rules! ImplI2sChannel { reg_block.out_link().modify(|_, w| w.outlink_start().set_bit()); } - fn clear_ch_out_done() { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_clr().write(|w| w.out_done().clear_bit_by_one()); - } - - fn is_ch_out_done_set() -> bool { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_raw().read().out_done().bit() - } - - fn listen_ch_out_done() { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().modify(|_, w| w.out_done().set_bit()); - } - - fn unlisten_ch_out_done() { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().modify(|_, w| w.out_done().clear_bit()); - } - - fn is_listening_ch_out_done() -> bool { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().read().out_done().bit() - } - - fn is_out_done() -> bool { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_raw().read().out_eof().bit() - } - fn last_out_dscr_address() -> usize { let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; reg_block.out_eof_des_addr().read().out_eof_des_addr().bits() as usize } - fn is_out_eof_interrupt_set() -> bool { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_raw().read().out_eof().bit() - } - - fn reset_out_eof_interrupt() { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_clr().write(|w| { - w.out_eof() - .clear_bit_by_one() - }); - } - fn set_in_burstmode(burst_mode: bool) { let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; reg_block.lc_conf() @@ -558,21 +511,6 @@ macro_rules! ImplI2sChannel { .modify(|_, w| unsafe { w.inlink_addr().bits(address) }); } - fn has_in_descriptor_error() -> bool { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_raw().read().in_dscr_err().bit() - } - - fn has_in_descriptor_error_dscr_empty() -> bool { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_raw().read().in_dscr_empty().bit() - } - - fn has_in_descriptor_error_err_eof() -> bool { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_raw().read().in_err_eof().bit() - } - fn set_in_peripheral(_peripheral: u8) { // no-op } @@ -582,124 +520,187 @@ macro_rules! ImplI2sChannel { reg_block.in_link().modify(|_, w| w.inlink_start().set_bit()); } - fn is_in_done() -> bool { + fn listen_out(interrupts: impl Into>) { let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_raw().read().in_done().bit() + reg_block.int_ena().modify(|_, w| { + for interrupt in interrupts.into() { + match interrupt { + DmaTxInterrupt::TotalEof => w.out_total_eof().set_bit(), + DmaTxInterrupt::DescriptorError => w.out_dscr_err().set_bit(), + DmaTxInterrupt::Eof => w.out_eof().set_bit(), + DmaTxInterrupt::Done => w.out_done().set_bit(), + }; + } + w + }) } - fn is_listening_in_eof() -> bool { + fn unlisten_out(interrupts: impl Into>) { let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().read().in_suc_eof().bit() + reg_block.int_ena().modify(|_, w| { + for interrupt in interrupts.into() { + match interrupt { + DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit(), + DmaTxInterrupt::DescriptorError => w.out_dscr_err().clear_bit(), + DmaTxInterrupt::Eof => w.out_eof().clear_bit(), + DmaTxInterrupt::Done => w.out_done().clear_bit(), + }; + } + w + }) } - fn is_listening_out_eof() -> bool { + fn is_listening_out() -> EnumSet { + let mut result = EnumSet::new(); + let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().read().out_eof().bit() + let int_ena = reg_block.int_ena().read(); + if int_ena.out_total_eof().bit_is_set() { + result |= DmaTxInterrupt::TotalEof; + } + if int_ena.out_dscr_err().bit_is_set() { + result |= DmaTxInterrupt::DescriptorError; + } + if int_ena.out_eof().bit_is_set() { + result |= DmaTxInterrupt::Eof; + } + if int_ena.out_done().bit_is_set() { + result |= DmaTxInterrupt::Done; + } + + result } - fn listen_in_eof() { + fn pending_out_interrupts() -> EnumSet { + let mut result = EnumSet::new(); + let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().modify(|_,w| w.in_suc_eof().set_bit() ); + let int_raw = reg_block.int_raw().read(); + if int_raw.out_total_eof().bit_is_set() { + result |= DmaTxInterrupt::TotalEof; + } + if int_raw.out_dscr_err().bit_is_set() { + result |= DmaTxInterrupt::DescriptorError; + } + if int_raw.out_eof().bit_is_set() { + result |= DmaTxInterrupt::Eof; + } + if int_raw.out_done().bit_is_set() { + result |= DmaTxInterrupt::Done; + } + + result } - fn listen_out_eof() { + fn clear_out(interrupts: impl Into>) { let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().modify(|_,w| w.out_eof().set_bit() ); + reg_block.int_clr().write(|w| { + for interrupt in interrupts.into() { + match interrupt { + DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit_by_one(), + DmaTxInterrupt::DescriptorError => w.out_dscr_err().clear_bit_by_one(), + DmaTxInterrupt::Eof => w.out_eof().clear_bit_by_one(), + DmaTxInterrupt::Done => w.out_done().clear_bit_by_one(), + }; + } + w + }) } - fn unlisten_in_eof() { + fn listen_in(interrupts: impl Into>) { let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().modify(|_,w| w.in_suc_eof().clear_bit() ); + reg_block.int_ena().modify(|_, w| { + for interrupt in interrupts.into() { + match interrupt { + DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().set_bit(), + DmaRxInterrupt::ErrorEof => w.in_err_eof().set_bit(), + DmaRxInterrupt::DescriptorError => w.in_dscr_err().set_bit(), + DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().set_bit(), + DmaRxInterrupt::Done => w.in_done().set_bit(), + }; + } + w + }) } - fn unlisten_out_eof() { + fn unlisten_in(interrupts: impl Into>) { let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().modify(|_,w| w.out_eof().clear_bit() ); + reg_block.int_ena().modify(|_, w| { + for interrupt in interrupts.into() { + match interrupt { + DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit(), + DmaRxInterrupt::ErrorEof => w.in_err_eof().clear_bit(), + DmaRxInterrupt::DescriptorError => w.in_dscr_err().clear_bit(), + DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().clear_bit(), + DmaRxInterrupt::Done => w.in_done().clear_bit(), + }; + } + w + }) } - fn listen_ch_in_done(){ + fn is_listening_in() -> EnumSet { + let mut result = EnumSet::new(); + let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().modify(|_, w| w.in_done().set_bit()); + let int_ena = reg_block.int_ena().read(); + if int_ena.in_dscr_err().bit_is_set() { + result |= DmaRxInterrupt::DescriptorError; + } + if int_ena.in_dscr_empty().bit_is_set() { + result |= DmaRxInterrupt::DescriptorEmpty; + } + if int_ena.in_suc_eof().bit_is_set() { + result |= DmaRxInterrupt::SuccessfulEof; + } + if int_ena.in_err_eof().bit_is_set() { + result |= DmaRxInterrupt::ErrorEof; + } + if int_ena.in_done().bit_is_set() { + result |= DmaRxInterrupt::Done; + } + + result } - fn clear_ch_in_done(){ + fn pending_in_interrupts() -> EnumSet { + let mut result = EnumSet::new(); + let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_clr().write(|w| w.in_done().clear_bit_by_one()); + let int_raw = reg_block.int_raw().read(); + if int_raw.in_dscr_err().bit_is_set() { + result |= DmaRxInterrupt::DescriptorError; + } + if int_raw.in_dscr_empty().bit_is_set() { + result |= DmaRxInterrupt::DescriptorEmpty; + } + if int_raw.in_suc_eof().bit_is_set() { + result |= DmaRxInterrupt::SuccessfulEof; + } + if int_raw.in_err_eof().bit_is_set() { + result |= DmaRxInterrupt::ErrorEof; + } + if int_raw.in_done().bit_is_set() { + result |= DmaRxInterrupt::Done; + } + + result } - fn is_ch_in_done_set() -> bool { + fn clear_in(interrupts: impl Into>) { let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_raw().read().in_done().bit() - } - - fn unlisten_ch_in_done() { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().modify(|_, w| w.in_done().clear_bit()); - } - - fn is_listening_ch_in_done() -> bool { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().read().in_done().bit() - } - - fn listen_in_descriptor_error(){ - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().modify(|_, w| w.in_dscr_err().set_bit()); - } - - fn unlisten_in_descriptor_error() { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().modify(|_, w| w.in_dscr_err().clear_bit()); - } - - fn is_listening_in_descriptor_error() -> bool { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().read().in_dscr_err().bit() - } - - fn listen_in_descriptor_error_dscr_empty() { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().modify(|_, w| w.in_dscr_empty().set_bit()); - } - - fn unlisten_in_descriptor_error_dscr_empty() { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().modify(|_, w| w.in_dscr_empty().clear_bit()); - } - - fn is_listening_in_descriptor_error_dscr_empty() -> bool{ - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().read().in_dscr_empty().bit() - } - - fn listen_in_descriptor_error_err_eof() { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().modify(|_, w| w.in_err_eof().set_bit()); - } - - fn unlisten_in_descriptor_error_err_eof() { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().modify(|_, w| w.in_err_eof().clear_bit()); - } - - fn is_listening_in_descriptor_error_err_eof() -> bool{ - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().read().in_err_eof().bit() - } - - fn listen_out_descriptor_error() { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().modify(|_, w| w.out_dscr_err().set_bit()); - } - - fn unlisten_out_descriptor_error() { - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().modify(|_, w| w.out_dscr_err().clear_bit()); - } - - fn is_listening_out_descriptor_error() -> bool{ - let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR }; - reg_block.int_ena().read().out_dscr_err().bit() + reg_block.int_clr().write(|w| { + for interrupt in interrupts.into() { + match interrupt { + DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit_by_one(), + DmaRxInterrupt::ErrorEof => w.in_err_eof().clear_bit_by_one(), + DmaRxInterrupt::DescriptorError => w.in_dscr_err().clear_bit_by_one(), + DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().clear_bit_by_one(), + DmaRxInterrupt::Done => w.in_done().clear_bit_by_one(), + }; + } + w + }) } }