diff options
| -rw-r--r-- | embassy-stm32/src/dma/dma.rs | 64 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/mod.rs | 2 |
2 files changed, 56 insertions, 10 deletions
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index ec5ac98a0..754685c24 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | use core::future::Future; | 1 | use core::future::Future; |
| 2 | use core::sync::atomic::{fence, Ordering}; | 2 | use core::sync::atomic::{fence, Ordering}; |
| 3 | use core::task::Poll; | 3 | use core::task::{Poll, Waker}; |
| 4 | 4 | ||
| 5 | use embassy::interrupt::{Interrupt, InterruptExt}; | 5 | use embassy::interrupt::{Interrupt, InterruptExt}; |
| 6 | use embassy::waitqueue::AtomicWaker; | 6 | use embassy::waitqueue::AtomicWaker; |
| @@ -61,14 +61,7 @@ pub(crate) unsafe fn do_transfer( | |||
| 61 | let ch = dma.st(channel_number as _); | 61 | let ch = dma.st(channel_number as _); |
| 62 | 62 | ||
| 63 | let on_drop = OnDrop::new(move || unsafe { | 63 | let on_drop = OnDrop::new(move || unsafe { |
| 64 | // Disable the channel and interrupts with the default value. | 64 | _stop(&dma, channel_number); |
| 65 | ch.cr().write(|_| ()); | ||
| 66 | |||
| 67 | // Wait for the transfer to complete when it was ongoing. | ||
| 68 | while ch.cr().read().en() {} | ||
| 69 | |||
| 70 | // "Subsequent reads and writes cannot be moved ahead of preceding reads." | ||
| 71 | fence(Ordering::Acquire); | ||
| 72 | }); | 65 | }); |
| 73 | 66 | ||
| 74 | #[cfg(dmamux)] | 67 | #[cfg(dmamux)] |
| @@ -125,6 +118,47 @@ pub(crate) unsafe fn do_transfer( | |||
| 125 | } | 118 | } |
| 126 | } | 119 | } |
| 127 | 120 | ||
| 121 | /// Stops the DMA channel. | ||
| 122 | unsafe fn _stop(dma: &pac::dma::Dma, ch: u8) { | ||
| 123 | // get a handle on the channel itself | ||
| 124 | let ch = dma.st(ch as _); | ||
| 125 | |||
| 126 | // Disable the channel and interrupts with the default value. | ||
| 127 | ch.cr().write(|_| ()); | ||
| 128 | |||
| 129 | // Wait for the transfer to complete when it was ongoing. | ||
| 130 | while ch.cr().read().en() {} | ||
| 131 | |||
| 132 | // "Subsequent reads and writes cannot be moved ahead of preceding reads." | ||
| 133 | fence(Ordering::Acquire); | ||
| 134 | } | ||
| 135 | |||
| 136 | /// Gets the running status of the channel | ||
| 137 | unsafe fn _is_stopped(dma: &pac::dma::Dma, ch: u8) -> bool{ | ||
| 138 | // get a handle on the channel itself | ||
| 139 | let ch = dma.st(ch as _); | ||
| 140 | |||
| 141 | // Wait for the transfer to complete when it was ongoing. | ||
| 142 | ch.cr().read().en() | ||
| 143 | } | ||
| 144 | |||
| 145 | /// Gets the total remaining transfers for the channel | ||
| 146 | /// Note: this will be zero for transfers that completed without cancellation. | ||
| 147 | unsafe fn _get_remaining_transfers(dma: &pac::dma::Dma, ch: u8) -> u16{ | ||
| 148 | // get a handle on the channel itself | ||
| 149 | let ch = dma.st(ch as _); | ||
| 150 | // read the remaining transfer count. If this is zero, the transfer completed fully. | ||
| 151 | ch.ndtr().read().ndt() | ||
| 152 | } | ||
| 153 | |||
| 154 | /// Sets the waker for the specified DMA channel | ||
| 155 | unsafe fn _set_waker(dma: &pac::dma::Dma, state_number: u8, waker: &Waker){ | ||
| 156 | let n = state_number as usize; | ||
| 157 | STATE.ch_wakers[n].register(waker); | ||
| 158 | |||
| 159 | } | ||
| 160 | |||
| 161 | |||
| 128 | macro_rules! dma_num { | 162 | macro_rules! dma_num { |
| 129 | (DMA1) => { | 163 | (DMA1) => { |
| 130 | 0 | 164 | 0 |
| @@ -251,6 +285,18 @@ pac::dma_channels! { | |||
| 251 | ) | 285 | ) |
| 252 | } | 286 | } |
| 253 | } | 287 | } |
| 288 | fn stop <'a>(&'a mut self){ | ||
| 289 | unsafe {_stop(&crate::pac::$dma_peri, $channel_num);} | ||
| 290 | } | ||
| 291 | fn is_stopped<'a>(&'a self) -> bool { | ||
| 292 | unsafe {_is_stopped(&crate::pac::$dma_peri, $channel_num)} | ||
| 293 | } | ||
| 294 | fn remaining_transfers<'a>(&'a mut self) -> u16 { | ||
| 295 | unsafe {_get_remaining_transfers(&crate::pac::$dma_peri, $channel_num)} | ||
| 296 | } | ||
| 297 | fn set_waker<'a>(&'a mut self, waker: &'a Waker) { | ||
| 298 | unsafe {_set_waker(&crate::pac::$dma_peri, $channel_num, waker )} | ||
| 299 | } | ||
| 254 | } | 300 | } |
| 255 | }; | 301 | }; |
| 256 | } | 302 | } |
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 0ecd6d864..aa2da1fa9 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs | |||
| @@ -55,7 +55,7 @@ pub trait Channel: sealed::Channel { | |||
| 55 | fn stop<'a>(&'a mut self); | 55 | fn stop<'a>(&'a mut self); |
| 56 | 56 | ||
| 57 | fn is_stopped<'a>(&self) -> bool; | 57 | fn is_stopped<'a>(&self) -> bool; |
| 58 | fn remaining_transfers<'a>(&'a mut self) -> usize; | 58 | fn remaining_transfers<'a>(&'a mut self) -> u16; |
| 59 | fn set_waker(&mut self, waker: &Waker); | 59 | fn set_waker(&mut self, waker: &Waker); |
| 60 | } | 60 | } |
| 61 | 61 | ||
