diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-12-08 02:30:46 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-12-08 02:30:46 +0000 |
| commit | b0da4dfa8c6613bc19980cd41e72ef9b410fce53 (patch) | |
| tree | bfe026c366953c48bc15f130ae1940fd5875af63 | |
| parent | 6081b36356878f969457c80b6069f7fefcde6a29 (diff) | |
| parent | 022c4cb7397e690080edc06e2b7d4dc8e19ccb0b (diff) | |
Merge #500
500: Low level DMA channel API. r=Dirbaio a=matoushybl
This should be an improved version of the PR by `@theunkn0wn1.`
Co-authored-by: Joshua Salzedo <[email protected]>
Co-authored-by: Matous Hybl <[email protected]>
Co-authored-by: Dario Nieuwenhuis <[email protected]>
| -rw-r--r-- | embassy-stm32/src/dma/bdma.rs | 344 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/dma.rs | 354 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/mod.rs | 198 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v2.rs | 6 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/v1.rs | 27 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/v2.rs | 27 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/v3.rs | 27 | ||||
| -rw-r--r-- | embassy-stm32/src/usart/v1.rs | 6 | ||||
| -rw-r--r-- | embassy-stm32/src/usart/v2.rs | 7 |
9 files changed, 593 insertions, 403 deletions
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 35c0b3ee7..b4c77757e 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs | |||
| @@ -1,20 +1,29 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | use core::future::Future; | ||
| 4 | use core::sync::atomic::{fence, Ordering}; | 3 | use core::sync::atomic::{fence, Ordering}; |
| 5 | use core::task::Poll; | 4 | use core::task::Waker; |
| 6 | 5 | ||
| 7 | use embassy::interrupt::{Interrupt, InterruptExt}; | 6 | use embassy::interrupt::{Interrupt, InterruptExt}; |
| 8 | use embassy::waitqueue::AtomicWaker; | 7 | use embassy::waitqueue::AtomicWaker; |
| 9 | use embassy_hal_common::drop::OnDrop; | ||
| 10 | use futures::future::poll_fn; | ||
| 11 | 8 | ||
| 12 | use crate::dma::{Channel, Request}; | 9 | use crate::dma::Request; |
| 13 | use crate::interrupt; | 10 | use crate::interrupt; |
| 14 | use crate::pac; | 11 | use crate::pac; |
| 15 | use crate::pac::bdma::vals; | 12 | use crate::pac::bdma::vals; |
| 16 | use crate::rcc::sealed::RccPeripheral; | 13 | use crate::rcc::sealed::RccPeripheral; |
| 17 | 14 | ||
| 15 | use super::{Word, WordSize}; | ||
| 16 | |||
| 17 | impl From<WordSize> for vals::Size { | ||
| 18 | fn from(raw: WordSize) -> Self { | ||
| 19 | match raw { | ||
| 20 | WordSize::OneByte => Self::BITS8, | ||
| 21 | WordSize::TwoBytes => Self::BITS16, | ||
| 22 | WordSize::FourBytes => Self::BITS32, | ||
| 23 | } | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 18 | const CH_COUNT: usize = pac::peripheral_count!(bdma) * 8; | 27 | const CH_COUNT: usize = pac::peripheral_count!(bdma) * 8; |
| 19 | 28 | ||
| 20 | struct State { | 29 | struct State { |
| @@ -32,92 +41,6 @@ impl State { | |||
| 32 | 41 | ||
| 33 | static STATE: State = State::new(); | 42 | static STATE: State = State::new(); |
| 34 | 43 | ||
| 35 | #[allow(unused)] | ||
| 36 | pub(crate) unsafe fn do_transfer( | ||
| 37 | dma: pac::bdma::Dma, | ||
| 38 | channel_number: u8, | ||
| 39 | state_number: u8, | ||
| 40 | request: Request, | ||
| 41 | dir: vals::Dir, | ||
| 42 | peri_addr: *const u8, | ||
| 43 | mem_addr: *mut u8, | ||
| 44 | mem_len: usize, | ||
| 45 | incr_mem: bool, | ||
| 46 | #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, | ||
| 47 | #[cfg(dmamux)] dmamux_ch_num: u8, | ||
| 48 | ) -> impl Future<Output = ()> { | ||
| 49 | // ndtr is max 16 bits. | ||
| 50 | assert!(mem_len <= 0xFFFF); | ||
| 51 | |||
| 52 | let ch = dma.ch(channel_number as _); | ||
| 53 | |||
| 54 | // Reset status | ||
| 55 | dma.ifcr().write(|w| { | ||
| 56 | w.set_tcif(channel_number as _, true); | ||
| 57 | w.set_teif(channel_number as _, true); | ||
| 58 | }); | ||
| 59 | |||
| 60 | let on_drop = OnDrop::new(move || unsafe { | ||
| 61 | // Disable the channel and interrupts with the default value. | ||
| 62 | ch.cr().write(|_| ()); | ||
| 63 | |||
| 64 | // Wait for the transfer to complete when it was ongoing. | ||
| 65 | while ch.cr().read().en() {} | ||
| 66 | |||
| 67 | // "Subsequent reads and writes cannot be moved ahead of preceding reads." | ||
| 68 | fence(Ordering::Acquire); | ||
| 69 | }); | ||
| 70 | |||
| 71 | #[cfg(dmamux)] | ||
| 72 | super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); | ||
| 73 | |||
| 74 | #[cfg(bdma_v2)] | ||
| 75 | critical_section::with(|_| { | ||
| 76 | dma.cselr() | ||
| 77 | .modify(|w| w.set_cs(channel_number as _, request)) | ||
| 78 | }); | ||
| 79 | |||
| 80 | // "Preceding reads and writes cannot be moved past subsequent writes." | ||
| 81 | fence(Ordering::Release); | ||
| 82 | |||
| 83 | ch.par().write_value(peri_addr as u32); | ||
| 84 | ch.mar().write_value(mem_addr as u32); | ||
| 85 | ch.ndtr().write(|w| w.set_ndt(mem_len as u16)); | ||
| 86 | ch.cr().write(|w| { | ||
| 87 | w.set_psize(vals::Size::BITS8); | ||
| 88 | w.set_msize(vals::Size::BITS8); | ||
| 89 | if incr_mem { | ||
| 90 | w.set_minc(vals::Inc::ENABLED); | ||
| 91 | } else { | ||
| 92 | w.set_minc(vals::Inc::DISABLED); | ||
| 93 | } | ||
| 94 | w.set_dir(dir); | ||
| 95 | w.set_teie(true); | ||
| 96 | w.set_tcie(true); | ||
| 97 | w.set_en(true); | ||
| 98 | }); | ||
| 99 | |||
| 100 | async move { | ||
| 101 | let res = poll_fn(|cx| { | ||
| 102 | STATE.ch_wakers[state_number as usize].register(cx.waker()); | ||
| 103 | |||
| 104 | let isr = dma.isr().read(); | ||
| 105 | |||
| 106 | // TODO handle error | ||
| 107 | assert!(!isr.teif(channel_number as _)); | ||
| 108 | |||
| 109 | if isr.tcif(channel_number as _) { | ||
| 110 | Poll::Ready(()) | ||
| 111 | } else { | ||
| 112 | Poll::Pending | ||
| 113 | } | ||
| 114 | }) | ||
| 115 | .await; | ||
| 116 | |||
| 117 | drop(on_drop) | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | macro_rules! dma_num { | 44 | macro_rules! dma_num { |
| 122 | (DMA1) => { | 45 | (DMA1) => { |
| 123 | 0 | 46 | 0 |
| @@ -136,7 +59,7 @@ unsafe fn on_irq() { | |||
| 136 | let isr = pac::$dma.isr().read(); | 59 | let isr = pac::$dma.isr().read(); |
| 137 | let dman = dma_num!($dma); | 60 | let dman = dma_num!($dma); |
| 138 | 61 | ||
| 139 | for chn in 0..crate::pac::dma_channels_count!($dma) { | 62 | for chn in 0..pac::dma_channels_count!($dma) { |
| 140 | let cr = pac::$dma.ch(chn).cr(); | 63 | let cr = pac::$dma.ch(chn).cr(); |
| 141 | if isr.tcif(chn) && cr.read().tcie() { | 64 | if isr.tcif(chn) && cr.read().tcie() { |
| 142 | cr.write(|_| ()); // Disable channel interrupts with the default value. | 65 | cr.write(|_| ()); // Disable channel interrupts with the default value. |
| @@ -164,88 +87,84 @@ pub(crate) unsafe fn init() { | |||
| 164 | 87 | ||
| 165 | pac::dma_channels! { | 88 | pac::dma_channels! { |
| 166 | ($channel_peri:ident, $dma_peri:ident, bdma, $channel_num:expr, $dmamux:tt) => { | 89 | ($channel_peri:ident, $dma_peri:ident, bdma, $channel_num:expr, $dmamux:tt) => { |
| 167 | impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {} | 90 | impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri { |
| 168 | impl Channel for crate::peripherals::$channel_peri | 91 | |
| 169 | { | 92 | unsafe fn start_write<W: Word>(&mut self, request: Request, buf: &[W], reg_addr: *mut W) { |
| 170 | type ReadFuture<'a> = impl Future<Output = ()> + 'a; | 93 | low_level_api::start_transfer( |
| 171 | type WriteFuture<'a> = impl Future<Output = ()> + 'a; | 94 | pac::$dma_peri, |
| 172 | 95 | $channel_num, | |
| 173 | fn read<'a>( | 96 | #[cfg(any(bdma_v2, dmamux))] |
| 174 | &'a mut self, | 97 | request, |
| 175 | request: Request, | 98 | vals::Dir::FROMMEMORY, |
| 176 | src: *mut u8, | 99 | reg_addr as *const u32, |
| 177 | buf: &'a mut [u8], | 100 | buf.as_ptr() as *mut u32, |
| 178 | ) -> Self::ReadFuture<'a> { | 101 | buf.len(), |
| 179 | unsafe { | 102 | true, |
| 180 | do_transfer( | 103 | vals::Size::from(W::bits()), |
| 181 | crate::pac::$dma_peri, | 104 | #[cfg(dmamux)] |
| 182 | $channel_num, | 105 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, |
| 183 | (dma_num!($dma_peri) * 8) + $channel_num, | 106 | #[cfg(dmamux)] |
| 184 | request, | 107 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, |
| 185 | vals::Dir::FROMPERIPHERAL, | 108 | ); |
| 186 | src, | ||
| 187 | buf.as_mut_ptr(), | ||
| 188 | buf.len(), | ||
| 189 | true, | ||
| 190 | #[cfg(dmamux)] | ||
| 191 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, | ||
| 192 | #[cfg(dmamux)] | ||
| 193 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, | ||
| 194 | ) | ||
| 195 | } | ||
| 196 | } | 109 | } |
| 197 | 110 | ||
| 198 | fn write<'a>( | 111 | |
| 199 | &'a mut self, | 112 | unsafe fn start_write_repeated<W: Word>(&mut self, request: Request, repeated: W, count: usize, reg_addr: *mut W) { |
| 200 | request: Request, | 113 | let buf = [repeated]; |
| 201 | buf: &'a [u8], | 114 | low_level_api::start_transfer( |
| 202 | dst: *mut u8, | 115 | pac::$dma_peri, |
| 203 | ) -> Self::WriteFuture<'a> { | 116 | $channel_num, |
| 204 | unsafe { | 117 | #[cfg(any(bdma_v2, dmamux))] |
| 205 | do_transfer( | 118 | request, |
| 206 | crate::pac::$dma_peri, | 119 | vals::Dir::FROMMEMORY, |
| 207 | $channel_num, | 120 | reg_addr as *const u32, |
| 208 | (dma_num!($dma_peri) * 8) + $channel_num, | 121 | buf.as_ptr() as *mut u32, |
| 209 | request, | 122 | count, |
| 210 | vals::Dir::FROMMEMORY, | 123 | false, |
| 211 | dst, | 124 | vals::Size::from(W::bits()), |
| 212 | buf.as_ptr() as *mut u8, | 125 | #[cfg(dmamux)] |
| 213 | buf.len(), | 126 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, |
| 214 | true, | 127 | #[cfg(dmamux)] |
| 215 | #[cfg(dmamux)] | 128 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, |
| 216 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, | 129 | ) |
| 217 | #[cfg(dmamux)] | ||
| 218 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, | ||
| 219 | ) | ||
| 220 | } | ||
| 221 | } | 130 | } |
| 222 | 131 | ||
| 223 | fn write_x<'a>( | 132 | unsafe fn start_read<W: Word>(&mut self, request: Request, reg_addr: *mut W, buf: &mut [W]) { |
| 224 | &'a mut self, | 133 | low_level_api::start_transfer( |
| 225 | request: Request, | 134 | pac::$dma_peri, |
| 226 | word: &u8, | 135 | $channel_num, |
| 227 | count: usize, | 136 | #[cfg(any(bdma_v2, dmamux))] |
| 228 | dst: *mut u8, | 137 | request, |
| 229 | ) -> Self::WriteFuture<'a> { | 138 | vals::Dir::FROMPERIPHERAL, |
| 230 | unsafe { | 139 | reg_addr as *const u32, |
| 231 | do_transfer( | 140 | buf.as_ptr() as *mut u32, |
| 232 | crate::pac::$dma_peri, | 141 | buf.len(), |
| 233 | $channel_num, | 142 | true, |
| 234 | (dma_num!($dma_peri) * 8) + $channel_num, | 143 | vals::Size::from(W::bits()), |
| 235 | request, | 144 | #[cfg(dmamux)] |
| 236 | vals::Dir::FROMMEMORY, | 145 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, |
| 237 | dst, | 146 | #[cfg(dmamux)] |
| 238 | word as *const u8 as *mut u8, | 147 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, |
| 239 | count, | 148 | ); |
| 240 | false, | 149 | } |
| 241 | #[cfg(dmamux)] | 150 | |
| 242 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, | 151 | fn request_stop(&mut self){ |
| 243 | #[cfg(dmamux)] | 152 | unsafe {low_level_api::request_stop(pac::$dma_peri, $channel_num);} |
| 244 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, | 153 | } |
| 245 | ) | 154 | |
| 246 | } | 155 | fn is_running(&self) -> bool { |
| 156 | unsafe {low_level_api::is_running(pac::$dma_peri, $channel_num)} | ||
| 157 | } | ||
| 158 | fn remaining_transfers(&mut self) -> u16 { | ||
| 159 | unsafe {low_level_api::get_remaining_transfers(pac::$dma_peri, $channel_num)} | ||
| 160 | } | ||
| 161 | |||
| 162 | fn set_waker(&mut self, waker: &Waker) { | ||
| 163 | unsafe {low_level_api::set_waker(dma_num!($dma_peri) * 8 + $channel_num, waker )} | ||
| 247 | } | 164 | } |
| 248 | } | 165 | } |
| 166 | |||
| 167 | impl crate::dma::Channel for crate::peripherals::$channel_peri {} | ||
| 249 | }; | 168 | }; |
| 250 | } | 169 | } |
| 251 | 170 | ||
| @@ -257,3 +176,92 @@ pac::interrupts! { | |||
| 257 | } | 176 | } |
| 258 | }; | 177 | }; |
| 259 | } | 178 | } |
| 179 | |||
| 180 | mod low_level_api { | ||
| 181 | use super::*; | ||
| 182 | |||
| 183 | pub unsafe fn start_transfer( | ||
| 184 | dma: pac::bdma::Dma, | ||
| 185 | channel_number: u8, | ||
| 186 | #[cfg(any(bdma_v2, dmamux))] request: Request, | ||
| 187 | dir: vals::Dir, | ||
| 188 | peri_addr: *const u32, | ||
| 189 | mem_addr: *mut u32, | ||
| 190 | mem_len: usize, | ||
| 191 | incr_mem: bool, | ||
| 192 | data_size: vals::Size, | ||
| 193 | #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, | ||
| 194 | #[cfg(dmamux)] dmamux_ch_num: u8, | ||
| 195 | ) { | ||
| 196 | let ch = dma.ch(channel_number as _); | ||
| 197 | |||
| 198 | reset_status(dma, channel_number); | ||
| 199 | |||
| 200 | #[cfg(dmamux)] | ||
| 201 | super::super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); | ||
| 202 | |||
| 203 | #[cfg(bdma_v2)] | ||
| 204 | critical_section::with(|_| { | ||
| 205 | dma.cselr() | ||
| 206 | .modify(|w| w.set_cs(channel_number as _, request)) | ||
| 207 | }); | ||
| 208 | |||
| 209 | // "Preceding reads and writes cannot be moved past subsequent writes." | ||
| 210 | fence(Ordering::SeqCst); | ||
| 211 | |||
| 212 | ch.par().write_value(peri_addr as u32); | ||
| 213 | ch.mar().write_value(mem_addr as u32); | ||
| 214 | ch.ndtr().write(|w| w.set_ndt(mem_len as u16)); | ||
| 215 | ch.cr().write(|w| { | ||
| 216 | w.set_psize(data_size); | ||
| 217 | w.set_msize(data_size); | ||
| 218 | if incr_mem { | ||
| 219 | w.set_minc(vals::Inc::ENABLED); | ||
| 220 | } else { | ||
| 221 | w.set_minc(vals::Inc::DISABLED); | ||
| 222 | } | ||
| 223 | w.set_dir(dir); | ||
| 224 | w.set_teie(true); | ||
| 225 | w.set_tcie(true); | ||
| 226 | w.set_en(true); | ||
| 227 | }); | ||
| 228 | } | ||
| 229 | |||
| 230 | pub unsafe fn request_stop(dma: pac::bdma::Dma, channel_number: u8) { | ||
| 231 | reset_status(dma, channel_number); | ||
| 232 | |||
| 233 | let ch = dma.ch(channel_number as _); | ||
| 234 | |||
| 235 | // Disable the channel and interrupts with the default value. | ||
| 236 | ch.cr().write(|_| ()); | ||
| 237 | |||
| 238 | // "Subsequent reads and writes cannot be moved ahead of preceding reads." | ||
| 239 | fence(Ordering::SeqCst); | ||
| 240 | } | ||
| 241 | |||
| 242 | pub unsafe fn is_running(dma: pac::bdma::Dma, ch: u8) -> bool { | ||
| 243 | let ch = dma.ch(ch as _); | ||
| 244 | ch.cr().read().en() | ||
| 245 | } | ||
| 246 | |||
| 247 | /// Gets the total remaining transfers for the channel | ||
| 248 | /// Note: this will be zero for transfers that completed without cancellation. | ||
| 249 | pub unsafe fn get_remaining_transfers(dma: pac::bdma::Dma, ch: u8) -> u16 { | ||
| 250 | // get a handle on the channel itself | ||
| 251 | let ch = dma.ch(ch as _); | ||
| 252 | // read the remaining transfer count. If this is zero, the transfer completed fully. | ||
| 253 | ch.ndtr().read().ndt() | ||
| 254 | } | ||
| 255 | |||
| 256 | /// Sets the waker for the specified DMA channel | ||
| 257 | pub unsafe fn set_waker(state_number: usize, waker: &Waker) { | ||
| 258 | STATE.ch_wakers[state_number].register(waker); | ||
| 259 | } | ||
| 260 | |||
| 261 | pub unsafe fn reset_status(dma: pac::bdma::Dma, channel_number: u8) { | ||
| 262 | dma.ifcr().write(|w| { | ||
| 263 | w.set_tcif(channel_number as _, true); | ||
| 264 | w.set_teif(channel_number as _, true); | ||
| 265 | }); | ||
| 266 | } | ||
| 267 | } | ||
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index ec5ac98a0..efe4d1d9d 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs | |||
| @@ -1,21 +1,28 @@ | |||
| 1 | use core::future::Future; | ||
| 2 | use core::sync::atomic::{fence, Ordering}; | 1 | use core::sync::atomic::{fence, Ordering}; |
| 3 | use core::task::Poll; | 2 | use core::task::Waker; |
| 4 | 3 | ||
| 5 | use embassy::interrupt::{Interrupt, InterruptExt}; | 4 | use embassy::interrupt::{Interrupt, InterruptExt}; |
| 6 | use embassy::waitqueue::AtomicWaker; | 5 | use embassy::waitqueue::AtomicWaker; |
| 7 | use embassy_hal_common::drop::OnDrop; | ||
| 8 | use futures::future::poll_fn; | ||
| 9 | 6 | ||
| 10 | use crate::interrupt; | 7 | use crate::interrupt; |
| 11 | use crate::pac; | 8 | use crate::pac; |
| 12 | use crate::pac::dma::{regs, vals}; | 9 | use crate::pac::dma::{regs, vals}; |
| 13 | use crate::rcc::sealed::RccPeripheral; | 10 | use crate::rcc::sealed::RccPeripheral; |
| 14 | 11 | ||
| 15 | use super::{Channel, Request}; | 12 | use super::{Request, Word, WordSize}; |
| 16 | 13 | ||
| 17 | const CH_COUNT: usize = pac::peripheral_count!(DMA) * 8; | 14 | const CH_COUNT: usize = pac::peripheral_count!(DMA) * 8; |
| 18 | 15 | ||
| 16 | impl From<WordSize> for vals::Size { | ||
| 17 | fn from(raw: WordSize) -> Self { | ||
| 18 | match raw { | ||
| 19 | WordSize::OneByte => Self::BITS8, | ||
| 20 | WordSize::TwoBytes => Self::BITS16, | ||
| 21 | WordSize::FourBytes => Self::BITS32, | ||
| 22 | } | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 19 | struct State { | 26 | struct State { |
| 20 | ch_wakers: [AtomicWaker; CH_COUNT], | 27 | ch_wakers: [AtomicWaker; CH_COUNT], |
| 21 | } | 28 | } |
| @@ -31,100 +38,6 @@ impl State { | |||
| 31 | 38 | ||
| 32 | static STATE: State = State::new(); | 39 | static STATE: State = State::new(); |
| 33 | 40 | ||
| 34 | //async unsafe fn do_transfer(ch: &mut impl Channel, ch_func: u8, src: *const u8, dst: &mut [u8]) { | ||
| 35 | |||
| 36 | #[allow(unused)] | ||
| 37 | pub(crate) unsafe fn do_transfer( | ||
| 38 | dma: pac::dma::Dma, | ||
| 39 | channel_number: u8, | ||
| 40 | state_number: u8, | ||
| 41 | request: Request, | ||
| 42 | dir: vals::Dir, | ||
| 43 | peri_addr: *const u8, | ||
| 44 | mem_addr: *mut u8, | ||
| 45 | mem_len: usize, | ||
| 46 | incr_mem: bool, | ||
| 47 | #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, | ||
| 48 | #[cfg(dmamux)] dmamux_ch_num: u8, | ||
| 49 | ) -> impl Future<Output = ()> { | ||
| 50 | // ndtr is max 16 bits. | ||
| 51 | assert!(mem_len <= 0xFFFF); | ||
| 52 | |||
| 53 | // Reset status | ||
| 54 | let isrn = channel_number as usize / 4; | ||
| 55 | let isrbit = channel_number as usize % 4; | ||
| 56 | dma.ifcr(isrn).write(|w| { | ||
| 57 | w.set_tcif(isrbit, true); | ||
| 58 | w.set_teif(isrbit, true); | ||
| 59 | }); | ||
| 60 | |||
| 61 | let ch = dma.st(channel_number as _); | ||
| 62 | |||
| 63 | let on_drop = OnDrop::new(move || unsafe { | ||
| 64 | // Disable the channel and interrupts with the default value. | ||
| 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 | }); | ||
| 73 | |||
| 74 | #[cfg(dmamux)] | ||
| 75 | super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); | ||
| 76 | |||
| 77 | // "Preceding reads and writes cannot be moved past subsequent writes." | ||
| 78 | fence(Ordering::Release); | ||
| 79 | |||
| 80 | unsafe { | ||
| 81 | ch.par().write_value(peri_addr as u32); | ||
| 82 | ch.m0ar().write_value(mem_addr as u32); | ||
| 83 | ch.ndtr().write_value(regs::Ndtr(mem_len as _)); | ||
| 84 | ch.cr().write(|w| { | ||
| 85 | w.set_dir(dir); | ||
| 86 | w.set_msize(vals::Size::BITS8); | ||
| 87 | w.set_psize(vals::Size::BITS8); | ||
| 88 | if incr_mem { | ||
| 89 | w.set_minc(vals::Inc::INCREMENTED); | ||
| 90 | } else { | ||
| 91 | w.set_minc(vals::Inc::FIXED); | ||
| 92 | } | ||
| 93 | w.set_pinc(vals::Inc::FIXED); | ||
| 94 | w.set_teie(true); | ||
| 95 | w.set_tcie(true); | ||
| 96 | #[cfg(dma_v1)] | ||
| 97 | w.set_trbuff(true); | ||
| 98 | |||
| 99 | #[cfg(dma_v2)] | ||
| 100 | w.set_chsel(request); | ||
| 101 | |||
| 102 | w.set_en(true); | ||
| 103 | }); | ||
| 104 | } | ||
| 105 | |||
| 106 | async move { | ||
| 107 | let res = poll_fn(|cx| { | ||
| 108 | let n = state_number as usize; | ||
| 109 | STATE.ch_wakers[n].register(cx.waker()); | ||
| 110 | |||
| 111 | let isr = dma.isr(isrn).read(); | ||
| 112 | |||
| 113 | // TODO handle error | ||
| 114 | assert!(!isr.teif(isrbit)); | ||
| 115 | |||
| 116 | if isr.tcif(isrbit) { | ||
| 117 | Poll::Ready(()) | ||
| 118 | } else { | ||
| 119 | Poll::Pending | ||
| 120 | } | ||
| 121 | }) | ||
| 122 | .await; | ||
| 123 | |||
| 124 | drop(on_drop) | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | macro_rules! dma_num { | 41 | macro_rules! dma_num { |
| 129 | (DMA1) => { | 42 | (DMA1) => { |
| 130 | 0 | 43 | 0 |
| @@ -170,88 +83,80 @@ pub(crate) unsafe fn init() { | |||
| 170 | 83 | ||
| 171 | pac::dma_channels! { | 84 | pac::dma_channels! { |
| 172 | ($channel_peri:ident, $dma_peri:ident, dma, $channel_num:expr, $dmamux:tt) => { | 85 | ($channel_peri:ident, $dma_peri:ident, dma, $channel_num:expr, $dmamux:tt) => { |
| 173 | impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {} | 86 | impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri { |
| 174 | impl Channel for crate::peripherals::$channel_peri | 87 | unsafe fn start_write<W: Word>(&mut self, request: Request, buf: &[W], reg_addr: *mut W) { |
| 175 | { | 88 | low_level_api::start_transfer( |
| 176 | type ReadFuture<'a> = impl Future<Output = ()> + 'a; | 89 | pac::$dma_peri, |
| 177 | type WriteFuture<'a> = impl Future<Output = ()> + 'a; | 90 | $channel_num, |
| 178 | 91 | request, | |
| 179 | fn read<'a>( | 92 | vals::Dir::MEMORYTOPERIPHERAL, |
| 180 | &'a mut self, | 93 | reg_addr as *const u32, |
| 181 | request: Request, | 94 | buf.as_ptr() as *mut u32, |
| 182 | src: *mut u8, | 95 | buf.len(), |
| 183 | buf: &'a mut [u8], | 96 | true, |
| 184 | ) -> Self::ReadFuture<'a> { | 97 | vals::Size::from(W::bits()), |
| 185 | unsafe { | 98 | #[cfg(dmamux)] |
| 186 | do_transfer( | 99 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, |
| 187 | crate::pac::$dma_peri, | 100 | #[cfg(dmamux)] |
| 188 | $channel_num, | 101 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, |
| 189 | (dma_num!($dma_peri) * 8) + $channel_num, | 102 | ) |
| 190 | request, | ||
| 191 | vals::Dir::PERIPHERALTOMEMORY, | ||
| 192 | src, | ||
| 193 | buf.as_mut_ptr(), | ||
| 194 | buf.len(), | ||
| 195 | true, | ||
| 196 | #[cfg(dmamux)] | ||
| 197 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, | ||
| 198 | #[cfg(dmamux)] | ||
| 199 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, | ||
| 200 | ) | ||
| 201 | } | ||
| 202 | } | 103 | } |
| 203 | 104 | ||
| 204 | fn write<'a>( | 105 | unsafe fn start_write_repeated<W: Word>(&mut self, request: Request, repeated: W, count: usize, reg_addr: *mut W) { |
| 205 | &'a mut self, | 106 | let buf = [repeated]; |
| 206 | request: Request, | 107 | low_level_api::start_transfer( |
| 207 | buf: &'a [u8], | 108 | pac::$dma_peri, |
| 208 | dst: *mut u8, | 109 | $channel_num, |
| 209 | ) -> Self::WriteFuture<'a> { | 110 | request, |
| 210 | unsafe { | 111 | vals::Dir::MEMORYTOPERIPHERAL, |
| 211 | do_transfer( | 112 | reg_addr as *const u32, |
| 212 | crate::pac::$dma_peri, | 113 | buf.as_ptr() as *mut u32, |
| 213 | $channel_num, | 114 | count, |
| 214 | (dma_num!($dma_peri) * 8) + $channel_num, | 115 | false, |
| 215 | request, | 116 | vals::Size::from(W::bits()), |
| 216 | vals::Dir::MEMORYTOPERIPHERAL, | 117 | #[cfg(dmamux)] |
| 217 | dst, | 118 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, |
| 218 | buf.as_ptr() as *mut u8, | 119 | #[cfg(dmamux)] |
| 219 | buf.len(), | 120 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, |
| 220 | true, | 121 | ) |
| 221 | #[cfg(dmamux)] | ||
| 222 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, | ||
| 223 | #[cfg(dmamux)] | ||
| 224 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, | ||
| 225 | ) | ||
| 226 | } | ||
| 227 | } | 122 | } |
| 228 | 123 | ||
| 229 | fn write_x<'a>( | 124 | unsafe fn start_read<W: Word>(&mut self, request: Request, reg_addr: *mut W, buf: &mut [W]) { |
| 230 | &'a mut self, | 125 | low_level_api::start_transfer( |
| 231 | request: Request, | 126 | pac::$dma_peri, |
| 232 | word: &u8, | 127 | $channel_num, |
| 233 | num: usize, | 128 | request, |
| 234 | dst: *mut u8, | 129 | vals::Dir::PERIPHERALTOMEMORY, |
| 235 | ) -> Self::WriteFuture<'a> { | 130 | reg_addr as *const u32, |
| 236 | unsafe { | 131 | buf.as_ptr() as *mut u32, |
| 237 | do_transfer( | 132 | buf.len(), |
| 238 | crate::pac::$dma_peri, | 133 | true, |
| 239 | $channel_num, | 134 | vals::Size::from(W::bits()), |
| 240 | (dma_num!($dma_peri) * 8) + $channel_num, | 135 | #[cfg(dmamux)] |
| 241 | request, | 136 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, |
| 242 | vals::Dir::MEMORYTOPERIPHERAL, | 137 | #[cfg(dmamux)] |
| 243 | dst, | 138 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, |
| 244 | word as *const u8 as *mut u8, | 139 | ); |
| 245 | num, | 140 | } |
| 246 | false, | 141 | |
| 247 | #[cfg(dmamux)] | 142 | fn request_stop(&mut self) { |
| 248 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, | 143 | unsafe {low_level_api::request_stop(pac::$dma_peri, $channel_num);} |
| 249 | #[cfg(dmamux)] | 144 | } |
| 250 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, | 145 | |
| 251 | ) | 146 | fn is_running(&self) -> bool { |
| 252 | } | 147 | unsafe {low_level_api::is_running(pac::$dma_peri, $channel_num)} |
| 148 | } | ||
| 149 | |||
| 150 | fn remaining_transfers(&mut self) -> u16 { | ||
| 151 | unsafe {low_level_api::get_remaining_transfers(pac::$dma_peri, $channel_num)} | ||
| 152 | } | ||
| 153 | |||
| 154 | fn set_waker(&mut self, waker: &Waker) { | ||
| 155 | unsafe {low_level_api::set_waker(dma_num!($dma_peri) * 8 + $channel_num, waker )} | ||
| 253 | } | 156 | } |
| 254 | } | 157 | } |
| 158 | |||
| 159 | impl crate::dma::Channel for crate::peripherals::$channel_peri { } | ||
| 255 | }; | 160 | }; |
| 256 | } | 161 | } |
| 257 | 162 | ||
| @@ -263,3 +168,102 @@ pac::interrupts! { | |||
| 263 | } | 168 | } |
| 264 | }; | 169 | }; |
| 265 | } | 170 | } |
| 171 | |||
| 172 | mod low_level_api { | ||
| 173 | use super::*; | ||
| 174 | |||
| 175 | pub unsafe fn start_transfer( | ||
| 176 | dma: pac::dma::Dma, | ||
| 177 | channel_number: u8, | ||
| 178 | request: Request, | ||
| 179 | dir: vals::Dir, | ||
| 180 | peri_addr: *const u32, | ||
| 181 | mem_addr: *mut u32, | ||
| 182 | mem_len: usize, | ||
| 183 | incr_mem: bool, | ||
| 184 | data_size: vals::Size, | ||
| 185 | #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, | ||
| 186 | #[cfg(dmamux)] dmamux_ch_num: u8, | ||
| 187 | ) { | ||
| 188 | #[cfg(dmamux)] | ||
| 189 | super::super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); | ||
| 190 | |||
| 191 | // "Preceding reads and writes cannot be moved past subsequent writes." | ||
| 192 | fence(Ordering::SeqCst); | ||
| 193 | |||
| 194 | reset_status(dma, channel_number); | ||
| 195 | |||
| 196 | let ch = dma.st(channel_number as _); | ||
| 197 | ch.par().write_value(peri_addr as u32); | ||
| 198 | ch.m0ar().write_value(mem_addr as u32); | ||
| 199 | ch.ndtr().write_value(regs::Ndtr(mem_len as _)); | ||
| 200 | ch.cr().write(|w| { | ||
| 201 | w.set_dir(dir); | ||
| 202 | w.set_msize(data_size); | ||
| 203 | w.set_psize(data_size); | ||
| 204 | w.set_pl(vals::Pl::VERYHIGH); | ||
| 205 | if incr_mem { | ||
| 206 | w.set_minc(vals::Inc::INCREMENTED); | ||
| 207 | } else { | ||
| 208 | w.set_minc(vals::Inc::FIXED); | ||
| 209 | } | ||
| 210 | w.set_pinc(vals::Inc::FIXED); | ||
| 211 | w.set_teie(true); | ||
| 212 | w.set_tcie(true); | ||
| 213 | #[cfg(dma_v1)] | ||
| 214 | w.set_trbuff(true); | ||
| 215 | |||
| 216 | #[cfg(dma_v2)] | ||
| 217 | w.set_chsel(request); | ||
| 218 | |||
| 219 | w.set_en(true); | ||
| 220 | }); | ||
| 221 | } | ||
| 222 | |||
| 223 | /// Stops the DMA channel. | ||
| 224 | pub unsafe fn request_stop(dma: pac::dma::Dma, channel_number: u8) { | ||
| 225 | // get a handle on the channel itself | ||
| 226 | let ch = dma.st(channel_number as _); | ||
| 227 | |||
| 228 | // Disable the channel. Keep the IEs enabled so the irqs still fire. | ||
| 229 | ch.cr().write(|w| { | ||
| 230 | w.set_teie(true); | ||
| 231 | w.set_tcie(true); | ||
| 232 | }); | ||
| 233 | |||
| 234 | // "Subsequent reads and writes cannot be moved ahead of preceding reads." | ||
| 235 | fence(Ordering::SeqCst); | ||
| 236 | } | ||
| 237 | |||
| 238 | /// Gets the running status of the channel | ||
| 239 | pub unsafe fn is_running(dma: pac::dma::Dma, ch: u8) -> bool { | ||
| 240 | // get a handle on the channel itself | ||
| 241 | let ch = dma.st(ch as _); | ||
| 242 | // Get whether it's enabled (running) | ||
| 243 | ch.cr().read().en() | ||
| 244 | } | ||
| 245 | |||
| 246 | /// Gets the total remaining transfers for the channel | ||
| 247 | /// Note: this will be zero for transfers that completed without cancellation. | ||
| 248 | pub unsafe fn get_remaining_transfers(dma: pac::dma::Dma, ch: u8) -> u16 { | ||
| 249 | // get a handle on the channel itself | ||
| 250 | let ch = dma.st(ch as _); | ||
| 251 | // read the remaining transfer count. If this is zero, the transfer completed fully. | ||
| 252 | ch.ndtr().read().ndt() | ||
| 253 | } | ||
| 254 | |||
| 255 | /// Sets the waker for the specified DMA channel | ||
| 256 | pub unsafe fn set_waker(state_number: usize, waker: &Waker) { | ||
| 257 | STATE.ch_wakers[state_number].register(waker); | ||
| 258 | } | ||
| 259 | |||
| 260 | pub unsafe fn reset_status(dma: pac::dma::Dma, channel_number: u8) { | ||
| 261 | let isrn = channel_number as usize / 4; | ||
| 262 | let isrbit = channel_number as usize % 4; | ||
| 263 | |||
| 264 | dma.ifcr(isrn).write(|w| { | ||
| 265 | w.set_tcif(isrbit, true); | ||
| 266 | w.set_teif(isrbit, true); | ||
| 267 | }); | ||
| 268 | } | ||
| 269 | } | ||
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 60f6a3020..accc55653 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs | |||
| @@ -9,7 +9,18 @@ mod dmamux; | |||
| 9 | pub use dmamux::*; | 9 | pub use dmamux::*; |
| 10 | 10 | ||
| 11 | use core::future::Future; | 11 | use core::future::Future; |
| 12 | use core::marker::PhantomData; | ||
| 13 | use core::pin::Pin; | ||
| 14 | use core::task::Waker; | ||
| 15 | use core::task::{Context, Poll}; | ||
| 12 | use embassy::util::Unborrow; | 16 | use embassy::util::Unborrow; |
| 17 | use embassy_hal_common::unborrow; | ||
| 18 | |||
| 19 | #[cfg(feature = "unstable-pac")] | ||
| 20 | pub use transfers::*; | ||
| 21 | |||
| 22 | #[cfg(not(feature = "unstable-pac"))] | ||
| 23 | pub(crate) use transfers::*; | ||
| 13 | 24 | ||
| 14 | #[cfg(any(bdma_v2, dma_v2, dmamux))] | 25 | #[cfg(any(bdma_v2, dma_v2, dmamux))] |
| 15 | pub type Request = u8; | 26 | pub type Request = u8; |
| @@ -17,41 +28,180 @@ pub type Request = u8; | |||
| 17 | pub type Request = (); | 28 | pub type Request = (); |
| 18 | 29 | ||
| 19 | pub(crate) mod sealed { | 30 | pub(crate) mod sealed { |
| 20 | pub trait Channel {} | 31 | use super::*; |
| 32 | |||
| 33 | pub trait Word {} | ||
| 34 | |||
| 35 | pub trait Channel { | ||
| 36 | /// Starts this channel for writing a stream of words. | ||
| 37 | /// | ||
| 38 | /// Safety: | ||
| 39 | /// - `buf` must be alive for the entire duration of the DMA transfer. | ||
| 40 | /// - `reg_addr` must be a valid peripheral register address to write to. | ||
| 41 | unsafe fn start_write<W: super::Word>( | ||
| 42 | &mut self, | ||
| 43 | request: Request, | ||
| 44 | buf: &[W], | ||
| 45 | reg_addr: *mut W, | ||
| 46 | ); | ||
| 47 | |||
| 48 | /// Starts this channel for writing a word repeatedly. | ||
| 49 | /// | ||
| 50 | /// Safety: | ||
| 51 | /// - `reg_addr` must be a valid peripheral register address to write to. | ||
| 52 | unsafe fn start_write_repeated<W: super::Word>( | ||
| 53 | &mut self, | ||
| 54 | request: Request, | ||
| 55 | repeated: W, | ||
| 56 | count: usize, | ||
| 57 | reg_addr: *mut W, | ||
| 58 | ); | ||
| 59 | |||
| 60 | /// Starts this channel for reading a stream of words. | ||
| 61 | /// | ||
| 62 | /// Safety: | ||
| 63 | /// - `buf` must be alive for the entire duration of the DMA transfer. | ||
| 64 | /// - `reg_addr` must be a valid peripheral register address to write to. | ||
| 65 | unsafe fn start_read<W: super::Word>( | ||
| 66 | &mut self, | ||
| 67 | request: Request, | ||
| 68 | reg_addr: *mut W, | ||
| 69 | buf: &mut [W], | ||
| 70 | ); | ||
| 71 | |||
| 72 | /// Requests the channel to stop. | ||
| 73 | /// NOTE: The channel does not immediately stop, you have to wait | ||
| 74 | /// for `is_running() = false`. | ||
| 75 | fn request_stop(&mut self); | ||
| 76 | |||
| 77 | /// Returns whether this channel is running or stopped. | ||
| 78 | /// | ||
| 79 | /// The channel stops running when it either completes or is manually stopped. | ||
| 80 | fn is_running(&self) -> bool; | ||
| 81 | |||
| 82 | /// Returns the total number of remaining transfers. | ||
| 83 | fn remaining_transfers(&mut self) -> u16; | ||
| 84 | |||
| 85 | /// Sets the waker that is called when this channel stops (either completed or manually stopped) | ||
| 86 | fn set_waker(&mut self, waker: &Waker); | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | pub enum WordSize { | ||
| 91 | OneByte, | ||
| 92 | TwoBytes, | ||
| 93 | FourBytes, | ||
| 94 | } | ||
| 95 | pub trait Word: sealed::Word { | ||
| 96 | fn bits() -> WordSize; | ||
| 97 | } | ||
| 98 | |||
| 99 | impl sealed::Word for u8 {} | ||
| 100 | impl Word for u8 { | ||
| 101 | fn bits() -> WordSize { | ||
| 102 | WordSize::OneByte | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | impl sealed::Word for u16 {} | ||
| 107 | impl Word for u16 { | ||
| 108 | fn bits() -> WordSize { | ||
| 109 | WordSize::TwoBytes | ||
| 110 | } | ||
| 21 | } | 111 | } |
| 22 | 112 | ||
| 23 | pub trait Channel: sealed::Channel { | 113 | impl sealed::Word for u32 {} |
| 24 | type ReadFuture<'a>: Future<Output = ()> + 'a | 114 | impl Word for u32 { |
| 25 | where | 115 | fn bits() -> WordSize { |
| 26 | Self: 'a; | 116 | WordSize::FourBytes |
| 117 | } | ||
| 118 | } | ||
| 27 | 119 | ||
| 28 | type WriteFuture<'a>: Future<Output = ()> + 'a | 120 | mod transfers { |
| 29 | where | 121 | use super::*; |
| 30 | Self: 'a; | ||
| 31 | 122 | ||
| 32 | fn read<'a>( | 123 | #[allow(unused)] |
| 33 | &'a mut self, | 124 | pub fn read<'a, W: Word>( |
| 125 | channel: impl Unborrow<Target = impl Channel> + 'a, | ||
| 34 | request: Request, | 126 | request: Request, |
| 35 | src: *mut u8, | 127 | reg_addr: *mut W, |
| 36 | buf: &'a mut [u8], | 128 | buf: &'a mut [W], |
| 37 | ) -> Self::ReadFuture<'a>; | 129 | ) -> impl Future<Output = ()> + 'a { |
| 130 | assert!(buf.len() <= 0xFFFF); | ||
| 131 | unborrow!(channel); | ||
| 132 | |||
| 133 | unsafe { channel.start_read::<W>(request, reg_addr, buf) }; | ||
| 134 | |||
| 135 | Transfer { | ||
| 136 | channel, | ||
| 137 | _phantom: PhantomData, | ||
| 138 | } | ||
| 139 | } | ||
| 38 | 140 | ||
| 39 | fn write<'a>( | 141 | #[allow(unused)] |
| 40 | &'a mut self, | 142 | pub fn write<'a, W: Word>( |
| 143 | channel: impl Unborrow<Target = impl Channel> + 'a, | ||
| 41 | request: Request, | 144 | request: Request, |
| 42 | buf: &'a [u8], | 145 | buf: &'a [W], |
| 43 | dst: *mut u8, | 146 | reg_addr: *mut W, |
| 44 | ) -> Self::WriteFuture<'a>; | 147 | ) -> impl Future<Output = ()> + 'a { |
| 148 | assert!(buf.len() <= 0xFFFF); | ||
| 149 | unborrow!(channel); | ||
| 150 | |||
| 151 | unsafe { channel.start_write::<W>(request, buf, reg_addr) }; | ||
| 45 | 152 | ||
| 46 | fn write_x<'a>( | 153 | Transfer { |
| 47 | &'a mut self, | 154 | channel, |
| 155 | _phantom: PhantomData, | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | #[allow(unused)] | ||
| 160 | pub fn write_repeated<'a, W: Word>( | ||
| 161 | channel: impl Unborrow<Target = impl Channel> + 'a, | ||
| 48 | request: Request, | 162 | request: Request, |
| 49 | word: &u8, | 163 | repeated: W, |
| 50 | num: usize, | 164 | count: usize, |
| 51 | dst: *mut u8, | 165 | reg_addr: *mut W, |
| 52 | ) -> Self::WriteFuture<'a>; | 166 | ) -> impl Future<Output = ()> + 'a { |
| 167 | unborrow!(channel); | ||
| 168 | |||
| 169 | unsafe { channel.start_write_repeated::<W>(request, repeated, count, reg_addr) }; | ||
| 170 | |||
| 171 | Transfer { | ||
| 172 | channel, | ||
| 173 | _phantom: PhantomData, | ||
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 177 | struct Transfer<'a, C: Channel> { | ||
| 178 | channel: C, | ||
| 179 | _phantom: PhantomData<&'a mut C>, | ||
| 180 | } | ||
| 181 | |||
| 182 | impl<'a, C: Channel> Drop for Transfer<'a, C> { | ||
| 183 | fn drop(&mut self) { | ||
| 184 | self.channel.request_stop(); | ||
| 185 | while self.channel.is_running() {} | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | impl<'a, C: Channel> Unpin for Transfer<'a, C> {} | ||
| 190 | impl<'a, C: Channel> Future for Transfer<'a, C> { | ||
| 191 | type Output = (); | ||
| 192 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
| 193 | self.channel.set_waker(cx.waker()); | ||
| 194 | if self.channel.is_running() { | ||
| 195 | Poll::Pending | ||
| 196 | } else { | ||
| 197 | Poll::Ready(()) | ||
| 198 | } | ||
| 199 | } | ||
| 200 | } | ||
| 53 | } | 201 | } |
| 54 | 202 | ||
| 203 | pub trait Channel: sealed::Channel + Unborrow<Target = Self> + 'static {} | ||
| 204 | |||
| 55 | pub struct NoDma; | 205 | pub struct NoDma; |
| 56 | 206 | ||
| 57 | unsafe impl Unborrow for NoDma { | 207 | unsafe impl Unborrow for NoDma { |
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 11c8ab975..94c4d9a7c 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -418,7 +418,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 418 | let dst = regs.txdr().ptr() as *mut u8; | 418 | let dst = regs.txdr().ptr() as *mut u8; |
| 419 | 419 | ||
| 420 | let ch = &mut self.tx_dma; | 420 | let ch = &mut self.tx_dma; |
| 421 | ch.write(ch.request(), bytes, dst) | 421 | let request = ch.request(); |
| 422 | crate::dma::write(ch, request, bytes, dst) | ||
| 422 | }; | 423 | }; |
| 423 | 424 | ||
| 424 | let state_number = T::state_number(); | 425 | let state_number = T::state_number(); |
| @@ -510,7 +511,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 510 | let src = regs.rxdr().ptr() as *mut u8; | 511 | let src = regs.rxdr().ptr() as *mut u8; |
| 511 | 512 | ||
| 512 | let ch = &mut self.rx_dma; | 513 | let ch = &mut self.rx_dma; |
| 513 | ch.read(ch.request(), src, buffer) | 514 | let request = ch.request(); |
| 515 | crate::dma::read(ch, request, src, buffer) | ||
| 514 | }; | 516 | }; |
| 515 | 517 | ||
| 516 | let state_number = T::state_number(); | 518 | let state_number = T::state_number(); |
diff --git a/embassy-stm32/src/spi/v1.rs b/embassy-stm32/src/spi/v1.rs index 92449ea80..98f05770b 100644 --- a/embassy-stm32/src/spi/v1.rs +++ b/embassy-stm32/src/spi/v1.rs | |||
| @@ -20,7 +20,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 20 | 20 | ||
| 21 | let request = self.txdma.request(); | 21 | let request = self.txdma.request(); |
| 22 | let dst = T::regs().tx_ptr(); | 22 | let dst = T::regs().tx_ptr(); |
| 23 | let f = self.txdma.write(request, write, dst); | 23 | let f = crate::dma::write(&mut self.txdma, request, write, dst); |
| 24 | 24 | ||
| 25 | unsafe { | 25 | unsafe { |
| 26 | T::regs().cr2().modify(|reg| { | 26 | T::regs().cr2().modify(|reg| { |
| @@ -54,14 +54,18 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 54 | 54 | ||
| 55 | let rx_request = self.rxdma.request(); | 55 | let rx_request = self.rxdma.request(); |
| 56 | let rx_src = T::regs().rx_ptr(); | 56 | let rx_src = T::regs().rx_ptr(); |
| 57 | let rx_f = self.rxdma.read(rx_request, rx_src, read); | 57 | let rx_f = crate::dma::read(&mut self.rxdma, rx_request, rx_src, read); |
| 58 | 58 | ||
| 59 | let tx_request = self.txdma.request(); | 59 | let tx_request = self.txdma.request(); |
| 60 | let tx_dst = T::regs().tx_ptr(); | 60 | let tx_dst = T::regs().tx_ptr(); |
| 61 | let clock_byte = 0x00; | 61 | let clock_byte = 0x00u8; |
| 62 | let tx_f = self | 62 | let tx_f = crate::dma::write_repeated( |
| 63 | .txdma | 63 | &mut self.txdma, |
| 64 | .write_x(tx_request, &clock_byte, clock_byte_count, tx_dst); | 64 | tx_request, |
| 65 | clock_byte, | ||
| 66 | clock_byte_count, | ||
| 67 | tx_dst, | ||
| 68 | ); | ||
| 65 | 69 | ||
| 66 | unsafe { | 70 | unsafe { |
| 67 | T::regs().cr2().modify(|reg| { | 71 | T::regs().cr2().modify(|reg| { |
| @@ -110,13 +114,16 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 110 | 114 | ||
| 111 | let rx_request = self.rxdma.request(); | 115 | let rx_request = self.rxdma.request(); |
| 112 | let rx_src = T::regs().rx_ptr(); | 116 | let rx_src = T::regs().rx_ptr(); |
| 113 | let rx_f = self | 117 | let rx_f = crate::dma::read( |
| 114 | .rxdma | 118 | &mut self.rxdma, |
| 115 | .read(rx_request, rx_src, &mut read[0..write.len()]); | 119 | rx_request, |
| 120 | rx_src, | ||
| 121 | &mut read[0..write.len()], | ||
| 122 | ); | ||
| 116 | 123 | ||
| 117 | let tx_request = self.txdma.request(); | 124 | let tx_request = self.txdma.request(); |
| 118 | let tx_dst = T::regs().tx_ptr(); | 125 | let tx_dst = T::regs().tx_ptr(); |
| 119 | let tx_f = self.txdma.write(tx_request, write, tx_dst); | 126 | let tx_f = crate::dma::write(&mut self.txdma, tx_request, write, tx_dst); |
| 120 | 127 | ||
| 121 | unsafe { | 128 | unsafe { |
| 122 | T::regs().cr2().modify(|reg| { | 129 | T::regs().cr2().modify(|reg| { |
diff --git a/embassy-stm32/src/spi/v2.rs b/embassy-stm32/src/spi/v2.rs index e24710dfe..286976329 100644 --- a/embassy-stm32/src/spi/v2.rs +++ b/embassy-stm32/src/spi/v2.rs | |||
| @@ -24,7 +24,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 24 | 24 | ||
| 25 | let request = self.txdma.request(); | 25 | let request = self.txdma.request(); |
| 26 | let dst = T::regs().tx_ptr(); | 26 | let dst = T::regs().tx_ptr(); |
| 27 | let f = self.txdma.write(request, write, dst); | 27 | let f = crate::dma::write(&mut self.txdma, request, write, dst); |
| 28 | 28 | ||
| 29 | unsafe { | 29 | unsafe { |
| 30 | T::regs().cr2().modify(|reg| { | 30 | T::regs().cr2().modify(|reg| { |
| @@ -67,14 +67,18 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 67 | 67 | ||
| 68 | let rx_request = self.rxdma.request(); | 68 | let rx_request = self.rxdma.request(); |
| 69 | let rx_src = T::regs().rx_ptr(); | 69 | let rx_src = T::regs().rx_ptr(); |
| 70 | let rx_f = self.rxdma.read(rx_request, rx_src, read); | 70 | let rx_f = crate::dma::read(&mut self.rxdma, rx_request, rx_src, read); |
| 71 | 71 | ||
| 72 | let tx_request = self.txdma.request(); | 72 | let tx_request = self.txdma.request(); |
| 73 | let tx_dst = T::regs().tx_ptr(); | 73 | let tx_dst = T::regs().tx_ptr(); |
| 74 | let clock_byte = 0x00; | 74 | let clock_byte = 0x00u8; |
| 75 | let tx_f = self | 75 | let tx_f = crate::dma::write_repeated( |
| 76 | .txdma | 76 | &mut self.txdma, |
| 77 | .write_x(tx_request, &clock_byte, clock_byte_count, tx_dst); | 77 | tx_request, |
| 78 | clock_byte, | ||
| 79 | clock_byte_count, | ||
| 80 | tx_dst, | ||
| 81 | ); | ||
| 78 | 82 | ||
| 79 | unsafe { | 83 | unsafe { |
| 80 | T::regs().cr2().modify(|reg| { | 84 | T::regs().cr2().modify(|reg| { |
| @@ -128,13 +132,16 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 128 | 132 | ||
| 129 | let rx_request = self.rxdma.request(); | 133 | let rx_request = self.rxdma.request(); |
| 130 | let rx_src = T::regs().rx_ptr(); | 134 | let rx_src = T::regs().rx_ptr(); |
| 131 | let rx_f = self | 135 | let rx_f = crate::dma::read( |
| 132 | .rxdma | 136 | &mut self.rxdma, |
| 133 | .read(rx_request, rx_src, &mut read[0..write.len()]); | 137 | rx_request, |
| 138 | rx_src, | ||
| 139 | &mut read[0..write.len()], | ||
| 140 | ); | ||
| 134 | 141 | ||
| 135 | let tx_request = self.txdma.request(); | 142 | let tx_request = self.txdma.request(); |
| 136 | let tx_dst = T::regs().tx_ptr(); | 143 | let tx_dst = T::regs().tx_ptr(); |
| 137 | let tx_f = self.txdma.write(tx_request, write, tx_dst); | 144 | let tx_f = crate::dma::write(&mut self.txdma, tx_request, write, tx_dst); |
| 138 | 145 | ||
| 139 | unsafe { | 146 | unsafe { |
| 140 | T::regs().cr2().modify(|reg| { | 147 | T::regs().cr2().modify(|reg| { |
diff --git a/embassy-stm32/src/spi/v3.rs b/embassy-stm32/src/spi/v3.rs index 6d75de035..c31415a2f 100644 --- a/embassy-stm32/src/spi/v3.rs +++ b/embassy-stm32/src/spi/v3.rs | |||
| @@ -24,7 +24,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 24 | 24 | ||
| 25 | let request = self.txdma.request(); | 25 | let request = self.txdma.request(); |
| 26 | let dst = T::regs().tx_ptr(); | 26 | let dst = T::regs().tx_ptr(); |
| 27 | let f = self.txdma.write(request, write, dst); | 27 | let f = crate::dma::write(&mut self.txdma, request, write, dst); |
| 28 | 28 | ||
| 29 | unsafe { | 29 | unsafe { |
| 30 | T::regs().cfg1().modify(|reg| { | 30 | T::regs().cfg1().modify(|reg| { |
| @@ -70,14 +70,18 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 70 | 70 | ||
| 71 | let rx_request = self.rxdma.request(); | 71 | let rx_request = self.rxdma.request(); |
| 72 | let rx_src = T::regs().rx_ptr(); | 72 | let rx_src = T::regs().rx_ptr(); |
| 73 | let rx_f = self.rxdma.read(rx_request, rx_src, read); | 73 | let rx_f = crate::dma::read(&mut self.rxdma, rx_request, rx_src, read); |
| 74 | 74 | ||
| 75 | let tx_request = self.txdma.request(); | 75 | let tx_request = self.txdma.request(); |
| 76 | let tx_dst = T::regs().tx_ptr(); | 76 | let tx_dst = T::regs().tx_ptr(); |
| 77 | let clock_byte = 0x00; | 77 | let clock_byte = 0x00u8; |
| 78 | let tx_f = self | 78 | let tx_f = crate::dma::write_repeated( |
| 79 | .txdma | 79 | &mut self.txdma, |
| 80 | .write_x(tx_request, &clock_byte, clock_byte_count, tx_dst); | 80 | tx_request, |
| 81 | clock_byte, | ||
| 82 | clock_byte_count, | ||
| 83 | tx_dst, | ||
| 84 | ); | ||
| 81 | 85 | ||
| 82 | unsafe { | 86 | unsafe { |
| 83 | T::regs().cfg1().modify(|reg| { | 87 | T::regs().cfg1().modify(|reg| { |
| @@ -132,13 +136,16 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 132 | 136 | ||
| 133 | let rx_request = self.rxdma.request(); | 137 | let rx_request = self.rxdma.request(); |
| 134 | let rx_src = T::regs().rx_ptr(); | 138 | let rx_src = T::regs().rx_ptr(); |
| 135 | let rx_f = self | 139 | let rx_f = crate::dma::read( |
| 136 | .rxdma | 140 | &mut self.rxdma, |
| 137 | .read(rx_request, rx_src, &mut read[0..write.len()]); | 141 | rx_request, |
| 142 | rx_src, | ||
| 143 | &mut read[0..write.len()], | ||
| 144 | ); | ||
| 138 | 145 | ||
| 139 | let tx_request = self.txdma.request(); | 146 | let tx_request = self.txdma.request(); |
| 140 | let tx_dst = T::regs().tx_ptr(); | 147 | let tx_dst = T::regs().tx_ptr(); |
| 141 | let tx_f = self.txdma.write(tx_request, write, tx_dst); | 148 | let tx_f = crate::dma::write(&mut self.txdma, tx_request, write, tx_dst); |
| 142 | 149 | ||
| 143 | unsafe { | 150 | unsafe { |
| 144 | T::regs().cfg1().modify(|reg| { | 151 | T::regs().cfg1().modify(|reg| { |
diff --git a/embassy-stm32/src/usart/v1.rs b/embassy-stm32/src/usart/v1.rs index 8cd392d18..10f87f2dd 100644 --- a/embassy-stm32/src/usart/v1.rs +++ b/embassy-stm32/src/usart/v1.rs | |||
| @@ -70,6 +70,7 @@ impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 70 | TxDma: crate::usart::TxDma<T>, | 70 | TxDma: crate::usart::TxDma<T>, |
| 71 | { | 71 | { |
| 72 | let ch = &mut self.tx_dma; | 72 | let ch = &mut self.tx_dma; |
| 73 | let request = ch.request(); | ||
| 73 | unsafe { | 74 | unsafe { |
| 74 | self.inner.regs().cr3().modify(|reg| { | 75 | self.inner.regs().cr3().modify(|reg| { |
| 75 | reg.set_dmat(true); | 76 | reg.set_dmat(true); |
| @@ -77,7 +78,7 @@ impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 77 | } | 78 | } |
| 78 | let r = self.inner.regs(); | 79 | let r = self.inner.regs(); |
| 79 | let dst = r.dr().ptr() as *mut u8; | 80 | let dst = r.dr().ptr() as *mut u8; |
| 80 | ch.write(ch.request(), buffer, dst).await; | 81 | crate::dma::write(ch, request, buffer, dst).await; |
| 81 | Ok(()) | 82 | Ok(()) |
| 82 | } | 83 | } |
| 83 | 84 | ||
| @@ -86,6 +87,7 @@ impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 86 | RxDma: crate::usart::RxDma<T>, | 87 | RxDma: crate::usart::RxDma<T>, |
| 87 | { | 88 | { |
| 88 | let ch = &mut self.rx_dma; | 89 | let ch = &mut self.rx_dma; |
| 90 | let request = ch.request(); | ||
| 89 | unsafe { | 91 | unsafe { |
| 90 | self.inner.regs().cr3().modify(|reg| { | 92 | self.inner.regs().cr3().modify(|reg| { |
| 91 | reg.set_dmar(true); | 93 | reg.set_dmar(true); |
| @@ -93,7 +95,7 @@ impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 93 | } | 95 | } |
| 94 | let r = self.inner.regs(); | 96 | let r = self.inner.regs(); |
| 95 | let src = r.dr().ptr() as *mut u8; | 97 | let src = r.dr().ptr() as *mut u8; |
| 96 | ch.read(ch.request(), src, buffer).await; | 98 | crate::dma::read(ch, request, src, buffer).await; |
| 97 | Ok(()) | 99 | Ok(()) |
| 98 | } | 100 | } |
| 99 | 101 | ||
diff --git a/embassy-stm32/src/usart/v2.rs b/embassy-stm32/src/usart/v2.rs index e6e5f69db..697adf459 100644 --- a/embassy-stm32/src/usart/v2.rs +++ b/embassy-stm32/src/usart/v2.rs | |||
| @@ -80,6 +80,7 @@ impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 80 | TxDma: crate::usart::TxDma<T>, | 80 | TxDma: crate::usart::TxDma<T>, |
| 81 | { | 81 | { |
| 82 | let ch = &mut self.tx_dma; | 82 | let ch = &mut self.tx_dma; |
| 83 | let request = ch.request(); | ||
| 83 | unsafe { | 84 | unsafe { |
| 84 | self.inner.regs().cr3().modify(|reg| { | 85 | self.inner.regs().cr3().modify(|reg| { |
| 85 | reg.set_dmat(true); | 86 | reg.set_dmat(true); |
| @@ -87,7 +88,7 @@ impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 87 | } | 88 | } |
| 88 | let r = self.inner.regs(); | 89 | let r = self.inner.regs(); |
| 89 | let dst = r.tdr().ptr() as *mut u8; | 90 | let dst = r.tdr().ptr() as *mut u8; |
| 90 | ch.write(ch.request(), buffer, dst).await; | 91 | crate::dma::write(ch, request, buffer, dst).await; |
| 91 | Ok(()) | 92 | Ok(()) |
| 92 | } | 93 | } |
| 93 | 94 | ||
| @@ -96,6 +97,7 @@ impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 96 | RxDma: crate::usart::RxDma<T>, | 97 | RxDma: crate::usart::RxDma<T>, |
| 97 | { | 98 | { |
| 98 | let ch = &mut self.rx_dma; | 99 | let ch = &mut self.rx_dma; |
| 100 | let request = ch.request(); | ||
| 99 | unsafe { | 101 | unsafe { |
| 100 | self.inner.regs().cr3().modify(|reg| { | 102 | self.inner.regs().cr3().modify(|reg| { |
| 101 | reg.set_dmar(true); | 103 | reg.set_dmar(true); |
| @@ -103,7 +105,8 @@ impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 103 | } | 105 | } |
| 104 | let r = self.inner.regs(); | 106 | let r = self.inner.regs(); |
| 105 | let src = r.rdr().ptr() as *mut u8; | 107 | let src = r.rdr().ptr() as *mut u8; |
| 106 | ch.read(ch.request(), src, buffer).await; | 108 | |
| 109 | crate::dma::read(ch, request, src, buffer).await; | ||
| 107 | Ok(()) | 110 | Ok(()) |
| 108 | } | 111 | } |
| 109 | 112 | ||
