diff --git a/rp2040-hal/src/dma/single_buffer.rs b/rp2040-hal/src/dma/single_buffer.rs index 161260e8f..f0ffc714c 100644 --- a/rp2040-hal/src/dma/single_buffer.rs +++ b/rp2040-hal/src/dma/single_buffer.rs @@ -112,4 +112,39 @@ where (self.ch, self.from, self.to) } + + /// Aborts the current transfer, returning the channel and targets + pub fn abort(mut self) -> (CH, FROM, TO) { + let irq0_was_enabled = self.ch.is_enabled_irq0(); + let irq1_was_enabled = self.ch.is_enabled_irq1(); + self.ch.disable_irq0(); + self.ch.disable_irq1(); + + // Safety: We only use the atomic alias of the register. + let chan_abort = unsafe { &*crate::pac::DMA::ptr() }.chan_abort(); + let abort_mask = (1 << self.ch.id()) as u16; + + chan_abort.write(|w| unsafe { w.chan_abort().bits(abort_mask) }); + + while chan_abort.read().chan_abort().bits() != 0 {} + + while !self.is_done() {} + + self.ch.check_irq0(); + self.ch.check_irq1(); + + if irq0_was_enabled { + self.ch.enable_irq0(); + } + + if irq1_was_enabled { + self.ch.enable_irq1(); + } + + // Make sure that memory contents reflect what the user intended. + cortex_m::asm::dsb(); + compiler_fence(Ordering::SeqCst); + + (self.ch, self.from, self.to) + } } diff --git a/rp2040-hal/src/dma/single_channel.rs b/rp2040-hal/src/dma/single_channel.rs index bfe444be7..1aaa5b4f2 100644 --- a/rp2040-hal/src/dma/single_channel.rs +++ b/rp2040-hal/src/dma/single_channel.rs @@ -31,6 +31,12 @@ pub trait SingleChannel: Sealed { } } + /// Check if the DMA_IRQ_0 signal for this channel is enabled. + fn is_enabled_irq0(&mut self) -> bool { + // Safety: We only use the atomic alias of the register. + unsafe { ((*DMA::ptr()).inte0().read().bits() & (1 << self.id())) != 0 } + } + #[deprecated(note = "Renamed to disable_irq0")] /// Disables the DMA_IRQ_0 signal for this channel. fn unlisten_irq0(&mut self) { @@ -75,6 +81,12 @@ pub trait SingleChannel: Sealed { } } + /// Check if the DMA_IRQ_1 signal for this channel is enabled. + fn is_enabled_irq1(&mut self) -> bool { + // Safety: We only use the atomic alias of the register. + unsafe { ((*DMA::ptr()).inte1().read().bits() & (1 << self.id())) != 0 } + } + #[deprecated(note = "Renamed to disable_irq1")] /// Disables the DMA_IRQ_1 signal for this channel. fn unlisten_irq1(&mut self) {