diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 35c0b3ee..d6941f33 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -2,7 +2,7 @@ use core::future::Future; use core::sync::atomic::{fence, Ordering}; -use core::task::Poll; +use core::task::{Poll, Waker}; use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::waitqueue::AtomicWaker; @@ -58,14 +58,7 @@ pub(crate) unsafe fn do_transfer( }); let on_drop = OnDrop::new(move || unsafe { - // Disable the channel and interrupts with the default value. - ch.cr().write(|_| ()); - - // Wait for the transfer to complete when it was ongoing. - while ch.cr().read().en() {} - - // "Subsequent reads and writes cannot be moved ahead of preceding reads." - fence(Ordering::Acquire); + _stop(dma , channel_number); }); #[cfg(dmamux)] @@ -118,6 +111,40 @@ pub(crate) unsafe fn do_transfer( } } +unsafe fn _stop(dma:pac::bdma::Dma, ch: u8) { + let ch = dma.ch(ch as _); + + // Disable the channel and interrupts with the default value. + ch.cr().write(|_| ()); + + // Wait for the transfer to complete when it was ongoing. + while ch.cr().read().en() {} + + // "Subsequent reads and writes cannot be moved ahead of preceding reads." + fence(Ordering::Acquire); +} + +unsafe fn _is_stopped(dma:pac::bdma::Dma, ch: u8) -> bool { + let ch = dma.ch(ch as _); + ch.cr().read().en() +} + +/// Gets the total remaining transfers for the channel +/// Note: this will be zero for transfers that completed without cancellation. +unsafe fn _get_remaining_transfers(dma: pac::bdma::Dma, ch: u8) -> u16{ + // get a handle on the channel itself + let ch = dma.ch(ch as _); + // read the remaining transfer count. If this is zero, the transfer completed fully. + ch.ndtr().read().ndt() +} + +/// Sets the waker for the specified DMA channel +unsafe fn _set_waker(dma: pac::bdma::Dma, state_number: u8, waker: &Waker){ + let n = state_number as usize; + STATE.ch_wakers[n].register(waker); + +} + macro_rules! dma_num { (DMA1) => { 0 @@ -245,6 +272,18 @@ pac::dma_channels! { ) } } + fn stop <'a>(&'a mut self){ + unsafe {_stop(crate::pac::$dma_peri, $channel_num);} + } + fn is_stopped<'a>(&'a self) -> bool { + unsafe {_is_stopped(crate::pac::$dma_peri, $channel_num)} + } + fn remaining_transfers<'a>(&'a mut self) -> u16 { + unsafe {_get_remaining_transfers(crate::pac::$dma_peri, $channel_num)} + } + fn set_waker<'a>(&'a mut self, waker: &'a Waker) { + unsafe {_set_waker(crate::pac::$dma_peri, $channel_num, waker )} + } } }; }