From fec14213ea7b79badc14eae38c4a0b0197499f3f Mon Sep 17 00:00:00 2001 From: etiennecollin Date: Mon, 25 Aug 2025 21:10:59 +0200 Subject: fix: modified dma channel state management See https://github.com/embassy-rs/embassy/pull/3923#discussion_r2094570176 --- embassy-stm32/src/dma/gpdma/mod.rs | 66 ++++++++++++++++++++--------- embassy-stm32/src/dma/gpdma/ringbuffered.rs | 54 +++++++++++++---------- embassy-stm32/src/ucpd.rs | 4 +- embassy-stm32/src/usart/ringbuffered.rs | 2 +- 4 files changed, 80 insertions(+), 46 deletions(-) diff --git a/embassy-stm32/src/dma/gpdma/mod.rs b/embassy-stm32/src/dma/gpdma/mod.rs index 2132f070a..d06eac60e 100644 --- a/embassy-stm32/src/dma/gpdma/mod.rs +++ b/embassy-stm32/src/dma/gpdma/mod.rs @@ -341,21 +341,25 @@ impl AnyChannel { ch.cr().modify(|w| w.set_en(true)); } - fn request_stop(&self) { + fn request_suspend(&self) { let info = self.info(); let ch = info.dma.ch(info.num); ch.cr().modify(|w| w.set_susp(true)) } - fn request_pause(&self) { + fn request_resume(&self) { let info = self.info(); let ch = info.dma.ch(info.num); - // Disable the channel without overwriting the existing configuration - ch.cr().modify(|w| { - w.set_en(false); - }); + ch.cr().modify(|w| w.set_susp(false)); + } + + fn request_reset(&self) { + let info = self.info(); + let ch = info.dma.ch(info.num); + + ch.cr().modify(|w| w.set_reset(true)); } fn is_running(&self) -> bool { @@ -406,11 +410,26 @@ impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> { Self { channel } } - /// Request the transfer to stop. + /// Request the transfer to suspend. + /// + /// To resume the transfer, call [`request_resume`](Self::request_resume) again. /// /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. - pub fn request_stop(&mut self) { - self.channel.request_stop() + pub fn request_suspend(&mut self) { + self.channel.request_suspend() + } + + /// Request the transfer to resume after being suspended. + pub fn request_resume(&mut self) { + self.channel.request_resume() + } + + /// Request the DMA to reset. + /// + /// The configuration for this channel will **not be preserved**. If you need to restart the transfer + /// at a later point with the same configuration, see [`request_suspend`](Self::request_suspend) instead. + pub fn request_reset(&mut self) { + self.channel.request_reset() } /// Return whether this transfer is still running. @@ -440,7 +459,7 @@ impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> { impl<'a, const ITEM_COUNT: usize> Drop for LinkedListTransfer<'a, ITEM_COUNT> { fn drop(&mut self) { - self.request_stop(); + self.request_suspend(); while self.is_running() {} // "Subsequent reads and writes cannot be moved ahead of preceding reads." @@ -589,21 +608,26 @@ impl<'a> Transfer<'a> { Self { channel } } - /// Request the transfer to stop. - /// The configuration for this channel will **not be preserved**. If you need to restart the transfer - /// at a later point with the same configuration, see [`request_pause`](Self::request_pause) instead. + /// Request the transfer to suspend. + /// + /// To resume the transfer, call [`request_resume`](Self::request_resume) again. /// /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. - pub fn request_stop(&mut self) { - self.channel.request_stop() + pub fn request_suspend(&mut self) { + self.channel.request_suspend() } - /// Request the transfer to pause, keeping the existing configuration for this channel. - /// To restart the transfer, call [`start`](Self::start) again. + /// Request the transfer to resume after being suspended. + pub fn request_resume(&mut self) { + self.channel.request_resume() + } + + /// Request the DMA to reset. /// - /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. - pub fn request_pause(&mut self) { - self.channel.request_pause() + /// The configuration for this channel will **not be preserved**. If you need to restart the transfer + /// at a later point with the same configuration, see [`request_suspend`](Self::request_suspend) instead. + pub fn request_reset(&mut self) { + self.channel.request_reset() } /// Return whether this transfer is still running. @@ -633,7 +657,7 @@ impl<'a> Transfer<'a> { impl<'a> Drop for Transfer<'a> { fn drop(&mut self) { - self.request_stop(); + self.request_suspend(); while self.is_running() {} // "Subsequent reads and writes cannot be moved ahead of preceding reads." diff --git a/embassy-stm32/src/dma/gpdma/ringbuffered.rs b/embassy-stm32/src/dma/gpdma/ringbuffered.rs index 87c482bfb..4532bda57 100644 --- a/embassy-stm32/src/dma/gpdma/ringbuffered.rs +++ b/embassy-stm32/src/dma/gpdma/ringbuffered.rs @@ -139,21 +139,26 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); } - /// Request the DMA to stop. - /// The configuration for this channel will **not be preserved**. If you need to restart the transfer - /// at a later point with the same configuration, see [`request_pause`](Self::request_pause) instead. + /// Request the DMA to suspend. + /// + /// To resume the transfer, call [`request_resume`](Self::request_resume) again. /// /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. - pub fn request_stop(&mut self) { - self.channel.request_stop() + pub fn request_suspend(&mut self) { + self.channel.request_suspend() + } + + /// Request the DMA to resume transfers after being suspended. + pub fn request_resume(&mut self) { + self.channel.request_resume() } - /// Request the transfer to pause, keeping the existing configuration for this channel. - /// To restart the transfer, call [`start`](Self::start) again. + /// Request the DMA to reset. /// - /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. - pub fn request_pause(&mut self) { - self.channel.request_pause() + /// The configuration for this channel will **not be preserved**. If you need to restart the transfer + /// at a later point with the same configuration, see [`request_suspend`](Self::request_suspend) instead. + pub fn request_reset(&mut self) { + self.channel.request_reset() } /// Return whether DMA is still running. @@ -185,7 +190,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> { fn drop(&mut self) { - self.request_stop(); + self.request_suspend(); while self.is_running() {} // "Subsequent reads and writes cannot be moved ahead of preceding reads." @@ -285,21 +290,26 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); } - /// Request the DMA to stop. - /// The configuration for this channel will **not be preserved**. If you need to restart the transfer - /// at a later point with the same configuration, see [`request_pause`](Self::request_pause) instead. + /// Request the DMA to suspend. + /// + /// To resume the transfer, call [`request_resume`](Self::request_resume) again. /// /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. - pub fn request_stop(&mut self) { - self.channel.request_stop() + pub fn request_suspend(&mut self) { + self.channel.request_suspend() + } + + /// Request the DMA to resume transfers after being suspended. + pub fn request_resume(&mut self) { + self.channel.request_resume() } - /// Request the transfer to pause, keeping the existing configuration for this channel. - /// To restart the transfer, call [`start`](Self::start) again. + /// Request the DMA to reset. /// - /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. - pub fn request_pause(&mut self) { - self.channel.request_pause() + /// The configuration for this channel will **not be preserved**. If you need to restart the transfer + /// at a later point with the same configuration, see [`request_suspend`](Self::request_suspend) instead. + pub fn request_reset(&mut self) { + self.channel.request_reset() } /// Return whether DMA is still running. @@ -331,7 +341,7 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { impl<'a, W: Word> Drop for WritableRingBuffer<'a, W> { fn drop(&mut self) { - self.request_stop(); + self.request_suspend(); while self.is_running() {} // "Subsequent reads and writes cannot be moved ahead of preceding reads." diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 0a80adb8f..967e43a8a 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -490,14 +490,14 @@ impl<'d, T: Instance> PdPhy<'d, T> { let sr = r.sr().read(); if sr.rxhrstdet() { - dma.request_stop(); + dma.request_suspend(); // Clean and re-enable hard reset receive interrupt. r.icr().write(|w| w.set_rxhrstdetcf(true)); r.imr().modify(|w| w.set_rxhrstdetie(true)); Poll::Ready(Err(RxError::HardReset)) } else if sr.rxmsgend() { - dma.request_stop(); + dma.request_suspend(); // Should be read immediately on interrupt. rxpaysz = r.rx_payszr().read().rxpaysz().into(); diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index 5f4e87834..bea56c991 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -165,7 +165,7 @@ impl<'d> RingBufferedUartRx<'d> { /// Stop DMA backed UART receiver fn stop_uart(&mut self) { - self.ring_buf.request_pause(); + self.ring_buf.request_suspend(); let r = self.info.regs; // clear all interrupts and DMA Rx Request -- cgit