From ac616d2d5676fc5f3f83cc8c7626507fb061b591 Mon Sep 17 00:00:00 2001 From: Elise Amber Katze Date: Sat, 18 May 2024 12:08:13 +0200 Subject: [PATCH] feat: add support for aborting DMA transfers --- rp2040-hal/src/dma/single_buffer.rs | 31 ++++++++++++++++++++++++++++ rp2040-hal/src/dma/single_channel.rs | 16 ++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/rp2040-hal/src/dma/single_buffer.rs b/rp2040-hal/src/dma/single_buffer.rs index 161260e8f..9c3c08cf0 100644 --- a/rp2040-hal/src/dma/single_buffer.rs +++ b/rp2040-hal/src/dma/single_buffer.rs @@ -112,4 +112,35 @@ 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(); + + unsafe { &*crate::pac::DMA::ptr() }.chan_abort().write(|w| unsafe { w.bits(1 << self.ch.id() as u32)}); + + while unsafe { &*crate::pac::DMA::ptr() }.chan_abort().read().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..909ada4e3 100644 --- a/rp2040-hal/src/dma/single_channel.rs +++ b/rp2040-hal/src/dma/single_channel.rs @@ -31,6 +31,14 @@ 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 +83,14 @@ 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) {