diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 29c9fd592..b4c77757e 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -59,7 +59,7 @@ unsafe fn on_irq() { let isr = pac::$dma.isr().read(); let dman = dma_num!($dma); - for chn in 0..crate::pac::dma_channels_count!($dma) { + for chn in 0..pac::dma_channels_count!($dma) { let cr = pac::$dma.ch(chn).cr(); if isr.tcif(chn) && cr.read().tcie() { cr.write(|_| ()); // Disable channel interrupts with the default value. @@ -90,9 +90,8 @@ pac::dma_channels! { impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri { unsafe fn start_write(&mut self, request: Request, buf: &[W], reg_addr: *mut W) { - low_level_api::reset_status(crate::pac::$dma_peri, $channel_num); low_level_api::start_transfer( - crate::pac::$dma_peri, + pac::$dma_peri, $channel_num, #[cfg(any(bdma_v2, dmamux))] request, @@ -112,9 +111,8 @@ pac::dma_channels! { unsafe fn start_write_repeated(&mut self, request: Request, repeated: W, count: usize, reg_addr: *mut W) { let buf = [repeated]; - low_level_api::reset_status(crate::pac::$dma_peri, $channel_num); low_level_api::start_transfer( - crate::pac::$dma_peri, + pac::$dma_peri, $channel_num, #[cfg(any(bdma_v2, dmamux))] request, @@ -132,9 +130,8 @@ pac::dma_channels! { } unsafe fn start_read(&mut self, request: Request, reg_addr: *mut W, buf: &mut [W]) { - low_level_api::reset_status(crate::pac::$dma_peri, $channel_num); low_level_api::start_transfer( - crate::pac::$dma_peri, + pac::$dma_peri, $channel_num, #[cfg(any(bdma_v2, dmamux))] request, @@ -152,14 +149,14 @@ pac::dma_channels! { } fn request_stop(&mut self){ - unsafe {low_level_api::request_stop(crate::pac::$dma_peri, $channel_num);} + unsafe {low_level_api::request_stop(pac::$dma_peri, $channel_num);} } fn is_running(&self) -> bool { - unsafe {low_level_api::is_running(crate::pac::$dma_peri, $channel_num)} + unsafe {low_level_api::is_running(pac::$dma_peri, $channel_num)} } fn remaining_transfers(&mut self) -> u16 { - unsafe {low_level_api::get_remaining_transfers(crate::pac::$dma_peri, $channel_num)} + unsafe {low_level_api::get_remaining_transfers(pac::$dma_peri, $channel_num)} } fn set_waker(&mut self, waker: &Waker) { @@ -198,6 +195,8 @@ mod low_level_api { ) { let ch = dma.ch(channel_number as _); + reset_status(dma, channel_number); + #[cfg(dmamux)] super::super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 05d62ef8f..efe4d1d9d 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -85,17 +85,15 @@ pac::dma_channels! { ($channel_peri:ident, $dma_peri:ident, dma, $channel_num:expr, $dmamux:tt) => { impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri { unsafe fn start_write(&mut self, request: Request, buf: &[W], reg_addr: *mut W) { - let isrn = $channel_num as usize / 4; - let isrbit = $channel_num as usize % 4; - low_level_api::reset_status(&crate::pac::$dma_peri, isrn, isrbit); low_level_api::start_transfer( + pac::$dma_peri, + $channel_num, request, vals::Dir::MEMORYTOPERIPHERAL, reg_addr as *const u32, buf.as_ptr() as *mut u32, buf.len(), true, - crate::pac::$dma_peri.st($channel_num as _), vals::Size::from(W::bits()), #[cfg(dmamux)] ::DMAMUX_REGS, @@ -106,17 +104,15 @@ pac::dma_channels! { unsafe fn start_write_repeated(&mut self, request: Request, repeated: W, count: usize, reg_addr: *mut W) { let buf = [repeated]; - let isrn = $channel_num as usize / 4; - let isrbit = $channel_num as usize % 4; - low_level_api::reset_status(&crate::pac::$dma_peri, isrn, isrbit); low_level_api::start_transfer( + pac::$dma_peri, + $channel_num, request, vals::Dir::MEMORYTOPERIPHERAL, reg_addr as *const u32, buf.as_ptr() as *mut u32, count, false, - crate::pac::$dma_peri.st($channel_num as _), vals::Size::from(W::bits()), #[cfg(dmamux)] ::DMAMUX_REGS, @@ -126,17 +122,15 @@ pac::dma_channels! { } unsafe fn start_read(&mut self, request: Request, reg_addr: *mut W, buf: &mut [W]) { - let isrn = $channel_num as usize / 4; - let isrbit = $channel_num as usize % 4; - low_level_api::reset_status(&crate::pac::$dma_peri, isrn, isrbit); low_level_api::start_transfer( + pac::$dma_peri, + $channel_num, request, vals::Dir::PERIPHERALTOMEMORY, reg_addr as *const u32, buf.as_ptr() as *mut u32, buf.len(), true, - crate::pac::$dma_peri.st($channel_num as _), vals::Size::from(W::bits()), #[cfg(dmamux)] ::DMAMUX_REGS, @@ -146,15 +140,15 @@ pac::dma_channels! { } fn request_stop(&mut self) { - unsafe {low_level_api::request_stop(&crate::pac::$dma_peri, $channel_num);} + unsafe {low_level_api::request_stop(pac::$dma_peri, $channel_num);} } fn is_running(&self) -> bool { - unsafe {low_level_api::is_running(&crate::pac::$dma_peri, $channel_num)} + unsafe {low_level_api::is_running(pac::$dma_peri, $channel_num)} } fn remaining_transfers(&mut self) -> u16 { - unsafe {low_level_api::get_remaining_transfers(&crate::pac::$dma_peri, $channel_num)} + unsafe {low_level_api::get_remaining_transfers(pac::$dma_peri, $channel_num)} } fn set_waker(&mut self, waker: &Waker) { @@ -179,13 +173,14 @@ mod low_level_api { use super::*; pub unsafe fn start_transfer( + dma: pac::dma::Dma, + channel_number: u8, request: Request, dir: vals::Dir, peri_addr: *const u32, mem_addr: *mut u32, mem_len: usize, incr_mem: bool, - ch: crate::pac::dma::St, data_size: vals::Size, #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, #[cfg(dmamux)] dmamux_ch_num: u8, @@ -196,6 +191,9 @@ mod low_level_api { // "Preceding reads and writes cannot be moved past subsequent writes." fence(Ordering::SeqCst); + reset_status(dma, channel_number); + + let ch = dma.st(channel_number as _); ch.par().write_value(peri_addr as u32); ch.m0ar().write_value(mem_addr as u32); ch.ndtr().write_value(regs::Ndtr(mem_len as _)); @@ -223,34 +221,31 @@ mod low_level_api { } /// Stops the DMA channel. - pub unsafe fn request_stop(dma: &pac::dma::Dma, channel_number: u8) { - // Reset status - let isrn = channel_number as usize / 4; - let isrbit = channel_number as usize % 4; - reset_status(dma, isrn, isrbit); - + pub unsafe fn request_stop(dma: pac::dma::Dma, channel_number: u8) { // get a handle on the channel itself let ch = dma.st(channel_number as _); - // Disable the channel and interrupts with the default value. - ch.cr().write(|_| ()); + // Disable the channel. Keep the IEs enabled so the irqs still fire. + ch.cr().write(|w| { + w.set_teie(true); + w.set_tcie(true); + }); // "Subsequent reads and writes cannot be moved ahead of preceding reads." fence(Ordering::SeqCst); } /// Gets the running status of the channel - pub unsafe fn is_running(dma: &pac::dma::Dma, ch: u8) -> bool { + pub unsafe fn is_running(dma: pac::dma::Dma, ch: u8) -> bool { // get a handle on the channel itself let ch = dma.st(ch as _); - - // Wait for the transfer to complete when it was ongoing. + // Get whether it's enabled (running) ch.cr().read().en() } /// Gets the total remaining transfers for the channel /// Note: this will be zero for transfers that completed without cancellation. - pub unsafe fn get_remaining_transfers(dma: &pac::dma::Dma, ch: u8) -> u16 { + pub unsafe fn get_remaining_transfers(dma: pac::dma::Dma, ch: u8) -> u16 { // get a handle on the channel itself let ch = dma.st(ch as _); // read the remaining transfer count. If this is zero, the transfer completed fully. @@ -262,7 +257,10 @@ mod low_level_api { STATE.ch_wakers[state_number].register(waker); } - pub unsafe fn reset_status(dma: &crate::pac::dma::Dma, isrn: usize, isrbit: usize) { + pub unsafe fn reset_status(dma: pac::dma::Dma, channel_number: u8) { + let isrn = channel_number as usize / 4; + let isrbit = channel_number as usize % 4; + dma.ifcr(isrn).write(|w| { w.set_tcif(isrbit, true); w.set_teif(isrbit, true);