diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index ec5ac98a..754685c2 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -1,6 +1,6 @@ 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; @@ -61,14 +61,7 @@ pub(crate) unsafe fn do_transfer( let ch = dma.st(channel_number as _); 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)] @@ -125,6 +118,47 @@ pub(crate) unsafe fn do_transfer( } } +/// Stops the DMA channel. +unsafe fn _stop(dma: &pac::dma::Dma, ch: u8) { + // get a handle on the channel itself + let ch = dma.st(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); +} + +/// Gets the running status of the channel +unsafe fn _is_stopped(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. + 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::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. + ch.ndtr().read().ndt() +} + +/// Sets the waker for the specified DMA channel +unsafe fn _set_waker(dma: &pac::dma::Dma, state_number: u8, waker: &Waker){ + let n = state_number as usize; + STATE.ch_wakers[n].register(waker); + +} + + macro_rules! dma_num { (DMA1) => { 0 @@ -251,6 +285,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 )} + } } }; } diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 0ecd6d86..aa2da1fa 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -55,7 +55,7 @@ pub trait Channel: sealed::Channel { fn stop<'a>(&'a mut self); fn is_stopped<'a>(&self) -> bool; - fn remaining_transfers<'a>(&'a mut self) -> usize; + fn remaining_transfers<'a>(&'a mut self) -> u16; fn set_waker(&mut self, waker: &Waker); }