aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-07-17 08:32:31 +0200
committerGitHub <[email protected]>2021-07-17 08:32:31 +0200
commit59953b5b5e4935747a7f5c9699702d29ca248a2e (patch)
treeb832ade1a4f07ecddc01f04290bb400115712510
parent69fb1b5418a4fb355d48b3b4357d0cd7562b5c4d (diff)
parentd7176da37c372d8a57283af540f4fecb532540aa (diff)
Merge pull request #295 from embassy-rs/all_dma
stm32: impl dma for all chips
-rw-r--r--.vscode/settings.json7
-rw-r--r--embassy-stm32/src/bdma/mod.rs413
-rw-r--r--embassy-stm32/src/dma/bdma.rs219
-rw-r--r--embassy-stm32/src/dma/dma.rs222
-rw-r--r--embassy-stm32/src/dma/dmamux.rs51
-rw-r--r--embassy-stm32/src/dma/mod.rs70
-rw-r--r--embassy-stm32/src/dma/v1.rs2
-rw-r--r--embassy-stm32/src/dma/v2.rs331
-rw-r--r--embassy-stm32/src/dma_traits.rs32
-rw-r--r--embassy-stm32/src/dmamux/mod.rs137
-rw-r--r--embassy-stm32/src/lib.rs14
-rw-r--r--embassy-stm32/src/usart/mod.rs75
-rw-r--r--embassy-stm32/src/usart/v1.rs45
-rw-r--r--embassy-stm32/src/usart/v2.rs15
-rw-r--r--examples/stm32f4/src/bin/spi.rs2
-rw-r--r--examples/stm32f4/src/bin/usart.rs3
-rw-r--r--examples/stm32f4/src/bin/usart_dma.rs11
-rw-r--r--examples/stm32h7/src/bin/usart.rs9
-rw-r--r--examples/stm32h7/src/bin/usart_dma.rs100
-rw-r--r--examples/stm32l4/src/bin/spi.rs2
-rw-r--r--examples/stm32l4/src/bin/usart.rs2
-rw-r--r--examples/stm32l4/src/bin/usart_dma.rs4
m---------stm32-data0
-rw-r--r--stm32-metapac-gen/src/lib.rs98
24 files changed, 818 insertions, 1046 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json
index ceb87ad53..a5a656637 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,12 +1,17 @@
1{ 1{
2 "editor.formatOnSave": true, 2 "editor.formatOnSave": true,
3 "rust-analyzer.assist.importEnforceGranularity": true,
4 "rust-analyzer.assist.importGranularity": "module",
3 "rust-analyzer.checkOnSave.allFeatures": false, 5 "rust-analyzer.checkOnSave.allFeatures": false,
4 "rust-analyzer.checkOnSave.allTargets": false, 6 "rust-analyzer.checkOnSave.allTargets": false,
7 "rust-analyzer.cargo.noDefaultFeatures": true,
8 "rust-analyzer.checkOnSave.noDefaultFeatures": true,
5 "rust-analyzer.cargo.target": "thumbv7em-none-eabi", 9 "rust-analyzer.cargo.target": "thumbv7em-none-eabi",
6 "rust-analyzer.cargo.features": [ 10 "rust-analyzer.cargo.features": [
7 // These are needed to prevent embassy-net from failing to build 11 // These are needed to prevent embassy-net from failing to build
8 "embassy-net/medium-ethernet", 12 "embassy-net/medium-ethernet",
9 "embassy-net/tcp" 13 "embassy-net/tcp",
14 "embassy-net/pool-16",
10 ], 15 ],
11 "rust-analyzer.procMacro.enable": true, 16 "rust-analyzer.procMacro.enable": true,
12 "rust-analyzer.cargo.runBuildScripts": true, 17 "rust-analyzer.cargo.runBuildScripts": true,
diff --git a/embassy-stm32/src/bdma/mod.rs b/embassy-stm32/src/bdma/mod.rs
deleted file mode 100644
index f57358f68..000000000
--- a/embassy-stm32/src/bdma/mod.rs
+++ /dev/null
@@ -1,413 +0,0 @@
1#![macro_use]
2
3use core::future::Future;
4use core::task::Poll;
5
6use atomic_polyfill::{AtomicU8, Ordering};
7use embassy::interrupt::{Interrupt, InterruptExt};
8use embassy::util::{AtomicWaker, OnDrop};
9use futures::future::poll_fn;
10
11use crate::dma_traits::{ReadDma, WriteDma};
12use crate::interrupt;
13use crate::pac;
14use crate::pac::bdma::vals;
15
16const CH_COUNT: usize = pac::peripheral_count!(bdma) * 8;
17const CH_STATUS_NONE: u8 = 0;
18const CH_STATUS_COMPLETED: u8 = 1;
19const CH_STATUS_ERROR: u8 = 2;
20
21struct State {
22 ch_wakers: [AtomicWaker; CH_COUNT],
23 ch_status: [AtomicU8; CH_COUNT],
24}
25
26impl State {
27 const fn new() -> Self {
28 const AW: AtomicWaker = AtomicWaker::new();
29 const AU: AtomicU8 = AtomicU8::new(CH_STATUS_NONE);
30 Self {
31 ch_wakers: [AW; CH_COUNT],
32 ch_status: [AU; CH_COUNT],
33 }
34 }
35}
36
37static STATE: State = State::new();
38
39#[allow(unused)]
40pub(crate) async unsafe fn transfer_p2m(
41 regs: pac::bdma::Ch,
42 state_number: u8,
43 src: *const u8,
44 dst: &mut [u8],
45 #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux,
46 #[cfg(dmamux)] dmamux_ch_num: u8,
47 #[cfg(dmamux)] request: u8,
48) {
49 // ndtr is max 16 bits.
50 assert!(dst.len() <= 0xFFFF);
51
52 // Reset status
53 // Generate a DMB here to flush the store buffer (M7) before enabling the DMA
54 STATE.ch_status[state_number as usize].store(CH_STATUS_NONE, Ordering::Release);
55
56 let on_drop = OnDrop::new(|| unsafe {
57 regs.cr().modify(|w| {
58 w.set_tcie(false);
59 w.set_teie(false);
60 w.set_en(false);
61 });
62 while regs.cr().read().en() {}
63 });
64
65 #[cfg(dmamux)]
66 crate::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request);
67
68 regs.par().write_value(src as u32);
69 regs.mar().write_value(dst.as_mut_ptr() as u32);
70 regs.ndtr().write(|w| w.set_ndt(dst.len() as u16));
71 regs.cr().write(|w| {
72 w.set_psize(vals::Size::BITS8);
73 w.set_msize(vals::Size::BITS8);
74 w.set_minc(vals::Inc::ENABLED);
75 w.set_teie(true);
76 w.set_tcie(true);
77 w.set_en(true);
78 });
79
80 let res = poll_fn(|cx| {
81 STATE.ch_wakers[state_number as usize].register(cx.waker());
82 match STATE.ch_status[state_number as usize].load(Ordering::Acquire) {
83 CH_STATUS_NONE => Poll::Pending,
84 x => Poll::Ready(x),
85 }
86 })
87 .await;
88
89 // TODO handle error
90 assert!(res == CH_STATUS_COMPLETED);
91}
92
93#[allow(unused)]
94pub(crate) async unsafe fn transfer_m2p(
95 regs: pac::bdma::Ch,
96 state_number: u8,
97 src: &[u8],
98 dst: *mut u8,
99 #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux,
100 #[cfg(dmamux)] dmamux_ch_num: u8,
101 #[cfg(dmamux)] request: u8,
102) {
103 // ndtr is max 16 bits.
104 assert!(src.len() <= 0xFFFF);
105
106 // Reset status
107 // Generate a DMB here to flush the store buffer (M7) before enabling the DMA
108 STATE.ch_status[state_number as usize].store(CH_STATUS_NONE, Ordering::Release);
109
110 let on_drop = OnDrop::new(|| unsafe {
111 regs.cr().modify(|w| {
112 w.set_tcie(false);
113 w.set_teie(false);
114 w.set_en(false);
115 });
116 while regs.cr().read().en() {}
117 });
118
119 #[cfg(dmamux)]
120 crate::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request);
121
122 regs.par().write_value(dst as u32);
123 regs.mar().write_value(src.as_ptr() as u32);
124 regs.ndtr().write(|w| w.set_ndt(src.len() as u16));
125 regs.cr().write(|w| {
126 w.set_psize(vals::Size::BITS8);
127 w.set_msize(vals::Size::BITS8);
128 w.set_minc(vals::Inc::ENABLED);
129 w.set_dir(vals::Dir::FROMMEMORY);
130 w.set_teie(true);
131 w.set_tcie(true);
132 w.set_en(true);
133 });
134
135 let res = poll_fn(|cx| {
136 STATE.ch_wakers[state_number as usize].register(cx.waker());
137 match STATE.ch_status[state_number as usize].load(Ordering::Acquire) {
138 CH_STATUS_NONE => Poll::Pending,
139 x => Poll::Ready(x),
140 }
141 })
142 .await;
143
144 // TODO handle error
145 assert!(res == CH_STATUS_COMPLETED);
146}
147
148unsafe fn on_irq() {
149 pac::peripherals! {
150 (bdma, $dma:ident) => {
151 let isr = pac::$dma.isr().read();
152 pac::$dma.ifcr().write_value(isr);
153 let dman = <crate::peripherals::$dma as sealed::Dma>::NUM as usize;
154
155 for chn in 0..crate::pac::dma_channels_count!($dma) {
156 let n = dman * 8 + chn;
157 if isr.teif(chn) {
158 STATE.ch_status[n].store(CH_STATUS_ERROR, Ordering::Relaxed);
159 STATE.ch_wakers[n].wake();
160 } else if isr.tcif(chn) {
161 STATE.ch_status[n].store(CH_STATUS_COMPLETED, Ordering::Relaxed);
162 STATE.ch_wakers[n].wake();
163 }
164 }
165 };
166 }
167}
168
169use crate::rcc::sealed::RccPeripheral;
170
171/// safety: must be called only once
172pub(crate) unsafe fn init() {
173 pac::interrupts! {
174 (DMA, $irq:ident) => {
175 crate::interrupt::$irq::steal().enable();
176 };
177 }
178 pac::peripherals! {
179 (bdma, $peri:ident) => {
180 <crate::peripherals::$peri as RccPeripheral>::enable();
181 };
182 }
183}
184
185pub(crate) mod sealed {
186 use super::*;
187
188 pub trait Dma {
189 const NUM: u8;
190 }
191
192 pub trait Channel {
193 const CH_NUM: u8;
194 const STATE_NUM: u8;
195 const DMA_REGS: pac::bdma::Dma;
196
197 fn regs(&self) -> pac::bdma::Ch {
198 Self::DMA_REGS.ch(Self::CH_NUM as usize)
199 }
200 }
201}
202
203pub trait Dma: sealed::Dma + Sized {}
204pub trait Channel: sealed::Channel + Sized {}
205
206macro_rules! impl_dma {
207 ($peri:ident) => {
208 impl Dma for crate::peripherals::$peri {}
209 impl sealed::Dma for crate::peripherals::$peri {
210 const NUM: u8 = dma_num!($peri);
211 }
212 };
213}
214
215macro_rules! impl_dma_channel {
216 ($channel_peri:ident, $dma_peri:ident, $ch_num:expr) => {
217 impl Channel for crate::peripherals::$channel_peri {}
218 impl sealed::Channel for crate::peripherals::$channel_peri {
219 const CH_NUM: u8 = $ch_num;
220 const STATE_NUM: u8 = (dma_num!($dma_peri) * 8) + $ch_num;
221 const DMA_REGS: pac::bdma::Dma = crate::pac::$dma_peri;
222
223 //#[inline]
224 //fn dma_regs() -> pac::bdma::Dma {
225 //crate::pac::$dma_peri
226 //}
227
228 //fn state_num(&self) -> usize {
229 //(dma_num!($dma_peri) * 8) + $ch_num
230 //}
231 }
232
233 #[cfg(not(dmamux))]
234 impl<T> WriteDma<T> for crate::peripherals::$channel_peri
235 where
236 T: 'static,
237 {
238 type WriteDmaFuture<'a> = impl Future<Output = ()>;
239
240 fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a>
241 where
242 T: 'a,
243 {
244 use sealed::Channel as _Channel;
245
246 let state_num = Self::STATE_NUM;
247 let regs = self.regs();
248
249 unsafe { transfer_m2p(regs, state_num, buf, dst) }
250 }
251 }
252
253 #[cfg(dmamux)]
254 impl<T> WriteDma<T> for crate::peripherals::$channel_peri
255 where
256 Self: crate::dmamux::sealed::PeripheralChannel<T, crate::dmamux::M2P>,
257 T: 'static,
258 {
259 type WriteDmaFuture<'a> = impl Future<Output = ()>;
260
261 fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a>
262 where
263 T: 'a,
264 {
265 use sealed::Channel as _Channel;
266
267 let state_num = Self::STATE_NUM;
268 let regs = self.regs();
269
270 use crate::dmamux::sealed::Channel as MuxChannel;
271 use crate::dmamux::sealed::PeripheralChannel;
272 let dmamux_regs = <crate::peripherals::$channel_peri as MuxChannel>::DMAMUX_REGS;
273 let dmamux_ch_num =
274 <crate::peripherals::$channel_peri as MuxChannel>::DMAMUX_CH_NUM;
275 let request = <crate::peripherals::$channel_peri as PeripheralChannel<
276 T,
277 crate::dmamux::M2P,
278 >>::REQUEST;
279 unsafe {
280 transfer_m2p(
281 regs,
282 state_num,
283 buf,
284 dst,
285 dmamux_regs,
286 dmamux_ch_num,
287 request,
288 )
289 }
290 }
291 }
292
293 #[cfg(not(dmamux))]
294 impl<T> ReadDma<T> for crate::peripherals::$channel_peri
295 where
296 T: 'static,
297 {
298 type ReadDmaFuture<'a> = impl Future<Output = ()>;
299
300 fn transfer<'a>(
301 &'a mut self,
302 src: *const u8,
303 buf: &'a mut [u8],
304 ) -> Self::ReadDmaFuture<'a>
305 where
306 T: 'a,
307 {
308 use sealed::Channel as _Channel;
309
310 let state_num = Self::STATE_NUM;
311 let regs = self.regs();
312 unsafe { transfer_p2m(regs, state_num, src, buf) }
313 }
314 }
315
316 #[cfg(dmamux)]
317 impl<T> ReadDma<T> for crate::peripherals::$channel_peri
318 where
319 Self: crate::dmamux::sealed::PeripheralChannel<T, crate::dmamux::P2M>,
320 T: 'static,
321 {
322 type ReadDmaFuture<'a> = impl Future<Output = ()>;
323
324 fn transfer<'a>(
325 &'a mut self,
326 src: *const u8,
327 buf: &'a mut [u8],
328 ) -> Self::ReadDmaFuture<'a>
329 where
330 T: 'a,
331 {
332 use sealed::Channel as _Channel;
333
334 let state_num = Self::STATE_NUM;
335 let regs = self.regs();
336
337 use crate::dmamux::sealed::Channel as MuxChannel;
338 use crate::dmamux::sealed::PeripheralChannel;
339 let dmamux_regs = <crate::peripherals::$channel_peri as MuxChannel>::DMAMUX_REGS;
340 let dmamux_ch_num =
341 <crate::peripherals::$channel_peri as MuxChannel>::DMAMUX_CH_NUM;
342 let request = <crate::peripherals::$channel_peri as PeripheralChannel<
343 T,
344 crate::dmamux::P2M,
345 >>::REQUEST;
346 unsafe {
347 transfer_p2m(
348 regs,
349 state_num,
350 src,
351 buf,
352 dmamux_regs,
353 dmamux_ch_num,
354 request,
355 )
356 }
357 }
358 }
359 };
360}
361
362macro_rules! dma_num {
363 (DMA1) => {
364 0
365 };
366 (DMA2) => {
367 1
368 };
369 (BDMA) => {
370 0
371 };
372}
373pac::peripherals! {
374 (bdma, $peri:ident) => {
375 impl_dma!($peri);
376 };
377}
378
379pac::bdma_channels! {
380 ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => {
381 impl_dma_channel!($channel_peri, $dma_peri, $channel_num);
382 };
383}
384
385pac::interrupts! {
386 (DMA, $irq:ident) => {
387 #[crate::interrupt]
388 unsafe fn $irq () {
389 on_irq()
390 }
391 };
392}
393
394#[cfg(usart)]
395use crate::usart;
396
397pac::peripherals! {
398 (usart, $peri:ident) => {
399 impl<T:Channel + crate::dma_traits::WriteDma<crate::peripherals::$peri>> usart::TxDma<crate::peripherals::$peri> for T {}
400 impl<T:Channel + crate::dma_traits::WriteDma<crate::peripherals::$peri>> usart::sealed::TxDma<crate::peripherals::$peri> for T {}
401
402 impl<T:Channel + crate::dma_traits::ReadDma<crate::peripherals::$peri>> usart::RxDma<crate::peripherals::$peri> for T {}
403 impl<T:Channel + crate::dma_traits::ReadDma<crate::peripherals::$peri>> usart::sealed::RxDma<crate::peripherals::$peri> for T {}
404 };
405
406 (uart, $peri:ident) => {
407 impl<T:Channel + crate::dma_traits::WriteDma<crate::peripherals::$peri>> usart::TxDma<crate::peripherals::$peri> for T {}
408 impl<T:Channel + crate::dma_traits::WriteDma<crate::peripherals::$peri>> usart::sealed::TxDma<crate::peripherals::$peri> for T {}
409
410 impl<T:Channel + crate::dma_traits::ReadDma<crate::peripherals::$peri>> usart::RxDma<crate::peripherals::$peri> for T {}
411 impl<T:Channel + crate::dma_traits::ReadDma<crate::peripherals::$peri>> usart::sealed::RxDma<crate::peripherals::$peri> for T {}
412 };
413}
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
new file mode 100644
index 000000000..4c26a9501
--- /dev/null
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -0,0 +1,219 @@
1#![macro_use]
2
3use core::future::Future;
4use core::task::Poll;
5
6use atomic_polyfill::{AtomicU8, Ordering};
7use embassy::interrupt::{Interrupt, InterruptExt};
8use embassy::util::{AtomicWaker, OnDrop};
9use futures::future::poll_fn;
10
11use crate::dma::{Channel, Request};
12use crate::interrupt;
13use crate::pac;
14use crate::pac::bdma::vals;
15use crate::rcc::sealed::RccPeripheral;
16
17const CH_COUNT: usize = pac::peripheral_count!(bdma) * 8;
18const CH_STATUS_NONE: u8 = 0;
19const CH_STATUS_COMPLETED: u8 = 1;
20const CH_STATUS_ERROR: u8 = 2;
21
22struct State {
23 ch_wakers: [AtomicWaker; CH_COUNT],
24 ch_status: [AtomicU8; CH_COUNT],
25}
26
27impl State {
28 const fn new() -> Self {
29 const AW: AtomicWaker = AtomicWaker::new();
30 const AU: AtomicU8 = AtomicU8::new(CH_STATUS_NONE);
31 Self {
32 ch_wakers: [AW; CH_COUNT],
33 ch_status: [AU; CH_COUNT],
34 }
35 }
36}
37
38static STATE: State = State::new();
39
40#[allow(unused)]
41pub(crate) async unsafe fn do_transfer(
42 dma: pac::bdma::Dma,
43 channel_number: u8,
44 state_number: u8,
45 request: Request,
46 dir: vals::Dir,
47 peri_addr: *const u8,
48 mem_addr: *mut u8,
49 mem_len: usize,
50 #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux,
51 #[cfg(dmamux)] dmamux_ch_num: u8,
52) {
53 // ndtr is max 16 bits.
54 assert!(mem_len <= 0xFFFF);
55
56 let ch = dma.ch(channel_number as _);
57
58 // Reset status
59 // Generate a DMB here to flush the store buffer (M7) before enabling the DMA
60 STATE.ch_status[state_number as usize].store(CH_STATUS_NONE, Ordering::Release);
61
62 let on_drop = OnDrop::new(|| unsafe {
63 ch.cr().modify(|w| {
64 w.set_tcie(false);
65 w.set_teie(false);
66 w.set_en(false);
67 });
68 while ch.cr().read().en() {}
69 });
70
71 #[cfg(dmamux)]
72 super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request);
73
74 #[cfg(bdma_v2)]
75 critical_section::with(|_| {
76 dma.cselr()
77 .modify(|w| w.set_cs(channel_number as _, request))
78 });
79
80 ch.par().write_value(peri_addr as u32);
81 ch.mar().write_value(mem_addr as u32);
82 ch.ndtr().write(|w| w.set_ndt(mem_len as u16));
83 ch.cr().write(|w| {
84 w.set_psize(vals::Size::BITS8);
85 w.set_msize(vals::Size::BITS8);
86 w.set_minc(vals::Inc::ENABLED);
87 w.set_dir(dir);
88 w.set_teie(true);
89 w.set_tcie(true);
90 w.set_en(true);
91 });
92
93 let res = poll_fn(|cx| {
94 STATE.ch_wakers[state_number as usize].register(cx.waker());
95 match STATE.ch_status[state_number as usize].load(Ordering::Acquire) {
96 CH_STATUS_NONE => Poll::Pending,
97 x => Poll::Ready(x),
98 }
99 })
100 .await;
101
102 // TODO handle error
103 assert!(res == CH_STATUS_COMPLETED);
104}
105
106macro_rules! dma_num {
107 (DMA1) => {
108 0
109 };
110 (DMA2) => {
111 1
112 };
113 (BDMA) => {
114 0
115 };
116}
117
118unsafe fn on_irq() {
119 pac::peripherals! {
120 (bdma, $dma:ident) => {
121 let isr = pac::$dma.isr().read();
122 pac::$dma.ifcr().write_value(isr);
123 let dman = dma_num!($dma);
124
125 for chn in 0..crate::pac::dma_channels_count!($dma) {
126 let n = dman * 8 + chn;
127 if isr.teif(chn) {
128 STATE.ch_status[n].store(CH_STATUS_ERROR, Ordering::Relaxed);
129 STATE.ch_wakers[n].wake();
130 } else if isr.tcif(chn) {
131 STATE.ch_status[n].store(CH_STATUS_COMPLETED, Ordering::Relaxed);
132 STATE.ch_wakers[n].wake();
133 }
134 }
135 };
136 }
137}
138
139/// safety: must be called only once
140pub(crate) unsafe fn init() {
141 pac::interrupts! {
142 (BDMA, $irq:ident) => {
143 crate::interrupt::$irq::steal().enable();
144 };
145 }
146 pac::peripherals! {
147 (bdma, $peri:ident) => {
148 crate::peripherals::$peri::enable();
149 };
150 }
151}
152
153pac::dma_channels! {
154 ($channel_peri:ident, $dma_peri:ident, bdma, $channel_num:expr, $dmamux:tt) => {
155 impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {}
156 impl Channel for crate::peripherals::$channel_peri
157 {
158 type ReadFuture<'a> = impl Future<Output = ()>;
159 type WriteFuture<'a> = impl Future<Output = ()>;
160
161 fn read<'a>(
162 &'a mut self,
163 request: Request,
164 src: *mut u8,
165 buf: &'a mut [u8],
166 ) -> Self::ReadFuture<'a> {
167 unsafe {
168 do_transfer(
169 crate::pac::$dma_peri,
170 $channel_num,
171 (dma_num!($dma_peri) * 8) + $channel_num,
172 request,
173 vals::Dir::FROMPERIPHERAL,
174 src,
175 buf.as_mut_ptr(),
176 buf.len(),
177 #[cfg(dmamux)]
178 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS,
179 #[cfg(dmamux)]
180 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM,
181 )
182 }
183 }
184
185 fn write<'a>(
186 &'a mut self,
187 request: Request,
188 buf: &'a [u8],
189 dst: *mut u8,
190 ) -> Self::WriteFuture<'a> {
191 unsafe {
192 do_transfer(
193 crate::pac::$dma_peri,
194 $channel_num,
195 (dma_num!($dma_peri) * 8) + $channel_num,
196 request,
197 vals::Dir::FROMMEMORY,
198 dst,
199 buf.as_ptr() as *mut u8,
200 buf.len(),
201 #[cfg(dmamux)]
202 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS,
203 #[cfg(dmamux)]
204 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM,
205 )
206 }
207 }
208 }
209 };
210}
211
212pac::interrupts! {
213 (BDMA, $irq:ident) => {
214 #[crate::interrupt]
215 unsafe fn $irq () {
216 on_irq()
217 }
218 };
219}
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
new file mode 100644
index 000000000..591279ef8
--- /dev/null
+++ b/embassy-stm32/src/dma/dma.rs
@@ -0,0 +1,222 @@
1use core::task::Poll;
2
3use atomic_polyfill::{AtomicU8, Ordering};
4use core::future::Future;
5use embassy::interrupt::{Interrupt, InterruptExt};
6use embassy::util::{AtomicWaker, OnDrop};
7use futures::future::poll_fn;
8
9use crate::interrupt;
10use crate::pac;
11use crate::pac::dma::{regs, vals};
12use crate::rcc::sealed::RccPeripheral;
13
14use super::{Channel, Request};
15
16const CH_COUNT: usize = pac::peripheral_count!(DMA) * 8;
17const CH_STATUS_NONE: u8 = 0;
18const CH_STATUS_COMPLETED: u8 = 1;
19const CH_STATUS_ERROR: u8 = 2;
20
21struct State {
22 ch_wakers: [AtomicWaker; CH_COUNT],
23 ch_status: [AtomicU8; CH_COUNT],
24}
25
26impl State {
27 const fn new() -> Self {
28 const AW: AtomicWaker = AtomicWaker::new();
29 const AU: AtomicU8 = AtomicU8::new(CH_STATUS_NONE);
30 Self {
31 ch_wakers: [AW; CH_COUNT],
32 ch_status: [AU; CH_COUNT],
33 }
34 }
35}
36
37static STATE: State = State::new();
38
39//async unsafe fn do_transfer(ch: &mut impl Channel, ch_func: u8, src: *const u8, dst: &mut [u8]) {
40
41#[allow(unused)]
42pub(crate) async unsafe fn do_transfer(
43 dma: pac::dma::Dma,
44 channel_number: u8,
45 state_number: u8,
46 request: Request,
47 dir: vals::Dir,
48 peri_addr: *const u8,
49 mem_addr: *mut u8,
50 mem_len: usize,
51 #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux,
52 #[cfg(dmamux)] dmamux_ch_num: u8,
53) {
54 // ndtr is max 16 bits.
55 assert!(mem_len <= 0xFFFF);
56
57 // Reset status
58 // Generate a DMB here to flush the store buffer (M7) before enabling the DMA
59 STATE.ch_status[state_number as usize].store(CH_STATUS_NONE, Ordering::Release);
60
61 let ch = dma.st(channel_number as _);
62
63 let on_drop = OnDrop::new(|| unsafe {
64 ch.cr().modify(|w| {
65 w.set_tcie(false);
66 w.set_teie(false);
67 w.set_en(false);
68 });
69 while ch.cr().read().en() {}
70 });
71
72 #[cfg(dmamux)]
73 super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request);
74
75 unsafe {
76 ch.par().write_value(peri_addr as u32);
77 ch.m0ar().write_value(mem_addr as u32);
78 ch.ndtr().write_value(regs::Ndtr(mem_len as _));
79 ch.cr().write(|w| {
80 w.set_dir(dir);
81 w.set_msize(vals::Size::BITS8);
82 w.set_psize(vals::Size::BITS8);
83 w.set_minc(vals::Inc::INCREMENTED);
84 w.set_pinc(vals::Inc::FIXED);
85 w.set_teie(true);
86 w.set_tcie(true);
87 #[cfg(dma_v1)]
88 w.set_trbuff(true);
89 w.set_en(true);
90
91 #[cfg(dma_v2)]
92 w.set_chsel(request);
93 });
94 }
95
96 let res = poll_fn(|cx| {
97 let n = channel_number as usize;
98 STATE.ch_wakers[n].register(cx.waker());
99 match STATE.ch_status[n].load(Ordering::Acquire) {
100 CH_STATUS_NONE => Poll::Pending,
101 x => Poll::Ready(x),
102 }
103 })
104 .await;
105
106 // TODO handle error
107 assert!(res == CH_STATUS_COMPLETED);
108}
109
110macro_rules! dma_num {
111 (DMA1) => {
112 0
113 };
114 (DMA2) => {
115 1
116 };
117}
118
119unsafe fn on_irq() {
120 pac::peripherals! {
121 (dma, $dma:ident) => {
122 for isrn in 0..2 {
123 let isr = pac::$dma.isr(isrn).read();
124 pac::$dma.ifcr(isrn).write_value(isr);
125 let dman = dma_num!($dma);
126
127 for chn in 0..4 {
128 let n = dman * 8 + isrn * 4 + chn;
129 if isr.teif(chn) {
130 STATE.ch_status[n].store(CH_STATUS_ERROR, Ordering::Relaxed);
131 STATE.ch_wakers[n].wake();
132 } else if isr.tcif(chn) {
133 STATE.ch_status[n].store(CH_STATUS_COMPLETED, Ordering::Relaxed);
134 STATE.ch_wakers[n].wake();
135 }
136 }
137 }
138 };
139 }
140}
141
142/// safety: must be called only once
143pub(crate) unsafe fn init() {
144 pac::interrupts! {
145 (DMA, $irq:ident) => {
146 interrupt::$irq::steal().enable();
147 };
148 }
149 pac::peripherals! {
150 (dma, $peri:ident) => {
151 crate::peripherals::$peri::enable();
152 };
153 }
154}
155
156pac::dma_channels! {
157 ($channel_peri:ident, $dma_peri:ident, dma, $channel_num:expr, $dmamux:tt) => {
158 impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {}
159 impl Channel for crate::peripherals::$channel_peri
160 {
161 type ReadFuture<'a> = impl Future<Output = ()>;
162 type WriteFuture<'a> = impl Future<Output = ()>;
163
164 fn read<'a>(
165 &'a mut self,
166 request: Request,
167 src: *mut u8,
168 buf: &'a mut [u8],
169 ) -> Self::ReadFuture<'a> {
170 unsafe {
171 do_transfer(
172 crate::pac::$dma_peri,
173 $channel_num,
174 (dma_num!($dma_peri) * 8) + $channel_num,
175 request,
176 vals::Dir::PERIPHERALTOMEMORY,
177 src,
178 buf.as_mut_ptr(),
179 buf.len(),
180 #[cfg(dmamux)]
181 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS,
182 #[cfg(dmamux)]
183 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM,
184 )
185 }
186 }
187
188 fn write<'a>(
189 &'a mut self,
190 request: Request,
191 buf: &'a [u8],
192 dst: *mut u8,
193 ) -> Self::WriteFuture<'a> {
194 unsafe {
195 do_transfer(
196 crate::pac::$dma_peri,
197 $channel_num,
198 (dma_num!($dma_peri) * 8) + $channel_num,
199 request,
200 vals::Dir::MEMORYTOPERIPHERAL,
201 dst,
202 buf.as_ptr() as *mut u8,
203 buf.len(),
204 #[cfg(dmamux)]
205 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS,
206 #[cfg(dmamux)]
207 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM,
208 )
209 }
210 }
211 }
212 };
213}
214
215pac::interrupts! {
216 (DMA, $irq:ident) => {
217 #[crate::interrupt]
218 unsafe fn $irq () {
219 on_irq()
220 }
221 };
222}
diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs
new file mode 100644
index 000000000..718859a44
--- /dev/null
+++ b/embassy-stm32/src/dma/dmamux.rs
@@ -0,0 +1,51 @@
1#![macro_use]
2
3use crate::pac;
4use crate::peripherals;
5
6pub(crate) unsafe fn configure_dmamux(
7 dmamux_regs: pac::dmamux::Dmamux,
8 dmamux_ch_num: u8,
9 request: u8,
10) {
11 let ch_mux_regs = dmamux_regs.ccr(dmamux_ch_num as _);
12 ch_mux_regs.write(|reg| {
13 reg.set_nbreq(0);
14 reg.set_dmareq_id(request);
15 });
16
17 ch_mux_regs.modify(|reg| {
18 reg.set_ege(true);
19 });
20}
21
22pub(crate) mod sealed {
23 use super::*;
24 pub trait MuxChannel {
25 const DMAMUX_CH_NUM: u8;
26 const DMAMUX_REGS: pac::dmamux::Dmamux;
27 }
28}
29
30pub struct DMAMUX1;
31#[cfg(rcc_h7)]
32pub struct DMAMUX2;
33
34pub trait MuxChannel: sealed::MuxChannel + super::Channel {
35 type Mux;
36}
37
38pac::dma_channels! {
39 ($channel_peri:ident, $dma_peri:ident, $version:ident, $channel_num:expr, {dmamux: $dmamux:ident, dmamux_channel: $dmamux_channel:expr}) => {
40 impl sealed::MuxChannel for peripherals::$channel_peri {
41 const DMAMUX_CH_NUM: u8 = $dmamux_channel;
42 const DMAMUX_REGS: pac::dmamux::Dmamux = pac::$dmamux;
43 }
44 impl MuxChannel for peripherals::$channel_peri {
45 type Mux = $dmamux;
46 }
47 };
48}
49
50/// safety: must be called only once
51pub(crate) unsafe fn init() {}
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index ed080cd16..fbf82b87b 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -1,9 +1,65 @@
1#![macro_use] 1#[cfg(bdma)]
2mod bdma;
3#[cfg(dma)]
4mod dma;
5#[cfg(dmamux)]
6mod dmamux;
2 7
3#[cfg_attr(dma_v1, path = "v1.rs")] 8#[cfg(dmamux)]
4#[cfg_attr(dma_v2, path = "v2.rs")] 9pub use dmamux::*;
5mod _version;
6 10
7#[cfg(dma)] 11use core::future::Future;
8#[allow(unused)] 12use embassy::util::Unborrow;
9pub use _version::*; 13
14#[cfg(any(bdma_v2, dma_v2, dmamux))]
15pub type Request = u8;
16#[cfg(not(any(bdma_v2, dma_v2, dmamux)))]
17pub type Request = ();
18
19pub(crate) mod sealed {
20 pub trait Channel {}
21}
22
23pub trait Channel: sealed::Channel {
24 type ReadFuture<'a>: Future<Output = ()> + 'a
25 where
26 Self: 'a;
27
28 type WriteFuture<'a>: Future<Output = ()> + 'a
29 where
30 Self: 'a;
31
32 fn read<'a>(
33 &'a mut self,
34 request: Request,
35 src: *mut u8,
36 buf: &'a mut [u8],
37 ) -> Self::ReadFuture<'a>;
38
39 fn write<'a>(
40 &'a mut self,
41 request: Request,
42 buf: &'a [u8],
43 dst: *mut u8,
44 ) -> Self::WriteFuture<'a>;
45}
46
47pub struct NoDma;
48
49unsafe impl Unborrow for NoDma {
50 type Target = NoDma;
51
52 unsafe fn unborrow(self) -> Self::Target {
53 self
54 }
55}
56
57// safety: must be called only once at startup
58pub(crate) unsafe fn init() {
59 #[cfg(bdma)]
60 bdma::init();
61 #[cfg(dma)]
62 dma::init();
63 #[cfg(dmamux)]
64 dmamux::init();
65}
diff --git a/embassy-stm32/src/dma/v1.rs b/embassy-stm32/src/dma/v1.rs
deleted file mode 100644
index 4544108e5..000000000
--- a/embassy-stm32/src/dma/v1.rs
+++ /dev/null
@@ -1,2 +0,0 @@
1/// safety: must be called only once
2pub(crate) unsafe fn init() {}
diff --git a/embassy-stm32/src/dma/v2.rs b/embassy-stm32/src/dma/v2.rs
deleted file mode 100644
index df3b922ff..000000000
--- a/embassy-stm32/src/dma/v2.rs
+++ /dev/null
@@ -1,331 +0,0 @@
1use core::task::Poll;
2
3use crate::dma_traits::{ReadDma, WriteDma};
4use atomic_polyfill::{AtomicU8, Ordering};
5use core::future::Future;
6use embassy::interrupt::{Interrupt, InterruptExt};
7use embassy::util::AtomicWaker;
8use futures::future::poll_fn;
9
10use crate::interrupt;
11use crate::pac;
12use crate::pac::dma::{regs, vals};
13
14use crate::pac::dma_channels;
15use crate::pac::interrupts;
16use crate::pac::peripheral_count;
17use crate::pac::peripheral_dma_channels;
18use crate::pac::peripherals;
19use crate::peripherals;
20
21const CH_COUNT: usize = peripheral_count!(DMA) * 8;
22const CH_STATUS_NONE: u8 = 0;
23const CH_STATUS_COMPLETED: u8 = 1;
24const CH_STATUS_ERROR: u8 = 2;
25
26struct State {
27 ch_wakers: [AtomicWaker; CH_COUNT],
28 ch_status: [AtomicU8; CH_COUNT],
29}
30
31impl State {
32 const fn new() -> Self {
33 const AW: AtomicWaker = AtomicWaker::new();
34 const AU: AtomicU8 = AtomicU8::new(CH_STATUS_NONE);
35 Self {
36 ch_wakers: [AW; CH_COUNT],
37 ch_status: [AU; CH_COUNT],
38 }
39 }
40}
41
42static STATE: State = State::new();
43
44#[allow(unused)] // Used by usart/v1.rs which may or may not be enabled
45pub(crate) async unsafe fn transfer_p2m(
46 ch: &mut impl Channel,
47 ch_func: u8,
48 src: *const u8,
49 dst: &mut [u8],
50) {
51 let n = ch.num();
52 let c = ch.regs();
53
54 // ndtr is max 16 bits.
55 assert!(dst.len() <= 0xFFFF);
56
57 // Reset status
58 // Generate a DMB here to flush the store buffer (M7) before enabling the DMA
59 STATE.ch_status[n].store(CH_STATUS_NONE, Ordering::Release);
60
61 unsafe {
62 c.par().write_value(src as _);
63 c.m0ar().write_value(dst.as_ptr() as _);
64 c.ndtr().write_value(regs::Ndtr(dst.len() as _));
65 c.cr().write(|w| {
66 w.set_dir(vals::Dir::PERIPHERALTOMEMORY);
67 w.set_msize(vals::Size::BITS8);
68 w.set_psize(vals::Size::BITS8);
69 w.set_minc(vals::Inc::INCREMENTED);
70 w.set_pinc(vals::Inc::FIXED);
71 w.set_chsel(ch_func);
72 w.set_teie(true);
73 w.set_tcie(true);
74 w.set_en(true);
75 });
76 }
77
78 let res = poll_fn(|cx| {
79 STATE.ch_wakers[n].register(cx.waker());
80 match STATE.ch_status[n].load(Ordering::Acquire) {
81 CH_STATUS_NONE => Poll::Pending,
82 x => Poll::Ready(x),
83 }
84 })
85 .await;
86
87 // TODO handle error
88 assert!(res == CH_STATUS_COMPLETED);
89}
90
91#[allow(unused)] // Used by usart/v1.rs which may or may not be enabled
92pub(crate) async unsafe fn transfer_m2p(
93 ch: &mut impl Channel,
94 ch_func: u8,
95 src: &[u8],
96 dst: *mut u8,
97) {
98 let n = ch.num();
99 let c = ch.regs();
100
101 // ndtr is max 16 bits.
102 assert!(src.len() <= 0xFFFF);
103
104 // Reset status
105 // Generate a DMB here to flush the store buffer (M7) before enabling the DMA
106 STATE.ch_status[n].store(CH_STATUS_NONE, Ordering::Release);
107
108 unsafe {
109 c.par().write_value(dst as _);
110 c.m0ar().write_value(src.as_ptr() as _);
111 c.ndtr().write_value(regs::Ndtr(src.len() as _));
112 c.cr().write(|w| {
113 w.set_dir(vals::Dir::MEMORYTOPERIPHERAL);
114 w.set_msize(vals::Size::BITS8);
115 w.set_psize(vals::Size::BITS8);
116 w.set_minc(vals::Inc::INCREMENTED);
117 w.set_pinc(vals::Inc::FIXED);
118 w.set_chsel(ch_func);
119 w.set_teie(true);
120 w.set_tcie(true);
121 w.set_en(true);
122 });
123 }
124
125 let res = poll_fn(|cx| {
126 STATE.ch_wakers[n].register(cx.waker());
127 match STATE.ch_status[n].load(Ordering::Acquire) {
128 CH_STATUS_NONE => {
129 let left = c.ndtr().read().ndt();
130 Poll::Pending
131 }
132 x => Poll::Ready(x),
133 }
134 })
135 .await;
136
137 // TODO handle error
138 assert!(res == CH_STATUS_COMPLETED);
139}
140
141unsafe fn on_irq() {
142 peripherals! {
143 (dma, $dma:ident) => {
144 for isrn in 0..2 {
145 let isr = pac::$dma.isr(isrn).read();
146 pac::$dma.ifcr(isrn).write_value(isr);
147 let dman = <peripherals::$dma as sealed::Dma>::num() as usize;
148
149 for chn in 0..4 {
150 let n = dman * 8 + isrn * 4 + chn;
151 if isr.teif(chn) {
152 STATE.ch_status[n].store(CH_STATUS_ERROR, Ordering::Relaxed);
153 STATE.ch_wakers[n].wake();
154 } else if isr.tcif(chn) {
155 STATE.ch_status[n].store(CH_STATUS_COMPLETED, Ordering::Relaxed);
156 STATE.ch_wakers[n].wake();
157 }
158 }
159 }
160 };
161 }
162}
163
164/// safety: must be called only once
165pub(crate) unsafe fn init() {
166 interrupts! {
167 (DMA, $irq:ident) => {
168 interrupt::$irq::steal().enable();
169 };
170 }
171}
172
173pub(crate) mod sealed {
174 use super::*;
175
176 pub trait Dma {
177 fn num() -> u8;
178 fn regs() -> &'static pac::dma::Dma;
179 }
180
181 pub trait Channel {
182 fn dma_regs() -> &'static pac::dma::Dma;
183
184 fn num(&self) -> usize;
185
186 fn ch_num(&self) -> u8;
187
188 fn regs(&self) -> pac::dma::St {
189 Self::dma_regs().st(self.ch_num() as _)
190 }
191 }
192
193 pub trait PeripheralChannel<PERI, OP>: Channel {
194 fn request(&self) -> u8;
195 }
196}
197
198pub trait Dma: sealed::Dma + Sized {}
199pub trait Channel: sealed::Channel + Sized {}
200pub trait PeripheralChannel<PERI, OP>: sealed::PeripheralChannel<PERI, OP> + Sized {}
201
202macro_rules! impl_dma {
203 ($peri:ident, $num:expr) => {
204 impl Dma for peripherals::$peri {}
205 impl sealed::Dma for peripherals::$peri {
206 fn num() -> u8 {
207 $num
208 }
209 fn regs() -> &'static pac::dma::Dma {
210 &pac::$peri
211 }
212 }
213 };
214}
215
216macro_rules! impl_dma_channel {
217 ($channel_peri:ident, $dma_peri:ident, $dma_num:expr, $ch_num:expr) => {
218 impl Channel for peripherals::$channel_peri {}
219 impl sealed::Channel for peripherals::$channel_peri {
220 #[inline]
221 fn dma_regs() -> &'static pac::dma::Dma {
222 &crate::pac::$dma_peri
223 }
224
225 fn num(&self) -> usize {
226 ($dma_num * 8) + $ch_num
227 }
228
229 fn ch_num(&self) -> u8 {
230 $ch_num
231 }
232 }
233
234 impl<T> WriteDma<T> for peripherals::$channel_peri
235 where
236 Self: sealed::PeripheralChannel<T, M2P>,
237 T: 'static,
238 {
239 type WriteDmaFuture<'a> = impl Future<Output = ()>;
240
241 fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a>
242 where
243 T: 'a,
244 {
245 let request = sealed::PeripheralChannel::<T, M2P>::request(self);
246 unsafe { transfer_m2p(self, request, buf, dst) }
247 }
248 }
249
250 impl<T> ReadDma<T> for peripherals::$channel_peri
251 where
252 Self: sealed::PeripheralChannel<T, P2M>,
253 T: 'static,
254 {
255 type ReadDmaFuture<'a> = impl Future<Output = ()>;
256
257 fn transfer<'a>(
258 &'a mut self,
259 src: *const u8,
260 buf: &'a mut [u8],
261 ) -> Self::ReadDmaFuture<'a>
262 where
263 T: 'a,
264 {
265 let request = sealed::PeripheralChannel::<T, P2M>::request(self);
266 unsafe { transfer_p2m(self, request, src, buf) }
267 }
268 }
269 };
270}
271
272peripherals! {
273 (dma, DMA1) => {
274 impl_dma!(DMA1, 0);
275 dma_channels! {
276 ($channel_peri:ident, DMA1, $channel_num:expr) => {
277 impl_dma_channel!($channel_peri, DMA1, 0, $channel_num);
278 };
279 }
280 };
281 (dma, DMA2) => {
282 impl_dma!(DMA2, 1);
283 dma_channels! {
284 ($channel_peri:ident, DMA2, $channel_num:expr) => {
285 impl_dma_channel!($channel_peri, DMA2, 1, $channel_num);
286 };
287 }
288 };
289}
290
291interrupts! {
292 (DMA, $irq:ident) => {
293 #[crate::interrupt]
294 unsafe fn $irq () {
295 on_irq()
296 }
297 };
298}
299
300pub struct P2M;
301pub struct M2P;
302
303#[cfg(usart)]
304use crate::usart;
305peripheral_dma_channels! {
306 ($peri:ident, usart, $kind:ident, RX, $channel_peri:ident, $dma_peri:ident, $channel_num:expr, $event_num:expr) => {
307 impl usart::RxDma<peripherals::$peri> for peripherals::$channel_peri { }
308 impl usart::sealed::RxDma<peripherals::$peri> for peripherals::$channel_peri { }
309
310 impl sealed::PeripheralChannel<peripherals::$peri, P2M> for peripherals::$channel_peri {
311 fn request(&self) -> u8 {
312 $event_num
313 }
314 }
315
316 impl PeripheralChannel<peripherals::$peri, P2M> for peripherals::$channel_peri { }
317 };
318
319 ($peri:ident, usart, $kind:ident, TX, $channel_peri:ident, $dma_peri:ident, $channel_num:expr, $event_num:expr) => {
320 impl usart::TxDma<peripherals::$peri> for peripherals::$channel_peri { }
321 impl usart::sealed::TxDma<peripherals::$peri> for peripherals::$channel_peri { }
322
323 impl sealed::PeripheralChannel<peripherals::$peri, M2P> for peripherals::$channel_peri {
324 fn request(&self) -> u8 {
325 $event_num
326 }
327 }
328
329 impl PeripheralChannel<peripherals::$peri, M2P> for peripherals::$channel_peri { }
330 };
331}
diff --git a/embassy-stm32/src/dma_traits.rs b/embassy-stm32/src/dma_traits.rs
deleted file mode 100644
index 6733d911a..000000000
--- a/embassy-stm32/src/dma_traits.rs
+++ /dev/null
@@ -1,32 +0,0 @@
1use core::future::Future;
2use embassy::util::Unborrow;
3
4pub trait WriteDma<T> {
5 type WriteDmaFuture<'a>: Future<Output = ()> + 'a
6 where
7 Self: 'a;
8
9 fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a>
10 where
11 T: 'a;
12}
13
14pub trait ReadDma<T> {
15 type ReadDmaFuture<'a>: Future<Output = ()> + 'a
16 where
17 Self: 'a;
18
19 fn transfer<'a>(&'a mut self, src: *const u8, buf: &'a mut [u8]) -> Self::ReadDmaFuture<'a>
20 where
21 T: 'a;
22}
23
24pub struct NoDma;
25
26unsafe impl Unborrow for NoDma {
27 type Target = NoDma;
28
29 unsafe fn unborrow(self) -> Self::Target {
30 self
31 }
32}
diff --git a/embassy-stm32/src/dmamux/mod.rs b/embassy-stm32/src/dmamux/mod.rs
deleted file mode 100644
index ecea0b290..000000000
--- a/embassy-stm32/src/dmamux/mod.rs
+++ /dev/null
@@ -1,137 +0,0 @@
1#![macro_use]
2
3use crate::pac;
4use crate::pac::bdma_channels;
5use crate::pac::dma_requests;
6use crate::pac::peripherals;
7use crate::peripherals;
8
9pub(crate) unsafe fn configure_dmamux(
10 dmamux_regs: pac::dmamux::Dmamux,
11 dmamux_ch_num: u8,
12 request: u8,
13) {
14 let ch_mux_regs = dmamux_regs.ccr(dmamux_ch_num as _);
15 ch_mux_regs.write(|reg| {
16 reg.set_nbreq(0);
17 reg.set_dmareq_id(request);
18 });
19
20 ch_mux_regs.modify(|reg| {
21 reg.set_ege(true);
22 });
23}
24
25pub(crate) mod sealed {
26 use super::*;
27
28 pub trait Channel {
29 const DMAMUX_CH_NUM: u8;
30 const DMAMUX_REGS: pac::dmamux::Dmamux;
31 }
32
33 pub trait PeripheralChannel<PERI, OP>: Channel {
34 const REQUEST: u8;
35 }
36}
37
38pub trait Channel: sealed::Channel {}
39pub trait PeripheralChannel<PERI, OP>: sealed::Channel {}
40
41pub struct P2M;
42pub struct M2P;
43
44macro_rules! dma_num {
45 (DMA1) => {
46 0
47 };
48 (DMA2) => {
49 1
50 };
51 (BDMA) => {
52 0
53 };
54}
55
56macro_rules! dmamux_peri {
57 (DMA1) => {
58 crate::pac::DMAMUX1
59 };
60 (DMA2) => {
61 crate::pac::DMAMUX1
62 };
63 (BDMA) => {
64 crate::pac::DMAMUX1
65 };
66}
67
68#[allow(unused)]
69macro_rules! impl_dma_channel {
70 ($channel_peri:ident, $channel_num:expr, $dma_peri: ident) => {
71 impl Channel for peripherals::$channel_peri {}
72 impl sealed::Channel for peripherals::$channel_peri {
73 const DMAMUX_CH_NUM: u8 = (dma_num!($dma_peri) * 8) + $channel_num;
74 const DMAMUX_REGS: pac::dmamux::Dmamux = dmamux_peri!($dma_peri);
75 }
76 };
77}
78
79peripherals! {
80 (bdma, $peri:ident) => {
81 bdma_channels! {
82 ($channel_peri:ident, $peri, $channel_num:expr) => {
83 impl_dma_channel!($channel_peri, $channel_num, $peri);
84 };
85 }
86 };
87}
88
89#[allow(unused)]
90macro_rules! impl_peripheral_channel {
91 ($channel_peri:ident, $direction:ident, $peri:ident, $request:expr) => {
92 impl sealed::PeripheralChannel<peripherals::$peri, $direction>
93 for peripherals::$channel_peri
94 {
95 const REQUEST: u8 = $request;
96 }
97
98 impl PeripheralChannel<peripherals::$peri, $direction> for peripherals::$channel_peri {}
99 };
100}
101
102#[allow(unused)]
103macro_rules! impl_usart_dma_requests {
104 ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => {
105 dma_requests! {
106 (usart, $peri:ident, RX, $request:expr) => {
107 impl_peripheral_channel!($channel_peri, P2M, $peri, $request);
108 };
109
110 (usart, $peri:ident, TX, $request:expr) => {
111 impl_peripheral_channel!($channel_peri, M2P, $peri, $request);
112 };
113
114 (uart, $peri:ident, RX, $request:expr) => {
115 impl_peripheral_channel!($channel_peri, P2M, $peri, $request);
116 };
117
118 (uart, $peri:ident, TX, $request:expr) => {
119 impl_peripheral_channel!($channel_peri, M2P, $peri, $request);
120 };
121 }
122 };
123}
124
125#[allow(unused)]
126#[cfg(usart)]
127use crate::usart;
128
129bdma_channels! {
130 ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => {
131 #[cfg(usart)]
132 impl_usart_dma_requests!($channel_peri, $dma_peri, $channel_num);
133 };
134}
135
136/// safety: must be called only once
137pub(crate) unsafe fn init() {}
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 22999a69e..c10310e2d 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -19,25 +19,18 @@ pub mod interrupt;
19pub mod time; 19pub mod time;
20 20
21// Always-present hardware 21// Always-present hardware
22pub mod dma;
22pub mod gpio; 23pub mod gpio;
23pub mod rcc; 24pub mod rcc;
24 25
25// Sometimes-present hardware 26// Sometimes-present hardware
26#[cfg(any(dma, bdma, dmamux))]
27pub mod dma_traits;
28 27
29#[cfg(adc)] 28#[cfg(adc)]
30pub mod adc; 29pub mod adc;
31#[cfg(bdma)]
32pub mod bdma;
33#[cfg(timer)] 30#[cfg(timer)]
34pub mod clock; 31pub mod clock;
35#[cfg(dac)] 32#[cfg(dac)]
36pub mod dac; 33pub mod dac;
37#[cfg(dma)]
38pub mod dma;
39#[cfg(dmamux)]
40pub mod dmamux;
41#[cfg(all(eth, feature = "net"))] 34#[cfg(all(eth, feature = "net"))]
42pub mod eth; 35pub mod eth;
43#[cfg(exti)] 36#[cfg(exti)]
@@ -94,12 +87,7 @@ pub fn init(config: Config) -> Peripherals {
94 let p = Peripherals::take(); 87 let p = Peripherals::take();
95 88
96 unsafe { 89 unsafe {
97 #[cfg(dma)]
98 dma::init(); 90 dma::init();
99 #[cfg(bdma)]
100 bdma::init();
101 #[cfg(dmamux)]
102 dmamux::init();
103 #[cfg(exti)] 91 #[cfg(exti)]
104 exti::init(); 92 exti::init();
105 93
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index c3ac8bc59..9df00d3a8 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -3,7 +3,7 @@
3#[cfg_attr(usart_v1, path = "v1.rs")] 3#[cfg_attr(usart_v1, path = "v1.rs")]
4#[cfg_attr(usart_v2, path = "v2.rs")] 4#[cfg_attr(usart_v2, path = "v2.rs")]
5mod _version; 5mod _version;
6use crate::peripherals; 6use crate::{dma, peripherals};
7pub use _version::*; 7pub use _version::*;
8 8
9use crate::gpio::Pin; 9use crate::gpio::Pin;
@@ -72,9 +72,6 @@ pub enum Error {
72pub(crate) mod sealed { 72pub(crate) mod sealed {
73 use super::*; 73 use super::*;
74 74
75 #[cfg(any(dma, bdma, dmamux))]
76 use crate::dma_traits::WriteDma;
77
78 pub trait Instance { 75 pub trait Instance {
79 fn regs(&self) -> crate::pac::usart::Usart; 76 fn regs(&self) -> crate::pac::usart::Usart;
80 } 77 }
@@ -94,11 +91,13 @@ pub(crate) mod sealed {
94 fn af_num(&self) -> u8; 91 fn af_num(&self) -> u8;
95 } 92 }
96 93
97 #[cfg(any(bdma, dma, dmamux))] 94 pub trait RxDma<T: Instance> {
98 pub trait RxDma<T: Instance> {} 95 fn request(&self) -> dma::Request;
96 }
99 97
100 #[cfg(any(bdma, dma, dmamux))] 98 pub trait TxDma<T: Instance> {
101 pub trait TxDma<T: Instance>: WriteDma<T> {} 99 fn request(&self) -> dma::Request;
100 }
102} 101}
103 102
104pub trait Instance: sealed::Instance + RccPeripheral {} 103pub trait Instance: sealed::Instance + RccPeripheral {}
@@ -107,12 +106,8 @@ pub trait TxPin<T: Instance>: sealed::TxPin<T> {}
107pub trait CtsPin<T: Instance>: sealed::CtsPin<T> {} 106pub trait CtsPin<T: Instance>: sealed::CtsPin<T> {}
108pub trait RtsPin<T: Instance>: sealed::RtsPin<T> {} 107pub trait RtsPin<T: Instance>: sealed::RtsPin<T> {}
109pub trait CkPin<T: Instance>: sealed::CkPin<T> {} 108pub trait CkPin<T: Instance>: sealed::CkPin<T> {}
110 109pub trait RxDma<T: Instance>: sealed::RxDma<T> + dma::Channel {}
111#[cfg(any(bdma, dma, dmamux))] 110pub trait TxDma<T: Instance>: sealed::TxDma<T> + dma::Channel {}
112pub trait RxDma<T: Instance>: sealed::RxDma<T> {}
113
114#[cfg(any(bdma, dma, dmamux))]
115pub trait TxDma<T: Instance>: sealed::TxDma<T> {}
116 111
117crate::pac::peripherals!( 112crate::pac::peripherals!(
118 (usart, $inst:ident) => { 113 (usart, $inst:ident) => {
@@ -141,46 +136,78 @@ macro_rules! impl_pin {
141crate::pac::peripheral_pins!( 136crate::pac::peripheral_pins!(
142 137
143 // USART 138 // USART
144
145 ($inst:ident, usart, USART, $pin:ident, TX, $af:expr) => { 139 ($inst:ident, usart, USART, $pin:ident, TX, $af:expr) => {
146 impl_pin!($inst, $pin, TxPin, $af); 140 impl_pin!($inst, $pin, TxPin, $af);
147 }; 141 };
148
149 ($inst:ident, usart, USART, $pin:ident, RX, $af:expr) => { 142 ($inst:ident, usart, USART, $pin:ident, RX, $af:expr) => {
150 impl_pin!($inst, $pin, RxPin, $af); 143 impl_pin!($inst, $pin, RxPin, $af);
151 }; 144 };
152
153 ($inst:ident, usart, USART, $pin:ident, CTS, $af:expr) => { 145 ($inst:ident, usart, USART, $pin:ident, CTS, $af:expr) => {
154 impl_pin!($inst, $pin, CtsPin, $af); 146 impl_pin!($inst, $pin, CtsPin, $af);
155 }; 147 };
156
157 ($inst:ident, usart, USART, $pin:ident, RTS, $af:expr) => { 148 ($inst:ident, usart, USART, $pin:ident, RTS, $af:expr) => {
158 impl_pin!($inst, $pin, RtsPin, $af); 149 impl_pin!($inst, $pin, RtsPin, $af);
159 }; 150 };
160
161 ($inst:ident, usart, USART, $pin:ident, CK, $af:expr) => { 151 ($inst:ident, usart, USART, $pin:ident, CK, $af:expr) => {
162 impl_pin!($inst, $pin, CkPin, $af); 152 impl_pin!($inst, $pin, CkPin, $af);
163 }; 153 };
164 154
165 // UART 155 // UART
166
167 ($inst:ident, uart, UART, $pin:ident, TX, $af:expr) => { 156 ($inst:ident, uart, UART, $pin:ident, TX, $af:expr) => {
168 impl_pin!($inst, $pin, TxPin, $af); 157 impl_pin!($inst, $pin, TxPin, $af);
169 }; 158 };
170
171 ($inst:ident, uart, UART, $pin:ident, RX, $af:expr) => { 159 ($inst:ident, uart, UART, $pin:ident, RX, $af:expr) => {
172 impl_pin!($inst, $pin, RxPin, $af); 160 impl_pin!($inst, $pin, RxPin, $af);
173 }; 161 };
174
175 ($inst:ident, uart, UART, $pin:ident, CTS, $af:expr) => { 162 ($inst:ident, uart, UART, $pin:ident, CTS, $af:expr) => {
176 impl_pin!($inst, $pin, CtsPin, $af); 163 impl_pin!($inst, $pin, CtsPin, $af);
177 }; 164 };
178
179 ($inst:ident, uart, UART, $pin:ident, RTS, $af:expr) => { 165 ($inst:ident, uart, UART, $pin:ident, RTS, $af:expr) => {
180 impl_pin!($inst, $pin, RtsPin, $af); 166 impl_pin!($inst, $pin, RtsPin, $af);
181 }; 167 };
182
183 ($inst:ident, uart, UART, $pin:ident, CK, $af:expr) => { 168 ($inst:ident, uart, UART, $pin:ident, CK, $af:expr) => {
184 impl_pin!($inst, $pin, CkPin, $af); 169 impl_pin!($inst, $pin, CkPin, $af);
185 }; 170 };
186); 171);
172
173macro_rules! impl_dma {
174 ($inst:ident, {dmamux: $dmamux:ident}, $signal:ident, $request:expr) => {
175 impl<T> sealed::$signal<peripherals::$inst> for T
176 where
177 T: crate::dma::MuxChannel<Mux = crate::dma::$dmamux>,
178 {
179 fn request(&self) -> dma::Request {
180 $request
181 }
182 }
183
184 impl<T> $signal<peripherals::$inst> for T where
185 T: crate::dma::MuxChannel<Mux = crate::dma::$dmamux>
186 {
187 }
188 };
189 ($inst:ident, {channel: $channel:ident}, $signal:ident, $request:expr) => {
190 impl sealed::$signal<peripherals::$inst> for peripherals::$channel {
191 fn request(&self) -> dma::Request {
192 $request
193 }
194 }
195
196 impl $signal<peripherals::$inst> for peripherals::$channel {}
197 };
198}
199
200crate::pac::peripheral_dma_channels! {
201 ($peri:ident, usart, $kind:ident, RX, $channel:tt, $request:expr) => {
202 impl_dma!($peri, $channel, RxDma, $request);
203 };
204 ($peri:ident, usart, $kind:ident, TX, $channel:tt, $request:expr) => {
205 impl_dma!($peri, $channel, TxDma, $request);
206 };
207 ($peri:ident, uart, $kind:ident, RX, $channel:tt, $request:expr) => {
208 impl_dma!($peri, $channel, RxDma, $request);
209 };
210 ($peri:ident, uart, $kind:ident, TX, $channel:tt, $request:expr) => {
211 impl_dma!($peri, $channel, TxDma, $request);
212 };
213}
diff --git a/embassy-stm32/src/usart/v1.rs b/embassy-stm32/src/usart/v1.rs
index 169938952..0f39c364b 100644
--- a/embassy-stm32/src/usart/v1.rs
+++ b/embassy-stm32/src/usart/v1.rs
@@ -1,25 +1,31 @@
1use core::future::Future;
1use core::marker::PhantomData; 2use core::marker::PhantomData;
2
3use embassy::util::Unborrow; 3use embassy::util::Unborrow;
4use embassy_extras::unborrow; 4use embassy_extras::unborrow;
5 5use futures::TryFutureExt;
6use crate::pac::usart::{regs, vals};
7 6
8use super::*; 7use super::*;
8use crate::dma::NoDma;
9use crate::pac::usart::{regs, vals};
9 10
10pub struct Uart<'d, T: Instance> { 11pub struct Uart<'d, T: Instance, TxDma = NoDma, RxDma = NoDma> {
11 inner: T, 12 inner: T,
12 phantom: PhantomData<&'d mut T>, 13 phantom: PhantomData<&'d mut T>,
14 tx_dma: TxDma,
15 #[allow(dead_code)]
16 rx_dma: RxDma,
13} 17}
14 18
15impl<'d, T: Instance> Uart<'d, T> { 19impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
16 pub fn new( 20 pub fn new(
17 inner: impl Unborrow<Target = T>, 21 inner: impl Unborrow<Target = T>,
18 rx: impl Unborrow<Target = impl RxPin<T>>, 22 rx: impl Unborrow<Target = impl RxPin<T>>,
19 tx: impl Unborrow<Target = impl TxPin<T>>, 23 tx: impl Unborrow<Target = impl TxPin<T>>,
24 tx_dma: impl Unborrow<Target = TxDma>,
25 rx_dma: impl Unborrow<Target = RxDma>,
20 config: Config, 26 config: Config,
21 ) -> Self { 27 ) -> Self {
22 unborrow!(inner, rx, tx); 28 unborrow!(inner, rx, tx, tx_dma, rx_dma);
23 29
24 T::enable(); 30 T::enable();
25 let pclk_freq = T::frequency(); 31 let pclk_freq = T::frequency();
@@ -53,11 +59,16 @@ impl<'d, T: Instance> Uart<'d, T> {
53 Self { 59 Self {
54 inner, 60 inner,
55 phantom: PhantomData, 61 phantom: PhantomData,
62 tx_dma,
63 rx_dma,
56 } 64 }
57 } 65 }
58 66
59 #[cfg(dma)] 67 async fn write_dma(&mut self, buffer: &[u8]) -> Result<(), Error>
60 pub async fn write_dma(&mut self, ch: &mut impl TxDma<T>, buffer: &[u8]) -> Result<(), Error> { 68 where
69 TxDma: crate::usart::TxDma<T>,
70 {
71 let ch = &mut self.tx_dma;
61 unsafe { 72 unsafe {
62 self.inner.regs().cr3().modify(|reg| { 73 self.inner.regs().cr3().modify(|reg| {
63 reg.set_dmat(true); 74 reg.set_dmat(true);
@@ -65,7 +76,7 @@ impl<'d, T: Instance> Uart<'d, T> {
65 } 76 }
66 let r = self.inner.regs(); 77 let r = self.inner.regs();
67 let dst = r.dr().ptr() as *mut u8; 78 let dst = r.dr().ptr() as *mut u8;
68 ch.transfer(buffer, dst).await; 79 ch.write(ch.request(), buffer, dst).await;
69 Ok(()) 80 Ok(())
70 } 81 }
71 82
@@ -98,7 +109,9 @@ impl<'d, T: Instance> Uart<'d, T> {
98 } 109 }
99} 110}
100 111
101impl<'d, T: Instance> embedded_hal::blocking::serial::Write<u8> for Uart<'d, T> { 112impl<'d, T: Instance, RxDma> embedded_hal::blocking::serial::Write<u8>
113 for Uart<'d, T, NoDma, RxDma>
114{
102 type Error = Error; 115 type Error = Error;
103 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 116 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
104 unsafe { 117 unsafe {
@@ -118,3 +131,15 @@ impl<'d, T: Instance> embedded_hal::blocking::serial::Write<u8> for Uart<'d, T>
118 Ok(()) 131 Ok(())
119 } 132 }
120} 133}
134
135// rustfmt::skip because intellij removes the 'where' claus on the associated type.
136#[rustfmt::skip]
137impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Write for Uart<'d, T, TxDma, RxDma>
138 where TxDma: crate::usart::TxDma<T>
139{
140 type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), embassy_traits::uart::Error>>;
141
142 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
143 self.write_dma(buf).map_err(|_| embassy_traits::uart::Error::Other)
144 }
145}
diff --git a/embassy-stm32/src/usart/v2.rs b/embassy-stm32/src/usart/v2.rs
index b958c0a0c..8a4d63b20 100644
--- a/embassy-stm32/src/usart/v2.rs
+++ b/embassy-stm32/src/usart/v2.rs
@@ -1,21 +1,18 @@
1use core::future::Future;
1use core::marker::PhantomData; 2use core::marker::PhantomData;
2
3use embassy::util::Unborrow; 3use embassy::util::Unborrow;
4use embassy_extras::unborrow; 4use embassy_extras::unborrow;
5
6use crate::pac::usart::{regs, vals};
7
8use super::*;
9use core::future::Future;
10use futures::TryFutureExt; 5use futures::TryFutureExt;
11 6
12use crate::dma_traits::NoDma; 7use super::*;
8use crate::dma::NoDma;
9use crate::pac::usart::{regs, vals};
13 10
14#[allow(dead_code)]
15pub struct Uart<'d, T: Instance, TxDma = NoDma, RxDma = NoDma> { 11pub struct Uart<'d, T: Instance, TxDma = NoDma, RxDma = NoDma> {
16 inner: T, 12 inner: T,
17 phantom: PhantomData<&'d mut T>, 13 phantom: PhantomData<&'d mut T>,
18 tx_dma: TxDma, 14 tx_dma: TxDma,
15 #[allow(dead_code)]
19 rx_dma: RxDma, 16 rx_dma: RxDma,
20} 17}
21 18
@@ -83,7 +80,7 @@ impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
83 } 80 }
84 let r = self.inner.regs(); 81 let r = self.inner.regs();
85 let dst = r.tdr().ptr() as *mut u8; 82 let dst = r.tdr().ptr() as *mut u8;
86 ch.transfer(buffer, dst).await; 83 ch.write(ch.request(), buffer, dst).await;
87 Ok(()) 84 Ok(())
88 } 85 }
89 86
diff --git a/examples/stm32f4/src/bin/spi.rs b/examples/stm32f4/src/bin/spi.rs
index dda0ee4ed..aa48ceed5 100644
--- a/examples/stm32f4/src/bin/spi.rs
+++ b/examples/stm32f4/src/bin/spi.rs
@@ -61,7 +61,7 @@ fn main() -> ! {
61 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); 61 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
62 62
63 loop { 63 loop {
64 let mut buf = [0x0A; 4]; 64 let mut buf = [0x0Au8; 4];
65 unwrap!(cs.set_low()); 65 unwrap!(cs.set_low());
66 unwrap!(spi.transfer(&mut buf)); 66 unwrap!(spi.transfer(&mut buf));
67 unwrap!(cs.set_high()); 67 unwrap!(cs.set_high());
diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs
index 42f154b05..31525036a 100644
--- a/examples/stm32f4/src/bin/usart.rs
+++ b/examples/stm32f4/src/bin/usart.rs
@@ -12,6 +12,7 @@ use cortex_m::prelude::_embedded_hal_blocking_serial_Write;
12use embassy::executor::Executor; 12use embassy::executor::Executor;
13use embassy::time::Clock; 13use embassy::time::Clock;
14use embassy::util::Forever; 14use embassy::util::Forever;
15use embassy_stm32::dma::NoDma;
15use embassy_stm32::usart::{Config, Uart}; 16use embassy_stm32::usart::{Config, Uart};
16use example_common::*; 17use example_common::*;
17 18
@@ -23,7 +24,7 @@ async fn main_task() {
23 let p = embassy_stm32::init(Default::default()); 24 let p = embassy_stm32::init(Default::default());
24 25
25 let config = Config::default(); 26 let config = Config::default();
26 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, config); 27 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, NoDma, NoDma, config);
27 28
28 usart.bwrite_all(b"Hello Embassy World!\r\n").unwrap(); 29 usart.bwrite_all(b"Hello Embassy World!\r\n").unwrap();
29 info!("wrote Hello, starting echo"); 30 info!("wrote Hello, starting echo");
diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs
index 66ca6242b..b578aebca 100644
--- a/examples/stm32f4/src/bin/usart_dma.rs
+++ b/examples/stm32f4/src/bin/usart_dma.rs
@@ -13,26 +13,25 @@ use cortex_m_rt::entry;
13use embassy::executor::Executor; 13use embassy::executor::Executor;
14use embassy::time::Clock; 14use embassy::time::Clock;
15use embassy::util::Forever; 15use embassy::util::Forever;
16use embassy_stm32::dma::NoDma;
16use embassy_stm32::usart::{Config, Uart}; 17use embassy_stm32::usart::{Config, Uart};
18use embassy_traits::uart::Write as _;
17use example_common::*; 19use example_common::*;
18use heapless::String; 20use heapless::String;
19use stm32f4::stm32f429 as pac; 21use stm32f4::stm32f429 as pac;
20 22
21#[embassy::task] 23#[embassy::task]
22async fn main_task() { 24async fn main_task() {
23 let mut p = embassy_stm32::init(Default::default()); 25 let p = embassy_stm32::init(Default::default());
24 26
25 let config = Config::default(); 27 let config = Config::default();
26 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, config); 28 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, p.DMA1_CH3, NoDma, config);
27 29
28 for n in 0u32.. { 30 for n in 0u32.. {
29 let mut s: String<128> = String::new(); 31 let mut s: String<128> = String::new();
30 core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap(); 32 core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap();
31 33
32 usart 34 usart.write(s.as_bytes()).await.unwrap();
33 .write_dma(&mut p.DMA1_3, s.as_bytes())
34 .await
35 .unwrap();
36 info!("wrote DMA"); 35 info!("wrote DMA");
37 } 36 }
38} 37}
diff --git a/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs
index d8e60158b..143f94491 100644
--- a/examples/stm32h7/src/bin/usart.rs
+++ b/examples/stm32h7/src/bin/usart.rs
@@ -1,4 +1,3 @@
1
2#![no_std] 1#![no_std]
3#![no_main] 2#![no_main]
4#![feature(trait_alias)] 3#![feature(trait_alias)]
@@ -13,12 +12,12 @@ use cortex_m::prelude::_embedded_hal_blocking_serial_Write;
13use embassy::executor::Executor; 12use embassy::executor::Executor;
14use embassy::time::Clock; 13use embassy::time::Clock;
15use embassy::util::Forever; 14use embassy::util::Forever;
15use embassy_stm32::dma::NoDma;
16use embassy_stm32::usart::{Config, Uart}; 16use embassy_stm32::usart::{Config, Uart};
17use embassy_stm32::dma_traits::NoDma;
18use example_common::*; 17use example_common::*;
19 18
20use stm32h7xx_hal as hal;
21use hal::prelude::*; 19use hal::prelude::*;
20use stm32h7xx_hal as hal;
22 21
23use cortex_m_rt::entry; 22use cortex_m_rt::entry;
24use stm32h7::stm32h743 as pac; 23use stm32h7::stm32h743 as pac;
@@ -60,8 +59,7 @@ fn main() -> ! {
60 59
61 let rcc = pp.RCC.constrain(); 60 let rcc = pp.RCC.constrain();
62 61
63 rcc 62 rcc.sys_ck(96.mhz())
64 .sys_ck(96.mhz())
65 .pclk1(48.mhz()) 63 .pclk1(48.mhz())
66 .pclk2(48.mhz()) 64 .pclk2(48.mhz())
67 .pclk3(48.mhz()) 65 .pclk3(48.mhz())
@@ -89,7 +87,6 @@ fn main() -> ! {
89 w 87 w
90 }); 88 });
91 89
92
93 unsafe { embassy::time::set_clock(&ZeroClock) }; 90 unsafe { embassy::time::set_clock(&ZeroClock) };
94 91
95 let executor = EXECUTOR.put(Executor::new()); 92 let executor = EXECUTOR.put(Executor::new());
diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs
new file mode 100644
index 000000000..0073d5c66
--- /dev/null
+++ b/examples/stm32h7/src/bin/usart_dma.rs
@@ -0,0 +1,100 @@
1#![no_std]
2#![no_main]
3#![feature(trait_alias)]
4#![feature(min_type_alias_impl_trait)]
5#![feature(impl_trait_in_bindings)]
6#![feature(type_alias_impl_trait)]
7#![allow(incomplete_features)]
8
9#[path = "../example_common.rs"]
10mod example_common;
11use core::fmt::Write;
12use embassy::executor::Executor;
13use embassy::time::Clock;
14use embassy::util::Forever;
15use embassy_stm32::dma::NoDma;
16use embassy_stm32::usart::{Config, Uart};
17use example_common::*;
18use embassy_traits::uart::Write as _Write;
19
20use hal::prelude::*;
21use stm32h7xx_hal as hal;
22
23use cortex_m_rt::entry;
24use stm32h7::stm32h743 as pac;
25use heapless::String;
26
27#[embassy::task]
28async fn main_task() {
29 let p = embassy_stm32::init(Default::default());
30
31 let config = Config::default();
32 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, p.DMA1_CH0, NoDma, config);
33
34 for n in 0u32.. {
35 let mut s: String<128> = String::new();
36 core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap();
37
38 usart.write(s.as_bytes()).await.ok();
39
40 info!("wrote DMA");
41 }
42
43}
44
45struct ZeroClock;
46
47impl Clock for ZeroClock {
48 fn now(&self) -> u64 {
49 0
50 }
51}
52
53static EXECUTOR: Forever<Executor> = Forever::new();
54
55#[entry]
56fn main() -> ! {
57 info!("Hello World!");
58
59 let pp = pac::Peripherals::take().unwrap();
60
61 let pwrcfg = pp.PWR.constrain().freeze();
62
63 let rcc = pp.RCC.constrain();
64
65 rcc.sys_ck(96.mhz())
66 .pclk1(48.mhz())
67 .pclk2(48.mhz())
68 .pclk3(48.mhz())
69 .pclk4(48.mhz())
70 .pll1_q_ck(48.mhz())
71 .freeze(pwrcfg, &pp.SYSCFG);
72
73 let pp = unsafe { pac::Peripherals::steal() };
74
75 pp.DBGMCU.cr.modify(|_, w| {
76 w.dbgsleep_d1().set_bit();
77 w.dbgstby_d1().set_bit();
78 w.dbgstop_d1().set_bit();
79 w.d1dbgcken().set_bit();
80 w
81 });
82
83 pp.RCC.ahb4enr.modify(|_, w| {
84 w.gpioaen().set_bit();
85 w.gpioben().set_bit();
86 w.gpiocen().set_bit();
87 w.gpioden().set_bit();
88 w.gpioeen().set_bit();
89 w.gpiofen().set_bit();
90 w
91 });
92
93 unsafe { embassy::time::set_clock(&ZeroClock) };
94
95 let executor = EXECUTOR.put(Executor::new());
96
97 executor.run(|spawner| {
98 unwrap!(spawner.spawn(main_task()));
99 })
100}
diff --git a/examples/stm32l4/src/bin/spi.rs b/examples/stm32l4/src/bin/spi.rs
index 45ccfcebc..7cac01fd4 100644
--- a/examples/stm32l4/src/bin/spi.rs
+++ b/examples/stm32l4/src/bin/spi.rs
@@ -57,7 +57,7 @@ fn main() -> ! {
57 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); 57 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
58 58
59 loop { 59 loop {
60 let mut buf = [0x0A; 4]; 60 let mut buf = [0x0Au8; 4];
61 unwrap!(cs.set_low()); 61 unwrap!(cs.set_low());
62 unwrap!(spi.transfer(&mut buf)); 62 unwrap!(spi.transfer(&mut buf));
63 unwrap!(cs.set_high()); 63 unwrap!(cs.set_high());
diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs
index e9a44f151..f572b1eff 100644
--- a/examples/stm32l4/src/bin/usart.rs
+++ b/examples/stm32l4/src/bin/usart.rs
@@ -13,7 +13,7 @@ use cortex_m_rt::entry;
13use embassy::executor::Executor; 13use embassy::executor::Executor;
14use embassy::time::Clock; 14use embassy::time::Clock;
15use embassy::util::Forever; 15use embassy::util::Forever;
16use embassy_stm32::dma_traits::NoDma; 16use embassy_stm32::dma::NoDma;
17use embassy_stm32::pac; 17use embassy_stm32::pac;
18use embassy_stm32::usart::{Config, Uart}; 18use embassy_stm32::usart::{Config, Uart};
19use example_common::*; 19use example_common::*;
diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs
index 1eadd3ad4..e325e3da3 100644
--- a/examples/stm32l4/src/bin/usart_dma.rs
+++ b/examples/stm32l4/src/bin/usart_dma.rs
@@ -13,7 +13,7 @@ use cortex_m_rt::entry;
13use embassy::executor::Executor; 13use embassy::executor::Executor;
14use embassy::time::Clock; 14use embassy::time::Clock;
15use embassy::util::Forever; 15use embassy::util::Forever;
16use embassy_stm32::dma_traits::NoDma; 16use embassy_stm32::dma::NoDma;
17use embassy_stm32::pac; 17use embassy_stm32::pac;
18use embassy_stm32::usart::{Config, Uart}; 18use embassy_stm32::usart::{Config, Uart};
19use embassy_traits::uart::Write as _; 19use embassy_traits::uart::Write as _;
@@ -25,7 +25,7 @@ async fn main_task() {
25 let p = embassy_stm32::init(Default::default()); 25 let p = embassy_stm32::init(Default::default());
26 26
27 let config = Config::default(); 27 let config = Config::default();
28 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, p.DMA1_3, NoDma, config); 28 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, p.DMA1_CH3, NoDma, config);
29 29
30 for n in 0u32.. { 30 for n in 0u32.. {
31 let mut s: String<128> = String::new(); 31 let mut s: String<128> = String::new();
diff --git a/stm32-data b/stm32-data
Subproject 32ca79020ec7523fe4c3fcfc02006cb1ea637a1 Subproject 8702a3a3bb83a59515dab2cf9f75952fa6edae8
diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs
index a9ee88002..fee991111 100644
--- a/stm32-metapac-gen/src/lib.rs
+++ b/stm32-metapac-gen/src/lib.rs
@@ -49,8 +49,6 @@ pub struct Peripheral {
49 pub pins: Vec<Pin>, 49 pub pins: Vec<Pin>,
50 #[serde(default)] 50 #[serde(default)]
51 pub dma_channels: HashMap<String, Vec<PeripheralDmaChannel>>, 51 pub dma_channels: HashMap<String, Vec<PeripheralDmaChannel>>,
52 #[serde(default)]
53 pub dma_requests: HashMap<String, u32>,
54} 52}
55 53
56#[derive(Debug, Eq, PartialEq, Clone, Deserialize)] 54#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
@@ -64,11 +62,14 @@ pub struct Pin {
64pub struct DmaChannel { 62pub struct DmaChannel {
65 pub dma: String, 63 pub dma: String,
66 pub channel: u32, 64 pub channel: u32,
65 pub dmamux: Option<String>,
66 pub dmamux_channel: Option<u32>,
67} 67}
68 68
69#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Hash)] 69#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Hash)]
70pub struct PeripheralDmaChannel { 70pub struct PeripheralDmaChannel {
71 pub channel: String, 71 pub channel: Option<String>,
72 pub dmamux: Option<String>,
72 pub request: Option<u32>, 73 pub request: Option<u32>,
73} 74}
74 75
@@ -266,24 +267,18 @@ pub fn gen(options: Options) {
266 let mut peripheral_pins_table: Vec<Vec<String>> = Vec::new(); 267 let mut peripheral_pins_table: Vec<Vec<String>> = Vec::new();
267 let mut peripheral_rcc_table: Vec<Vec<String>> = Vec::new(); 268 let mut peripheral_rcc_table: Vec<Vec<String>> = Vec::new();
268 let mut dma_channels_table: Vec<Vec<String>> = Vec::new(); 269 let mut dma_channels_table: Vec<Vec<String>> = Vec::new();
269 let mut bdma_channels_table: Vec<Vec<String>> = Vec::new();
270 let mut dma_requests_table: Vec<Vec<String>> = Vec::new();
271 let mut peripheral_dma_channels_table: Vec<Vec<String>> = Vec::new(); 270 let mut peripheral_dma_channels_table: Vec<Vec<String>> = Vec::new();
272 let mut peripheral_counts: HashMap<String, u8> = HashMap::new(); 271 let mut peripheral_counts: HashMap<String, u8> = HashMap::new();
273 let mut dma_channel_counts: HashMap<String, u8> = HashMap::new(); 272 let mut dma_channel_counts: HashMap<String, u8> = HashMap::new();
274 273
275 let dma_base = core
276 .peripherals
277 .get(&"DMA".to_string())
278 .unwrap_or_else(|| core.peripherals.get(&"DMA1".to_string()).unwrap())
279 .address;
280 let dma_stride = 0x400;
281
282 let gpio_base = core.peripherals.get(&"GPIOA".to_string()).unwrap().address; 274 let gpio_base = core.peripherals.get(&"GPIOA".to_string()).unwrap().address;
283 let gpio_stride = 0x400; 275 let gpio_stride = 0x400;
284 276
285 let number_suffix_re = Regex::new("^(.*?)[0-9]*$").unwrap(); 277 let number_suffix_re = Regex::new("^(.*?)[0-9]*$").unwrap();
286 278
279 let mut has_bdma = false;
280 let mut has_dma = false;
281
287 for (name, p) in &core.peripherals { 282 for (name, p) in &core.peripherals {
288 let captures = number_suffix_re.captures(&name).unwrap(); 283 let captures = number_suffix_re.captures(&name).unwrap();
289 let root_peri_name = captures.get(1).unwrap().as_str().to_string(); 284 let root_peri_name = captures.get(1).unwrap().as_str().to_string();
@@ -303,6 +298,12 @@ pub fn gen(options: Options) {
303 if let Some(block) = &p.block { 298 if let Some(block) = &p.block {
304 let bi = BlockInfo::parse(block); 299 let bi = BlockInfo::parse(block);
305 300
301 if bi.module == "bdma" {
302 has_bdma = true
303 } else if bi.module == "dma" {
304 has_dma = true
305 }
306
306 peripheral_counts.insert( 307 peripheral_counts.insert(
307 bi.module.clone(), 308 bi.module.clone(),
308 peripheral_counts.get(&bi.module).map_or(1, |v| v + 1), 309 peripheral_counts.get(&bi.module).map_or(1, |v| v + 1),
@@ -321,27 +322,24 @@ pub fn gen(options: Options) {
321 peripheral_pins_table.push(row); 322 peripheral_pins_table.push(row);
322 } 323 }
323 324
324 for dma_request in &p.dma_requests { 325 for (request, dma_channels) in &p.dma_channels {
325 let mut row = Vec::new();
326 row.push(bi.module.clone());
327 row.push(name.clone());
328 row.push(dma_request.0.clone());
329 row.push(dma_request.1.to_string());
330 dma_requests_table.push(row);
331 }
332
333 for (event, dma_channels) in &p.dma_channels {
334 for channel in dma_channels.iter() { 326 for channel in dma_channels.iter() {
335 let mut row = Vec::new(); 327 let mut row = Vec::new();
336 row.push(name.clone()); 328 row.push(name.clone());
337 row.push(bi.module.clone()); 329 row.push(bi.module.clone());
338 row.push(bi.block.clone()); 330 row.push(bi.block.clone());
339 row.push(event.clone()); 331 row.push(request.clone());
340 row.push(channel.channel.clone()); 332 if let Some(channel) = &channel.channel {
341 row.push(core.dma_channels[&channel.channel].dma.clone()); 333 row.push(format!("{{channel: {}}}", channel));
342 row.push(core.dma_channels[&channel.channel].channel.to_string()); 334 } else if let Some(dmamux) = &channel.dmamux {
335 row.push(format!("{{dmamux: {}}}", dmamux));
336 } else {
337 unreachable!();
338 }
343 if let Some(request) = channel.request { 339 if let Some(request) = channel.request {
344 row.push(request.to_string()); 340 row.push(request.to_string());
341 } else {
342 row.push("()".to_string());
345 } 343 }
346 peripheral_dma_channels_table.push(row); 344 peripheral_dma_channels_table.push(row);
347 } 345 }
@@ -381,15 +379,6 @@ pub fn gen(options: Options) {
381 ]); 379 ]);
382 } 380 }
383 } 381 }
384 "dma" => {
385 let dma_num = if name == "DMA" {
386 0
387 } else {
388 let dma_letter = name.chars().skip(3).next().unwrap();
389 dma_letter as u32 - '1' as u32
390 };
391 assert_eq!(p.address, dma_base + dma_stride * dma_num);
392 }
393 _ => {} 382 _ => {}
394 } 383 }
395 384
@@ -489,21 +478,25 @@ pub fn gen(options: Options) {
489 478
490 for (id, channel_info) in &core.dma_channels { 479 for (id, channel_info) in &core.dma_channels {
491 let mut row = Vec::new(); 480 let mut row = Vec::new();
492 let dma_peri = core.peripherals.get(&channel_info.dma); 481 let dma_peri = core.peripherals.get(&channel_info.dma).unwrap();
482 let bi = BlockInfo::parse(dma_peri.block.as_ref().unwrap());
483
493 row.push(id.clone()); 484 row.push(id.clone());
494 row.push(channel_info.dma.clone()); 485 row.push(channel_info.dma.clone());
486 row.push(bi.module.clone());
495 row.push(channel_info.channel.to_string()); 487 row.push(channel_info.channel.to_string());
496 if let Some(dma_peri) = dma_peri { 488 if let Some(dmamux) = &channel_info.dmamux {
497 if let Some(ref block) = dma_peri.block { 489 let dmamux_channel = channel_info.dmamux_channel.unwrap();
498 let bi = BlockInfo::parse(block); 490 row.push(format!(
499 if bi.module == "bdma" { 491 "{{dmamux: {}, dmamux_channel: {}}}",
500 bdma_channels_table.push(row); 492 dmamux, dmamux_channel
501 } else { 493 ));
502 dma_channels_table.push(row); 494 } else {
503 } 495 row.push("{}".to_string());
504 }
505 } 496 }
506 497
498 dma_channels_table.push(row);
499
507 let dma_peri_name = channel_info.dma.clone(); 500 let dma_peri_name = channel_info.dma.clone();
508 dma_channel_counts.insert( 501 dma_channel_counts.insert(
509 dma_peri_name.clone(), 502 dma_peri_name.clone(),
@@ -522,8 +515,17 @@ pub fn gen(options: Options) {
522 515
523 interrupt_table.push(vec![name.clone()]); 516 interrupt_table.push(vec![name.clone()]);
524 517
525 if name.starts_with("DMA") || name.contains("_DMA") { 518 if name.starts_with("DMA1_") || name.starts_with("DMA2_") || name.contains("_DMA") {
526 interrupt_table.push(vec!["DMA".to_string(), name.clone()]); 519 if has_dma {
520 interrupt_table.push(vec!["DMA".to_string(), name.clone()]);
521 } else if has_bdma {
522 interrupt_table.push(vec!["BDMA".to_string(), name.clone()]);
523 }
524 }
525
526 if name.starts_with("BDMA_") || name.starts_with("BDMA1_") || name.starts_with("BDMA2_")
527 {
528 interrupt_table.push(vec!["BDMA".to_string(), name.clone()]);
527 } 529 }
528 530
529 if name.contains("EXTI") { 531 if name.contains("EXTI") {
@@ -557,8 +559,6 @@ pub fn gen(options: Options) {
557 ); 559 );
558 make_table(&mut extra, "peripheral_rcc", &peripheral_rcc_table); 560 make_table(&mut extra, "peripheral_rcc", &peripheral_rcc_table);
559 make_table(&mut extra, "dma_channels", &dma_channels_table); 561 make_table(&mut extra, "dma_channels", &dma_channels_table);
560 make_table(&mut extra, "bdma_channels", &bdma_channels_table);
561 make_table(&mut extra, "dma_requests", &dma_requests_table);
562 make_peripheral_counts(&mut extra, &peripheral_counts); 562 make_peripheral_counts(&mut extra, &peripheral_counts);
563 make_dma_channel_counts(&mut extra, &dma_channel_counts); 563 make_dma_channel_counts(&mut extra, &dma_channel_counts);
564 564