diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-04-17 00:04:54 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2023-04-18 16:37:35 +0200 |
| commit | 173c65b5430e57548cc747f0387dd001e30b1ac1 (patch) | |
| tree | 2e57d661c2f6612256b693e28ed3b96bb5a1745e | |
| parent | 46227bec1e948ea89de7d4e8a8dc98df5d7a25f0 (diff) | |
stm32/dma: refactor.
| -rw-r--r-- | embassy-stm32/build.rs | 12 | ||||
| -rw-r--r-- | embassy-stm32/src/dcmi.rs | 13 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/bdma.rs | 403 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/dma.rs | 568 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/dmamux.rs | 22 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/gpdma.rs | 402 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/mod.rs | 317 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v2.rs | 6 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 7 | ||||
| -rw-r--r-- | embassy-stm32/src/qspi/mod.rs | 32 | ||||
| -rw-r--r-- | embassy-stm32/src/sdmmc/mod.rs | 243 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/mod.rs | 23 | ||||
| -rw-r--r-- | embassy-stm32/src/traits.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/usart/mod.rs | 27 |
14 files changed, 1005 insertions, 1072 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index c7d12e13a..9f84caefb 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -260,7 +260,7 @@ fn main() { | |||
| 260 | // ======== | 260 | // ======== |
| 261 | // Generate DMA IRQs. | 261 | // Generate DMA IRQs. |
| 262 | 262 | ||
| 263 | let mut dma_irqs: HashMap<&str, Vec<(&str, &str)>> = HashMap::new(); | 263 | let mut dma_irqs: HashMap<&str, Vec<(&str, &str, &str)>> = HashMap::new(); |
| 264 | 264 | ||
| 265 | for p in METADATA.peripherals { | 265 | for p in METADATA.peripherals { |
| 266 | if let Some(r) = &p.registers { | 266 | if let Some(r) = &p.registers { |
| @@ -270,7 +270,10 @@ fn main() { | |||
| 270 | continue; | 270 | continue; |
| 271 | } | 271 | } |
| 272 | for irq in p.interrupts { | 272 | for irq in p.interrupts { |
| 273 | dma_irqs.entry(irq.interrupt).or_default().push((p.name, irq.signal)); | 273 | dma_irqs |
| 274 | .entry(irq.interrupt) | ||
| 275 | .or_default() | ||
| 276 | .push((r.kind, p.name, irq.signal)); | ||
| 274 | } | 277 | } |
| 275 | } | 278 | } |
| 276 | } | 279 | } |
| @@ -279,13 +282,14 @@ fn main() { | |||
| 279 | for (irq, channels) in dma_irqs { | 282 | for (irq, channels) in dma_irqs { |
| 280 | let irq = format_ident!("{}", irq); | 283 | let irq = format_ident!("{}", irq); |
| 281 | 284 | ||
| 282 | let channels = channels.iter().map(|(dma, ch)| format_ident!("{}_{}", dma, ch)); | 285 | let xdma = format_ident!("{}", channels[0].0); |
| 286 | let channels = channels.iter().map(|(_, dma, ch)| format_ident!("{}_{}", dma, ch)); | ||
| 283 | 287 | ||
| 284 | g.extend(quote! { | 288 | g.extend(quote! { |
| 285 | #[crate::interrupt] | 289 | #[crate::interrupt] |
| 286 | unsafe fn #irq () { | 290 | unsafe fn #irq () { |
| 287 | #( | 291 | #( |
| 288 | <crate::peripherals::#channels as crate::dma::sealed::Channel>::on_irq(); | 292 | <crate::peripherals::#channels as crate::dma::#xdma::sealed::Channel>::on_irq(); |
| 289 | )* | 293 | )* |
| 290 | } | 294 | } |
| 291 | }); | 295 | }); |
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs index 20e1a4070..0b34553cf 100644 --- a/embassy-stm32/src/dcmi.rs +++ b/embassy-stm32/src/dcmi.rs | |||
| @@ -4,6 +4,7 @@ use core::task::Poll; | |||
| 4 | use embassy_hal_common::{into_ref, PeripheralRef}; | 4 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 5 | use embassy_sync::waitqueue::AtomicWaker; | 5 | use embassy_sync::waitqueue::AtomicWaker; |
| 6 | 6 | ||
| 7 | use crate::dma::Transfer; | ||
| 7 | use crate::gpio::sealed::AFType; | 8 | use crate::gpio::sealed::AFType; |
| 8 | use crate::gpio::Speed; | 9 | use crate::gpio::Speed; |
| 9 | use crate::interrupt::{Interrupt, InterruptExt}; | 10 | use crate::interrupt::{Interrupt, InterruptExt}; |
| @@ -385,14 +386,11 @@ where | |||
| 385 | return self.capture_giant(buffer).await; | 386 | return self.capture_giant(buffer).await; |
| 386 | } | 387 | } |
| 387 | } | 388 | } |
| 388 | |||
| 389 | async fn capture_small(&mut self, buffer: &mut [u32]) -> Result<(), Error> { | 389 | async fn capture_small(&mut self, buffer: &mut [u32]) -> Result<(), Error> { |
| 390 | let channel = &mut self.dma; | ||
| 391 | let request = channel.request(); | ||
| 392 | |||
| 393 | let r = self.inner.regs(); | 390 | let r = self.inner.regs(); |
| 394 | let src = r.dr().ptr() as *mut u32; | 391 | let src = r.dr().ptr() as *mut u32; |
| 395 | let dma_read = crate::dma::read(channel, request, src, buffer); | 392 | let request = self.dma.request(); |
| 393 | let dma_read = unsafe { Transfer::new_read(&mut self.dma, request, src, buffer, Default::default()) }; | ||
| 396 | 394 | ||
| 397 | Self::clear_interrupt_flags(); | 395 | Self::clear_interrupt_flags(); |
| 398 | Self::enable_irqs(); | 396 | Self::enable_irqs(); |
| @@ -436,7 +434,9 @@ where | |||
| 436 | result | 434 | result |
| 437 | } | 435 | } |
| 438 | 436 | ||
| 439 | async fn capture_giant(&mut self, buffer: &mut [u32]) -> Result<(), Error> { | 437 | async fn capture_giant(&mut self, _buffer: &mut [u32]) -> Result<(), Error> { |
| 438 | todo!() | ||
| 439 | /* | ||
| 440 | use crate::dma::TransferOptions; | 440 | use crate::dma::TransferOptions; |
| 441 | 441 | ||
| 442 | let data_len = buffer.len(); | 442 | let data_len = buffer.len(); |
| @@ -542,6 +542,7 @@ where | |||
| 542 | unsafe { Self::toggle(false) }; | 542 | unsafe { Self::toggle(false) }; |
| 543 | 543 | ||
| 544 | result | 544 | result |
| 545 | */ | ||
| 545 | } | 546 | } |
| 546 | } | 547 | } |
| 547 | 548 | ||
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 5a7a408bb..cf1222c46 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs | |||
| @@ -1,18 +1,31 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | use core::future::Future; | ||
| 4 | use core::pin::Pin; | ||
| 3 | use core::sync::atomic::{fence, Ordering}; | 5 | use core::sync::atomic::{fence, Ordering}; |
| 4 | use core::task::Waker; | 6 | use core::task::{Context, Poll}; |
| 5 | 7 | ||
| 6 | use embassy_cortex_m::interrupt::Priority; | 8 | use embassy_cortex_m::interrupt::Priority; |
| 9 | use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | ||
| 7 | use embassy_sync::waitqueue::AtomicWaker; | 10 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | 11 | ||
| 9 | use super::{TransferOptions, Word, WordSize}; | 12 | use super::{Dir, Word, WordSize}; |
| 10 | use crate::_generated::BDMA_CHANNEL_COUNT; | 13 | use crate::_generated::BDMA_CHANNEL_COUNT; |
| 11 | use crate::dma::Request; | ||
| 12 | use crate::interrupt::{Interrupt, InterruptExt}; | 14 | use crate::interrupt::{Interrupt, InterruptExt}; |
| 13 | use crate::pac; | 15 | use crate::pac; |
| 14 | use crate::pac::bdma::vals; | 16 | use crate::pac::bdma::vals; |
| 15 | 17 | ||
| 18 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 19 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 20 | #[non_exhaustive] | ||
| 21 | pub struct TransferOptions {} | ||
| 22 | |||
| 23 | impl Default for TransferOptions { | ||
| 24 | fn default() -> Self { | ||
| 25 | Self {} | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 16 | impl From<WordSize> for vals::Size { | 29 | impl From<WordSize> for vals::Size { |
| 17 | fn from(raw: WordSize) -> Self { | 30 | fn from(raw: WordSize) -> Self { |
| 18 | match raw { | 31 | match raw { |
| @@ -23,6 +36,15 @@ impl From<WordSize> for vals::Size { | |||
| 23 | } | 36 | } |
| 24 | } | 37 | } |
| 25 | 38 | ||
| 39 | impl From<Dir> for vals::Dir { | ||
| 40 | fn from(raw: Dir) -> Self { | ||
| 41 | match raw { | ||
| 42 | Dir::MemoryToPeripheral => Self::FROMMEMORY, | ||
| 43 | Dir::PeripheralToMemory => Self::FROMPERIPHERAL, | ||
| 44 | } | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 26 | struct State { | 48 | struct State { |
| 27 | ch_wakers: [AtomicWaker; BDMA_CHANNEL_COUNT], | 49 | ch_wakers: [AtomicWaker; BDMA_CHANNEL_COUNT], |
| 28 | } | 50 | } |
| @@ -55,228 +77,267 @@ foreach_dma_channel! { | |||
| 55 | // BDMA1 in H7 doesn't use DMAMUX, which breaks | 77 | // BDMA1 in H7 doesn't use DMAMUX, which breaks |
| 56 | }; | 78 | }; |
| 57 | ($channel_peri:ident, $dma_peri:ident, bdma, $channel_num:expr, $index:expr, $dmamux:tt) => { | 79 | ($channel_peri:ident, $dma_peri:ident, bdma, $channel_num:expr, $index:expr, $dmamux:tt) => { |
| 58 | impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri { | 80 | impl sealed::Channel for crate::peripherals::$channel_peri { |
| 59 | 81 | fn regs(&self) -> pac::bdma::Dma { | |
| 60 | unsafe fn start_write<W: Word>(&mut self, _request: Request, buf: *const[W], reg_addr: *mut W, options: TransferOptions) { | 82 | pac::$dma_peri |
| 61 | let (ptr, len) = super::slice_ptr_parts(buf); | ||
| 62 | low_level_api::start_transfer( | ||
| 63 | pac::$dma_peri, | ||
| 64 | $channel_num, | ||
| 65 | #[cfg(any(bdma_v2, dmamux))] | ||
| 66 | _request, | ||
| 67 | vals::Dir::FROMMEMORY, | ||
| 68 | reg_addr as *const u32, | ||
| 69 | ptr as *mut u32, | ||
| 70 | len, | ||
| 71 | true, | ||
| 72 | vals::Size::from(W::bits()), | ||
| 73 | options, | ||
| 74 | #[cfg(dmamux)] | ||
| 75 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, | ||
| 76 | #[cfg(dmamux)] | ||
| 77 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, | ||
| 78 | ); | ||
| 79 | } | 83 | } |
| 80 | 84 | fn num(&self) -> usize { | |
| 81 | unsafe fn start_write_repeated<W: Word>(&mut self, _request: Request, repeated: *const W, count: usize, reg_addr: *mut W, options: TransferOptions) { | 85 | $channel_num |
| 82 | low_level_api::start_transfer( | ||
| 83 | pac::$dma_peri, | ||
| 84 | $channel_num, | ||
| 85 | #[cfg(any(bdma_v2, dmamux))] | ||
| 86 | _request, | ||
| 87 | vals::Dir::FROMMEMORY, | ||
| 88 | reg_addr as *const u32, | ||
| 89 | repeated as *mut u32, | ||
| 90 | count, | ||
| 91 | false, | ||
| 92 | vals::Size::from(W::bits()), | ||
| 93 | options, | ||
| 94 | #[cfg(dmamux)] | ||
| 95 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, | ||
| 96 | #[cfg(dmamux)] | ||
| 97 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, | ||
| 98 | ) | ||
| 99 | } | 86 | } |
| 100 | 87 | fn index(&self) -> usize { | |
| 101 | unsafe fn start_read<W: Word>(&mut self, _request: Request, reg_addr: *const W, buf: *mut [W], options: TransferOptions) { | 88 | $index |
| 102 | let (ptr, len) = super::slice_ptr_parts_mut(buf); | ||
| 103 | low_level_api::start_transfer( | ||
| 104 | pac::$dma_peri, | ||
| 105 | $channel_num, | ||
| 106 | #[cfg(any(bdma_v2, dmamux))] | ||
| 107 | _request, | ||
| 108 | vals::Dir::FROMPERIPHERAL, | ||
| 109 | reg_addr as *const u32, | ||
| 110 | ptr as *mut u32, | ||
| 111 | len, | ||
| 112 | true, | ||
| 113 | vals::Size::from(W::bits()), | ||
| 114 | options, | ||
| 115 | #[cfg(dmamux)] | ||
| 116 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, | ||
| 117 | #[cfg(dmamux)] | ||
| 118 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, | ||
| 119 | ); | ||
| 120 | } | 89 | } |
| 121 | 90 | fn on_irq() { | |
| 122 | unsafe fn start_double_buffered_read<W: super::Word>( | 91 | unsafe { on_irq_inner(pac::$dma_peri, $channel_num, $index) } |
| 123 | &mut self, | ||
| 124 | _request: Request, | ||
| 125 | _reg_addr: *const W, | ||
| 126 | _buffer0: *mut W, | ||
| 127 | _buffer1: *mut W, | ||
| 128 | _buffer_len: usize, | ||
| 129 | _options: TransferOptions, | ||
| 130 | ) { | ||
| 131 | panic!("Unsafe double buffered mode is unavailable on BDMA"); | ||
| 132 | } | 92 | } |
| 93 | } | ||
| 133 | 94 | ||
| 134 | unsafe fn set_buffer0<W: super::Word>(&mut self, _buffer: *mut W) { | 95 | impl Channel for crate::peripherals::$channel_peri {} |
| 135 | panic!("Unsafe double buffered mode is unavailable on BDMA"); | 96 | }; |
| 136 | } | 97 | } |
| 137 | 98 | ||
| 138 | unsafe fn set_buffer1<W: super::Word>(&mut self, _buffer: *mut W) { | 99 | /// Safety: Must be called with a matching set of parameters for a valid dma channel |
| 139 | panic!("Unsafe double buffered mode is unavailable on BDMA"); | 100 | pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index: usize) { |
| 140 | } | 101 | let isr = dma.isr().read(); |
| 102 | let cr = dma.ch(channel_num).cr(); | ||
| 141 | 103 | ||
| 142 | unsafe fn is_buffer0_accessible(&mut self) -> bool { | 104 | if isr.teif(channel_num) { |
| 143 | panic!("Unsafe double buffered mode is unavailable on BDMA"); | 105 | panic!("DMA: error on BDMA@{:08x} channel {}", dma.0 as u32, channel_num); |
| 144 | } | 106 | } |
| 107 | if isr.tcif(channel_num) && cr.read().tcie() { | ||
| 108 | cr.write(|_| ()); // Disable channel interrupts with the default value. | ||
| 109 | STATE.ch_wakers[index].wake(); | ||
| 110 | } | ||
| 111 | } | ||
| 145 | 112 | ||
| 146 | fn request_stop(&mut self){ | 113 | #[cfg(any(bdma_v2, dmamux))] |
| 147 | unsafe {low_level_api::request_stop(pac::$dma_peri, $channel_num);} | 114 | pub type Request = u8; |
| 148 | } | 115 | #[cfg(not(any(bdma_v2, dmamux)))] |
| 116 | pub type Request = (); | ||
| 149 | 117 | ||
| 150 | fn is_running(&self) -> bool { | 118 | #[cfg(dmamux)] |
| 151 | unsafe {low_level_api::is_running(pac::$dma_peri, $channel_num)} | 119 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} |
| 152 | } | 120 | #[cfg(not(dmamux))] |
| 153 | fn remaining_transfers(&mut self) -> u16 { | 121 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} |
| 154 | unsafe {low_level_api::get_remaining_transfers(pac::$dma_peri, $channel_num)} | ||
| 155 | } | ||
| 156 | 122 | ||
| 157 | fn set_waker(&mut self, waker: &Waker) { | 123 | pub(crate) mod sealed { |
| 158 | unsafe { low_level_api::set_waker($index, waker) } | 124 | use super::*; |
| 159 | } | ||
| 160 | 125 | ||
| 161 | fn on_irq() { | 126 | pub trait Channel { |
| 162 | unsafe { | 127 | fn regs(&self) -> pac::bdma::Dma; |
| 163 | low_level_api::on_irq_inner(pac::$dma_peri, $channel_num, $index); | 128 | fn num(&self) -> usize; |
| 164 | } | 129 | fn index(&self) -> usize; |
| 165 | } | 130 | fn on_irq(); |
| 166 | } | 131 | } |
| 132 | } | ||
| 167 | 133 | ||
| 168 | impl crate::dma::Channel for crate::peripherals::$channel_peri {} | 134 | #[must_use = "futures do nothing unless you `.await` or poll them"] |
| 169 | }; | 135 | pub struct Transfer<'a, C: Channel> { |
| 136 | channel: PeripheralRef<'a, C>, | ||
| 170 | } | 137 | } |
| 171 | 138 | ||
| 172 | mod low_level_api { | 139 | impl<'a, C: Channel> Transfer<'a, C> { |
| 173 | use super::*; | 140 | pub unsafe fn new_read<W: Word>( |
| 141 | channel: impl Peripheral<P = C> + 'a, | ||
| 142 | request: Request, | ||
| 143 | peri_addr: *mut W, | ||
| 144 | buf: &'a mut [W], | ||
| 145 | options: TransferOptions, | ||
| 146 | ) -> Self { | ||
| 147 | Self::new_read_raw(channel, request, peri_addr, buf, options) | ||
| 148 | } | ||
| 174 | 149 | ||
| 175 | pub unsafe fn start_transfer( | 150 | pub unsafe fn new_read_raw<W: Word>( |
| 176 | dma: pac::bdma::Dma, | 151 | channel: impl Peripheral<P = C> + 'a, |
| 177 | channel_number: u8, | 152 | request: Request, |
| 178 | #[cfg(any(bdma_v2, dmamux))] request: Request, | 153 | peri_addr: *mut W, |
| 179 | dir: vals::Dir, | 154 | buf: *mut [W], |
| 180 | peri_addr: *const u32, | ||
| 181 | mem_addr: *mut u32, | ||
| 182 | mem_len: usize, | ||
| 183 | incr_mem: bool, | ||
| 184 | data_size: vals::Size, | ||
| 185 | options: TransferOptions, | 155 | options: TransferOptions, |
| 186 | #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, | 156 | ) -> Self { |
| 187 | #[cfg(dmamux)] dmamux_ch_num: u8, | 157 | into_ref!(channel); |
| 188 | ) { | 158 | |
| 189 | assert!(options.mburst == crate::dma::Burst::Single, "Burst mode not supported"); | 159 | let (ptr, len) = super::slice_ptr_parts_mut(buf); |
| 190 | assert!(options.pburst == crate::dma::Burst::Single, "Burst mode not supported"); | 160 | assert!(len > 0 && len <= 0xFFFF); |
| 191 | assert!( | 161 | |
| 192 | options.flow_ctrl == crate::dma::FlowControl::Dma, | 162 | Self::new_inner( |
| 193 | "Peripheral flow control not supported" | 163 | channel, |
| 194 | ); | 164 | request, |
| 195 | assert!(options.fifo_threshold.is_none(), "FIFO mode not supported"); | 165 | Dir::PeripheralToMemory, |
| 166 | peri_addr as *const u32, | ||
| 167 | ptr as *mut u32, | ||
| 168 | len, | ||
| 169 | true, | ||
| 170 | W::bits(), | ||
| 171 | options, | ||
| 172 | ) | ||
| 173 | } | ||
| 196 | 174 | ||
| 197 | let ch = dma.ch(channel_number as _); | 175 | pub unsafe fn new_write<W: Word>( |
| 176 | channel: impl Peripheral<P = C> + 'a, | ||
| 177 | request: Request, | ||
| 178 | buf: &'a [W], | ||
| 179 | peri_addr: *mut W, | ||
| 180 | options: TransferOptions, | ||
| 181 | ) -> Self { | ||
| 182 | Self::new_write_raw(channel, request, buf, peri_addr, options) | ||
| 183 | } | ||
| 198 | 184 | ||
| 199 | reset_status(dma, channel_number); | 185 | pub unsafe fn new_write_raw<W: Word>( |
| 186 | channel: impl Peripheral<P = C> + 'a, | ||
| 187 | request: Request, | ||
| 188 | buf: *const [W], | ||
| 189 | peri_addr: *mut W, | ||
| 190 | options: TransferOptions, | ||
| 191 | ) -> Self { | ||
| 192 | into_ref!(channel); | ||
| 193 | |||
| 194 | let (ptr, len) = super::slice_ptr_parts(buf); | ||
| 195 | assert!(len > 0 && len <= 0xFFFF); | ||
| 196 | |||
| 197 | Self::new_inner( | ||
| 198 | channel, | ||
| 199 | request, | ||
| 200 | Dir::MemoryToPeripheral, | ||
| 201 | peri_addr as *const u32, | ||
| 202 | ptr as *mut u32, | ||
| 203 | len, | ||
| 204 | true, | ||
| 205 | W::bits(), | ||
| 206 | options, | ||
| 207 | ) | ||
| 208 | } | ||
| 200 | 209 | ||
| 201 | #[cfg(dmamux)] | 210 | pub unsafe fn new_write_repeated<W: Word>( |
| 202 | super::super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); | 211 | channel: impl Peripheral<P = C> + 'a, |
| 212 | request: Request, | ||
| 213 | repeated: &'a W, | ||
| 214 | count: usize, | ||
| 215 | peri_addr: *mut W, | ||
| 216 | options: TransferOptions, | ||
| 217 | ) -> Self { | ||
| 218 | into_ref!(channel); | ||
| 219 | |||
| 220 | Self::new_inner( | ||
| 221 | channel, | ||
| 222 | request, | ||
| 223 | Dir::MemoryToPeripheral, | ||
| 224 | peri_addr as *const u32, | ||
| 225 | repeated as *const W as *mut u32, | ||
| 226 | count, | ||
| 227 | false, | ||
| 228 | W::bits(), | ||
| 229 | options, | ||
| 230 | ) | ||
| 231 | } | ||
| 203 | 232 | ||
| 204 | #[cfg(bdma_v2)] | 233 | unsafe fn new_inner( |
| 205 | critical_section::with(|_| dma.cselr().modify(|w| w.set_cs(channel_number as _, request))); | 234 | channel: PeripheralRef<'a, C>, |
| 235 | _request: Request, | ||
| 236 | dir: Dir, | ||
| 237 | peri_addr: *const u32, | ||
| 238 | mem_addr: *mut u32, | ||
| 239 | mem_len: usize, | ||
| 240 | incr_mem: bool, | ||
| 241 | data_size: WordSize, | ||
| 242 | _options: TransferOptions, | ||
| 243 | ) -> Self { | ||
| 244 | let ch = channel.regs().ch(channel.num()); | ||
| 206 | 245 | ||
| 207 | // "Preceding reads and writes cannot be moved past subsequent writes." | 246 | // "Preceding reads and writes cannot be moved past subsequent writes." |
| 208 | fence(Ordering::SeqCst); | 247 | fence(Ordering::SeqCst); |
| 209 | 248 | ||
| 249 | #[cfg(bdma_v2)] | ||
| 250 | critical_section::with(|_| channel.regs().cselr().modify(|w| w.set_cs(channel.num(), _request))); | ||
| 251 | |||
| 252 | let mut this = Self { channel }; | ||
| 253 | this.clear_irqs(); | ||
| 254 | |||
| 255 | #[cfg(dmamux)] | ||
| 256 | super::dmamux::configure_dmamux(&mut *this.channel, _request); | ||
| 257 | |||
| 210 | ch.par().write_value(peri_addr as u32); | 258 | ch.par().write_value(peri_addr as u32); |
| 211 | ch.mar().write_value(mem_addr as u32); | 259 | ch.mar().write_value(mem_addr as u32); |
| 212 | ch.ndtr().write(|w| w.set_ndt(mem_len as u16)); | 260 | ch.ndtr().write(|w| w.set_ndt(mem_len as u16)); |
| 213 | ch.cr().write(|w| { | 261 | ch.cr().write(|w| { |
| 214 | w.set_psize(data_size); | 262 | w.set_psize(data_size.into()); |
| 215 | w.set_msize(data_size); | 263 | w.set_msize(data_size.into()); |
| 216 | if incr_mem { | 264 | if incr_mem { |
| 217 | w.set_minc(vals::Inc::ENABLED); | 265 | w.set_minc(vals::Inc::ENABLED); |
| 218 | } else { | 266 | } else { |
| 219 | w.set_minc(vals::Inc::DISABLED); | 267 | w.set_minc(vals::Inc::DISABLED); |
| 220 | } | 268 | } |
| 221 | w.set_dir(dir); | 269 | w.set_dir(dir.into()); |
| 222 | w.set_teie(true); | 270 | w.set_teie(true); |
| 223 | w.set_tcie(true); | 271 | w.set_tcie(true); |
| 224 | w.set_en(true); | 272 | w.set_en(true); |
| 225 | }); | 273 | }); |
| 226 | } | ||
| 227 | 274 | ||
| 228 | pub unsafe fn request_stop(dma: pac::bdma::Dma, channel_number: u8) { | 275 | this |
| 229 | reset_status(dma, channel_number); | 276 | } |
| 230 | 277 | ||
| 231 | let ch = dma.ch(channel_number as _); | 278 | fn clear_irqs(&mut self) { |
| 279 | unsafe { | ||
| 280 | self.channel.regs().ifcr().write(|w| { | ||
| 281 | w.set_tcif(self.channel.num(), true); | ||
| 282 | w.set_teif(self.channel.num(), true); | ||
| 283 | }) | ||
| 284 | } | ||
| 285 | } | ||
| 232 | 286 | ||
| 233 | // Disable the channel and interrupts with the default value. | 287 | pub fn request_stop(&mut self) { |
| 234 | ch.cr().write(|_| ()); | 288 | let ch = self.channel.regs().ch(self.channel.num()); |
| 235 | 289 | ||
| 236 | // "Subsequent reads and writes cannot be moved ahead of preceding reads." | 290 | // Disable the channel. Keep the IEs enabled so the irqs still fire. |
| 237 | fence(Ordering::SeqCst); | 291 | unsafe { |
| 292 | ch.cr().write(|w| { | ||
| 293 | w.set_teie(true); | ||
| 294 | w.set_tcie(true); | ||
| 295 | }) | ||
| 296 | } | ||
| 238 | } | 297 | } |
| 239 | 298 | ||
| 240 | pub unsafe fn is_running(dma: pac::bdma::Dma, ch: u8) -> bool { | 299 | pub fn is_running(&mut self) -> bool { |
| 241 | let ch = dma.ch(ch as _); | 300 | let ch = self.channel.regs().ch(self.channel.num()); |
| 242 | ch.cr().read().en() | 301 | unsafe { ch.cr().read() }.en() |
| 243 | } | 302 | } |
| 244 | 303 | ||
| 245 | /// Gets the total remaining transfers for the channel | 304 | /// Gets the total remaining transfers for the channel |
| 246 | /// Note: this will be zero for transfers that completed without cancellation. | 305 | /// Note: this will be zero for transfers that completed without cancellation. |
| 247 | pub unsafe fn get_remaining_transfers(dma: pac::bdma::Dma, ch: u8) -> u16 { | 306 | pub fn get_remaining_transfers(&self) -> u16 { |
| 248 | // get a handle on the channel itself | 307 | let ch = self.channel.regs().ch(self.channel.num()); |
| 249 | let ch = dma.ch(ch as _); | 308 | unsafe { ch.ndtr().read() }.ndt() |
| 250 | // read the remaining transfer count. If this is zero, the transfer completed fully. | ||
| 251 | ch.ndtr().read().ndt() as u16 | ||
| 252 | } | 309 | } |
| 253 | 310 | ||
| 254 | /// Sets the waker for the specified DMA channel | 311 | pub fn blocking_wait(mut self) { |
| 255 | pub unsafe fn set_waker(state_number: usize, waker: &Waker) { | 312 | while self.is_running() {} |
| 256 | STATE.ch_wakers[state_number].register(waker); | ||
| 257 | } | ||
| 258 | 313 | ||
| 259 | pub unsafe fn reset_status(dma: pac::bdma::Dma, channel_number: u8) { | 314 | // "Subsequent reads and writes cannot be moved ahead of preceding reads." |
| 260 | dma.ifcr().write(|w| { | 315 | fence(Ordering::SeqCst); |
| 261 | w.set_tcif(channel_number as _, true); | 316 | |
| 262 | w.set_teif(channel_number as _, true); | 317 | core::mem::forget(self); |
| 263 | }); | ||
| 264 | } | 318 | } |
| 319 | } | ||
| 265 | 320 | ||
| 266 | /// Safety: Must be called with a matching set of parameters for a valid dma channel | 321 | impl<'a, C: Channel> Drop for Transfer<'a, C> { |
| 267 | pub unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: u8, index: u8) { | 322 | fn drop(&mut self) { |
| 268 | let channel_num = channel_num as usize; | 323 | self.request_stop(); |
| 269 | let index = index as usize; | 324 | while self.is_running() {} |
| 270 | 325 | ||
| 271 | let isr = dma.isr().read(); | 326 | // "Subsequent reads and writes cannot be moved ahead of preceding reads." |
| 272 | let cr = dma.ch(channel_num).cr(); | 327 | fence(Ordering::SeqCst); |
| 328 | } | ||
| 329 | } | ||
| 273 | 330 | ||
| 274 | if isr.teif(channel_num) { | 331 | impl<'a, C: Channel> Unpin for Transfer<'a, C> {} |
| 275 | panic!("DMA: error on BDMA@{:08x} channel {}", dma.0 as u32, channel_num); | 332 | impl<'a, C: Channel> Future for Transfer<'a, C> { |
| 276 | } | 333 | type Output = (); |
| 277 | if isr.tcif(channel_num) && cr.read().tcie() { | 334 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
| 278 | cr.write(|_| ()); // Disable channel interrupts with the default value. | 335 | STATE.ch_wakers[self.channel.index()].register(cx.waker()); |
| 279 | STATE.ch_wakers[index].wake(); | 336 | |
| 337 | if self.is_running() { | ||
| 338 | Poll::Pending | ||
| 339 | } else { | ||
| 340 | Poll::Ready(()) | ||
| 280 | } | 341 | } |
| 281 | } | 342 | } |
| 282 | } | 343 | } |
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 59937f4b0..9052aa110 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs | |||
| @@ -1,15 +1,44 @@ | |||
| 1 | use core::future::Future; | ||
| 2 | use core::pin::Pin; | ||
| 1 | use core::sync::atomic::{fence, Ordering}; | 3 | use core::sync::atomic::{fence, Ordering}; |
| 2 | use core::task::Waker; | 4 | use core::task::{Context, Poll}; |
| 3 | 5 | ||
| 4 | use embassy_cortex_m::interrupt::Priority; | 6 | use embassy_cortex_m::interrupt::Priority; |
| 7 | use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | ||
| 5 | use embassy_sync::waitqueue::AtomicWaker; | 8 | use embassy_sync::waitqueue::AtomicWaker; |
| 9 | use pac::dma::regs; | ||
| 6 | 10 | ||
| 7 | use super::{Burst, FifoThreshold, FlowControl, Request, TransferOptions, Word, WordSize}; | 11 | use super::{Dir, Word, WordSize}; |
| 8 | use crate::_generated::DMA_CHANNEL_COUNT; | 12 | use crate::_generated::DMA_CHANNEL_COUNT; |
| 9 | use crate::interrupt::{Interrupt, InterruptExt}; | 13 | use crate::interrupt::{Interrupt, InterruptExt}; |
| 10 | use crate::pac::dma::{regs, vals}; | 14 | use crate::pac::dma::vals; |
| 11 | use crate::{interrupt, pac}; | 15 | use crate::{interrupt, pac}; |
| 12 | 16 | ||
| 17 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 18 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 19 | #[non_exhaustive] | ||
| 20 | pub struct TransferOptions { | ||
| 21 | /// Peripheral burst transfer configuration | ||
| 22 | pub pburst: Burst, | ||
| 23 | /// Memory burst transfer configuration | ||
| 24 | pub mburst: Burst, | ||
| 25 | /// Flow control configuration | ||
| 26 | pub flow_ctrl: FlowControl, | ||
| 27 | /// FIFO threshold for DMA FIFO mode. If none, direct mode is used. | ||
| 28 | pub fifo_threshold: Option<FifoThreshold>, | ||
| 29 | } | ||
| 30 | |||
| 31 | impl Default for TransferOptions { | ||
| 32 | fn default() -> Self { | ||
| 33 | Self { | ||
| 34 | pburst: Burst::Single, | ||
| 35 | mburst: Burst::Single, | ||
| 36 | flow_ctrl: FlowControl::Dma, | ||
| 37 | fifo_threshold: None, | ||
| 38 | } | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 13 | impl From<WordSize> for vals::Size { | 42 | impl From<WordSize> for vals::Size { |
| 14 | fn from(raw: WordSize) -> Self { | 43 | fn from(raw: WordSize) -> Self { |
| 15 | match raw { | 44 | match raw { |
| @@ -20,6 +49,28 @@ impl From<WordSize> for vals::Size { | |||
| 20 | } | 49 | } |
| 21 | } | 50 | } |
| 22 | 51 | ||
| 52 | impl From<Dir> for vals::Dir { | ||
| 53 | fn from(raw: Dir) -> Self { | ||
| 54 | match raw { | ||
| 55 | Dir::MemoryToPeripheral => Self::MEMORYTOPERIPHERAL, | ||
| 56 | Dir::PeripheralToMemory => Self::PERIPHERALTOMEMORY, | ||
| 57 | } | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 62 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 63 | pub enum Burst { | ||
| 64 | /// Single transfer | ||
| 65 | Single, | ||
| 66 | /// Incremental burst of 4 beats | ||
| 67 | Incr4, | ||
| 68 | /// Incremental burst of 8 beats | ||
| 69 | Incr8, | ||
| 70 | /// Incremental burst of 16 beats | ||
| 71 | Incr16, | ||
| 72 | } | ||
| 73 | |||
| 23 | impl From<Burst> for vals::Burst { | 74 | impl From<Burst> for vals::Burst { |
| 24 | fn from(burst: Burst) -> Self { | 75 | fn from(burst: Burst) -> Self { |
| 25 | match burst { | 76 | match burst { |
| @@ -31,6 +82,15 @@ impl From<Burst> for vals::Burst { | |||
| 31 | } | 82 | } |
| 32 | } | 83 | } |
| 33 | 84 | ||
| 85 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 86 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 87 | pub enum FlowControl { | ||
| 88 | /// Flow control by DMA | ||
| 89 | Dma, | ||
| 90 | /// Flow control by peripheral | ||
| 91 | Peripheral, | ||
| 92 | } | ||
| 93 | |||
| 34 | impl From<FlowControl> for vals::Pfctrl { | 94 | impl From<FlowControl> for vals::Pfctrl { |
| 35 | fn from(flow: FlowControl) -> Self { | 95 | fn from(flow: FlowControl) -> Self { |
| 36 | match flow { | 96 | match flow { |
| @@ -40,6 +100,19 @@ impl From<FlowControl> for vals::Pfctrl { | |||
| 40 | } | 100 | } |
| 41 | } | 101 | } |
| 42 | 102 | ||
| 103 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 104 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 105 | pub enum FifoThreshold { | ||
| 106 | /// 1/4 full FIFO | ||
| 107 | Quarter, | ||
| 108 | /// 1/2 full FIFO | ||
| 109 | Half, | ||
| 110 | /// 3/4 full FIFO | ||
| 111 | ThreeQuarters, | ||
| 112 | /// Full FIFO | ||
| 113 | Full, | ||
| 114 | } | ||
| 115 | |||
| 43 | impl From<FifoThreshold> for vals::Fth { | 116 | impl From<FifoThreshold> for vals::Fth { |
| 44 | fn from(value: FifoThreshold) -> Self { | 117 | fn from(value: FifoThreshold) -> Self { |
| 45 | match value { | 118 | match value { |
| @@ -51,27 +124,15 @@ impl From<FifoThreshold> for vals::Fth { | |||
| 51 | } | 124 | } |
| 52 | } | 125 | } |
| 53 | 126 | ||
| 54 | struct ChannelState { | ||
| 55 | waker: AtomicWaker, | ||
| 56 | } | ||
| 57 | |||
| 58 | impl ChannelState { | ||
| 59 | const fn new() -> Self { | ||
| 60 | Self { | ||
| 61 | waker: AtomicWaker::new(), | ||
| 62 | } | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | struct State { | 127 | struct State { |
| 67 | channels: [ChannelState; DMA_CHANNEL_COUNT], | 128 | ch_wakers: [AtomicWaker; DMA_CHANNEL_COUNT], |
| 68 | } | 129 | } |
| 69 | 130 | ||
| 70 | impl State { | 131 | impl State { |
| 71 | const fn new() -> Self { | 132 | const fn new() -> Self { |
| 72 | const CH: ChannelState = ChannelState::new(); | 133 | const AW: AtomicWaker = AtomicWaker::new(); |
| 73 | Self { | 134 | Self { |
| 74 | channels: [CH; DMA_CHANNEL_COUNT], | 135 | ch_wakers: [AW; DMA_CHANNEL_COUNT], |
| 75 | } | 136 | } |
| 76 | } | 137 | } |
| 77 | } | 138 | } |
| @@ -92,158 +153,183 @@ pub(crate) unsafe fn init(irq_priority: Priority) { | |||
| 92 | 153 | ||
| 93 | foreach_dma_channel! { | 154 | foreach_dma_channel! { |
| 94 | ($channel_peri:ident, $dma_peri:ident, dma, $channel_num:expr, $index:expr, $dmamux:tt) => { | 155 | ($channel_peri:ident, $dma_peri:ident, dma, $channel_num:expr, $index:expr, $dmamux:tt) => { |
| 95 | impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri { | 156 | impl sealed::Channel for crate::peripherals::$channel_peri { |
| 96 | unsafe fn start_write<W: Word>(&mut self, request: Request, buf: *const [W], reg_addr: *mut W, options: TransferOptions) { | 157 | fn regs(&self) -> pac::dma::Dma { |
| 97 | let (ptr, len) = super::slice_ptr_parts(buf); | 158 | pac::$dma_peri |
| 98 | low_level_api::start_transfer( | ||
| 99 | pac::$dma_peri, | ||
| 100 | $channel_num, | ||
| 101 | request, | ||
| 102 | vals::Dir::MEMORYTOPERIPHERAL, | ||
| 103 | reg_addr as *const u32, | ||
| 104 | ptr as *mut u32, | ||
| 105 | len, | ||
| 106 | true, | ||
| 107 | vals::Size::from(W::bits()), | ||
| 108 | options, | ||
| 109 | #[cfg(dmamux)] | ||
| 110 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, | ||
| 111 | #[cfg(dmamux)] | ||
| 112 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, | ||
| 113 | ) | ||
| 114 | } | 159 | } |
| 115 | 160 | fn num(&self) -> usize { | |
| 116 | unsafe fn start_write_repeated<W: Word>(&mut self, request: Request, repeated: *const W, count: usize, reg_addr: *mut W, options: TransferOptions) { | 161 | $channel_num |
| 117 | low_level_api::start_transfer( | ||
| 118 | pac::$dma_peri, | ||
| 119 | $channel_num, | ||
| 120 | request, | ||
| 121 | vals::Dir::MEMORYTOPERIPHERAL, | ||
| 122 | reg_addr as *const u32, | ||
| 123 | repeated as *mut u32, | ||
| 124 | count, | ||
| 125 | false, | ||
| 126 | vals::Size::from(W::bits()), | ||
| 127 | options, | ||
| 128 | #[cfg(dmamux)] | ||
| 129 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, | ||
| 130 | #[cfg(dmamux)] | ||
| 131 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, | ||
| 132 | ) | ||
| 133 | } | 162 | } |
| 134 | 163 | fn index(&self) -> usize { | |
| 135 | unsafe fn start_read<W: Word>(&mut self, request: Request, reg_addr: *const W, buf: *mut [W], options: TransferOptions) { | 164 | $index |
| 136 | let (ptr, len) = super::slice_ptr_parts_mut(buf); | ||
| 137 | low_level_api::start_transfer( | ||
| 138 | pac::$dma_peri, | ||
| 139 | $channel_num, | ||
| 140 | request, | ||
| 141 | vals::Dir::PERIPHERALTOMEMORY, | ||
| 142 | reg_addr as *const u32, | ||
| 143 | ptr as *mut u32, | ||
| 144 | len, | ||
| 145 | true, | ||
| 146 | vals::Size::from(W::bits()), | ||
| 147 | options, | ||
| 148 | #[cfg(dmamux)] | ||
| 149 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, | ||
| 150 | #[cfg(dmamux)] | ||
| 151 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, | ||
| 152 | ); | ||
| 153 | } | 165 | } |
| 154 | 166 | fn on_irq() { | |
| 155 | unsafe fn start_double_buffered_read<W: Word>( | 167 | unsafe { on_irq_inner(pac::$dma_peri, $channel_num, $index) } |
| 156 | &mut self, | ||
| 157 | request: Request, | ||
| 158 | reg_addr: *const W, | ||
| 159 | buffer0: *mut W, | ||
| 160 | buffer1: *mut W, | ||
| 161 | buffer_len: usize, | ||
| 162 | options: TransferOptions, | ||
| 163 | ) { | ||
| 164 | low_level_api::start_dbm_transfer( | ||
| 165 | pac::$dma_peri, | ||
| 166 | $channel_num, | ||
| 167 | request, | ||
| 168 | vals::Dir::PERIPHERALTOMEMORY, | ||
| 169 | reg_addr as *const u32, | ||
| 170 | buffer0 as *mut u32, | ||
| 171 | buffer1 as *mut u32, | ||
| 172 | buffer_len, | ||
| 173 | true, | ||
| 174 | vals::Size::from(W::bits()), | ||
| 175 | options, | ||
| 176 | #[cfg(dmamux)] | ||
| 177 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, | ||
| 178 | #[cfg(dmamux)] | ||
| 179 | <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM, | ||
| 180 | ); | ||
| 181 | } | 168 | } |
| 169 | } | ||
| 182 | 170 | ||
| 183 | unsafe fn set_buffer0<W: Word>(&mut self, buffer: *mut W) { | 171 | impl Channel for crate::peripherals::$channel_peri {} |
| 184 | low_level_api::set_dbm_buffer0(pac::$dma_peri, $channel_num, buffer as *mut u32); | 172 | }; |
| 185 | } | 173 | } |
| 186 | 174 | ||
| 187 | unsafe fn set_buffer1<W: Word>(&mut self, buffer: *mut W) { | 175 | /// Safety: Must be called with a matching set of parameters for a valid dma channel |
| 188 | low_level_api::set_dbm_buffer1(pac::$dma_peri, $channel_num, buffer as *mut u32); | 176 | pub(crate) unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: usize, index: usize) { |
| 189 | } | 177 | let cr = dma.st(channel_num).cr(); |
| 178 | let isr = dma.isr(channel_num / 4).read(); | ||
| 190 | 179 | ||
| 191 | unsafe fn is_buffer0_accessible(&mut self) -> bool { | 180 | if isr.teif(channel_num % 4) { |
| 192 | low_level_api::is_buffer0_accessible(pac::$dma_peri, $channel_num) | 181 | panic!("DMA: error on DMA@{:08x} channel {}", dma.0 as u32, channel_num); |
| 193 | } | 182 | } |
| 194 | 183 | ||
| 195 | fn request_stop(&mut self) { | 184 | if isr.tcif(channel_num % 4) && cr.read().tcie() { |
| 196 | unsafe {low_level_api::request_stop(pac::$dma_peri, $channel_num);} | 185 | /* acknowledge transfer complete interrupt */ |
| 197 | } | 186 | dma.ifcr(channel_num / 4).write(|w| w.set_tcif(channel_num % 4, true)); |
| 187 | STATE.ch_wakers[index].wake(); | ||
| 188 | } | ||
| 189 | } | ||
| 198 | 190 | ||
| 199 | fn is_running(&self) -> bool { | 191 | #[cfg(any(dma_v2, dmamux))] |
| 200 | unsafe {low_level_api::is_running(pac::$dma_peri, $channel_num)} | 192 | pub type Request = u8; |
| 201 | } | 193 | #[cfg(not(any(dma_v2, dmamux)))] |
| 194 | pub type Request = (); | ||
| 202 | 195 | ||
| 203 | fn remaining_transfers(&mut self) -> u16 { | 196 | #[cfg(dmamux)] |
| 204 | unsafe {low_level_api::get_remaining_transfers(pac::$dma_peri, $channel_num)} | 197 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} |
| 205 | } | 198 | #[cfg(not(dmamux))] |
| 199 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} | ||
| 206 | 200 | ||
| 207 | fn set_waker(&mut self, waker: &Waker) { | 201 | pub(crate) mod sealed { |
| 208 | unsafe {low_level_api::set_waker($index, waker )} | 202 | use super::*; |
| 209 | } | ||
| 210 | 203 | ||
| 211 | fn on_irq() { | 204 | pub trait Channel { |
| 212 | unsafe { | 205 | fn regs(&self) -> pac::dma::Dma; |
| 213 | low_level_api::on_irq_inner(pac::$dma_peri, $channel_num, $index); | 206 | fn num(&self) -> usize; |
| 214 | } | 207 | fn index(&self) -> usize; |
| 215 | } | 208 | fn on_irq(); |
| 216 | } | 209 | } |
| 217 | impl crate::dma::Channel for crate::peripherals::$channel_peri { } | ||
| 218 | }; | ||
| 219 | } | 210 | } |
| 220 | 211 | ||
| 221 | mod low_level_api { | 212 | #[must_use = "futures do nothing unless you `.await` or poll them"] |
| 222 | use super::*; | 213 | pub struct Transfer<'a, C: Channel> { |
| 214 | channel: PeripheralRef<'a, C>, | ||
| 215 | } | ||
| 216 | |||
| 217 | impl<'a, C: Channel> Transfer<'a, C> { | ||
| 218 | pub unsafe fn new_read<W: Word>( | ||
| 219 | channel: impl Peripheral<P = C> + 'a, | ||
| 220 | request: Request, | ||
| 221 | peri_addr: *mut W, | ||
| 222 | buf: &'a mut [W], | ||
| 223 | options: TransferOptions, | ||
| 224 | ) -> Self { | ||
| 225 | Self::new_read_raw(channel, request, peri_addr, buf, options) | ||
| 226 | } | ||
| 227 | |||
| 228 | pub unsafe fn new_read_raw<W: Word>( | ||
| 229 | channel: impl Peripheral<P = C> + 'a, | ||
| 230 | request: Request, | ||
| 231 | peri_addr: *mut W, | ||
| 232 | buf: *mut [W], | ||
| 233 | options: TransferOptions, | ||
| 234 | ) -> Self { | ||
| 235 | into_ref!(channel); | ||
| 236 | |||
| 237 | let (ptr, len) = super::slice_ptr_parts_mut(buf); | ||
| 238 | assert!(len > 0 && len <= 0xFFFF); | ||
| 239 | |||
| 240 | Self::new_inner( | ||
| 241 | channel, | ||
| 242 | request, | ||
| 243 | Dir::PeripheralToMemory, | ||
| 244 | peri_addr as *const u32, | ||
| 245 | ptr as *mut u32, | ||
| 246 | len, | ||
| 247 | true, | ||
| 248 | W::bits(), | ||
| 249 | options, | ||
| 250 | ) | ||
| 251 | } | ||
| 252 | |||
| 253 | pub unsafe fn new_write<W: Word>( | ||
| 254 | channel: impl Peripheral<P = C> + 'a, | ||
| 255 | request: Request, | ||
| 256 | buf: &'a [W], | ||
| 257 | peri_addr: *mut W, | ||
| 258 | options: TransferOptions, | ||
| 259 | ) -> Self { | ||
| 260 | Self::new_write_raw(channel, request, buf, peri_addr, options) | ||
| 261 | } | ||
| 262 | |||
| 263 | pub unsafe fn new_write_raw<W: Word>( | ||
| 264 | channel: impl Peripheral<P = C> + 'a, | ||
| 265 | request: Request, | ||
| 266 | buf: *const [W], | ||
| 267 | peri_addr: *mut W, | ||
| 268 | options: TransferOptions, | ||
| 269 | ) -> Self { | ||
| 270 | into_ref!(channel); | ||
| 271 | |||
| 272 | let (ptr, len) = super::slice_ptr_parts(buf); | ||
| 273 | assert!(len > 0 && len <= 0xFFFF); | ||
| 274 | |||
| 275 | Self::new_inner( | ||
| 276 | channel, | ||
| 277 | request, | ||
| 278 | Dir::MemoryToPeripheral, | ||
| 279 | peri_addr as *const u32, | ||
| 280 | ptr as *mut u32, | ||
| 281 | len, | ||
| 282 | true, | ||
| 283 | W::bits(), | ||
| 284 | options, | ||
| 285 | ) | ||
| 286 | } | ||
| 223 | 287 | ||
| 224 | pub unsafe fn start_transfer( | 288 | pub unsafe fn new_write_repeated<W: Word>( |
| 225 | dma: pac::dma::Dma, | 289 | channel: impl Peripheral<P = C> + 'a, |
| 226 | channel_number: u8, | ||
| 227 | request: Request, | 290 | request: Request, |
| 228 | dir: vals::Dir, | 291 | repeated: &'a W, |
| 292 | count: usize, | ||
| 293 | peri_addr: *mut W, | ||
| 294 | options: TransferOptions, | ||
| 295 | ) -> Self { | ||
| 296 | into_ref!(channel); | ||
| 297 | |||
| 298 | Self::new_inner( | ||
| 299 | channel, | ||
| 300 | request, | ||
| 301 | Dir::MemoryToPeripheral, | ||
| 302 | peri_addr as *const u32, | ||
| 303 | repeated as *const W as *mut u32, | ||
| 304 | count, | ||
| 305 | false, | ||
| 306 | W::bits(), | ||
| 307 | options, | ||
| 308 | ) | ||
| 309 | } | ||
| 310 | |||
| 311 | unsafe fn new_inner( | ||
| 312 | channel: PeripheralRef<'a, C>, | ||
| 313 | _request: Request, | ||
| 314 | dir: Dir, | ||
| 229 | peri_addr: *const u32, | 315 | peri_addr: *const u32, |
| 230 | mem_addr: *mut u32, | 316 | mem_addr: *mut u32, |
| 231 | mem_len: usize, | 317 | mem_len: usize, |
| 232 | incr_mem: bool, | 318 | incr_mem: bool, |
| 233 | data_size: vals::Size, | 319 | data_size: WordSize, |
| 234 | options: TransferOptions, | 320 | options: TransferOptions, |
| 235 | #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, | 321 | ) -> Self { |
| 236 | #[cfg(dmamux)] dmamux_ch_num: u8, | 322 | let ch = channel.regs().st(channel.num()); |
| 237 | ) { | ||
| 238 | #[cfg(dmamux)] | ||
| 239 | super::super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); | ||
| 240 | 323 | ||
| 241 | // "Preceding reads and writes cannot be moved past subsequent writes." | 324 | // "Preceding reads and writes cannot be moved past subsequent writes." |
| 242 | fence(Ordering::SeqCst); | 325 | fence(Ordering::SeqCst); |
| 243 | 326 | ||
| 244 | reset_status(dma, channel_number); | 327 | let mut this = Self { channel }; |
| 328 | this.clear_irqs(); | ||
| 329 | |||
| 330 | #[cfg(dmamux)] | ||
| 331 | super::dmamux::configure_dmamux(&mut *this.channel, _request); | ||
| 245 | 332 | ||
| 246 | let ch = dma.st(channel_number as _); | ||
| 247 | ch.par().write_value(peri_addr as u32); | 333 | ch.par().write_value(peri_addr as u32); |
| 248 | ch.m0ar().write_value(mem_addr as u32); | 334 | ch.m0ar().write_value(mem_addr as u32); |
| 249 | ch.ndtr().write_value(regs::Ndtr(mem_len as _)); | 335 | ch.ndtr().write_value(regs::Ndtr(mem_len as _)); |
| @@ -258,90 +344,22 @@ mod low_level_api { | |||
| 258 | } | 344 | } |
| 259 | }); | 345 | }); |
| 260 | ch.cr().write(|w| { | 346 | ch.cr().write(|w| { |
| 261 | w.set_dir(dir); | 347 | w.set_dir(dir.into()); |
| 262 | w.set_msize(data_size); | 348 | w.set_msize(data_size.into()); |
| 263 | w.set_psize(data_size); | 349 | w.set_psize(data_size.into()); |
| 264 | w.set_pl(vals::Pl::VERYHIGH); | ||
| 265 | if incr_mem { | ||
| 266 | w.set_minc(vals::Inc::INCREMENTED); | ||
| 267 | } else { | ||
| 268 | w.set_minc(vals::Inc::FIXED); | ||
| 269 | } | ||
| 270 | w.set_pinc(vals::Inc::FIXED); | ||
| 271 | w.set_teie(true); | ||
| 272 | w.set_tcie(true); | ||
| 273 | #[cfg(dma_v1)] | ||
| 274 | w.set_trbuff(true); | ||
| 275 | |||
| 276 | #[cfg(dma_v2)] | ||
| 277 | w.set_chsel(request); | ||
| 278 | |||
| 279 | w.set_pburst(options.pburst.into()); | ||
| 280 | w.set_mburst(options.mburst.into()); | ||
| 281 | w.set_pfctrl(options.flow_ctrl.into()); | ||
| 282 | |||
| 283 | w.set_en(true); | ||
| 284 | }); | ||
| 285 | } | ||
| 286 | |||
| 287 | pub unsafe fn start_dbm_transfer( | ||
| 288 | dma: pac::dma::Dma, | ||
| 289 | channel_number: u8, | ||
| 290 | request: Request, | ||
| 291 | dir: vals::Dir, | ||
| 292 | peri_addr: *const u32, | ||
| 293 | mem0_addr: *mut u32, | ||
| 294 | mem1_addr: *mut u32, | ||
| 295 | mem_len: usize, | ||
| 296 | incr_mem: bool, | ||
| 297 | data_size: vals::Size, | ||
| 298 | options: TransferOptions, | ||
| 299 | #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, | ||
| 300 | #[cfg(dmamux)] dmamux_ch_num: u8, | ||
| 301 | ) { | ||
| 302 | #[cfg(dmamux)] | ||
| 303 | super::super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); | ||
| 304 | |||
| 305 | trace!( | ||
| 306 | "Starting DBM transfer with 0: 0x{:x}, 1: 0x{:x}, len: 0x{:x}", | ||
| 307 | mem0_addr as u32, | ||
| 308 | mem1_addr as u32, | ||
| 309 | mem_len | ||
| 310 | ); | ||
| 311 | |||
| 312 | // "Preceding reads and writes cannot be moved past subsequent writes." | ||
| 313 | fence(Ordering::SeqCst); | ||
| 314 | |||
| 315 | reset_status(dma, channel_number); | ||
| 316 | |||
| 317 | let ch = dma.st(channel_number as _); | ||
| 318 | ch.par().write_value(peri_addr as u32); | ||
| 319 | ch.m0ar().write_value(mem0_addr as u32); | ||
| 320 | // configures the second buffer for DBM | ||
| 321 | ch.m1ar().write_value(mem1_addr as u32); | ||
| 322 | ch.ndtr().write_value(regs::Ndtr(mem_len as _)); | ||
| 323 | ch.cr().write(|w| { | ||
| 324 | w.set_dir(dir); | ||
| 325 | w.set_msize(data_size); | ||
| 326 | w.set_psize(data_size); | ||
| 327 | w.set_pl(vals::Pl::VERYHIGH); | 350 | w.set_pl(vals::Pl::VERYHIGH); |
| 328 | if incr_mem { | 351 | w.set_minc(match incr_mem { |
| 329 | w.set_minc(vals::Inc::INCREMENTED); | 352 | true => vals::Inc::INCREMENTED, |
| 330 | } else { | 353 | false => vals::Inc::FIXED, |
| 331 | w.set_minc(vals::Inc::FIXED); | 354 | }); |
| 332 | } | ||
| 333 | w.set_pinc(vals::Inc::FIXED); | 355 | w.set_pinc(vals::Inc::FIXED); |
| 334 | w.set_teie(true); | 356 | w.set_teie(true); |
| 335 | w.set_tcie(true); | 357 | w.set_tcie(true); |
| 336 | |||
| 337 | #[cfg(dma_v1)] | 358 | #[cfg(dma_v1)] |
| 338 | w.set_trbuff(true); | 359 | w.set_trbuff(true); |
| 339 | 360 | ||
| 340 | #[cfg(dma_v2)] | 361 | #[cfg(dma_v2)] |
| 341 | w.set_chsel(request); | 362 | w.set_chsel(_request); |
| 342 | |||
| 343 | // enable double buffered mode | ||
| 344 | w.set_dbm(vals::Dbm::ENABLED); | ||
| 345 | 363 | ||
| 346 | w.set_pburst(options.pburst.into()); | 364 | w.set_pburst(options.pburst.into()); |
| 347 | w.set_mburst(options.mburst.into()); | 365 | w.set_mburst(options.mburst.into()); |
| @@ -349,92 +367,76 @@ mod low_level_api { | |||
| 349 | 367 | ||
| 350 | w.set_en(true); | 368 | w.set_en(true); |
| 351 | }); | 369 | }); |
| 352 | } | ||
| 353 | 370 | ||
| 354 | pub unsafe fn set_dbm_buffer0(dma: pac::dma::Dma, channel_number: u8, mem_addr: *mut u32) { | 371 | this |
| 355 | // get a handle on the channel itself | ||
| 356 | let ch = dma.st(channel_number as _); | ||
| 357 | // change M0AR to the new address | ||
| 358 | ch.m0ar().write_value(mem_addr as _); | ||
| 359 | } | 372 | } |
| 360 | 373 | ||
| 361 | pub unsafe fn set_dbm_buffer1(dma: pac::dma::Dma, channel_number: u8, mem_addr: *mut u32) { | 374 | fn clear_irqs(&mut self) { |
| 362 | // get a handle on the channel itself | 375 | let isrn = self.channel.num() / 4; |
| 363 | let ch = dma.st(channel_number as _); | 376 | let isrbit = self.channel.num() % 4; |
| 364 | // change M1AR to the new address | ||
| 365 | ch.m1ar().write_value(mem_addr as _); | ||
| 366 | } | ||
| 367 | 377 | ||
| 368 | pub unsafe fn is_buffer0_accessible(dma: pac::dma::Dma, channel_number: u8) -> bool { | 378 | unsafe { |
| 369 | // get a handle on the channel itself | 379 | self.channel.regs().ifcr(isrn).write(|w| { |
| 370 | let ch = dma.st(channel_number as _); | 380 | w.set_tcif(isrbit, true); |
| 371 | // check the current target register value | 381 | w.set_teif(isrbit, true); |
| 372 | ch.cr().read().ct() == vals::Ct::MEMORY1 | 382 | }) |
| 383 | } | ||
| 373 | } | 384 | } |
| 374 | 385 | ||
| 375 | /// Stops the DMA channel. | 386 | pub fn request_stop(&mut self) { |
| 376 | pub unsafe fn request_stop(dma: pac::dma::Dma, channel_number: u8) { | 387 | let ch = self.channel.regs().st(self.channel.num()); |
| 377 | // get a handle on the channel itself | ||
| 378 | let ch = dma.st(channel_number as _); | ||
| 379 | 388 | ||
| 380 | // Disable the channel. Keep the IEs enabled so the irqs still fire. | 389 | // Disable the channel. Keep the IEs enabled so the irqs still fire. |
| 381 | ch.cr().write(|w| { | 390 | unsafe { |
| 382 | w.set_teie(true); | 391 | ch.cr().write(|w| { |
| 383 | w.set_tcie(true); | 392 | w.set_teie(true); |
| 384 | }); | 393 | w.set_tcie(true); |
| 385 | 394 | }) | |
| 386 | // "Subsequent reads and writes cannot be moved ahead of preceding reads." | 395 | } |
| 387 | fence(Ordering::SeqCst); | ||
| 388 | } | 396 | } |
| 389 | 397 | ||
| 390 | /// Gets the running status of the channel | 398 | pub fn is_running(&mut self) -> bool { |
| 391 | pub unsafe fn is_running(dma: pac::dma::Dma, ch: u8) -> bool { | 399 | let ch = self.channel.regs().st(self.channel.num()); |
| 392 | // get a handle on the channel itself | 400 | unsafe { ch.cr().read() }.en() |
| 393 | let ch = dma.st(ch as _); | ||
| 394 | // Get whether it's enabled (running) | ||
| 395 | ch.cr().read().en() | ||
| 396 | } | 401 | } |
| 397 | 402 | ||
| 398 | /// Gets the total remaining transfers for the channel | 403 | /// Gets the total remaining transfers for the channel |
| 399 | /// Note: this will be zero for transfers that completed without cancellation. | 404 | /// Note: this will be zero for transfers that completed without cancellation. |
| 400 | pub unsafe fn get_remaining_transfers(dma: pac::dma::Dma, ch: u8) -> u16 { | 405 | pub fn get_remaining_transfers(&self) -> u16 { |
| 401 | // get a handle on the channel itself | 406 | let ch = self.channel.regs().st(self.channel.num()); |
| 402 | let ch = dma.st(ch as _); | 407 | unsafe { ch.ndtr().read() }.ndt() |
| 403 | // read the remaining transfer count. If this is zero, the transfer completed fully. | ||
| 404 | ch.ndtr().read().ndt() | ||
| 405 | } | 408 | } |
| 406 | 409 | ||
| 407 | /// Sets the waker for the specified DMA channel | 410 | pub fn blocking_wait(mut self) { |
| 408 | pub unsafe fn set_waker(state_number: usize, waker: &Waker) { | 411 | while self.is_running() {} |
| 409 | STATE.channels[state_number].waker.register(waker); | ||
| 410 | } | ||
| 411 | 412 | ||
| 412 | pub unsafe fn reset_status(dma: pac::dma::Dma, channel_number: u8) { | 413 | // "Subsequent reads and writes cannot be moved ahead of preceding reads." |
| 413 | let isrn = channel_number as usize / 4; | 414 | fence(Ordering::SeqCst); |
| 414 | let isrbit = channel_number as usize % 4; | ||
| 415 | 415 | ||
| 416 | dma.ifcr(isrn).write(|w| { | 416 | core::mem::forget(self); |
| 417 | w.set_tcif(isrbit, true); | ||
| 418 | w.set_teif(isrbit, true); | ||
| 419 | }); | ||
| 420 | } | 417 | } |
| 418 | } | ||
| 421 | 419 | ||
| 422 | /// Safety: Must be called with a matching set of parameters for a valid dma channel | 420 | impl<'a, C: Channel> Drop for Transfer<'a, C> { |
| 423 | pub unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: u8, state_index: u8) { | 421 | fn drop(&mut self) { |
| 424 | let channel_num = channel_num as usize; | 422 | self.request_stop(); |
| 425 | let state_index = state_index as usize; | 423 | while self.is_running() {} |
| 426 | 424 | ||
| 427 | let cr = dma.st(channel_num).cr(); | 425 | // "Subsequent reads and writes cannot be moved ahead of preceding reads." |
| 428 | let isr = dma.isr(channel_num / 4).read(); | 426 | fence(Ordering::SeqCst); |
| 427 | } | ||
| 428 | } | ||
| 429 | 429 | ||
| 430 | if isr.teif(channel_num % 4) { | 430 | impl<'a, C: Channel> Unpin for Transfer<'a, C> {} |
| 431 | panic!("DMA: error on DMA@{:08x} channel {}", dma.0 as u32, channel_num); | 431 | impl<'a, C: Channel> Future for Transfer<'a, C> { |
| 432 | } | 432 | type Output = (); |
| 433 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
| 434 | STATE.ch_wakers[self.channel.index()].register(cx.waker()); | ||
| 433 | 435 | ||
| 434 | if isr.tcif(channel_num % 4) && cr.read().tcie() { | 436 | if self.is_running() { |
| 435 | /* acknowledge transfer complete interrupt */ | 437 | Poll::Pending |
| 436 | dma.ifcr(channel_num / 4).write(|w| w.set_tcif(channel_num % 4, true)); | 438 | } else { |
| 437 | STATE.channels[state_index].waker.wake(); | 439 | Poll::Ready(()) |
| 438 | } | 440 | } |
| 439 | } | 441 | } |
| 440 | } | 442 | } |
diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs index e9967e349..a8c4c5827 100644 --- a/embassy-stm32/src/dma/dmamux.rs +++ b/embassy-stm32/src/dma/dmamux.rs | |||
| @@ -2,8 +2,8 @@ | |||
| 2 | 2 | ||
| 3 | use crate::{pac, peripherals}; | 3 | use crate::{pac, peripherals}; |
| 4 | 4 | ||
| 5 | pub(crate) unsafe fn configure_dmamux(dmamux_regs: pac::dmamux::Dmamux, dmamux_ch_num: u8, request: u8) { | 5 | pub(crate) unsafe fn configure_dmamux<M: MuxChannel>(channel: &mut M, request: u8) { |
| 6 | let ch_mux_regs = dmamux_regs.ccr(dmamux_ch_num as _); | 6 | let ch_mux_regs = channel.mux_regs().ccr(channel.mux_num()); |
| 7 | ch_mux_regs.write(|reg| { | 7 | ch_mux_regs.write(|reg| { |
| 8 | reg.set_nbreq(0); | 8 | reg.set_nbreq(0); |
| 9 | reg.set_dmareq_id(request); | 9 | reg.set_dmareq_id(request); |
| @@ -14,11 +14,11 @@ pub(crate) unsafe fn configure_dmamux(dmamux_regs: pac::dmamux::Dmamux, dmamux_c | |||
| 14 | }); | 14 | }); |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | pub(crate) mod sealed { | 17 | pub(crate) mod dmamux_sealed { |
| 18 | use super::*; | 18 | use super::*; |
| 19 | pub trait MuxChannel { | 19 | pub trait MuxChannel { |
| 20 | const DMAMUX_CH_NUM: u8; | 20 | fn mux_regs(&self) -> pac::dmamux::Dmamux; |
| 21 | const DMAMUX_REGS: pac::dmamux::Dmamux; | 21 | fn mux_num(&self) -> usize; |
| 22 | } | 22 | } |
| 23 | } | 23 | } |
| 24 | 24 | ||
| @@ -26,15 +26,19 @@ pub struct DMAMUX1; | |||
| 26 | #[cfg(stm32h7)] | 26 | #[cfg(stm32h7)] |
| 27 | pub struct DMAMUX2; | 27 | pub struct DMAMUX2; |
| 28 | 28 | ||
| 29 | pub trait MuxChannel: sealed::MuxChannel + super::Channel { | 29 | pub trait MuxChannel: dmamux_sealed::MuxChannel { |
| 30 | type Mux; | 30 | type Mux; |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | foreach_dma_channel! { | 33 | foreach_dma_channel! { |
| 34 | ($channel_peri:ident, $dma_peri:ident, $version:ident, $channel_num:expr, $index:expr, {dmamux: $dmamux:ident, dmamux_channel: $dmamux_channel:expr}) => { | 34 | ($channel_peri:ident, $dma_peri:ident, $version:ident, $channel_num:expr, $index:expr, {dmamux: $dmamux:ident, dmamux_channel: $dmamux_channel:expr}) => { |
| 35 | impl sealed::MuxChannel for peripherals::$channel_peri { | 35 | impl dmamux_sealed::MuxChannel for peripherals::$channel_peri { |
| 36 | const DMAMUX_CH_NUM: u8 = $dmamux_channel; | 36 | fn mux_regs(&self) -> pac::dmamux::Dmamux { |
| 37 | const DMAMUX_REGS: pac::dmamux::Dmamux = pac::$dmamux; | 37 | pac::$dmamux |
| 38 | } | ||
| 39 | fn mux_num(&self) -> usize { | ||
| 40 | $dmamux_channel | ||
| 41 | } | ||
| 38 | } | 42 | } |
| 39 | impl MuxChannel for peripherals::$channel_peri { | 43 | impl MuxChannel for peripherals::$channel_peri { |
| 40 | type Mux = $dmamux; | 44 | type Mux = $dmamux; |
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index 6f26fd194..5c6676a5f 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs | |||
| @@ -1,13 +1,30 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 3 | use core::future::Future; | ||
| 4 | use core::pin::Pin; | ||
| 1 | use core::sync::atomic::{fence, Ordering}; | 5 | use core::sync::atomic::{fence, Ordering}; |
| 2 | use core::task::Waker; | 6 | use core::task::{Context, Poll}; |
| 3 | 7 | ||
| 8 | use embassy_cortex_m::interrupt::Priority; | ||
| 9 | use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | ||
| 4 | use embassy_sync::waitqueue::AtomicWaker; | 10 | use embassy_sync::waitqueue::AtomicWaker; |
| 5 | 11 | ||
| 6 | use super::{Request, TransferOptions, Word, WordSize}; | 12 | use super::{Dir, Word, WordSize}; |
| 7 | use crate::_generated::GPDMA_CHANNEL_COUNT; | 13 | use crate::_generated::GPDMA_CHANNEL_COUNT; |
| 8 | use crate::interrupt::{Interrupt, InterruptExt}; | 14 | use crate::interrupt::{Interrupt, InterruptExt}; |
| 9 | use crate::pac::gpdma::{vals, Gpdma}; | 15 | use crate::pac; |
| 10 | use crate::{interrupt, pac}; | 16 | use crate::pac::gpdma::vals; |
| 17 | |||
| 18 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 19 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 20 | #[non_exhaustive] | ||
| 21 | pub struct TransferOptions {} | ||
| 22 | |||
| 23 | impl Default for TransferOptions { | ||
| 24 | fn default() -> Self { | ||
| 25 | Self {} | ||
| 26 | } | ||
| 27 | } | ||
| 11 | 28 | ||
| 12 | impl From<WordSize> for vals::ChTr1Dw { | 29 | impl From<WordSize> for vals::ChTr1Dw { |
| 13 | fn from(raw: WordSize) -> Self { | 30 | fn from(raw: WordSize) -> Self { |
| @@ -19,27 +36,15 @@ impl From<WordSize> for vals::ChTr1Dw { | |||
| 19 | } | 36 | } |
| 20 | } | 37 | } |
| 21 | 38 | ||
| 22 | struct ChannelState { | ||
| 23 | waker: AtomicWaker, | ||
| 24 | } | ||
| 25 | |||
| 26 | impl ChannelState { | ||
| 27 | const fn new() -> Self { | ||
| 28 | Self { | ||
| 29 | waker: AtomicWaker::new(), | ||
| 30 | } | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | struct State { | 39 | struct State { |
| 35 | channels: [ChannelState; GPDMA_CHANNEL_COUNT], | 40 | ch_wakers: [AtomicWaker; GPDMA_CHANNEL_COUNT], |
| 36 | } | 41 | } |
| 37 | 42 | ||
| 38 | impl State { | 43 | impl State { |
| 39 | const fn new() -> Self { | 44 | const fn new() -> Self { |
| 40 | const CH: ChannelState = ChannelState::new(); | 45 | const AW: AtomicWaker = AtomicWaker::new(); |
| 41 | Self { | 46 | Self { |
| 42 | channels: [CH; GPDMA_CHANNEL_COUNT], | 47 | ch_wakers: [AW; GPDMA_CHANNEL_COUNT], |
| 43 | } | 48 | } |
| 44 | } | 49 | } |
| 45 | } | 50 | } |
| @@ -47,10 +52,12 @@ impl State { | |||
| 47 | static STATE: State = State::new(); | 52 | static STATE: State = State::new(); |
| 48 | 53 | ||
| 49 | /// safety: must be called only once | 54 | /// safety: must be called only once |
| 50 | pub(crate) unsafe fn init() { | 55 | pub(crate) unsafe fn init(irq_priority: Priority) { |
| 51 | foreach_interrupt! { | 56 | foreach_interrupt! { |
| 52 | ($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => { | 57 | ($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => { |
| 53 | interrupt::$irq::steal().enable(); | 58 | let irq = crate::interrupt::$irq::steal(); |
| 59 | irq.set_priority(irq_priority); | ||
| 60 | irq.enable(); | ||
| 54 | }; | 61 | }; |
| 55 | } | 62 | } |
| 56 | crate::_generated::init_gpdma(); | 63 | crate::_generated::init_gpdma(); |
| @@ -58,117 +65,171 @@ pub(crate) unsafe fn init() { | |||
| 58 | 65 | ||
| 59 | foreach_dma_channel! { | 66 | foreach_dma_channel! { |
| 60 | ($channel_peri:ident, $dma_peri:ident, gpdma, $channel_num:expr, $index:expr, $dmamux:tt) => { | 67 | ($channel_peri:ident, $dma_peri:ident, gpdma, $channel_num:expr, $index:expr, $dmamux:tt) => { |
| 61 | impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri { | 68 | impl sealed::Channel for crate::peripherals::$channel_peri { |
| 62 | unsafe fn start_write<W: Word>(&mut self, request: Request, buf: *const [W], reg_addr: *mut W, options: TransferOptions) { | 69 | fn regs(&self) -> pac::gpdma::Gpdma { |
| 63 | let (ptr, len) = super::slice_ptr_parts(buf); | 70 | pac::$dma_peri |
| 64 | low_level_api::start_transfer( | ||
| 65 | pac::$dma_peri, | ||
| 66 | $channel_num, | ||
| 67 | request, | ||
| 68 | low_level_api::Dir::MemoryToPeripheral, | ||
| 69 | reg_addr as *const u32, | ||
| 70 | ptr as *mut u32, | ||
| 71 | len, | ||
| 72 | true, | ||
| 73 | W::bits(), | ||
| 74 | options, | ||
| 75 | ) | ||
| 76 | } | 71 | } |
| 77 | 72 | fn num(&self) -> usize { | |
| 78 | unsafe fn start_write_repeated<W: Word>(&mut self, request: Request, repeated: *const W, count: usize, reg_addr: *mut W, options: TransferOptions) { | 73 | $channel_num |
| 79 | low_level_api::start_transfer( | ||
| 80 | pac::$dma_peri, | ||
| 81 | $channel_num, | ||
| 82 | request, | ||
| 83 | low_level_api::Dir::MemoryToPeripheral, | ||
| 84 | reg_addr as *const u32, | ||
| 85 | repeated as *mut u32, | ||
| 86 | count, | ||
| 87 | false, | ||
| 88 | W::bits(), | ||
| 89 | options, | ||
| 90 | ) | ||
| 91 | } | 74 | } |
| 92 | 75 | fn index(&self) -> usize { | |
| 93 | unsafe fn start_read<W: Word>(&mut self, request: Request, reg_addr: *const W, buf: *mut [W], options: TransferOptions) { | 76 | $index |
| 94 | let (ptr, len) = super::slice_ptr_parts_mut(buf); | ||
| 95 | low_level_api::start_transfer( | ||
| 96 | pac::$dma_peri, | ||
| 97 | $channel_num, | ||
| 98 | request, | ||
| 99 | low_level_api::Dir::PeripheralToMemory, | ||
| 100 | reg_addr as *const u32, | ||
| 101 | ptr as *mut u32, | ||
| 102 | len, | ||
| 103 | true, | ||
| 104 | W::bits(), | ||
| 105 | options, | ||
| 106 | ); | ||
| 107 | } | 77 | } |
| 108 | 78 | fn on_irq() { | |
| 109 | unsafe fn start_double_buffered_read<W: Word>( | 79 | unsafe { on_irq_inner(pac::$dma_peri, $channel_num, $index) } |
| 110 | &mut self, | ||
| 111 | _request: Request, | ||
| 112 | _reg_addr: *const W, | ||
| 113 | _buffer0: *mut W, | ||
| 114 | _buffer1: *mut W, | ||
| 115 | _buffer_len: usize, | ||
| 116 | _options: TransferOptions, | ||
| 117 | ) { | ||
| 118 | panic!("Unsafe double buffered mode is unavailable on GPBDMA"); | ||
| 119 | } | 80 | } |
| 81 | } | ||
| 120 | 82 | ||
| 121 | unsafe fn set_buffer0<W: Word>(&mut self, _buffer: *mut W) { | 83 | impl Channel for crate::peripherals::$channel_peri {} |
| 122 | panic!("Unsafe double buffered mode is unavailable on GPBDMA"); | 84 | }; |
| 123 | } | 85 | } |
| 124 | 86 | ||
| 125 | unsafe fn set_buffer1<W: Word>(&mut self, _buffer: *mut W) { | 87 | /// Safety: Must be called with a matching set of parameters for a valid dma channel |
| 126 | panic!("Unsafe double buffered mode is unavailable on GPBDMA"); | 88 | pub(crate) unsafe fn on_irq_inner(dma: pac::gpdma::Gpdma, channel_num: usize, index: usize) { |
| 127 | } | 89 | let ch = dma.ch(channel_num); |
| 90 | let sr = ch.sr().read(); | ||
| 128 | 91 | ||
| 129 | unsafe fn is_buffer0_accessible(&mut self) -> bool { | 92 | if sr.dtef() { |
| 130 | panic!("Unsafe double buffered mode is unavailable on GPBDMA"); | 93 | panic!( |
| 131 | } | 94 | "DMA: data transfer error on DMA@{:08x} channel {}", |
| 95 | dma.0 as u32, channel_num | ||
| 96 | ); | ||
| 97 | } | ||
| 98 | if sr.usef() { | ||
| 99 | panic!( | ||
| 100 | "DMA: user settings error on DMA@{:08x} channel {}", | ||
| 101 | dma.0 as u32, channel_num | ||
| 102 | ); | ||
| 103 | } | ||
| 132 | 104 | ||
| 133 | fn request_stop(&mut self) { | 105 | if sr.suspf() || sr.tcf() { |
| 134 | unsafe {low_level_api::request_stop(pac::$dma_peri, $channel_num);} | 106 | // disable all xxIEs to prevent the irq from firing again. |
| 135 | } | 107 | ch.cr().write(|_| {}); |
| 136 | 108 | ||
| 137 | fn is_running(&self) -> bool { | 109 | // Wake the future. It'll look at tcf and see it's set. |
| 138 | unsafe {low_level_api::is_running(pac::$dma_peri, $channel_num)} | 110 | STATE.ch_wakers[index].wake(); |
| 139 | } | 111 | } |
| 112 | } | ||
| 140 | 113 | ||
| 141 | fn remaining_transfers(&mut self) -> u16 { | 114 | pub type Request = u8; |
| 142 | unsafe {low_level_api::get_remaining_transfers(pac::$dma_peri, $channel_num)} | ||
| 143 | } | ||
| 144 | 115 | ||
| 145 | fn set_waker(&mut self, waker: &Waker) { | 116 | #[cfg(dmamux)] |
| 146 | unsafe {low_level_api::set_waker($index, waker )} | 117 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} |
| 147 | } | 118 | #[cfg(not(dmamux))] |
| 119 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} | ||
| 148 | 120 | ||
| 149 | fn on_irq() { | 121 | pub(crate) mod sealed { |
| 150 | unsafe { | 122 | use super::*; |
| 151 | low_level_api::on_irq_inner(pac::$dma_peri, $channel_num, $index); | 123 | |
| 152 | } | 124 | pub trait Channel { |
| 153 | } | 125 | fn regs(&self) -> pac::gpdma::Gpdma; |
| 154 | } | 126 | fn num(&self) -> usize; |
| 155 | impl crate::dma::Channel for crate::peripherals::$channel_peri { } | 127 | fn index(&self) -> usize; |
| 156 | }; | 128 | fn on_irq(); |
| 129 | } | ||
| 157 | } | 130 | } |
| 158 | 131 | ||
| 159 | mod low_level_api { | 132 | #[must_use = "futures do nothing unless you `.await` or poll them"] |
| 160 | use super::*; | 133 | pub struct Transfer<'a, C: Channel> { |
| 134 | channel: PeripheralRef<'a, C>, | ||
| 135 | } | ||
| 161 | 136 | ||
| 162 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 137 | impl<'a, C: Channel> Transfer<'a, C> { |
| 163 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 138 | pub unsafe fn new_read<W: Word>( |
| 164 | pub enum Dir { | 139 | channel: impl Peripheral<P = C> + 'a, |
| 165 | MemoryToPeripheral, | 140 | request: Request, |
| 166 | PeripheralToMemory, | 141 | peri_addr: *mut W, |
| 142 | buf: &'a mut [W], | ||
| 143 | options: TransferOptions, | ||
| 144 | ) -> Self { | ||
| 145 | Self::new_read_raw(channel, request, peri_addr, buf, options) | ||
| 167 | } | 146 | } |
| 168 | 147 | ||
| 169 | pub unsafe fn start_transfer( | 148 | pub unsafe fn new_read_raw<W: Word>( |
| 170 | dma: Gpdma, | 149 | channel: impl Peripheral<P = C> + 'a, |
| 171 | channel_number: u8, | 150 | request: Request, |
| 151 | peri_addr: *mut W, | ||
| 152 | buf: *mut [W], | ||
| 153 | options: TransferOptions, | ||
| 154 | ) -> Self { | ||
| 155 | into_ref!(channel); | ||
| 156 | |||
| 157 | let (ptr, len) = super::slice_ptr_parts_mut(buf); | ||
| 158 | assert!(len > 0 && len <= 0xFFFF); | ||
| 159 | |||
| 160 | Self::new_inner( | ||
| 161 | channel, | ||
| 162 | request, | ||
| 163 | Dir::PeripheralToMemory, | ||
| 164 | peri_addr as *const u32, | ||
| 165 | ptr as *mut u32, | ||
| 166 | len, | ||
| 167 | true, | ||
| 168 | W::bits(), | ||
| 169 | options, | ||
| 170 | ) | ||
| 171 | } | ||
| 172 | |||
| 173 | pub unsafe fn new_write<W: Word>( | ||
| 174 | channel: impl Peripheral<P = C> + 'a, | ||
| 175 | request: Request, | ||
| 176 | buf: &'a [W], | ||
| 177 | peri_addr: *mut W, | ||
| 178 | options: TransferOptions, | ||
| 179 | ) -> Self { | ||
| 180 | Self::new_write_raw(channel, request, buf, peri_addr, options) | ||
| 181 | } | ||
| 182 | |||
| 183 | pub unsafe fn new_write_raw<W: Word>( | ||
| 184 | channel: impl Peripheral<P = C> + 'a, | ||
| 185 | request: Request, | ||
| 186 | buf: *const [W], | ||
| 187 | peri_addr: *mut W, | ||
| 188 | options: TransferOptions, | ||
| 189 | ) -> Self { | ||
| 190 | into_ref!(channel); | ||
| 191 | |||
| 192 | let (ptr, len) = super::slice_ptr_parts(buf); | ||
| 193 | assert!(len > 0 && len <= 0xFFFF); | ||
| 194 | |||
| 195 | Self::new_inner( | ||
| 196 | channel, | ||
| 197 | request, | ||
| 198 | Dir::MemoryToPeripheral, | ||
| 199 | peri_addr as *const u32, | ||
| 200 | ptr as *mut u32, | ||
| 201 | len, | ||
| 202 | true, | ||
| 203 | W::bits(), | ||
| 204 | options, | ||
| 205 | ) | ||
| 206 | } | ||
| 207 | |||
| 208 | pub unsafe fn new_write_repeated<W: Word>( | ||
| 209 | channel: impl Peripheral<P = C> + 'a, | ||
| 210 | request: Request, | ||
| 211 | repeated: &'a W, | ||
| 212 | count: usize, | ||
| 213 | peri_addr: *mut W, | ||
| 214 | options: TransferOptions, | ||
| 215 | ) -> Self { | ||
| 216 | into_ref!(channel); | ||
| 217 | |||
| 218 | Self::new_inner( | ||
| 219 | channel, | ||
| 220 | request, | ||
| 221 | Dir::MemoryToPeripheral, | ||
| 222 | peri_addr as *const u32, | ||
| 223 | repeated as *const W as *mut u32, | ||
| 224 | count, | ||
| 225 | false, | ||
| 226 | W::bits(), | ||
| 227 | options, | ||
| 228 | ) | ||
| 229 | } | ||
| 230 | |||
| 231 | unsafe fn new_inner( | ||
| 232 | channel: PeripheralRef<'a, C>, | ||
| 172 | request: Request, | 233 | request: Request, |
| 173 | dir: Dir, | 234 | dir: Dir, |
| 174 | peri_addr: *const u32, | 235 | peri_addr: *const u32, |
| @@ -176,24 +237,19 @@ mod low_level_api { | |||
| 176 | mem_len: usize, | 237 | mem_len: usize, |
| 177 | incr_mem: bool, | 238 | incr_mem: bool, |
| 178 | data_size: WordSize, | 239 | data_size: WordSize, |
| 179 | options: TransferOptions, | 240 | _options: TransferOptions, |
| 180 | ) { | 241 | ) -> Self { |
| 181 | assert!(options.mburst == crate::dma::Burst::Single, "Burst mode not supported"); | 242 | let ch = channel.regs().ch(channel.num()); |
| 182 | assert!(options.pburst == crate::dma::Burst::Single, "Burst mode not supported"); | ||
| 183 | assert!( | ||
| 184 | options.flow_ctrl == crate::dma::FlowControl::Dma, | ||
| 185 | "Peripheral flow control not supported" | ||
| 186 | ); | ||
| 187 | assert!(options.fifo_threshold.is_none(), "FIFO mode not supported"); | ||
| 188 | 243 | ||
| 189 | // "Preceding reads and writes cannot be moved past subsequent writes." | 244 | // "Preceding reads and writes cannot be moved past subsequent writes." |
| 190 | fence(Ordering::SeqCst); | 245 | fence(Ordering::SeqCst); |
| 191 | 246 | ||
| 192 | let ch = dma.ch(channel_number as _); | 247 | let this = Self { channel }; |
| 193 | 248 | ||
| 194 | // Reset ch | 249 | #[cfg(dmamux)] |
| 195 | ch.cr().write(|w| w.set_reset(true)); | 250 | super::dmamux::configure_dmamux(&mut *this.channel, request); |
| 196 | 251 | ||
| 252 | ch.cr().write(|w| w.set_reset(true)); | ||
| 197 | ch.llr().write(|_| {}); // no linked list | 253 | ch.llr().write(|_| {}); // no linked list |
| 198 | ch.tr1().write(|w| { | 254 | ch.tr1().write(|w| { |
| 199 | w.set_sdw(data_size.into()); | 255 | w.set_sdw(data_size.into()); |
| @@ -234,72 +290,66 @@ mod low_level_api { | |||
| 234 | // Start it | 290 | // Start it |
| 235 | w.set_en(true); | 291 | w.set_en(true); |
| 236 | }); | 292 | }); |
| 293 | |||
| 294 | this | ||
| 237 | } | 295 | } |
| 238 | 296 | ||
| 239 | /// Stops the DMA channel. | 297 | pub fn request_stop(&mut self) { |
| 240 | pub unsafe fn request_stop(dma: Gpdma, channel_number: u8) { | 298 | let ch = self.channel.regs().ch(self.channel.num()); |
| 241 | // get a handle on the channel itself | ||
| 242 | let ch = dma.ch(channel_number as _); | ||
| 243 | 299 | ||
| 244 | // Disable the channel. Keep the IEs enabled so the irqs still fire. | 300 | // Disable the channel. Keep the IEs enabled so the irqs still fire. |
| 245 | ch.cr().write(|w| { | 301 | unsafe { |
| 246 | w.set_tcie(true); | 302 | ch.cr().write(|w| { |
| 247 | w.set_useie(true); | 303 | w.set_tcie(true); |
| 248 | w.set_dteie(true); | 304 | w.set_useie(true); |
| 249 | w.set_suspie(true); | 305 | w.set_dteie(true); |
| 250 | }); | 306 | w.set_suspie(true); |
| 251 | 307 | }) | |
| 252 | // "Subsequent reads and writes cannot be moved ahead of preceding reads." | 308 | } |
| 253 | fence(Ordering::SeqCst); | ||
| 254 | } | 309 | } |
| 255 | 310 | ||
| 256 | /// Gets the running status of the channel | 311 | pub fn is_running(&mut self) -> bool { |
| 257 | pub unsafe fn is_running(dma: Gpdma, ch: u8) -> bool { | 312 | let ch = self.channel.regs().ch(self.channel.num()); |
| 258 | let ch = dma.ch(ch as _); | 313 | !unsafe { ch.sr().read() }.tcf() |
| 259 | !ch.sr().read().tcf() | ||
| 260 | } | 314 | } |
| 261 | 315 | ||
| 262 | /// Gets the total remaining transfers for the channel | 316 | /// Gets the total remaining transfers for the channel |
| 263 | /// Note: this will be zero for transfers that completed without cancellation. | 317 | /// Note: this will be zero for transfers that completed without cancellation. |
| 264 | pub unsafe fn get_remaining_transfers(dma: Gpdma, ch: u8) -> u16 { | 318 | pub fn get_remaining_transfers(&self) -> u16 { |
| 265 | // get a handle on the channel itself | 319 | let ch = self.channel.regs().ch(self.channel.num()); |
| 266 | let ch = dma.ch(ch as _); | 320 | unsafe { ch.br1().read() }.bndt() |
| 267 | // read the remaining transfer count. If this is zero, the transfer completed fully. | ||
| 268 | ch.br1().read().bndt() | ||
| 269 | } | 321 | } |
| 270 | 322 | ||
| 271 | /// Sets the waker for the specified DMA channel | 323 | pub fn blocking_wait(mut self) { |
| 272 | pub unsafe fn set_waker(state_number: usize, waker: &Waker) { | 324 | while self.is_running() {} |
| 273 | STATE.channels[state_number].waker.register(waker); | ||
| 274 | } | ||
| 275 | 325 | ||
| 276 | /// Safety: Must be called with a matching set of parameters for a valid dma channel | 326 | // "Subsequent reads and writes cannot be moved ahead of preceding reads." |
| 277 | pub unsafe fn on_irq_inner(dma: Gpdma, channel_num: u8, state_index: u8) { | 327 | fence(Ordering::SeqCst); |
| 278 | let channel_num = channel_num as usize; | ||
| 279 | let state_index = state_index as usize; | ||
| 280 | 328 | ||
| 281 | let ch = dma.ch(channel_num); | 329 | core::mem::forget(self); |
| 282 | let sr = ch.sr().read(); | 330 | } |
| 331 | } | ||
| 283 | 332 | ||
| 284 | if sr.dtef() { | 333 | impl<'a, C: Channel> Drop for Transfer<'a, C> { |
| 285 | panic!( | 334 | fn drop(&mut self) { |
| 286 | "DMA: data transfer error on DMA@{:08x} channel {}", | 335 | self.request_stop(); |
| 287 | dma.0 as u32, channel_num | 336 | while self.is_running() {} |
| 288 | ); | 337 | |
| 289 | } | 338 | // "Subsequent reads and writes cannot be moved ahead of preceding reads." |
| 290 | if sr.usef() { | 339 | fence(Ordering::SeqCst); |
| 291 | panic!( | 340 | } |
| 292 | "DMA: user settings error on DMA@{:08x} channel {}", | 341 | } |
| 293 | dma.0 as u32, channel_num | ||
| 294 | ); | ||
| 295 | } | ||
| 296 | 342 | ||
| 297 | if sr.suspf() || sr.tcf() { | 343 | impl<'a, C: Channel> Unpin for Transfer<'a, C> {} |
| 298 | // disable all xxIEs to prevent the irq from firing again. | 344 | impl<'a, C: Channel> Future for Transfer<'a, C> { |
| 299 | ch.cr().write(|_| {}); | 345 | type Output = (); |
| 346 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
| 347 | STATE.ch_wakers[self.channel.index()].register(cx.waker()); | ||
| 300 | 348 | ||
| 301 | // Wake the future. It'll look at tcf and see it's set. | 349 | if self.is_running() { |
| 302 | STATE.channels[state_index].waker.wake(); | 350 | Poll::Pending |
| 351 | } else { | ||
| 352 | Poll::Ready(()) | ||
| 303 | } | 353 | } |
| 304 | } | 354 | } |
| 305 | } | 355 | } |
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 0030bd575..d29ef4a1f 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs | |||
| @@ -1,124 +1,39 @@ | |||
| 1 | #[cfg(bdma)] | ||
| 2 | pub(crate) mod bdma; | ||
| 3 | #[cfg(dma)] | 1 | #[cfg(dma)] |
| 4 | pub(crate) mod dma; | 2 | pub(crate) mod dma; |
| 3 | #[cfg(dma)] | ||
| 4 | pub use dma::*; | ||
| 5 | |||
| 6 | // stm32h7 has both dma and bdma. In that case, we export dma as "main" dma, | ||
| 7 | // and bdma as "secondary", under `embassy_stm32::dma::bdma`. | ||
| 8 | #[cfg(all(bdma, dma))] | ||
| 9 | pub mod bdma; | ||
| 10 | |||
| 11 | #[cfg(all(bdma, not(dma)))] | ||
| 12 | pub(crate) mod bdma; | ||
| 13 | #[cfg(all(bdma, not(dma)))] | ||
| 14 | pub use bdma::*; | ||
| 15 | |||
| 16 | #[cfg(gpdma)] | ||
| 17 | pub(crate) mod gpdma; | ||
| 18 | #[cfg(gpdma)] | ||
| 19 | pub use gpdma::*; | ||
| 20 | |||
| 5 | #[cfg(dmamux)] | 21 | #[cfg(dmamux)] |
| 6 | mod dmamux; | 22 | mod dmamux; |
| 7 | #[cfg(gpdma)] | ||
| 8 | mod gpdma; | ||
| 9 | 23 | ||
| 10 | use core::future::Future; | ||
| 11 | use core::mem; | 24 | use core::mem; |
| 12 | use core::pin::Pin; | ||
| 13 | use core::task::{Context, Poll, Waker}; | ||
| 14 | 25 | ||
| 15 | #[cfg(any(dma, bdma))] | ||
| 16 | use embassy_cortex_m::interrupt::Priority; | 26 | use embassy_cortex_m::interrupt::Priority; |
| 17 | use embassy_hal_common::{impl_peripheral, into_ref}; | 27 | use embassy_hal_common::impl_peripheral; |
| 18 | 28 | ||
| 19 | #[cfg(dmamux)] | 29 | #[cfg(dmamux)] |
| 20 | pub use self::dmamux::*; | 30 | pub use self::dmamux::*; |
| 21 | use crate::Peripheral; | ||
| 22 | |||
| 23 | #[cfg(feature = "unstable-pac")] | ||
| 24 | pub mod low_level { | ||
| 25 | pub use super::transfers::*; | ||
| 26 | } | ||
| 27 | |||
| 28 | pub(crate) use transfers::*; | ||
| 29 | |||
| 30 | #[cfg(any(bdma_v2, dma_v2, dmamux, gpdma))] | ||
| 31 | pub type Request = u8; | ||
| 32 | #[cfg(not(any(bdma_v2, dma_v2, dmamux, gpdma)))] | ||
| 33 | pub type Request = (); | ||
| 34 | |||
| 35 | pub(crate) mod sealed { | ||
| 36 | use super::*; | ||
| 37 | |||
| 38 | pub trait Word {} | ||
| 39 | |||
| 40 | pub trait Channel { | ||
| 41 | /// Starts this channel for writing a stream of words. | ||
| 42 | /// | ||
| 43 | /// Safety: | ||
| 44 | /// - `buf` must point to a valid buffer for DMA reading. | ||
| 45 | /// - `buf` must be alive for the entire duration of the DMA transfer. | ||
| 46 | /// - `reg_addr` must be a valid peripheral register address to write to. | ||
| 47 | unsafe fn start_write<W: super::Word>( | ||
| 48 | &mut self, | ||
| 49 | request: Request, | ||
| 50 | buf: *const [W], | ||
| 51 | reg_addr: *mut W, | ||
| 52 | options: TransferOptions, | ||
| 53 | ); | ||
| 54 | |||
| 55 | /// Starts this channel for writing a word repeatedly. | ||
| 56 | /// | ||
| 57 | /// Safety: | ||
| 58 | /// - `reg_addr` must be a valid peripheral register address to write to. | ||
| 59 | unsafe fn start_write_repeated<W: super::Word>( | ||
| 60 | &mut self, | ||
| 61 | request: Request, | ||
| 62 | repeated: *const W, | ||
| 63 | count: usize, | ||
| 64 | reg_addr: *mut W, | ||
| 65 | options: TransferOptions, | ||
| 66 | ); | ||
| 67 | |||
| 68 | /// Starts this channel for reading a stream of words. | ||
| 69 | /// | ||
| 70 | /// Safety: | ||
| 71 | /// - `buf` must point to a valid buffer for DMA writing. | ||
| 72 | /// - `buf` must be alive for the entire duration of the DMA transfer. | ||
| 73 | /// - `reg_addr` must be a valid peripheral register address to read from. | ||
| 74 | unsafe fn start_read<W: super::Word>( | ||
| 75 | &mut self, | ||
| 76 | request: Request, | ||
| 77 | reg_addr: *const W, | ||
| 78 | buf: *mut [W], | ||
| 79 | options: TransferOptions, | ||
| 80 | ); | ||
| 81 | |||
| 82 | /// DMA double-buffered mode is unsafe as UB can happen when the hardware writes to a buffer currently owned by the software | ||
| 83 | /// more information can be found here: https://github.com/embassy-rs/embassy/issues/702 | ||
| 84 | /// This feature is now used solely for the purposes of implementing giant DMA transfers required for DCMI | ||
| 85 | unsafe fn start_double_buffered_read<W: super::Word>( | ||
| 86 | &mut self, | ||
| 87 | request: Request, | ||
| 88 | reg_addr: *const W, | ||
| 89 | buffer0: *mut W, | ||
| 90 | buffer1: *mut W, | ||
| 91 | buffer_len: usize, | ||
| 92 | options: TransferOptions, | ||
| 93 | ); | ||
| 94 | |||
| 95 | unsafe fn set_buffer0<W: super::Word>(&mut self, buffer: *mut W); | ||
| 96 | |||
| 97 | unsafe fn set_buffer1<W: super::Word>(&mut self, buffer: *mut W); | ||
| 98 | |||
| 99 | unsafe fn is_buffer0_accessible(&mut self) -> bool; | ||
| 100 | |||
| 101 | /// Requests the channel to stop. | ||
| 102 | /// NOTE: The channel does not immediately stop, you have to wait | ||
| 103 | /// for `is_running() = false`. | ||
| 104 | fn request_stop(&mut self); | ||
| 105 | |||
| 106 | /// Returns whether this channel is running or stopped. | ||
| 107 | /// | ||
| 108 | /// The channel stops running when it either completes or is manually stopped. | ||
| 109 | fn is_running(&self) -> bool; | ||
| 110 | 31 | ||
| 111 | /// Returns the total number of remaining transfers. | 32 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| 112 | fn remaining_transfers(&mut self) -> u16; | 33 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 113 | 34 | enum Dir { | |
| 114 | /// Sets the waker that is called when this channel stops (either completed or manually stopped) | 35 | MemoryToPeripheral, |
| 115 | fn set_waker(&mut self, waker: &Waker); | 36 | PeripheralToMemory, |
| 116 | |||
| 117 | /// This is called when this channel triggers an interrupt. | ||
| 118 | /// Note: Because some channels share an interrupt, this function might be | ||
| 119 | /// called for a channel that didn't trigger an interrupt. | ||
| 120 | fn on_irq(); | ||
| 121 | } | ||
| 122 | } | 37 | } |
| 123 | 38 | ||
| 124 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 39 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| @@ -139,191 +54,39 @@ impl WordSize { | |||
| 139 | } | 54 | } |
| 140 | } | 55 | } |
| 141 | 56 | ||
| 142 | pub trait Word: sealed::Word { | 57 | mod word_sealed { |
| 58 | pub trait Word {} | ||
| 59 | } | ||
| 60 | |||
| 61 | pub trait Word: word_sealed::Word { | ||
| 143 | fn bits() -> WordSize; | 62 | fn bits() -> WordSize; |
| 144 | } | 63 | } |
| 145 | 64 | ||
| 146 | impl sealed::Word for u8 {} | 65 | impl word_sealed::Word for u8 {} |
| 147 | impl Word for u8 { | 66 | impl Word for u8 { |
| 148 | fn bits() -> WordSize { | 67 | fn bits() -> WordSize { |
| 149 | WordSize::OneByte | 68 | WordSize::OneByte |
| 150 | } | 69 | } |
| 151 | } | 70 | } |
| 152 | 71 | ||
| 153 | impl sealed::Word for u16 {} | 72 | impl word_sealed::Word for u16 {} |
| 154 | impl Word for u16 { | 73 | impl Word for u16 { |
| 155 | fn bits() -> WordSize { | 74 | fn bits() -> WordSize { |
| 156 | WordSize::TwoBytes | 75 | WordSize::TwoBytes |
| 157 | } | 76 | } |
| 158 | } | 77 | } |
| 159 | 78 | ||
| 160 | impl sealed::Word for u32 {} | 79 | impl word_sealed::Word for u32 {} |
| 161 | impl Word for u32 { | 80 | impl Word for u32 { |
| 162 | fn bits() -> WordSize { | 81 | fn bits() -> WordSize { |
| 163 | WordSize::FourBytes | 82 | WordSize::FourBytes |
| 164 | } | 83 | } |
| 165 | } | 84 | } |
| 166 | 85 | ||
| 167 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 168 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 169 | pub enum Burst { | ||
| 170 | /// Single transfer | ||
| 171 | Single, | ||
| 172 | /// Incremental burst of 4 beats | ||
| 173 | Incr4, | ||
| 174 | /// Incremental burst of 8 beats | ||
| 175 | Incr8, | ||
| 176 | /// Incremental burst of 16 beats | ||
| 177 | Incr16, | ||
| 178 | } | ||
| 179 | |||
| 180 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 181 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 182 | pub enum FlowControl { | ||
| 183 | /// Flow control by DMA | ||
| 184 | Dma, | ||
| 185 | /// Flow control by peripheral | ||
| 186 | Peripheral, | ||
| 187 | } | ||
| 188 | |||
| 189 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 190 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 191 | pub enum FifoThreshold { | ||
| 192 | /// 1/4 full FIFO | ||
| 193 | Quarter, | ||
| 194 | /// 1/2 full FIFO | ||
| 195 | Half, | ||
| 196 | /// 3/4 full FIFO | ||
| 197 | ThreeQuarters, | ||
| 198 | /// Full FIFO | ||
| 199 | Full, | ||
| 200 | } | ||
| 201 | |||
| 202 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 203 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 204 | pub struct TransferOptions { | ||
| 205 | /// Peripheral burst transfer configuration | ||
| 206 | pub pburst: Burst, | ||
| 207 | /// Memory burst transfer configuration | ||
| 208 | pub mburst: Burst, | ||
| 209 | /// Flow control configuration | ||
| 210 | pub flow_ctrl: FlowControl, | ||
| 211 | /// FIFO threshold for DMA FIFO mode. If none, direct mode is used. | ||
| 212 | pub fifo_threshold: Option<FifoThreshold>, | ||
| 213 | } | ||
| 214 | |||
| 215 | impl Default for TransferOptions { | ||
| 216 | fn default() -> Self { | ||
| 217 | Self { | ||
| 218 | pburst: Burst::Single, | ||
| 219 | mburst: Burst::Single, | ||
| 220 | flow_ctrl: FlowControl::Dma, | ||
| 221 | fifo_threshold: None, | ||
| 222 | } | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | mod transfers { | ||
| 227 | use embassy_hal_common::PeripheralRef; | ||
| 228 | |||
| 229 | use super::*; | ||
| 230 | |||
| 231 | #[allow(unused)] | ||
| 232 | pub fn read<'a, W: Word>( | ||
| 233 | channel: impl Peripheral<P = impl Channel> + 'a, | ||
| 234 | request: Request, | ||
| 235 | reg_addr: *mut W, | ||
| 236 | buf: &'a mut [W], | ||
| 237 | ) -> impl Future<Output = ()> + 'a { | ||
| 238 | assert!(buf.len() > 0 && buf.len() <= 0xFFFF); | ||
| 239 | into_ref!(channel); | ||
| 240 | |||
| 241 | unsafe { channel.start_read::<W>(request, reg_addr, buf, Default::default()) }; | ||
| 242 | |||
| 243 | Transfer::new(channel) | ||
| 244 | } | ||
| 245 | |||
| 246 | #[allow(unused)] | ||
| 247 | pub fn write<'a, W: Word>( | ||
| 248 | channel: impl Peripheral<P = impl Channel> + 'a, | ||
| 249 | request: Request, | ||
| 250 | buf: &'a [W], | ||
| 251 | reg_addr: *mut W, | ||
| 252 | ) -> impl Future<Output = ()> + 'a { | ||
| 253 | assert!(buf.len() > 0 && buf.len() <= 0xFFFF); | ||
| 254 | into_ref!(channel); | ||
| 255 | |||
| 256 | unsafe { channel.start_write::<W>(request, buf, reg_addr, Default::default()) }; | ||
| 257 | |||
| 258 | Transfer::new(channel) | ||
| 259 | } | ||
| 260 | |||
| 261 | #[allow(unused)] | ||
| 262 | pub fn write_repeated<'a, W: Word>( | ||
| 263 | channel: impl Peripheral<P = impl Channel> + 'a, | ||
| 264 | request: Request, | ||
| 265 | repeated: *const W, | ||
| 266 | count: usize, | ||
| 267 | reg_addr: *mut W, | ||
| 268 | ) -> impl Future<Output = ()> + 'a { | ||
| 269 | into_ref!(channel); | ||
| 270 | |||
| 271 | unsafe { channel.start_write_repeated::<W>(request, repeated, count, reg_addr, Default::default()) }; | ||
| 272 | |||
| 273 | Transfer::new(channel) | ||
| 274 | } | ||
| 275 | |||
| 276 | #[must_use = "futures do nothing unless you `.await` or poll them"] | ||
| 277 | pub(crate) struct Transfer<'a, C: Channel> { | ||
| 278 | channel: PeripheralRef<'a, C>, | ||
| 279 | } | ||
| 280 | |||
| 281 | impl<'a, C: Channel> Transfer<'a, C> { | ||
| 282 | pub(crate) fn new(channel: impl Peripheral<P = C> + 'a) -> Self { | ||
| 283 | into_ref!(channel); | ||
| 284 | Self { channel } | ||
| 285 | } | ||
| 286 | } | ||
| 287 | |||
| 288 | impl<'a, C: Channel> Drop for Transfer<'a, C> { | ||
| 289 | fn drop(&mut self) { | ||
| 290 | self.channel.request_stop(); | ||
| 291 | while self.channel.is_running() {} | ||
| 292 | } | ||
| 293 | } | ||
| 294 | |||
| 295 | impl<'a, C: Channel> Unpin for Transfer<'a, C> {} | ||
| 296 | impl<'a, C: Channel> Future for Transfer<'a, C> { | ||
| 297 | type Output = (); | ||
| 298 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
| 299 | self.channel.set_waker(cx.waker()); | ||
| 300 | if self.channel.is_running() { | ||
| 301 | Poll::Pending | ||
| 302 | } else { | ||
| 303 | Poll::Ready(()) | ||
| 304 | } | ||
| 305 | } | ||
| 306 | } | ||
| 307 | } | ||
| 308 | |||
| 309 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} | ||
| 310 | |||
| 311 | pub struct NoDma; | 86 | pub struct NoDma; |
| 312 | 87 | ||
| 313 | impl_peripheral!(NoDma); | 88 | impl_peripheral!(NoDma); |
| 314 | 89 | ||
| 315 | // safety: must be called only once at startup | ||
| 316 | pub(crate) unsafe fn init(#[cfg(bdma)] bdma_priority: Priority, #[cfg(dma)] dma_priority: Priority) { | ||
| 317 | #[cfg(bdma)] | ||
| 318 | bdma::init(bdma_priority); | ||
| 319 | #[cfg(dma)] | ||
| 320 | dma::init(dma_priority); | ||
| 321 | #[cfg(dmamux)] | ||
| 322 | dmamux::init(); | ||
| 323 | #[cfg(gpdma)] | ||
| 324 | gpdma::init(); | ||
| 325 | } | ||
| 326 | |||
| 327 | // TODO: replace transmutes with core::ptr::metadata once it's stable | 90 | // TODO: replace transmutes with core::ptr::metadata once it's stable |
| 328 | #[allow(unused)] | 91 | #[allow(unused)] |
| 329 | pub(crate) fn slice_ptr_parts<T>(slice: *const [T]) -> (usize, usize) { | 92 | pub(crate) fn slice_ptr_parts<T>(slice: *const [T]) -> (usize, usize) { |
| @@ -334,3 +97,19 @@ pub(crate) fn slice_ptr_parts<T>(slice: *const [T]) -> (usize, usize) { | |||
| 334 | pub(crate) fn slice_ptr_parts_mut<T>(slice: *mut [T]) -> (usize, usize) { | 97 | pub(crate) fn slice_ptr_parts_mut<T>(slice: *mut [T]) -> (usize, usize) { |
| 335 | unsafe { mem::transmute(slice) } | 98 | unsafe { mem::transmute(slice) } |
| 336 | } | 99 | } |
| 100 | |||
| 101 | // safety: must be called only once at startup | ||
| 102 | pub(crate) unsafe fn init( | ||
| 103 | #[cfg(bdma)] bdma_priority: Priority, | ||
| 104 | #[cfg(dma)] dma_priority: Priority, | ||
| 105 | #[cfg(gpdma)] gpdma_priority: Priority, | ||
| 106 | ) { | ||
| 107 | #[cfg(bdma)] | ||
| 108 | bdma::init(bdma_priority); | ||
| 109 | #[cfg(dma)] | ||
| 110 | dma::init(dma_priority); | ||
| 111 | #[cfg(gpdma)] | ||
| 112 | gpdma::init(gpdma_priority); | ||
| 113 | #[cfg(dmamux)] | ||
| 114 | dmamux::init(); | ||
| 115 | } | ||
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 7218f7706..39e6702e5 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -8,7 +8,7 @@ use embassy_hal_common::drop::OnDrop; | |||
| 8 | use embassy_hal_common::{into_ref, PeripheralRef}; | 8 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 9 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| 10 | 10 | ||
| 11 | use crate::dma::NoDma; | 11 | use crate::dma::{NoDma, Transfer}; |
| 12 | use crate::gpio::sealed::AFType; | 12 | use crate::gpio::sealed::AFType; |
| 13 | use crate::gpio::Pull; | 13 | use crate::gpio::Pull; |
| 14 | use crate::i2c::{Error, Instance, SclPin, SdaPin}; | 14 | use crate::i2c::{Error, Instance, SclPin, SdaPin}; |
| @@ -476,7 +476,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 476 | 476 | ||
| 477 | let ch = &mut self.tx_dma; | 477 | let ch = &mut self.tx_dma; |
| 478 | let request = ch.request(); | 478 | let request = ch.request(); |
| 479 | crate::dma::write(ch, request, write, dst) | 479 | Transfer::new_write(ch, request, write, dst, Default::default()) |
| 480 | }; | 480 | }; |
| 481 | 481 | ||
| 482 | let state = T::state(); | 482 | let state = T::state(); |
| @@ -576,7 +576,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 576 | 576 | ||
| 577 | let ch = &mut self.rx_dma; | 577 | let ch = &mut self.rx_dma; |
| 578 | let request = ch.request(); | 578 | let request = ch.request(); |
| 579 | crate::dma::read(ch, request, src, buffer) | 579 | Transfer::new_read(ch, request, src, buffer, Default::default()) |
| 580 | }; | 580 | }; |
| 581 | 581 | ||
| 582 | let state = T::state(); | 582 | let state = T::state(); |
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 0dbc9e5c8..bbde2da57 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -78,7 +78,6 @@ pub(crate) mod _generated { | |||
| 78 | // Reexports | 78 | // Reexports |
| 79 | pub use _generated::{peripherals, Peripherals}; | 79 | pub use _generated::{peripherals, Peripherals}; |
| 80 | pub use embassy_cortex_m::executor; | 80 | pub use embassy_cortex_m::executor; |
| 81 | #[cfg(any(dma, bdma))] | ||
| 82 | use embassy_cortex_m::interrupt::Priority; | 81 | use embassy_cortex_m::interrupt::Priority; |
| 83 | pub use embassy_cortex_m::interrupt::_export::interrupt; | 82 | pub use embassy_cortex_m::interrupt::_export::interrupt; |
| 84 | pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | 83 | pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; |
| @@ -96,6 +95,8 @@ pub struct Config { | |||
| 96 | pub bdma_interrupt_priority: Priority, | 95 | pub bdma_interrupt_priority: Priority, |
| 97 | #[cfg(dma)] | 96 | #[cfg(dma)] |
| 98 | pub dma_interrupt_priority: Priority, | 97 | pub dma_interrupt_priority: Priority, |
| 98 | #[cfg(gpdma)] | ||
| 99 | pub gpdma_interrupt_priority: Priority, | ||
| 99 | } | 100 | } |
| 100 | 101 | ||
| 101 | impl Default for Config { | 102 | impl Default for Config { |
| @@ -108,6 +109,8 @@ impl Default for Config { | |||
| 108 | bdma_interrupt_priority: Priority::P0, | 109 | bdma_interrupt_priority: Priority::P0, |
| 109 | #[cfg(dma)] | 110 | #[cfg(dma)] |
| 110 | dma_interrupt_priority: Priority::P0, | 111 | dma_interrupt_priority: Priority::P0, |
| 112 | #[cfg(gpdma)] | ||
| 113 | gpdma_interrupt_priority: Priority::P0, | ||
| 111 | } | 114 | } |
| 112 | } | 115 | } |
| 113 | } | 116 | } |
| @@ -151,6 +154,8 @@ pub fn init(config: Config) -> Peripherals { | |||
| 151 | config.bdma_interrupt_priority, | 154 | config.bdma_interrupt_priority, |
| 152 | #[cfg(dma)] | 155 | #[cfg(dma)] |
| 153 | config.dma_interrupt_priority, | 156 | config.dma_interrupt_priority, |
| 157 | #[cfg(gpdma)] | ||
| 158 | config.gpdma_interrupt_priority, | ||
| 154 | ); | 159 | ); |
| 155 | #[cfg(feature = "exti")] | 160 | #[cfg(feature = "exti")] |
| 156 | exti::init(); | 161 | exti::init(); |
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index f33319620..c3126b37f 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs | |||
| @@ -5,7 +5,7 @@ pub mod enums; | |||
| 5 | use embassy_hal_common::{into_ref, PeripheralRef}; | 5 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 6 | use enums::*; | 6 | use enums::*; |
| 7 | 7 | ||
| 8 | use crate::dma::TransferOptions; | 8 | use crate::dma::Transfer; |
| 9 | use crate::gpio::sealed::AFType; | 9 | use crate::gpio::sealed::AFType; |
| 10 | use crate::gpio::AnyPin; | 10 | use crate::gpio::AnyPin; |
| 11 | use crate::pac::quadspi::Quadspi as Regs; | 11 | use crate::pac::quadspi::Quadspi as Regs; |
| @@ -230,9 +230,6 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { | |||
| 230 | unsafe { | 230 | unsafe { |
| 231 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); | 231 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); |
| 232 | 232 | ||
| 233 | let request = self.dma.request(); | ||
| 234 | let options = TransferOptions::default(); | ||
| 235 | |||
| 236 | T::REGS.ccr().modify(|v| { | 233 | T::REGS.ccr().modify(|v| { |
| 237 | v.set_fmode(QspiMode::IndirectRead.into()); | 234 | v.set_fmode(QspiMode::IndirectRead.into()); |
| 238 | }); | 235 | }); |
| @@ -241,12 +238,18 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { | |||
| 241 | v.set_address(current_ar); | 238 | v.set_address(current_ar); |
| 242 | }); | 239 | }); |
| 243 | 240 | ||
| 244 | self.dma | 241 | let request = self.dma.request(); |
| 245 | .start_read(request, T::REGS.dr().ptr() as *mut u8, buf, options); | 242 | let transfer = Transfer::new_read( |
| 243 | &mut self.dma, | ||
| 244 | request, | ||
| 245 | T::REGS.dr().ptr() as *mut u8, | ||
| 246 | buf, | ||
| 247 | Default::default(), | ||
| 248 | ); | ||
| 246 | 249 | ||
| 247 | T::REGS.cr().modify(|v| v.set_dmaen(true)); | 250 | T::REGS.cr().modify(|v| v.set_dmaen(true)); |
| 248 | 251 | ||
| 249 | while self.dma.is_running() {} | 252 | transfer.blocking_wait(); |
| 250 | } | 253 | } |
| 251 | } | 254 | } |
| 252 | 255 | ||
| @@ -257,19 +260,22 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { | |||
| 257 | unsafe { | 260 | unsafe { |
| 258 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); | 261 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); |
| 259 | 262 | ||
| 260 | let request = self.dma.request(); | ||
| 261 | let options = TransferOptions::default(); | ||
| 262 | |||
| 263 | T::REGS.ccr().modify(|v| { | 263 | T::REGS.ccr().modify(|v| { |
| 264 | v.set_fmode(QspiMode::IndirectWrite.into()); | 264 | v.set_fmode(QspiMode::IndirectWrite.into()); |
| 265 | }); | 265 | }); |
| 266 | 266 | ||
| 267 | self.dma | 267 | let request = self.dma.request(); |
| 268 | .start_write(request, buf, T::REGS.dr().ptr() as *mut u8, options); | 268 | let transfer = Transfer::new_write( |
| 269 | &mut self.dma, | ||
| 270 | request, | ||
| 271 | buf, | ||
| 272 | T::REGS.dr().ptr() as *mut u8, | ||
| 273 | Default::default(), | ||
| 274 | ); | ||
| 269 | 275 | ||
| 270 | T::REGS.cr().modify(|v| v.set_dmaen(true)); | 276 | T::REGS.cr().modify(|v| v.set_dmaen(true)); |
| 271 | 277 | ||
| 272 | while self.dma.is_running() {} | 278 | transfer.blocking_wait(); |
| 273 | } | 279 | } |
| 274 | } | 280 | } |
| 275 | 281 | ||
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 23ece3a2a..433f73d79 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs | |||
| @@ -185,6 +185,21 @@ fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(bool, u16, Hertz), Error> { | |||
| 185 | } | 185 | } |
| 186 | } | 186 | } |
| 187 | 187 | ||
| 188 | #[cfg(sdmmc_v1)] | ||
| 189 | type Transfer<'a, C> = crate::dma::Transfer<'a, C>; | ||
| 190 | #[cfg(sdmmc_v2)] | ||
| 191 | type Transfer<'a, C> = core::marker::PhantomData<&'a mut C>; | ||
| 192 | |||
| 193 | #[cfg(all(sdmmc_v1, dma))] | ||
| 194 | const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions { | ||
| 195 | pburst: crate::dma::Burst::Incr4, | ||
| 196 | mburst: crate::dma::Burst::Incr4, | ||
| 197 | flow_ctrl: crate::dma::FlowControl::Peripheral, | ||
| 198 | fifo_threshold: Some(crate::dma::FifoThreshold::Full), | ||
| 199 | }; | ||
| 200 | #[cfg(all(sdmmc_v1, not(dma)))] | ||
| 201 | const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions {}; | ||
| 202 | |||
| 188 | /// SDMMC configuration | 203 | /// SDMMC configuration |
| 189 | /// | 204 | /// |
| 190 | /// Default values: | 205 | /// Default values: |
| @@ -490,7 +505,12 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 490 | /// # Safety | 505 | /// # Safety |
| 491 | /// | 506 | /// |
| 492 | /// `buffer` must be valid for the whole transfer and word aligned | 507 | /// `buffer` must be valid for the whole transfer and word aligned |
| 493 | unsafe fn prepare_datapath_read(&mut self, buffer: *mut [u32], length_bytes: u32, block_size: u8) { | 508 | fn prepare_datapath_read<'a>( |
| 509 | &'a mut self, | ||
| 510 | buffer: &'a mut [u32], | ||
| 511 | length_bytes: u32, | ||
| 512 | block_size: u8, | ||
| 513 | ) -> Transfer<'a, Dma> { | ||
| 494 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); | 514 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); |
| 495 | let regs = T::regs(); | 515 | let regs = T::regs(); |
| 496 | 516 | ||
| @@ -499,48 +519,52 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 499 | Self::clear_interrupt_flags(); | 519 | Self::clear_interrupt_flags(); |
| 500 | 520 | ||
| 501 | // NOTE(unsafe) We have exclusive access to the regisers | 521 | // NOTE(unsafe) We have exclusive access to the regisers |
| 522 | unsafe { | ||
| 523 | regs.dtimer() | ||
| 524 | .write(|w| w.set_datatime(self.config.data_transfer_timeout)); | ||
| 525 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); | ||
| 502 | 526 | ||
| 503 | regs.dtimer() | 527 | #[cfg(sdmmc_v1)] |
| 504 | .write(|w| w.set_datatime(self.config.data_transfer_timeout)); | 528 | let transfer = { |
| 505 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); | 529 | let request = self.dma.request(); |
| 530 | Transfer::new_read( | ||
| 531 | &mut self.dma, | ||
| 532 | request, | ||
| 533 | regs.fifor().ptr() as *mut u32, | ||
| 534 | buffer, | ||
| 535 | DMA_TRANSFER_OPTIONS, | ||
| 536 | ) | ||
| 537 | }; | ||
| 538 | #[cfg(sdmmc_v2)] | ||
| 539 | let transfer = { | ||
| 540 | regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32)); | ||
| 541 | regs.idmactrlr().modify(|w| w.set_idmaen(true)); | ||
| 542 | core::marker::PhantomData | ||
| 543 | }; | ||
| 506 | 544 | ||
| 507 | #[cfg(sdmmc_v1)] | 545 | regs.dctrl().modify(|w| { |
| 508 | { | 546 | w.set_dblocksize(block_size); |
| 509 | let request = self.dma.request(); | 547 | w.set_dtdir(true); |
| 510 | self.dma.start_read( | 548 | #[cfg(sdmmc_v1)] |
| 511 | request, | 549 | { |
| 512 | regs.fifor().ptr() as *const u32, | 550 | w.set_dmaen(true); |
| 513 | buffer, | 551 | w.set_dten(true); |
| 514 | crate::dma::TransferOptions { | 552 | } |
| 515 | pburst: crate::dma::Burst::Incr4, | 553 | }); |
| 516 | mburst: crate::dma::Burst::Incr4, | ||
| 517 | flow_ctrl: crate::dma::FlowControl::Peripheral, | ||
| 518 | fifo_threshold: Some(crate::dma::FifoThreshold::Full), | ||
| 519 | ..Default::default() | ||
| 520 | }, | ||
| 521 | ); | ||
| 522 | } | ||
| 523 | #[cfg(sdmmc_v2)] | ||
| 524 | { | ||
| 525 | regs.idmabase0r().write(|w| w.set_idmabase0(buffer as *mut u32 as u32)); | ||
| 526 | regs.idmactrlr().modify(|w| w.set_idmaen(true)); | ||
| 527 | } | ||
| 528 | 554 | ||
| 529 | regs.dctrl().modify(|w| { | 555 | transfer |
| 530 | w.set_dblocksize(block_size); | 556 | } |
| 531 | w.set_dtdir(true); | ||
| 532 | #[cfg(sdmmc_v1)] | ||
| 533 | { | ||
| 534 | w.set_dmaen(true); | ||
| 535 | w.set_dten(true); | ||
| 536 | } | ||
| 537 | }); | ||
| 538 | } | 557 | } |
| 539 | 558 | ||
| 540 | /// # Safety | 559 | /// # Safety |
| 541 | /// | 560 | /// |
| 542 | /// `buffer` must be valid for the whole transfer and word aligned | 561 | /// `buffer` must be valid for the whole transfer and word aligned |
| 543 | unsafe fn prepare_datapath_write(&mut self, buffer: *const [u32], length_bytes: u32, block_size: u8) { | 562 | fn prepare_datapath_write<'a>( |
| 563 | &'a mut self, | ||
| 564 | buffer: &'a [u32], | ||
| 565 | length_bytes: u32, | ||
| 566 | block_size: u8, | ||
| 567 | ) -> Transfer<'a, Dma> { | ||
| 544 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); | 568 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); |
| 545 | let regs = T::regs(); | 569 | let regs = T::regs(); |
| 546 | 570 | ||
| @@ -549,43 +573,41 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 549 | Self::clear_interrupt_flags(); | 573 | Self::clear_interrupt_flags(); |
| 550 | 574 | ||
| 551 | // NOTE(unsafe) We have exclusive access to the regisers | 575 | // NOTE(unsafe) We have exclusive access to the regisers |
| 576 | unsafe { | ||
| 577 | regs.dtimer() | ||
| 578 | .write(|w| w.set_datatime(self.config.data_transfer_timeout)); | ||
| 579 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); | ||
| 552 | 580 | ||
| 553 | regs.dtimer() | 581 | #[cfg(sdmmc_v1)] |
| 554 | .write(|w| w.set_datatime(self.config.data_transfer_timeout)); | 582 | let transfer = { |
| 555 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); | 583 | let request = self.dma.request(); |
| 584 | Transfer::new_write( | ||
| 585 | &mut self.dma, | ||
| 586 | request, | ||
| 587 | buffer, | ||
| 588 | regs.fifor().ptr() as *mut u32, | ||
| 589 | DMA_TRANSFER_OPTIONS, | ||
| 590 | ) | ||
| 591 | }; | ||
| 592 | #[cfg(sdmmc_v2)] | ||
| 593 | let transfer = { | ||
| 594 | regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_ptr() as u32)); | ||
| 595 | regs.idmactrlr().modify(|w| w.set_idmaen(true)); | ||
| 596 | core::marker::PhantomData | ||
| 597 | }; | ||
| 556 | 598 | ||
| 557 | #[cfg(sdmmc_v1)] | 599 | regs.dctrl().modify(|w| { |
| 558 | { | 600 | w.set_dblocksize(block_size); |
| 559 | let request = self.dma.request(); | 601 | w.set_dtdir(false); |
| 560 | self.dma.start_write( | 602 | #[cfg(sdmmc_v1)] |
| 561 | request, | 603 | { |
| 562 | buffer, | 604 | w.set_dmaen(true); |
| 563 | regs.fifor().ptr() as *mut u32, | 605 | w.set_dten(true); |
| 564 | crate::dma::TransferOptions { | 606 | } |
| 565 | pburst: crate::dma::Burst::Incr4, | 607 | }); |
| 566 | mburst: crate::dma::Burst::Incr4, | ||
| 567 | flow_ctrl: crate::dma::FlowControl::Peripheral, | ||
| 568 | fifo_threshold: Some(crate::dma::FifoThreshold::Full), | ||
| 569 | ..Default::default() | ||
| 570 | }, | ||
| 571 | ); | ||
| 572 | } | ||
| 573 | #[cfg(sdmmc_v2)] | ||
| 574 | { | ||
| 575 | regs.idmabase0r() | ||
| 576 | .write(|w| w.set_idmabase0(buffer as *const u32 as u32)); | ||
| 577 | regs.idmactrlr().modify(|w| w.set_idmaen(true)); | ||
| 578 | } | ||
| 579 | 608 | ||
| 580 | regs.dctrl().modify(|w| { | 609 | transfer |
| 581 | w.set_dblocksize(block_size); | 610 | } |
| 582 | w.set_dtdir(false); | ||
| 583 | #[cfg(sdmmc_v1)] | ||
| 584 | { | ||
| 585 | w.set_dmaen(true); | ||
| 586 | w.set_dten(true); | ||
| 587 | } | ||
| 588 | }); | ||
| 589 | } | 611 | } |
| 590 | 612 | ||
| 591 | /// Stops the DMA datapath | 613 | /// Stops the DMA datapath |
| @@ -662,11 +684,9 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 662 | let regs = T::regs(); | 684 | let regs = T::regs(); |
| 663 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); | 685 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); |
| 664 | 686 | ||
| 665 | unsafe { | 687 | let transfer = self.prepare_datapath_read(&mut status, 64, 6); |
| 666 | self.prepare_datapath_read(&mut status, 64, 6); | 688 | Self::data_interrupts(true); |
| 667 | Self::data_interrupts(true); | 689 | Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6 |
| 668 | } | ||
| 669 | self.cmd(Cmd::cmd6(set_function), true)?; // CMD6 | ||
| 670 | 690 | ||
| 671 | let res = poll_fn(|cx| { | 691 | let res = poll_fn(|cx| { |
| 672 | T::state().register(cx.waker()); | 692 | T::state().register(cx.waker()); |
| @@ -696,6 +716,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 696 | Ok(_) => { | 716 | Ok(_) => { |
| 697 | on_drop.defuse(); | 717 | on_drop.defuse(); |
| 698 | Self::stop_datapath(); | 718 | Self::stop_datapath(); |
| 719 | drop(transfer); | ||
| 699 | 720 | ||
| 700 | // Function Selection of Function Group 1 | 721 | // Function Selection of Function Group 1 |
| 701 | let selection = (u32::from_be(status[4]) >> 24) & 0xF; | 722 | let selection = (u32::from_be(status[4]) >> 24) & 0xF; |
| @@ -718,7 +739,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 718 | let regs = T::regs(); | 739 | let regs = T::regs(); |
| 719 | let rca = card.rca; | 740 | let rca = card.rca; |
| 720 | 741 | ||
| 721 | self.cmd(Cmd::card_status(rca << 16), false)?; // CMD13 | 742 | Self::cmd(Cmd::card_status(rca << 16), false)?; // CMD13 |
| 722 | 743 | ||
| 723 | // NOTE(unsafe) Atomic read with no side-effects | 744 | // NOTE(unsafe) Atomic read with no side-effects |
| 724 | let r1 = unsafe { regs.respr(0).read().cardstatus() }; | 745 | let r1 = unsafe { regs.respr(0).read().cardstatus() }; |
| @@ -730,8 +751,8 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 730 | let card = self.card.as_mut().ok_or(Error::NoCard)?; | 751 | let card = self.card.as_mut().ok_or(Error::NoCard)?; |
| 731 | let rca = card.rca; | 752 | let rca = card.rca; |
| 732 | 753 | ||
| 733 | self.cmd(Cmd::set_block_length(64), false)?; // CMD16 | 754 | Self::cmd(Cmd::set_block_length(64), false)?; // CMD16 |
| 734 | self.cmd(Cmd::app_cmd(rca << 16), false)?; // APP | 755 | Self::cmd(Cmd::app_cmd(rca << 16), false)?; // APP |
| 735 | 756 | ||
| 736 | let mut status = [0u32; 16]; | 757 | let mut status = [0u32; 16]; |
| 737 | 758 | ||
| @@ -739,11 +760,9 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 739 | let regs = T::regs(); | 760 | let regs = T::regs(); |
| 740 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); | 761 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); |
| 741 | 762 | ||
| 742 | unsafe { | 763 | let transfer = self.prepare_datapath_read(&mut status, 64, 6); |
| 743 | self.prepare_datapath_read(&mut status, 64, 6); | 764 | Self::data_interrupts(true); |
| 744 | Self::data_interrupts(true); | 765 | Self::cmd(Cmd::card_status(0), true)?; |
| 745 | } | ||
| 746 | self.cmd(Cmd::card_status(0), true)?; | ||
| 747 | 766 | ||
| 748 | let res = poll_fn(|cx| { | 767 | let res = poll_fn(|cx| { |
| 749 | T::state().register(cx.waker()); | 768 | T::state().register(cx.waker()); |
| @@ -764,6 +783,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 764 | if res.is_ok() { | 783 | if res.is_ok() { |
| 765 | on_drop.defuse(); | 784 | on_drop.defuse(); |
| 766 | Self::stop_datapath(); | 785 | Self::stop_datapath(); |
| 786 | drop(transfer); | ||
| 767 | 787 | ||
| 768 | for byte in status.iter_mut() { | 788 | for byte in status.iter_mut() { |
| 769 | *byte = u32::from_be(*byte); | 789 | *byte = u32::from_be(*byte); |
| @@ -781,7 +801,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 781 | // Determine Relative Card Address (RCA) of given card | 801 | // Determine Relative Card Address (RCA) of given card |
| 782 | let rca = card.map(|c| c.rca << 16).unwrap_or(0); | 802 | let rca = card.map(|c| c.rca << 16).unwrap_or(0); |
| 783 | 803 | ||
| 784 | let r = self.cmd(Cmd::sel_desel_card(rca), false); | 804 | let r = Self::cmd(Cmd::sel_desel_card(rca), false); |
| 785 | match (r, rca) { | 805 | match (r, rca) { |
| 786 | (Err(Error::Timeout), 0) => Ok(()), | 806 | (Err(Error::Timeout), 0) => Ok(()), |
| 787 | _ => r, | 807 | _ => r, |
| @@ -842,8 +862,8 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 842 | 862 | ||
| 843 | async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { | 863 | async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { |
| 844 | // Read the the 64-bit SCR register | 864 | // Read the the 64-bit SCR register |
| 845 | self.cmd(Cmd::set_block_length(8), false)?; // CMD16 | 865 | Self::cmd(Cmd::set_block_length(8), false)?; // CMD16 |
| 846 | self.cmd(Cmd::app_cmd(card.rca << 16), false)?; | 866 | Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; |
| 847 | 867 | ||
| 848 | let mut scr = [0u32; 2]; | 868 | let mut scr = [0u32; 2]; |
| 849 | 869 | ||
| @@ -851,11 +871,9 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 851 | let regs = T::regs(); | 871 | let regs = T::regs(); |
| 852 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); | 872 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); |
| 853 | 873 | ||
| 854 | unsafe { | 874 | let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3); |
| 855 | self.prepare_datapath_read(&mut scr[..], 8, 3); | 875 | Self::data_interrupts(true); |
| 856 | Self::data_interrupts(true); | 876 | Self::cmd(Cmd::cmd51(), true)?; |
| 857 | } | ||
| 858 | self.cmd(Cmd::cmd51(), true)?; | ||
| 859 | 877 | ||
| 860 | let res = poll_fn(|cx| { | 878 | let res = poll_fn(|cx| { |
| 861 | T::state().register(cx.waker()); | 879 | T::state().register(cx.waker()); |
| @@ -876,6 +894,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 876 | if res.is_ok() { | 894 | if res.is_ok() { |
| 877 | on_drop.defuse(); | 895 | on_drop.defuse(); |
| 878 | Self::stop_datapath(); | 896 | Self::stop_datapath(); |
| 897 | drop(transfer); | ||
| 879 | 898 | ||
| 880 | unsafe { | 899 | unsafe { |
| 881 | let scr_bytes = &*(&scr as *const [u32; 2] as *const [u8; 8]); | 900 | let scr_bytes = &*(&scr as *const [u32; 2] as *const [u8; 8]); |
| @@ -887,7 +906,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 887 | 906 | ||
| 888 | /// Send command to card | 907 | /// Send command to card |
| 889 | #[allow(unused_variables)] | 908 | #[allow(unused_variables)] |
| 890 | fn cmd(&self, cmd: Cmd, data: bool) -> Result<(), Error> { | 909 | fn cmd(cmd: Cmd, data: bool) -> Result<(), Error> { |
| 891 | let regs = T::regs(); | 910 | let regs = T::regs(); |
| 892 | 911 | ||
| 893 | Self::clear_interrupt_flags(); | 912 | Self::clear_interrupt_flags(); |
| @@ -1005,10 +1024,10 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1005 | }); | 1024 | }); |
| 1006 | 1025 | ||
| 1007 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); | 1026 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); |
| 1008 | self.cmd(Cmd::idle(), false)?; | 1027 | Self::cmd(Cmd::idle(), false)?; |
| 1009 | 1028 | ||
| 1010 | // Check if cards supports CMD8 (with pattern) | 1029 | // Check if cards supports CMD8 (with pattern) |
| 1011 | self.cmd(Cmd::hs_send_ext_csd(0x1AA), false)?; | 1030 | Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?; |
| 1012 | let r1 = regs.respr(0).read().cardstatus(); | 1031 | let r1 = regs.respr(0).read().cardstatus(); |
| 1013 | 1032 | ||
| 1014 | let mut card = if r1 == 0x1AA { | 1033 | let mut card = if r1 == 0x1AA { |
| @@ -1020,14 +1039,14 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1020 | 1039 | ||
| 1021 | let ocr = loop { | 1040 | let ocr = loop { |
| 1022 | // Signal that next command is a app command | 1041 | // Signal that next command is a app command |
| 1023 | self.cmd(Cmd::app_cmd(0), false)?; // CMD55 | 1042 | Self::cmd(Cmd::app_cmd(0), false)?; // CMD55 |
| 1024 | 1043 | ||
| 1025 | let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32 | 1044 | let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32 |
| 1026 | | CmdAppOper::HIGH_CAPACITY as u32 | 1045 | | CmdAppOper::HIGH_CAPACITY as u32 |
| 1027 | | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32; | 1046 | | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32; |
| 1028 | 1047 | ||
| 1029 | // Initialize card | 1048 | // Initialize card |
| 1030 | match self.cmd(Cmd::app_op_cmd(arg), false) { | 1049 | match Self::cmd(Cmd::app_op_cmd(arg), false) { |
| 1031 | // ACMD41 | 1050 | // ACMD41 |
| 1032 | Ok(_) => (), | 1051 | Ok(_) => (), |
| 1033 | Err(Error::Crc) => (), | 1052 | Err(Error::Crc) => (), |
| @@ -1048,7 +1067,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1048 | } | 1067 | } |
| 1049 | card.ocr = ocr; | 1068 | card.ocr = ocr; |
| 1050 | 1069 | ||
| 1051 | self.cmd(Cmd::all_send_cid(), false)?; // CMD2 | 1070 | Self::cmd(Cmd::all_send_cid(), false)?; // CMD2 |
| 1052 | let cid0 = regs.respr(0).read().cardstatus() as u128; | 1071 | let cid0 = regs.respr(0).read().cardstatus() as u128; |
| 1053 | let cid1 = regs.respr(1).read().cardstatus() as u128; | 1072 | let cid1 = regs.respr(1).read().cardstatus() as u128; |
| 1054 | let cid2 = regs.respr(2).read().cardstatus() as u128; | 1073 | let cid2 = regs.respr(2).read().cardstatus() as u128; |
| @@ -1056,10 +1075,10 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1056 | let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); | 1075 | let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); |
| 1057 | card.cid = cid.into(); | 1076 | card.cid = cid.into(); |
| 1058 | 1077 | ||
| 1059 | self.cmd(Cmd::send_rel_addr(), false)?; | 1078 | Self::cmd(Cmd::send_rel_addr(), false)?; |
| 1060 | card.rca = regs.respr(0).read().cardstatus() >> 16; | 1079 | card.rca = regs.respr(0).read().cardstatus() >> 16; |
| 1061 | 1080 | ||
| 1062 | self.cmd(Cmd::send_csd(card.rca << 16), false)?; | 1081 | Self::cmd(Cmd::send_csd(card.rca << 16), false)?; |
| 1063 | let csd0 = regs.respr(0).read().cardstatus() as u128; | 1082 | let csd0 = regs.respr(0).read().cardstatus() as u128; |
| 1064 | let csd1 = regs.respr(1).read().cardstatus() as u128; | 1083 | let csd1 = regs.respr(1).read().cardstatus() as u128; |
| 1065 | let csd2 = regs.respr(2).read().cardstatus() as u128; | 1084 | let csd2 = regs.respr(2).read().cardstatus() as u128; |
| @@ -1077,8 +1096,8 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1077 | BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2), | 1096 | BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2), |
| 1078 | _ => (BusWidth::One, 0), | 1097 | _ => (BusWidth::One, 0), |
| 1079 | }; | 1098 | }; |
| 1080 | self.cmd(Cmd::app_cmd(card.rca << 16), false)?; | 1099 | Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; |
| 1081 | self.cmd(Cmd::cmd6(acmd_arg), false)?; | 1100 | Self::cmd(Cmd::cmd6(acmd_arg), false)?; |
| 1082 | 1101 | ||
| 1083 | // CPSMACT and DPSMACT must be 0 to set WIDBUS | 1102 | // CPSMACT and DPSMACT must be 0 to set WIDBUS |
| 1084 | Self::wait_idle(); | 1103 | Self::wait_idle(); |
| @@ -1139,16 +1158,14 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1139 | CardCapacity::SDSC => block_idx * 512, | 1158 | CardCapacity::SDSC => block_idx * 512, |
| 1140 | _ => block_idx, | 1159 | _ => block_idx, |
| 1141 | }; | 1160 | }; |
| 1142 | self.cmd(Cmd::set_block_length(512), false)?; // CMD16 | 1161 | Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 |
| 1143 | 1162 | ||
| 1144 | let regs = T::regs(); | 1163 | let regs = T::regs(); |
| 1145 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); | 1164 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); |
| 1146 | 1165 | ||
| 1147 | unsafe { | 1166 | let transfer = self.prepare_datapath_read(buffer, 512, 9); |
| 1148 | self.prepare_datapath_read(buffer, 512, 9); | 1167 | Self::data_interrupts(true); |
| 1149 | Self::data_interrupts(true); | 1168 | Self::cmd(Cmd::read_single_block(address), true)?; |
| 1150 | } | ||
| 1151 | self.cmd(Cmd::read_single_block(address), true)?; | ||
| 1152 | 1169 | ||
| 1153 | let res = poll_fn(|cx| { | 1170 | let res = poll_fn(|cx| { |
| 1154 | T::state().register(cx.waker()); | 1171 | T::state().register(cx.waker()); |
| @@ -1169,6 +1186,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1169 | if res.is_ok() { | 1186 | if res.is_ok() { |
| 1170 | on_drop.defuse(); | 1187 | on_drop.defuse(); |
| 1171 | Self::stop_datapath(); | 1188 | Self::stop_datapath(); |
| 1189 | drop(transfer); | ||
| 1172 | } | 1190 | } |
| 1173 | res | 1191 | res |
| 1174 | } | 1192 | } |
| @@ -1185,22 +1203,20 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1185 | CardCapacity::SDSC => block_idx * 512, | 1203 | CardCapacity::SDSC => block_idx * 512, |
| 1186 | _ => block_idx, | 1204 | _ => block_idx, |
| 1187 | }; | 1205 | }; |
| 1188 | self.cmd(Cmd::set_block_length(512), false)?; // CMD16 | 1206 | Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 |
| 1189 | 1207 | ||
| 1190 | let regs = T::regs(); | 1208 | let regs = T::regs(); |
| 1191 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); | 1209 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); |
| 1192 | 1210 | ||
| 1193 | // sdmmc_v1 uses different cmd/dma order than v2, but only for writes | 1211 | // sdmmc_v1 uses different cmd/dma order than v2, but only for writes |
| 1194 | #[cfg(sdmmc_v1)] | 1212 | #[cfg(sdmmc_v1)] |
| 1195 | self.cmd(Cmd::write_single_block(address), true)?; | 1213 | Self::cmd(Cmd::write_single_block(address), true)?; |
| 1196 | 1214 | ||
| 1197 | unsafe { | 1215 | let transfer = self.prepare_datapath_write(buffer, 512, 9); |
| 1198 | self.prepare_datapath_write(buffer as *const [u32; 128], 512, 9); | 1216 | Self::data_interrupts(true); |
| 1199 | Self::data_interrupts(true); | ||
| 1200 | } | ||
| 1201 | 1217 | ||
| 1202 | #[cfg(sdmmc_v2)] | 1218 | #[cfg(sdmmc_v2)] |
| 1203 | self.cmd(Cmd::write_single_block(address), true)?; | 1219 | Self::cmd(Cmd::write_single_block(address), true)?; |
| 1204 | 1220 | ||
| 1205 | let res = poll_fn(|cx| { | 1221 | let res = poll_fn(|cx| { |
| 1206 | T::state().register(cx.waker()); | 1222 | T::state().register(cx.waker()); |
| @@ -1222,6 +1238,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1222 | Ok(_) => { | 1238 | Ok(_) => { |
| 1223 | on_drop.defuse(); | 1239 | on_drop.defuse(); |
| 1224 | Self::stop_datapath(); | 1240 | Self::stop_datapath(); |
| 1241 | drop(transfer); | ||
| 1225 | 1242 | ||
| 1226 | // TODO: Make this configurable | 1243 | // TODO: Make this configurable |
| 1227 | let mut timeout: u32 = 0x00FF_FFFF; | 1244 | let mut timeout: u32 = 0x00FF_FFFF; |
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 481ea4abc..7858cb3e8 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs | |||
| @@ -421,8 +421,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 421 | 421 | ||
| 422 | let tx_request = self.txdma.request(); | 422 | let tx_request = self.txdma.request(); |
| 423 | let tx_dst = T::REGS.tx_ptr(); | 423 | let tx_dst = T::REGS.tx_ptr(); |
| 424 | unsafe { self.txdma.start_write(tx_request, data, tx_dst, Default::default()) } | 424 | let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) }; |
| 425 | let tx_f = Transfer::new(&mut self.txdma); | ||
| 426 | 425 | ||
| 427 | unsafe { | 426 | unsafe { |
| 428 | set_txdmaen(T::REGS, true); | 427 | set_txdmaen(T::REGS, true); |
| @@ -468,13 +467,21 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 468 | 467 | ||
| 469 | let rx_request = self.rxdma.request(); | 468 | let rx_request = self.rxdma.request(); |
| 470 | let rx_src = T::REGS.rx_ptr(); | 469 | let rx_src = T::REGS.rx_ptr(); |
| 471 | unsafe { self.rxdma.start_read(rx_request, rx_src, data, Default::default()) }; | 470 | let rx_f = unsafe { Transfer::new_read(&mut self.rxdma, rx_request, rx_src, data, Default::default()) }; |
| 472 | let rx_f = Transfer::new(&mut self.rxdma); | ||
| 473 | 471 | ||
| 474 | let tx_request = self.txdma.request(); | 472 | let tx_request = self.txdma.request(); |
| 475 | let tx_dst = T::REGS.tx_ptr(); | 473 | let tx_dst = T::REGS.tx_ptr(); |
| 476 | let clock_byte = 0x00u8; | 474 | let clock_byte = 0x00u8; |
| 477 | let tx_f = crate::dma::write_repeated(&mut self.txdma, tx_request, &clock_byte, clock_byte_count, tx_dst); | 475 | let tx_f = unsafe { |
| 476 | Transfer::new_write_repeated( | ||
| 477 | &mut self.txdma, | ||
| 478 | tx_request, | ||
| 479 | &clock_byte, | ||
| 480 | clock_byte_count, | ||
| 481 | tx_dst, | ||
| 482 | Default::default(), | ||
| 483 | ) | ||
| 484 | }; | ||
| 478 | 485 | ||
| 479 | unsafe { | 486 | unsafe { |
| 480 | set_txdmaen(T::REGS, true); | 487 | set_txdmaen(T::REGS, true); |
| @@ -521,13 +528,11 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 521 | 528 | ||
| 522 | let rx_request = self.rxdma.request(); | 529 | let rx_request = self.rxdma.request(); |
| 523 | let rx_src = T::REGS.rx_ptr(); | 530 | let rx_src = T::REGS.rx_ptr(); |
| 524 | unsafe { self.rxdma.start_read(rx_request, rx_src, read, Default::default()) }; | 531 | let rx_f = unsafe { Transfer::new_read_raw(&mut self.rxdma, rx_request, rx_src, read, Default::default()) }; |
| 525 | let rx_f = Transfer::new(&mut self.rxdma); | ||
| 526 | 532 | ||
| 527 | let tx_request = self.txdma.request(); | 533 | let tx_request = self.txdma.request(); |
| 528 | let tx_dst = T::REGS.tx_ptr(); | 534 | let tx_dst = T::REGS.tx_ptr(); |
| 529 | unsafe { self.txdma.start_write(tx_request, write, tx_dst, Default::default()) } | 535 | let tx_f = unsafe { Transfer::new_write_raw(&mut self.txdma, tx_request, write, tx_dst, Default::default()) }; |
| 530 | let tx_f = Transfer::new(&mut self.txdma); | ||
| 531 | 536 | ||
| 532 | unsafe { | 537 | unsafe { |
| 533 | set_txdmaen(T::REGS, true); | 538 | set_txdmaen(T::REGS, true); |
diff --git a/embassy-stm32/src/traits.rs b/embassy-stm32/src/traits.rs index 45cc4e725..ffce7bd42 100644 --- a/embassy-stm32/src/traits.rs +++ b/embassy-stm32/src/traits.rs | |||
| @@ -34,7 +34,7 @@ macro_rules! dma_trait_impl { | |||
| 34 | (crate::$mod:ident::$trait:ident, $instance:ident, {dmamux: $dmamux:ident}, $request:expr) => { | 34 | (crate::$mod:ident::$trait:ident, $instance:ident, {dmamux: $dmamux:ident}, $request:expr) => { |
| 35 | impl<T> crate::$mod::$trait<crate::peripherals::$instance> for T | 35 | impl<T> crate::$mod::$trait<crate::peripherals::$instance> for T |
| 36 | where | 36 | where |
| 37 | T: crate::dma::MuxChannel<Mux = crate::dma::$dmamux>, | 37 | T: crate::dma::Channel + crate::dma::MuxChannel<Mux = crate::dma::$dmamux>, |
| 38 | { | 38 | { |
| 39 | fn request(&self) -> crate::dma::Request { | 39 | fn request(&self) -> crate::dma::Request { |
| 40 | $request | 40 | $request |
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 8bbba305b..b8656b586 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs | |||
| @@ -6,11 +6,11 @@ use core::sync::atomic::{compiler_fence, Ordering}; | |||
| 6 | use core::task::Poll; | 6 | use core::task::Poll; |
| 7 | 7 | ||
| 8 | use embassy_cortex_m::interrupt::InterruptExt; | 8 | use embassy_cortex_m::interrupt::InterruptExt; |
| 9 | use embassy_futures::select::{select, Either}; | ||
| 10 | use embassy_hal_common::drop::OnDrop; | 9 | use embassy_hal_common::drop::OnDrop; |
| 11 | use embassy_hal_common::{into_ref, PeripheralRef}; | 10 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 11 | use futures::future::{select, Either}; | ||
| 12 | 12 | ||
| 13 | use crate::dma::NoDma; | 13 | use crate::dma::{NoDma, Transfer}; |
| 14 | use crate::gpio::sealed::AFType; | 14 | use crate::gpio::sealed::AFType; |
| 15 | #[cfg(any(lpuart_v1, lpuart_v2))] | 15 | #[cfg(any(lpuart_v1, lpuart_v2))] |
| 16 | use crate::pac::lpuart::{regs, vals, Lpuart as Regs}; | 16 | use crate::pac::lpuart::{regs, vals, Lpuart as Regs}; |
| @@ -91,7 +91,7 @@ enum ReadCompletionEvent { | |||
| 91 | // DMA Read transfer completed first | 91 | // DMA Read transfer completed first |
| 92 | DmaCompleted, | 92 | DmaCompleted, |
| 93 | // Idle line detected first | 93 | // Idle line detected first |
| 94 | Idle, | 94 | Idle(usize), |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { | 97 | pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { |
| @@ -183,7 +183,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | |||
| 183 | } | 183 | } |
| 184 | // If we don't assign future to a variable, the data register pointer | 184 | // If we don't assign future to a variable, the data register pointer |
| 185 | // is held across an await and makes the future non-Send. | 185 | // is held across an await and makes the future non-Send. |
| 186 | let transfer = crate::dma::write(ch, request, buffer, tdr(T::regs())); | 186 | let transfer = unsafe { Transfer::new_write(ch, request, buffer, tdr(T::regs()), Default::default()) }; |
| 187 | transfer.await; | 187 | transfer.await; |
| 188 | Ok(()) | 188 | Ok(()) |
| 189 | } | 189 | } |
| @@ -430,10 +430,12 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 430 | let ch = &mut self.rx_dma; | 430 | let ch = &mut self.rx_dma; |
| 431 | let request = ch.request(); | 431 | let request = ch.request(); |
| 432 | 432 | ||
| 433 | let buffer_len = buffer.len(); | ||
| 434 | |||
| 433 | // Start USART DMA | 435 | // Start USART DMA |
| 434 | // will not do anything yet because DMAR is not yet set | 436 | // will not do anything yet because DMAR is not yet set |
| 435 | // future which will complete when DMA Read request completes | 437 | // future which will complete when DMA Read request completes |
| 436 | let transfer = crate::dma::read(ch, request, rdr(T::regs()), buffer); | 438 | let transfer = unsafe { Transfer::new_read(ch, request, rdr(T::regs()), buffer, Default::default()) }; |
| 437 | 439 | ||
| 438 | // SAFETY: The only way we might have a problem is using split rx and tx | 440 | // SAFETY: The only way we might have a problem is using split rx and tx |
| 439 | // here we only modify or read Rx related flags, interrupts and DMA channel | 441 | // here we only modify or read Rx related flags, interrupts and DMA channel |
| @@ -565,13 +567,15 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 565 | // when transfer is dropped, it will stop the DMA request | 567 | // when transfer is dropped, it will stop the DMA request |
| 566 | let r = match select(transfer, idle).await { | 568 | let r = match select(transfer, idle).await { |
| 567 | // DMA transfer completed first | 569 | // DMA transfer completed first |
| 568 | Either::First(()) => Ok(ReadCompletionEvent::DmaCompleted), | 570 | Either::Left(((), _)) => Ok(ReadCompletionEvent::DmaCompleted), |
| 569 | 571 | ||
| 570 | // Idle line detected first | 572 | // Idle line detected first |
| 571 | Either::Second(Ok(())) => Ok(ReadCompletionEvent::Idle), | 573 | Either::Right((Ok(()), transfer)) => Ok(ReadCompletionEvent::Idle( |
| 574 | buffer_len - transfer.get_remaining_transfers() as usize, | ||
| 575 | )), | ||
| 572 | 576 | ||
| 573 | // error occurred | 577 | // error occurred |
| 574 | Either::Second(Err(e)) => Err(e), | 578 | Either::Right((Err(e), _)) => Err(e), |
| 575 | }; | 579 | }; |
| 576 | 580 | ||
| 577 | drop(on_drop); | 581 | drop(on_drop); |
| @@ -594,14 +598,9 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 594 | // wait for DMA to complete or IDLE line detection if requested | 598 | // wait for DMA to complete or IDLE line detection if requested |
| 595 | let res = self.inner_read_run(buffer, enable_idle_line_detection).await; | 599 | let res = self.inner_read_run(buffer, enable_idle_line_detection).await; |
| 596 | 600 | ||
| 597 | let ch = &mut self.rx_dma; | ||
| 598 | |||
| 599 | match res { | 601 | match res { |
| 600 | Ok(ReadCompletionEvent::DmaCompleted) => Ok(buffer_len), | 602 | Ok(ReadCompletionEvent::DmaCompleted) => Ok(buffer_len), |
| 601 | Ok(ReadCompletionEvent::Idle) => { | 603 | Ok(ReadCompletionEvent::Idle(n)) => Ok(n), |
| 602 | let n = buffer_len - (ch.remaining_transfers() as usize); | ||
| 603 | Ok(n) | ||
| 604 | } | ||
| 605 | Err(e) => Err(e), | 604 | Err(e) => Err(e), |
| 606 | } | 605 | } |
| 607 | } | 606 | } |
