aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/build.rs12
-rw-r--r--embassy-stm32/src/dcmi.rs42
-rw-r--r--embassy-stm32/src/dma/bdma.rs403
-rw-r--r--embassy-stm32/src/dma/dma.rs675
-rw-r--r--embassy-stm32/src/dma/dmamux.rs22
-rw-r--r--embassy-stm32/src/dma/gpdma.rs402
-rw-r--r--embassy-stm32/src/dma/mod.rs317
-rw-r--r--embassy-stm32/src/i2c/v2.rs6
-rw-r--r--embassy-stm32/src/lib.rs7
-rw-r--r--embassy-stm32/src/qspi/mod.rs32
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs243
-rw-r--r--embassy-stm32/src/spi/mod.rs23
-rw-r--r--embassy-stm32/src/traits.rs2
-rw-r--r--embassy-stm32/src/usart/mod.rs27
14 files changed, 1157 insertions, 1056 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index a85d3db6e..a00c6c416 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -268,7 +268,7 @@ fn main() {
268 // ======== 268 // ========
269 // Generate DMA IRQs. 269 // Generate DMA IRQs.
270 270
271 let mut dma_irqs: HashMap<&str, Vec<(&str, &str)>> = HashMap::new(); 271 let mut dma_irqs: HashMap<&str, Vec<(&str, &str, &str)>> = HashMap::new();
272 272
273 for p in METADATA.peripherals { 273 for p in METADATA.peripherals {
274 if let Some(r) = &p.registers { 274 if let Some(r) = &p.registers {
@@ -278,7 +278,10 @@ fn main() {
278 continue; 278 continue;
279 } 279 }
280 for irq in p.interrupts { 280 for irq in p.interrupts {
281 dma_irqs.entry(irq.interrupt).or_default().push((p.name, irq.signal)); 281 dma_irqs
282 .entry(irq.interrupt)
283 .or_default()
284 .push((r.kind, p.name, irq.signal));
282 } 285 }
283 } 286 }
284 } 287 }
@@ -287,13 +290,14 @@ fn main() {
287 for (irq, channels) in dma_irqs { 290 for (irq, channels) in dma_irqs {
288 let irq = format_ident!("{}", irq); 291 let irq = format_ident!("{}", irq);
289 292
290 let channels = channels.iter().map(|(dma, ch)| format_ident!("{}_{}", dma, ch)); 293 let xdma = format_ident!("{}", channels[0].0);
294 let channels = channels.iter().map(|(_, dma, ch)| format_ident!("{}_{}", dma, ch));
291 295
292 g.extend(quote! { 296 g.extend(quote! {
293 #[crate::interrupt] 297 #[crate::interrupt]
294 unsafe fn #irq () { 298 unsafe fn #irq () {
295 #( 299 #(
296 <crate::peripherals::#channels as crate::dma::sealed::Channel>::on_irq(); 300 <crate::peripherals::#channels as crate::dma::#xdma::sealed::Channel>::on_irq();
297 )* 301 )*
298 } 302 }
299 }); 303 });
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs
index 20e1a4070..c19be86c6 100644
--- a/embassy-stm32/src/dcmi.rs
+++ b/embassy-stm32/src/dcmi.rs
@@ -4,6 +4,7 @@ use core::task::Poll;
4use embassy_hal_common::{into_ref, PeripheralRef}; 4use embassy_hal_common::{into_ref, PeripheralRef};
5use embassy_sync::waitqueue::AtomicWaker; 5use embassy_sync::waitqueue::AtomicWaker;
6 6
7use crate::dma::Transfer;
7use crate::gpio::sealed::AFType; 8use crate::gpio::sealed::AFType;
8use crate::gpio::Speed; 9use crate::gpio::Speed;
9use crate::interrupt::{Interrupt, InterruptExt}; 10use 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,6 +434,12 @@ where
436 result 434 result
437 } 435 }
438 436
437 #[cfg(not(dma))]
438 async fn capture_giant(&mut self, _buffer: &mut [u32]) -> Result<(), Error> {
439 panic!("capturing to buffers larger than 0xffff is only supported on DMA for now, not on BDMA or GPDMA.");
440 }
441
442 #[cfg(dma)]
439 async fn capture_giant(&mut self, buffer: &mut [u32]) -> Result<(), Error> { 443 async fn capture_giant(&mut self, buffer: &mut [u32]) -> Result<(), Error> {
440 use crate::dma::TransferOptions; 444 use crate::dma::TransferOptions;
441 445
@@ -460,16 +464,24 @@ where
460 let r = self.inner.regs(); 464 let r = self.inner.regs();
461 let src = r.dr().ptr() as *mut u32; 465 let src = r.dr().ptr() as *mut u32;
462 466
463 unsafe { 467 let mut transfer = unsafe {
464 channel.start_double_buffered_read(request, src, m0ar, m1ar, chunk_size, TransferOptions::default()); 468 crate::dma::DoubleBuffered::new_read(
465 } 469 &mut self.dma,
470 request,
471 src,
472 m0ar,
473 m1ar,
474 chunk_size,
475 TransferOptions::default(),
476 )
477 };
466 478
467 let mut last_chunk_set_for_transfer = false; 479 let mut last_chunk_set_for_transfer = false;
468 let mut buffer0_last_accessible = false; 480 let mut buffer0_last_accessible = false;
469 let dma_result = poll_fn(|cx| { 481 let dma_result = poll_fn(|cx| {
470 channel.set_waker(cx.waker()); 482 transfer.set_waker(cx.waker());
471 483
472 let buffer0_currently_accessible = unsafe { channel.is_buffer0_accessible() }; 484 let buffer0_currently_accessible = transfer.is_buffer0_accessible();
473 485
474 // check if the accessible buffer changed since last poll 486 // check if the accessible buffer changed since last poll
475 if buffer0_last_accessible == buffer0_currently_accessible { 487 if buffer0_last_accessible == buffer0_currently_accessible {
@@ -480,21 +492,21 @@ where
480 if remaining_chunks != 0 { 492 if remaining_chunks != 0 {
481 if remaining_chunks % 2 == 0 && buffer0_currently_accessible { 493 if remaining_chunks % 2 == 0 && buffer0_currently_accessible {
482 m0ar = unsafe { m0ar.add(2 * chunk_size) }; 494 m0ar = unsafe { m0ar.add(2 * chunk_size) };
483 unsafe { channel.set_buffer0(m0ar) } 495 unsafe { transfer.set_buffer0(m0ar) }
484 remaining_chunks -= 1; 496 remaining_chunks -= 1;
485 } else if !buffer0_currently_accessible { 497 } else if !buffer0_currently_accessible {
486 m1ar = unsafe { m1ar.add(2 * chunk_size) }; 498 m1ar = unsafe { m1ar.add(2 * chunk_size) };
487 unsafe { channel.set_buffer1(m1ar) }; 499 unsafe { transfer.set_buffer1(m1ar) };
488 remaining_chunks -= 1; 500 remaining_chunks -= 1;
489 } 501 }
490 } else { 502 } else {
491 if buffer0_currently_accessible { 503 if buffer0_currently_accessible {
492 unsafe { channel.set_buffer0(buffer.as_mut_ptr()) } 504 unsafe { transfer.set_buffer0(buffer.as_mut_ptr()) }
493 } else { 505 } else {
494 unsafe { channel.set_buffer1(buffer.as_mut_ptr()) } 506 unsafe { transfer.set_buffer1(buffer.as_mut_ptr()) }
495 } 507 }
496 if last_chunk_set_for_transfer { 508 if last_chunk_set_for_transfer {
497 channel.request_stop(); 509 transfer.request_stop();
498 return Poll::Ready(()); 510 return Poll::Ready(());
499 } 511 }
500 last_chunk_set_for_transfer = true; 512 last_chunk_set_for_transfer = true;
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
3use core::future::Future;
4use core::pin::Pin;
3use core::sync::atomic::{fence, Ordering}; 5use core::sync::atomic::{fence, Ordering};
4use core::task::Waker; 6use core::task::{Context, Poll};
5 7
6use embassy_cortex_m::interrupt::Priority; 8use embassy_cortex_m::interrupt::Priority;
9use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
7use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
8 11
9use super::{TransferOptions, Word, WordSize}; 12use super::{Dir, Word, WordSize};
10use crate::_generated::BDMA_CHANNEL_COUNT; 13use crate::_generated::BDMA_CHANNEL_COUNT;
11use crate::dma::Request;
12use crate::interrupt::{Interrupt, InterruptExt}; 14use crate::interrupt::{Interrupt, InterruptExt};
13use crate::pac; 15use crate::pac;
14use crate::pac::bdma::vals; 16use crate::pac::bdma::vals;
15 17
18#[derive(Debug, Copy, Clone, PartialEq, Eq)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20#[non_exhaustive]
21pub struct TransferOptions {}
22
23impl Default for TransferOptions {
24 fn default() -> Self {
25 Self {}
26 }
27}
28
16impl From<WordSize> for vals::Size { 29impl 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
39impl 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
26struct State { 48struct 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"); 100pub(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);} 114pub type Request = u8;
148 } 115#[cfg(not(any(bdma_v2, dmamux)))]
116pub 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)} 119pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {}
152 } 120#[cfg(not(dmamux))]
153 fn remaining_transfers(&mut self) -> u16 { 121pub 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) { 123pub(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 }; 135pub struct Transfer<'a, C: Channel> {
136 channel: PeripheralRef<'a, C>,
170} 137}
171 138
172mod low_level_api { 139impl<'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 321impl<'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) { 331impl<'a, C: Channel> Unpin for Transfer<'a, C> {}
275 panic!("DMA: error on BDMA@{:08x} channel {}", dma.0 as u32, channel_num); 332impl<'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..62c092241 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -1,15 +1,45 @@
1use core::future::Future;
2use core::marker::PhantomData;
3use core::pin::Pin;
1use core::sync::atomic::{fence, Ordering}; 4use core::sync::atomic::{fence, Ordering};
2use core::task::Waker; 5use core::task::{Context, Poll, Waker};
3 6
4use embassy_cortex_m::interrupt::Priority; 7use embassy_cortex_m::interrupt::Priority;
8use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
5use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10use pac::dma::regs;
6 11
7use super::{Burst, FifoThreshold, FlowControl, Request, TransferOptions, Word, WordSize}; 12use super::{Dir, Word, WordSize};
8use crate::_generated::DMA_CHANNEL_COUNT; 13use crate::_generated::DMA_CHANNEL_COUNT;
9use crate::interrupt::{Interrupt, InterruptExt}; 14use crate::interrupt::{Interrupt, InterruptExt};
10use crate::pac::dma::{regs, vals}; 15use crate::pac::dma::vals;
11use crate::{interrupt, pac}; 16use crate::{interrupt, pac};
12 17
18#[derive(Debug, Copy, Clone, PartialEq, Eq)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20#[non_exhaustive]
21pub struct TransferOptions {
22 /// Peripheral burst transfer configuration
23 pub pburst: Burst,
24 /// Memory burst transfer configuration
25 pub mburst: Burst,
26 /// Flow control configuration
27 pub flow_ctrl: FlowControl,
28 /// FIFO threshold for DMA FIFO mode. If none, direct mode is used.
29 pub fifo_threshold: Option<FifoThreshold>,
30}
31
32impl Default for TransferOptions {
33 fn default() -> Self {
34 Self {
35 pburst: Burst::Single,
36 mburst: Burst::Single,
37 flow_ctrl: FlowControl::Dma,
38 fifo_threshold: None,
39 }
40 }
41}
42
13impl From<WordSize> for vals::Size { 43impl From<WordSize> for vals::Size {
14 fn from(raw: WordSize) -> Self { 44 fn from(raw: WordSize) -> Self {
15 match raw { 45 match raw {
@@ -20,6 +50,28 @@ impl From<WordSize> for vals::Size {
20 } 50 }
21} 51}
22 52
53impl From<Dir> for vals::Dir {
54 fn from(raw: Dir) -> Self {
55 match raw {
56 Dir::MemoryToPeripheral => Self::MEMORYTOPERIPHERAL,
57 Dir::PeripheralToMemory => Self::PERIPHERALTOMEMORY,
58 }
59 }
60}
61
62#[derive(Debug, Copy, Clone, PartialEq, Eq)]
63#[cfg_attr(feature = "defmt", derive(defmt::Format))]
64pub enum Burst {
65 /// Single transfer
66 Single,
67 /// Incremental burst of 4 beats
68 Incr4,
69 /// Incremental burst of 8 beats
70 Incr8,
71 /// Incremental burst of 16 beats
72 Incr16,
73}
74
23impl From<Burst> for vals::Burst { 75impl From<Burst> for vals::Burst {
24 fn from(burst: Burst) -> Self { 76 fn from(burst: Burst) -> Self {
25 match burst { 77 match burst {
@@ -31,6 +83,15 @@ impl From<Burst> for vals::Burst {
31 } 83 }
32} 84}
33 85
86#[derive(Debug, Copy, Clone, PartialEq, Eq)]
87#[cfg_attr(feature = "defmt", derive(defmt::Format))]
88pub enum FlowControl {
89 /// Flow control by DMA
90 Dma,
91 /// Flow control by peripheral
92 Peripheral,
93}
94
34impl From<FlowControl> for vals::Pfctrl { 95impl From<FlowControl> for vals::Pfctrl {
35 fn from(flow: FlowControl) -> Self { 96 fn from(flow: FlowControl) -> Self {
36 match flow { 97 match flow {
@@ -40,6 +101,19 @@ impl From<FlowControl> for vals::Pfctrl {
40 } 101 }
41} 102}
42 103
104#[derive(Debug, Copy, Clone, PartialEq, Eq)]
105#[cfg_attr(feature = "defmt", derive(defmt::Format))]
106pub enum FifoThreshold {
107 /// 1/4 full FIFO
108 Quarter,
109 /// 1/2 full FIFO
110 Half,
111 /// 3/4 full FIFO
112 ThreeQuarters,
113 /// Full FIFO
114 Full,
115}
116
43impl From<FifoThreshold> for vals::Fth { 117impl From<FifoThreshold> for vals::Fth {
44 fn from(value: FifoThreshold) -> Self { 118 fn from(value: FifoThreshold) -> Self {
45 match value { 119 match value {
@@ -51,27 +125,15 @@ impl From<FifoThreshold> for vals::Fth {
51 } 125 }
52} 126}
53 127
54struct ChannelState {
55 waker: AtomicWaker,
56}
57
58impl ChannelState {
59 const fn new() -> Self {
60 Self {
61 waker: AtomicWaker::new(),
62 }
63 }
64}
65
66struct State { 128struct State {
67 channels: [ChannelState; DMA_CHANNEL_COUNT], 129 ch_wakers: [AtomicWaker; DMA_CHANNEL_COUNT],
68} 130}
69 131
70impl State { 132impl State {
71 const fn new() -> Self { 133 const fn new() -> Self {
72 const CH: ChannelState = ChannelState::new(); 134 const AW: AtomicWaker = AtomicWaker::new();
73 Self { 135 Self {
74 channels: [CH; DMA_CHANNEL_COUNT], 136 ch_wakers: [AW; DMA_CHANNEL_COUNT],
75 } 137 }
76 } 138 }
77} 139}
@@ -92,158 +154,183 @@ pub(crate) unsafe fn init(irq_priority: Priority) {
92 154
93foreach_dma_channel! { 155foreach_dma_channel! {
94 ($channel_peri:ident, $dma_peri:ident, dma, $channel_num:expr, $index:expr, $dmamux:tt) => { 156 ($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 { 157 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) { 158 fn regs(&self) -> pac::dma::Dma {
97 let (ptr, len) = super::slice_ptr_parts(buf); 159 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 } 160 }
115 161 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) { 162 $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 } 163 }
134 164 fn index(&self) -> usize {
135 unsafe fn start_read<W: Word>(&mut self, request: Request, reg_addr: *const W, buf: *mut [W], options: TransferOptions) { 165 $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 } 166 }
154 167 fn on_irq() {
155 unsafe fn start_double_buffered_read<W: Word>( 168 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 } 169 }
170 }
182 171
183 unsafe fn set_buffer0<W: Word>(&mut self, buffer: *mut W) { 172 impl Channel for crate::peripherals::$channel_peri {}
184 low_level_api::set_dbm_buffer0(pac::$dma_peri, $channel_num, buffer as *mut u32); 173 };
185 } 174}
186 175
187 unsafe fn set_buffer1<W: Word>(&mut self, buffer: *mut W) { 176/// 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); 177pub(crate) unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: usize, index: usize) {
189 } 178 let cr = dma.st(channel_num).cr();
179 let isr = dma.isr(channel_num / 4).read();
190 180
191 unsafe fn is_buffer0_accessible(&mut self) -> bool { 181 if isr.teif(channel_num % 4) {
192 low_level_api::is_buffer0_accessible(pac::$dma_peri, $channel_num) 182 panic!("DMA: error on DMA@{:08x} channel {}", dma.0 as u32, channel_num);
193 } 183 }
194 184
195 fn request_stop(&mut self) { 185 if isr.tcif(channel_num % 4) && cr.read().tcie() {
196 unsafe {low_level_api::request_stop(pac::$dma_peri, $channel_num);} 186 /* acknowledge transfer complete interrupt */
197 } 187 dma.ifcr(channel_num / 4).write(|w| w.set_tcif(channel_num % 4, true));
188 STATE.ch_wakers[index].wake();
189 }
190}
198 191
199 fn is_running(&self) -> bool { 192#[cfg(any(dma_v2, dmamux))]
200 unsafe {low_level_api::is_running(pac::$dma_peri, $channel_num)} 193pub type Request = u8;
201 } 194#[cfg(not(any(dma_v2, dmamux)))]
195pub type Request = ();
202 196
203 fn remaining_transfers(&mut self) -> u16 { 197#[cfg(dmamux)]
204 unsafe {low_level_api::get_remaining_transfers(pac::$dma_peri, $channel_num)} 198pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {}
205 } 199#[cfg(not(dmamux))]
200pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {}
206 201
207 fn set_waker(&mut self, waker: &Waker) { 202pub(crate) mod sealed {
208 unsafe {low_level_api::set_waker($index, waker )} 203 use super::*;
209 }
210 204
211 fn on_irq() { 205 pub trait Channel {
212 unsafe { 206 fn regs(&self) -> pac::dma::Dma;
213 low_level_api::on_irq_inner(pac::$dma_peri, $channel_num, $index); 207 fn num(&self) -> usize;
214 } 208 fn index(&self) -> usize;
215 } 209 fn on_irq();
216 } 210 }
217 impl crate::dma::Channel for crate::peripherals::$channel_peri { }
218 };
219} 211}
220 212
221mod low_level_api { 213#[must_use = "futures do nothing unless you `.await` or poll them"]
222 use super::*; 214pub struct Transfer<'a, C: Channel> {
215 channel: PeripheralRef<'a, C>,
216}
217
218impl<'a, C: Channel> Transfer<'a, C> {
219 pub unsafe fn new_read<W: Word>(
220 channel: impl Peripheral<P = C> + 'a,
221 request: Request,
222 peri_addr: *mut W,
223 buf: &'a mut [W],
224 options: TransferOptions,
225 ) -> Self {
226 Self::new_read_raw(channel, request, peri_addr, buf, options)
227 }
228
229 pub unsafe fn new_read_raw<W: Word>(
230 channel: impl Peripheral<P = C> + 'a,
231 request: Request,
232 peri_addr: *mut W,
233 buf: *mut [W],
234 options: TransferOptions,
235 ) -> Self {
236 into_ref!(channel);
237
238 let (ptr, len) = super::slice_ptr_parts_mut(buf);
239 assert!(len > 0 && len <= 0xFFFF);
240
241 Self::new_inner(
242 channel,
243 request,
244 Dir::PeripheralToMemory,
245 peri_addr as *const u32,
246 ptr as *mut u32,
247 len,
248 true,
249 W::bits(),
250 options,
251 )
252 }
253
254 pub unsafe fn new_write<W: Word>(
255 channel: impl Peripheral<P = C> + 'a,
256 request: Request,
257 buf: &'a [W],
258 peri_addr: *mut W,
259 options: TransferOptions,
260 ) -> Self {
261 Self::new_write_raw(channel, request, buf, peri_addr, options)
262 }
263
264 pub unsafe fn new_write_raw<W: Word>(
265 channel: impl Peripheral<P = C> + 'a,
266 request: Request,
267 buf: *const [W],
268 peri_addr: *mut W,
269 options: TransferOptions,
270 ) -> Self {
271 into_ref!(channel);
272
273 let (ptr, len) = super::slice_ptr_parts(buf);
274 assert!(len > 0 && len <= 0xFFFF);
275
276 Self::new_inner(
277 channel,
278 request,
279 Dir::MemoryToPeripheral,
280 peri_addr as *const u32,
281 ptr as *mut u32,
282 len,
283 true,
284 W::bits(),
285 options,
286 )
287 }
223 288
224 pub unsafe fn start_transfer( 289 pub unsafe fn new_write_repeated<W: Word>(
225 dma: pac::dma::Dma, 290 channel: impl Peripheral<P = C> + 'a,
226 channel_number: u8,
227 request: Request, 291 request: Request,
228 dir: vals::Dir, 292 repeated: &'a W,
293 count: usize,
294 peri_addr: *mut W,
295 options: TransferOptions,
296 ) -> Self {
297 into_ref!(channel);
298
299 Self::new_inner(
300 channel,
301 request,
302 Dir::MemoryToPeripheral,
303 peri_addr as *const u32,
304 repeated as *const W as *mut u32,
305 count,
306 false,
307 W::bits(),
308 options,
309 )
310 }
311
312 unsafe fn new_inner(
313 channel: PeripheralRef<'a, C>,
314 _request: Request,
315 dir: Dir,
229 peri_addr: *const u32, 316 peri_addr: *const u32,
230 mem_addr: *mut u32, 317 mem_addr: *mut u32,
231 mem_len: usize, 318 mem_len: usize,
232 incr_mem: bool, 319 incr_mem: bool,
233 data_size: vals::Size, 320 data_size: WordSize,
234 options: TransferOptions, 321 options: TransferOptions,
235 #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, 322 ) -> Self {
236 #[cfg(dmamux)] dmamux_ch_num: u8, 323 let ch = channel.regs().st(channel.num());
237 ) {
238 #[cfg(dmamux)]
239 super::super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request);
240 324
241 // "Preceding reads and writes cannot be moved past subsequent writes." 325 // "Preceding reads and writes cannot be moved past subsequent writes."
242 fence(Ordering::SeqCst); 326 fence(Ordering::SeqCst);
243 327
244 reset_status(dma, channel_number); 328 let mut this = Self { channel };
329 this.clear_irqs();
330
331 #[cfg(dmamux)]
332 super::dmamux::configure_dmamux(&mut *this.channel, _request);
245 333
246 let ch = dma.st(channel_number as _);
247 ch.par().write_value(peri_addr as u32); 334 ch.par().write_value(peri_addr as u32);
248 ch.m0ar().write_value(mem_addr as u32); 335 ch.m0ar().write_value(mem_addr as u32);
249 ch.ndtr().write_value(regs::Ndtr(mem_len as _)); 336 ch.ndtr().write_value(regs::Ndtr(mem_len as _));
@@ -258,15 +345,14 @@ mod low_level_api {
258 } 345 }
259 }); 346 });
260 ch.cr().write(|w| { 347 ch.cr().write(|w| {
261 w.set_dir(dir); 348 w.set_dir(dir.into());
262 w.set_msize(data_size); 349 w.set_msize(data_size.into());
263 w.set_psize(data_size); 350 w.set_psize(data_size.into());
264 w.set_pl(vals::Pl::VERYHIGH); 351 w.set_pl(vals::Pl::VERYHIGH);
265 if incr_mem { 352 w.set_minc(match incr_mem {
266 w.set_minc(vals::Inc::INCREMENTED); 353 true => vals::Inc::INCREMENTED,
267 } else { 354 false => vals::Inc::FIXED,
268 w.set_minc(vals::Inc::FIXED); 355 });
269 }
270 w.set_pinc(vals::Inc::FIXED); 356 w.set_pinc(vals::Inc::FIXED);
271 w.set_teie(true); 357 w.set_teie(true);
272 w.set_tcie(true); 358 w.set_tcie(true);
@@ -274,7 +360,7 @@ mod low_level_api {
274 w.set_trbuff(true); 360 w.set_trbuff(true);
275 361
276 #[cfg(dma_v2)] 362 #[cfg(dma_v2)]
277 w.set_chsel(request); 363 w.set_chsel(_request);
278 364
279 w.set_pburst(options.pburst.into()); 365 w.set_pburst(options.pburst.into());
280 w.set_mburst(options.mburst.into()); 366 w.set_mburst(options.mburst.into());
@@ -282,66 +368,148 @@ mod low_level_api {
282 368
283 w.set_en(true); 369 w.set_en(true);
284 }); 370 });
371
372 this
285 } 373 }
286 374
287 pub unsafe fn start_dbm_transfer( 375 fn clear_irqs(&mut self) {
288 dma: pac::dma::Dma, 376 let isrn = self.channel.num() / 4;
289 channel_number: u8, 377 let isrbit = self.channel.num() % 4;
290 request: Request, 378
291 dir: vals::Dir, 379 unsafe {
292 peri_addr: *const u32, 380 self.channel.regs().ifcr(isrn).write(|w| {
293 mem0_addr: *mut u32, 381 w.set_tcif(isrbit, true);
294 mem1_addr: *mut u32, 382 w.set_teif(isrbit, true);
295 mem_len: usize, 383 })
296 incr_mem: bool, 384 }
297 data_size: vals::Size, 385 }
386
387 pub fn request_stop(&mut self) {
388 let ch = self.channel.regs().st(self.channel.num());
389
390 // Disable the channel. Keep the IEs enabled so the irqs still fire.
391 unsafe {
392 ch.cr().write(|w| {
393 w.set_teie(true);
394 w.set_tcie(true);
395 })
396 }
397 }
398
399 pub fn is_running(&mut self) -> bool {
400 let ch = self.channel.regs().st(self.channel.num());
401 unsafe { ch.cr().read() }.en()
402 }
403
404 /// Gets the total remaining transfers for the channel
405 /// Note: this will be zero for transfers that completed without cancellation.
406 pub fn get_remaining_transfers(&self) -> u16 {
407 let ch = self.channel.regs().st(self.channel.num());
408 unsafe { ch.ndtr().read() }.ndt()
409 }
410
411 pub fn blocking_wait(mut self) {
412 while self.is_running() {}
413
414 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
415 fence(Ordering::SeqCst);
416
417 core::mem::forget(self);
418 }
419}
420
421impl<'a, C: Channel> Drop for Transfer<'a, C> {
422 fn drop(&mut self) {
423 self.request_stop();
424 while self.is_running() {}
425
426 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
427 fence(Ordering::SeqCst);
428 }
429}
430
431impl<'a, C: Channel> Unpin for Transfer<'a, C> {}
432impl<'a, C: Channel> Future for Transfer<'a, C> {
433 type Output = ();
434 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
435 STATE.ch_wakers[self.channel.index()].register(cx.waker());
436
437 if self.is_running() {
438 Poll::Pending
439 } else {
440 Poll::Ready(())
441 }
442 }
443}
444
445// ==================================
446
447#[must_use = "futures do nothing unless you `.await` or poll them"]
448pub struct DoubleBuffered<'a, C: Channel, W: Word> {
449 channel: PeripheralRef<'a, C>,
450 _phantom: PhantomData<W>,
451}
452
453impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
454 pub unsafe fn new_read(
455 channel: impl Peripheral<P = C> + 'a,
456 _request: Request,
457 peri_addr: *mut W,
458 buf0: *mut W,
459 buf1: *mut W,
460 len: usize,
298 options: TransferOptions, 461 options: TransferOptions,
299 #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, 462 ) -> Self {
300 #[cfg(dmamux)] dmamux_ch_num: u8, 463 into_ref!(channel);
301 ) { 464 assert!(len > 0 && len <= 0xFFFF);
302 #[cfg(dmamux)] 465
303 super::super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); 466 let dir = Dir::PeripheralToMemory;
467 let data_size = W::bits();
304 468
305 trace!( 469 let channel_number = channel.num();
306 "Starting DBM transfer with 0: 0x{:x}, 1: 0x{:x}, len: 0x{:x}", 470 let dma = channel.regs();
307 mem0_addr as u32,
308 mem1_addr as u32,
309 mem_len
310 );
311 471
312 // "Preceding reads and writes cannot be moved past subsequent writes." 472 // "Preceding reads and writes cannot be moved past subsequent writes."
313 fence(Ordering::SeqCst); 473 fence(Ordering::SeqCst);
314 474
315 reset_status(dma, channel_number); 475 let mut this = Self {
476 channel,
477 _phantom: PhantomData,
478 };
479 this.clear_irqs();
480
481 #[cfg(dmamux)]
482 super::dmamux::configure_dmamux(&mut *this.channel, _request);
316 483
317 let ch = dma.st(channel_number as _); 484 let ch = dma.st(channel_number);
318 ch.par().write_value(peri_addr as u32); 485 ch.par().write_value(peri_addr as u32);
319 ch.m0ar().write_value(mem0_addr as u32); 486 ch.m0ar().write_value(buf0 as u32);
320 // configures the second buffer for DBM 487 ch.m1ar().write_value(buf1 as u32);
321 ch.m1ar().write_value(mem1_addr as u32); 488 ch.ndtr().write_value(regs::Ndtr(len as _));
322 ch.ndtr().write_value(regs::Ndtr(mem_len as _)); 489 ch.fcr().write(|w| {
323 ch.cr().write(|w| { 490 if let Some(fth) = options.fifo_threshold {
324 w.set_dir(dir); 491 // FIFO mode
325 w.set_msize(data_size); 492 w.set_dmdis(vals::Dmdis::DISABLED);
326 w.set_psize(data_size); 493 w.set_fth(fth.into());
327 w.set_pl(vals::Pl::VERYHIGH);
328 if incr_mem {
329 w.set_minc(vals::Inc::INCREMENTED);
330 } else { 494 } else {
331 w.set_minc(vals::Inc::FIXED); 495 // Direct mode
496 w.set_dmdis(vals::Dmdis::ENABLED);
332 } 497 }
498 });
499 ch.cr().write(|w| {
500 w.set_dir(dir.into());
501 w.set_msize(data_size.into());
502 w.set_psize(data_size.into());
503 w.set_pl(vals::Pl::VERYHIGH);
504 w.set_minc(vals::Inc::INCREMENTED);
333 w.set_pinc(vals::Inc::FIXED); 505 w.set_pinc(vals::Inc::FIXED);
334 w.set_teie(true); 506 w.set_teie(true);
335 w.set_tcie(true); 507 w.set_tcie(true);
336
337 #[cfg(dma_v1)] 508 #[cfg(dma_v1)]
338 w.set_trbuff(true); 509 w.set_trbuff(true);
339 510
340 #[cfg(dma_v2)] 511 #[cfg(dma_v2)]
341 w.set_chsel(request); 512 w.set_chsel(_request);
342
343 // enable double buffered mode
344 w.set_dbm(vals::Dbm::ENABLED);
345 513
346 w.set_pburst(options.pburst.into()); 514 w.set_pburst(options.pburst.into());
347 w.set_mburst(options.mburst.into()); 515 w.set_mburst(options.mburst.into());
@@ -349,92 +517,83 @@ mod low_level_api {
349 517
350 w.set_en(true); 518 w.set_en(true);
351 }); 519 });
520
521 this
352 } 522 }
353 523
354 pub unsafe fn set_dbm_buffer0(dma: pac::dma::Dma, channel_number: u8, mem_addr: *mut u32) { 524 fn clear_irqs(&mut self) {
355 // get a handle on the channel itself 525 let channel_number = self.channel.num();
356 let ch = dma.st(channel_number as _); 526 let dma = self.channel.regs();
357 // change M0AR to the new address 527 let isrn = channel_number / 4;
358 ch.m0ar().write_value(mem_addr as _); 528 let isrbit = channel_number % 4;
529
530 unsafe {
531 dma.ifcr(isrn).write(|w| {
532 w.set_tcif(isrbit, true);
533 w.set_teif(isrbit, true);
534 })
535 }
359 } 536 }
360 537
361 pub unsafe fn set_dbm_buffer1(dma: pac::dma::Dma, channel_number: u8, mem_addr: *mut u32) { 538 pub unsafe fn set_buffer0(&mut self, buffer: *mut W) {
362 // get a handle on the channel itself 539 let ch = self.channel.regs().st(self.channel.num());
363 let ch = dma.st(channel_number as _); 540 ch.m0ar().write_value(buffer as _);
364 // change M1AR to the new address
365 ch.m1ar().write_value(mem_addr as _);
366 } 541 }
367 542
368 pub unsafe fn is_buffer0_accessible(dma: pac::dma::Dma, channel_number: u8) -> bool { 543 pub unsafe fn set_buffer1(&mut self, buffer: *mut W) {
369 // get a handle on the channel itself 544 let ch = self.channel.regs().st(self.channel.num());
370 let ch = dma.st(channel_number as _); 545 ch.m1ar().write_value(buffer as _);
371 // check the current target register value
372 ch.cr().read().ct() == vals::Ct::MEMORY1
373 } 546 }
374 547
375 /// Stops the DMA channel. 548 pub fn is_buffer0_accessible(&mut self) -> bool {
376 pub unsafe fn request_stop(dma: pac::dma::Dma, channel_number: u8) { 549 let ch = self.channel.regs().st(self.channel.num());
377 // get a handle on the channel itself 550 unsafe { ch.cr().read() }.ct() == vals::Ct::MEMORY1
378 let ch = dma.st(channel_number as _); 551 }
379 552
380 // Disable the channel. Keep the IEs enabled so the irqs still fire. 553 pub fn set_waker(&mut self, waker: &Waker) {
381 ch.cr().write(|w| { 554 STATE.ch_wakers[self.channel.index()].register(waker);
382 w.set_teie(true); 555 }
383 w.set_tcie(true);
384 });
385 556
386 // "Subsequent reads and writes cannot be moved ahead of preceding reads." 557 pub fn request_stop(&mut self) {
387 fence(Ordering::SeqCst); 558 let ch = self.channel.regs().st(self.channel.num());
559
560 // Disable the channel. Keep the IEs enabled so the irqs still fire.
561 unsafe {
562 ch.cr().write(|w| {
563 w.set_teie(true);
564 w.set_tcie(true);
565 })
566 }
388 } 567 }
389 568
390 /// Gets the running status of the channel 569 pub fn is_running(&mut self) -> bool {
391 pub unsafe fn is_running(dma: pac::dma::Dma, ch: u8) -> bool { 570 let ch = self.channel.regs().st(self.channel.num());
392 // get a handle on the channel itself 571 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 } 572 }
397 573
398 /// Gets the total remaining transfers for the channel 574 /// Gets the total remaining transfers for the channel
399 /// Note: this will be zero for transfers that completed without cancellation. 575 /// 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 { 576 pub fn get_remaining_transfers(&self) -> u16 {
401 // get a handle on the channel itself 577 let ch = self.channel.regs().st(self.channel.num());
402 let ch = dma.st(ch as _); 578 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 } 579 }
406 580
407 /// Sets the waker for the specified DMA channel 581 pub fn blocking_wait(mut self) {
408 pub unsafe fn set_waker(state_number: usize, waker: &Waker) { 582 while self.is_running() {}
409 STATE.channels[state_number].waker.register(waker);
410 }
411 583
412 pub unsafe fn reset_status(dma: pac::dma::Dma, channel_number: u8) { 584 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
413 let isrn = channel_number as usize / 4; 585 fence(Ordering::SeqCst);
414 let isrbit = channel_number as usize % 4;
415 586
416 dma.ifcr(isrn).write(|w| { 587 core::mem::forget(self);
417 w.set_tcif(isrbit, true);
418 w.set_teif(isrbit, true);
419 });
420 } 588 }
589}
421 590
422 /// Safety: Must be called with a matching set of parameters for a valid dma channel 591impl<'a, C: Channel, W: Word> Drop for DoubleBuffered<'a, C, W> {
423 pub unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: u8, state_index: u8) { 592 fn drop(&mut self) {
424 let channel_num = channel_num as usize; 593 self.request_stop();
425 let state_index = state_index as usize; 594 while self.is_running() {}
426
427 let cr = dma.st(channel_num).cr();
428 let isr = dma.isr(channel_num / 4).read();
429
430 if isr.teif(channel_num % 4) {
431 panic!("DMA: error on DMA@{:08x} channel {}", dma.0 as u32, channel_num);
432 }
433 595
434 if isr.tcif(channel_num % 4) && cr.read().tcie() { 596 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
435 /* acknowledge transfer complete interrupt */ 597 fence(Ordering::SeqCst);
436 dma.ifcr(channel_num / 4).write(|w| w.set_tcif(channel_num % 4, true));
437 STATE.channels[state_index].waker.wake();
438 }
439 } 598 }
440} 599}
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
3use crate::{pac, peripherals}; 3use crate::{pac, peripherals};
4 4
5pub(crate) unsafe fn configure_dmamux(dmamux_regs: pac::dmamux::Dmamux, dmamux_ch_num: u8, request: u8) { 5pub(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
17pub(crate) mod sealed { 17pub(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)]
27pub struct DMAMUX2; 27pub struct DMAMUX2;
28 28
29pub trait MuxChannel: sealed::MuxChannel + super::Channel { 29pub trait MuxChannel: dmamux_sealed::MuxChannel {
30 type Mux; 30 type Mux;
31} 31}
32 32
33foreach_dma_channel! { 33foreach_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
3use core::future::Future;
4use core::pin::Pin;
1use core::sync::atomic::{fence, Ordering}; 5use core::sync::atomic::{fence, Ordering};
2use core::task::Waker; 6use core::task::{Context, Poll};
3 7
8use embassy_cortex_m::interrupt::Priority;
9use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
4use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
5 11
6use super::{Request, TransferOptions, Word, WordSize}; 12use super::{Dir, Word, WordSize};
7use crate::_generated::GPDMA_CHANNEL_COUNT; 13use crate::_generated::GPDMA_CHANNEL_COUNT;
8use crate::interrupt::{Interrupt, InterruptExt}; 14use crate::interrupt::{Interrupt, InterruptExt};
9use crate::pac::gpdma::{vals, Gpdma}; 15use crate::pac;
10use crate::{interrupt, pac}; 16use crate::pac::gpdma::vals;
17
18#[derive(Debug, Copy, Clone, PartialEq, Eq)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20#[non_exhaustive]
21pub struct TransferOptions {}
22
23impl Default for TransferOptions {
24 fn default() -> Self {
25 Self {}
26 }
27}
11 28
12impl From<WordSize> for vals::ChTr1Dw { 29impl 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
22struct ChannelState {
23 waker: AtomicWaker,
24}
25
26impl ChannelState {
27 const fn new() -> Self {
28 Self {
29 waker: AtomicWaker::new(),
30 }
31 }
32}
33
34struct State { 39struct State {
35 channels: [ChannelState; GPDMA_CHANNEL_COUNT], 40 ch_wakers: [AtomicWaker; GPDMA_CHANNEL_COUNT],
36} 41}
37 42
38impl State { 43impl 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 {
47static STATE: State = State::new(); 52static STATE: State = State::new();
48 53
49/// safety: must be called only once 54/// safety: must be called only once
50pub(crate) unsafe fn init() { 55pub(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
59foreach_dma_channel! { 66foreach_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"); 88pub(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 { 114pub 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 )} 117pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {}
147 } 118#[cfg(not(dmamux))]
119pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {}
148 120
149 fn on_irq() { 121pub(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
159mod low_level_api { 132#[must_use = "futures do nothing unless you `.await` or poll them"]
160 use super::*; 133pub struct Transfer<'a, C: Channel> {
134 channel: PeripheralRef<'a, C>,
135}
161 136
162 #[derive(Debug, Copy, Clone, PartialEq, Eq)] 137impl<'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() { 333impl<'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() { 343impl<'a, C: Channel> Unpin for Transfer<'a, C> {}
298 // disable all xxIEs to prevent the irq from firing again. 344impl<'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)]
2pub(crate) mod bdma;
3#[cfg(dma)] 1#[cfg(dma)]
4pub(crate) mod dma; 2pub(crate) mod dma;
3#[cfg(dma)]
4pub 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))]
9pub mod bdma;
10
11#[cfg(all(bdma, not(dma)))]
12pub(crate) mod bdma;
13#[cfg(all(bdma, not(dma)))]
14pub use bdma::*;
15
16#[cfg(gpdma)]
17pub(crate) mod gpdma;
18#[cfg(gpdma)]
19pub use gpdma::*;
20
5#[cfg(dmamux)] 21#[cfg(dmamux)]
6mod dmamux; 22mod dmamux;
7#[cfg(gpdma)]
8mod gpdma;
9 23
10use core::future::Future;
11use core::mem; 24use core::mem;
12use core::pin::Pin;
13use core::task::{Context, Poll, Waker};
14 25
15#[cfg(any(dma, bdma))]
16use embassy_cortex_m::interrupt::Priority; 26use embassy_cortex_m::interrupt::Priority;
17use embassy_hal_common::{impl_peripheral, into_ref}; 27use embassy_hal_common::impl_peripheral;
18 28
19#[cfg(dmamux)] 29#[cfg(dmamux)]
20pub use self::dmamux::*; 30pub use self::dmamux::*;
21use crate::Peripheral;
22
23#[cfg(feature = "unstable-pac")]
24pub mod low_level {
25 pub use super::transfers::*;
26}
27
28pub(crate) use transfers::*;
29
30#[cfg(any(bdma_v2, dma_v2, dmamux, gpdma))]
31pub type Request = u8;
32#[cfg(not(any(bdma_v2, dma_v2, dmamux, gpdma)))]
33pub type Request = ();
34
35pub(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 34enum 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
142pub trait Word: sealed::Word { 57mod word_sealed {
58 pub trait Word {}
59}
60
61pub trait Word: word_sealed::Word {
143 fn bits() -> WordSize; 62 fn bits() -> WordSize;
144} 63}
145 64
146impl sealed::Word for u8 {} 65impl word_sealed::Word for u8 {}
147impl Word for u8 { 66impl Word for u8 {
148 fn bits() -> WordSize { 67 fn bits() -> WordSize {
149 WordSize::OneByte 68 WordSize::OneByte
150 } 69 }
151} 70}
152 71
153impl sealed::Word for u16 {} 72impl word_sealed::Word for u16 {}
154impl Word for u16 { 73impl Word for u16 {
155 fn bits() -> WordSize { 74 fn bits() -> WordSize {
156 WordSize::TwoBytes 75 WordSize::TwoBytes
157 } 76 }
158} 77}
159 78
160impl sealed::Word for u32 {} 79impl word_sealed::Word for u32 {}
161impl Word for u32 { 80impl 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))]
169pub 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))]
182pub 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))]
191pub 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))]
204pub 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
215impl 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
226mod 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
309pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {}
310
311pub struct NoDma; 86pub struct NoDma;
312 87
313impl_peripheral!(NoDma); 88impl_peripheral!(NoDma);
314 89
315// safety: must be called only once at startup
316pub(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)]
329pub(crate) fn slice_ptr_parts<T>(slice: *const [T]) -> (usize, usize) { 92pub(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) {
334pub(crate) fn slice_ptr_parts_mut<T>(slice: *mut [T]) -> (usize, usize) { 97pub(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
102pub(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;
8use embassy_hal_common::{into_ref, PeripheralRef}; 8use embassy_hal_common::{into_ref, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10 10
11use crate::dma::NoDma; 11use crate::dma::{NoDma, Transfer};
12use crate::gpio::sealed::AFType; 12use crate::gpio::sealed::AFType;
13use crate::gpio::Pull; 13use crate::gpio::Pull;
14use crate::i2c::{Error, Instance, SclPin, SdaPin}; 14use 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
79pub use _generated::{peripherals, Peripherals}; 79pub use _generated::{peripherals, Peripherals};
80pub use embassy_cortex_m::executor; 80pub use embassy_cortex_m::executor;
81#[cfg(any(dma, bdma))]
82use embassy_cortex_m::interrupt::Priority; 81use embassy_cortex_m::interrupt::Priority;
83pub use embassy_cortex_m::interrupt::_export::interrupt; 82pub use embassy_cortex_m::interrupt::_export::interrupt;
84pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 83pub 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
101impl Default for Config { 102impl 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;
5use embassy_hal_common::{into_ref, PeripheralRef}; 5use embassy_hal_common::{into_ref, PeripheralRef};
6use enums::*; 6use enums::*;
7 7
8use crate::dma::TransferOptions; 8use crate::dma::Transfer;
9use crate::gpio::sealed::AFType; 9use crate::gpio::sealed::AFType;
10use crate::gpio::AnyPin; 10use crate::gpio::AnyPin;
11use crate::pac::quadspi::Quadspi as Regs; 11use 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)]
189type Transfer<'a, C> = crate::dma::Transfer<'a, C>;
190#[cfg(sdmmc_v2)]
191type Transfer<'a, C> = core::marker::PhantomData<&'a mut C>;
192
193#[cfg(all(sdmmc_v1, dma))]
194const 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)))]
201const 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};
6use core::task::Poll; 6use core::task::Poll;
7 7
8use embassy_cortex_m::interrupt::InterruptExt; 8use embassy_cortex_m::interrupt::InterruptExt;
9use embassy_futures::select::{select, Either};
10use embassy_hal_common::drop::OnDrop; 9use embassy_hal_common::drop::OnDrop;
11use embassy_hal_common::{into_ref, PeripheralRef}; 10use embassy_hal_common::{into_ref, PeripheralRef};
11use futures::future::{select, Either};
12 12
13use crate::dma::NoDma; 13use crate::dma::{NoDma, Transfer};
14use crate::gpio::sealed::AFType; 14use crate::gpio::sealed::AFType;
15#[cfg(any(lpuart_v1, lpuart_v2))] 15#[cfg(any(lpuart_v1, lpuart_v2))]
16use crate::pac::lpuart::{regs, vals, Lpuart as Regs}; 16use 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
97pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { 97pub 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 }