aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob McWhirter <[email protected]>2021-07-13 13:33:38 -0400
committerGitHub <[email protected]>2021-07-13 13:33:38 -0400
commitb6eb5dcf2f0f06527a7ed677f44cb0528c6b182e (patch)
treea3851981c44ca0e9fd5e34c6b97935a142c3b832
parent8f28d6b4b1e74b3b3b64fd3a28ce1ea9072b7cbb (diff)
parent6e0e83cfd907c504c8d2ce05a7304b49565361ff (diff)
Merge pull request #282 from bobmcwhirter/dmamux_thales
BDMA + DMAMUX + H7 with major help from @thalesfragoso
-rw-r--r--embassy-stm32/src/bdma/mod.rs430
-rw-r--r--embassy-stm32/src/dma/mod.rs23
-rw-r--r--embassy-stm32/src/dma/v2.rs3
-rw-r--r--embassy-stm32/src/dma_traits.rs21
-rw-r--r--embassy-stm32/src/dmamux/mod.rs137
-rw-r--r--embassy-stm32/src/lib.rs14
-rw-r--r--embassy-stm32/src/rcc/h7/mod.rs1
-rw-r--r--embassy-stm32/src/rcc/l0/mod.rs2
-rw-r--r--embassy-stm32/src/rcc/mod.rs3
-rw-r--r--embassy-stm32/src/usart/mod.rs16
-rw-r--r--embassy-stm32/src/usart/v2.rs118
-rw-r--r--embassy-stm32/src/usart/v3.rs2
-rw-r--r--examples/stm32l4/src/bin/usart.rs4
-rw-r--r--examples/stm32l4/src/bin/usart_dma.rs96
m---------stm32-data0
-rw-r--r--stm32-metapac-gen/src/lib.rs74
16 files changed, 846 insertions, 98 deletions
diff --git a/embassy-stm32/src/bdma/mod.rs b/embassy-stm32/src/bdma/mod.rs
index e85ade5df..39e8bec3b 100644
--- a/embassy-stm32/src/bdma/mod.rs
+++ b/embassy-stm32/src/bdma/mod.rs
@@ -1,69 +1,413 @@
1#![macro_use] 1#![macro_use]
2 2
3#[cfg_attr(bdma_v1, path = "v1.rs")] 3use core::future::Future;
4#[cfg_attr(bdma_v2, path = "v2.rs")] 4use core::task::Poll;
5mod _version;
6 5
7#[allow(unused)] 6use atomic_polyfill::{AtomicU8, Ordering};
8pub use _version::*; 7use embassy::interrupt::{Interrupt, InterruptExt};
8use embassy::util::{AtomicWaker, OnDrop};
9use futures::future::poll_fn;
9 10
11use crate::dma_traits::{ReadDma, WriteDma};
12use crate::interrupt;
10use crate::pac; 13use crate::pac;
11use crate::peripherals; 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::enable();
181 };
182 }
183}
12 184
13pub(crate) mod sealed { 185pub(crate) mod sealed {
14 use super::*; 186 use super::*;
15 187
188 pub trait Dma {
189 const NUM: u8;
190 }
191
16 pub trait Channel { 192 pub trait Channel {
17 fn num(&self) -> u8; 193 const CH_NUM: u8;
194 const STATE_NUM: u8;
195 const DMA_REGS: pac::bdma::Dma;
18 196
19 fn dma_num(&self) -> u8 { 197 fn regs(&self) -> pac::bdma::Ch {
20 self.num() / 8 198 Self::DMA_REGS.ch(Self::CH_NUM as usize)
21 }
22 fn ch_num(&self) -> u8 {
23 self.num() % 8
24 }
25 fn regs(&self) -> pac::dma::Dma {
26 pac::DMA(self.num() as _)
27 } 199 }
28 } 200 }
29} 201}
30 202
203pub trait Dma: sealed::Dma + Sized {}
31pub trait Channel: sealed::Channel + Sized {} 204pub trait Channel: sealed::Channel + Sized {}
32 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
33macro_rules! impl_dma_channel { 215macro_rules! impl_dma_channel {
34 ($channel_peri:ident, $dma_num:expr, $ch_num:expr) => { 216 ($channel_peri:ident, $dma_peri:ident, $ch_num:expr) => {
35 impl Channel for peripherals::$channel_peri {} 217 impl Channel for crate::peripherals::$channel_peri {}
36 impl sealed::Channel for peripherals::$channel_peri { 218 impl sealed::Channel for crate::peripherals::$channel_peri {
37 #[inline] 219 const CH_NUM: u8 = $ch_num;
38 fn num(&self) -> u8 { 220 const STATE_NUM: u8 = (dma_num!($dma_peri) * 8) + $ch_num;
39 $dma_num * 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 }
40 } 357 }
41 } 358 }
42 }; 359 };
43} 360}
44 361
45/* 362macro_rules! dma_num {
46crate::pac::peripherals!( 363 (DMA1) => {
47 (dma,DMA1) => { 364 0
48 impl_dma_channel!(DMA1_CH0, 0, 0); 365 };
49 impl_dma_channel!(DMA1_CH1, 0, 1); 366 (DMA2) => {
50 impl_dma_channel!(DMA1_CH2, 0, 2); 367 1
51 impl_dma_channel!(DMA1_CH3, 0, 3); 368 };
52 impl_dma_channel!(DMA1_CH4, 0, 4); 369 (BDMA) => {
53 impl_dma_channel!(DMA1_CH5, 0, 5); 370 0
54 impl_dma_channel!(DMA1_CH6, 0, 6); 371 };
55 impl_dma_channel!(DMA1_CH7, 0, 7); 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 {}
56 }; 404 };
57 405
58 (dma,DMA2) => { 406 (uart, $peri:ident) => {
59 impl_dma_channel!(DMA2_CH0, 1, 0); 407 impl<T:Channel + crate::dma_traits::WriteDma<crate::peripherals::$peri>> usart::TxDma<crate::peripherals::$peri> for T {}
60 impl_dma_channel!(DMA2_CH1, 1, 1); 408 impl<T:Channel + crate::dma_traits::WriteDma<crate::peripherals::$peri>> usart::sealed::TxDma<crate::peripherals::$peri> for T {}
61 impl_dma_channel!(DMA2_CH2, 1, 2); 409
62 impl_dma_channel!(DMA2_CH3, 1, 3); 410 impl<T:Channel + crate::dma_traits::ReadDma<crate::peripherals::$peri>> usart::RxDma<crate::peripherals::$peri> for T {}
63 impl_dma_channel!(DMA2_CH4, 1, 4); 411 impl<T:Channel + crate::dma_traits::ReadDma<crate::peripherals::$peri>> usart::sealed::RxDma<crate::peripherals::$peri> for T {}
64 impl_dma_channel!(DMA2_CH5, 1, 5);
65 impl_dma_channel!(DMA2_CH6, 1, 6);
66 impl_dma_channel!(DMA2_CH7, 1, 7);
67 }; 412 };
68); 413}
69 */
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index 466cfa033..ed080cd16 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -1,6 +1,5 @@
1#![macro_use] 1#![macro_use]
2 2
3#[cfg(dma)]
4#[cfg_attr(dma_v1, path = "v1.rs")] 3#[cfg_attr(dma_v1, path = "v1.rs")]
5#[cfg_attr(dma_v2, path = "v2.rs")] 4#[cfg_attr(dma_v2, path = "v2.rs")]
6mod _version; 5mod _version;
@@ -8,25 +7,3 @@ mod _version;
8#[cfg(dma)] 7#[cfg(dma)]
9#[allow(unused)] 8#[allow(unused)]
10pub use _version::*; 9pub use _version::*;
11
12use core::future::Future;
13
14pub trait WriteDma<T> {
15 type WriteDmaFuture<'a>: Future<Output = ()> + 'a
16 where
17 Self: 'a;
18
19 fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a>
20 where
21 T: 'a;
22}
23
24pub trait ReadDma<T> {
25 type ReadDmaFuture<'a>: Future<Output = ()> + 'a
26 where
27 Self: 'a;
28
29 fn transfer<'a>(&'a mut self, src: *const u8, buf: &'a mut [u8]) -> Self::ReadDmaFuture<'a>
30 where
31 T: 'a;
32}
diff --git a/embassy-stm32/src/dma/v2.rs b/embassy-stm32/src/dma/v2.rs
index e7cd24710..df3b922ff 100644
--- a/embassy-stm32/src/dma/v2.rs
+++ b/embassy-stm32/src/dma/v2.rs
@@ -1,11 +1,12 @@
1use core::task::Poll; 1use core::task::Poll;
2 2
3use crate::dma_traits::{ReadDma, WriteDma};
3use atomic_polyfill::{AtomicU8, Ordering}; 4use atomic_polyfill::{AtomicU8, Ordering};
5use core::future::Future;
4use embassy::interrupt::{Interrupt, InterruptExt}; 6use embassy::interrupt::{Interrupt, InterruptExt};
5use embassy::util::AtomicWaker; 7use embassy::util::AtomicWaker;
6use futures::future::poll_fn; 8use futures::future::poll_fn;
7 9
8use super::*;
9use crate::interrupt; 10use crate::interrupt;
10use crate::pac; 11use crate::pac;
11use crate::pac::dma::{regs, vals}; 12use crate::pac::dma::{regs, vals};
diff --git a/embassy-stm32/src/dma_traits.rs b/embassy-stm32/src/dma_traits.rs
new file mode 100644
index 000000000..8f1a9f40e
--- /dev/null
+++ b/embassy-stm32/src/dma_traits.rs
@@ -0,0 +1,21 @@
1use core::future::Future;
2
3pub trait WriteDma<T> {
4 type WriteDmaFuture<'a>: Future<Output = ()> + 'a
5 where
6 Self: 'a;
7
8 fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a>
9 where
10 T: 'a;
11}
12
13pub trait ReadDma<T> {
14 type ReadDmaFuture<'a>: Future<Output = ()> + 'a
15 where
16 Self: 'a;
17
18 fn transfer<'a>(&'a mut self, src: *const u8, buf: &'a mut [u8]) -> Self::ReadDmaFuture<'a>
19 where
20 T: 'a;
21}
diff --git a/embassy-stm32/src/dmamux/mod.rs b/embassy-stm32/src/dmamux/mod.rs
new file mode 100644
index 000000000..ecea0b290
--- /dev/null
+++ b/embassy-stm32/src/dmamux/mod.rs
@@ -0,0 +1,137 @@
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 76a6ecd88..4b2826ae8 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -20,14 +20,21 @@ pub mod gpio;
20pub mod rcc; 20pub mod rcc;
21 21
22// Sometimes-present hardware 22// Sometimes-present hardware
23#[cfg(any(dma, bdma, dmamux))]
24pub mod dma_traits;
25
23#[cfg(adc)] 26#[cfg(adc)]
24pub mod adc; 27pub mod adc;
28#[cfg(bdma)]
29pub mod bdma;
25#[cfg(timer)] 30#[cfg(timer)]
26pub mod clock; 31pub mod clock;
27#[cfg(dac)] 32#[cfg(dac)]
28pub mod dac; 33pub mod dac;
29#[cfg(any(dma, dmamux))] 34#[cfg(dma)]
30pub mod dma; 35pub mod dma;
36#[cfg(dmamux)]
37pub mod dmamux;
31#[cfg(all(eth, feature = "net"))] 38#[cfg(all(eth, feature = "net"))]
32pub mod eth; 39pub mod eth;
33#[cfg(exti)] 40#[cfg(exti)]
@@ -86,8 +93,13 @@ pub fn init(config: Config) -> Peripherals {
86 unsafe { 93 unsafe {
87 #[cfg(dma)] 94 #[cfg(dma)]
88 dma::init(); 95 dma::init();
96 #[cfg(bdma)]
97 bdma::init();
98 #[cfg(dmamux)]
99 dmamux::init();
89 #[cfg(exti)] 100 #[cfg(exti)]
90 exti::init(); 101 exti::init();
102
91 rcc::init(config.rcc); 103 rcc::init(config.rcc);
92 } 104 }
93 105
diff --git a/embassy-stm32/src/rcc/h7/mod.rs b/embassy-stm32/src/rcc/h7/mod.rs
index 309902335..5ec531820 100644
--- a/embassy-stm32/src/rcc/h7/mod.rs
+++ b/embassy-stm32/src/rcc/h7/mod.rs
@@ -532,6 +532,7 @@ pub unsafe fn init(config: Config) {
532 ahb1: core_clocks.hclk, 532 ahb1: core_clocks.hclk,
533 ahb2: core_clocks.hclk, 533 ahb2: core_clocks.hclk,
534 ahb3: core_clocks.hclk, 534 ahb3: core_clocks.hclk,
535 ahb4: core_clocks.hclk,
535 apb1: core_clocks.pclk1, 536 apb1: core_clocks.pclk1,
536 apb2: core_clocks.pclk2, 537 apb2: core_clocks.pclk2,
537 apb4: core_clocks.pclk4, 538 apb4: core_clocks.pclk4,
diff --git a/embassy-stm32/src/rcc/l0/mod.rs b/embassy-stm32/src/rcc/l0/mod.rs
index 0b11e708f..6107d5f55 100644
--- a/embassy-stm32/src/rcc/l0/mod.rs
+++ b/embassy-stm32/src/rcc/l0/mod.rs
@@ -170,7 +170,7 @@ impl<'d> Rcc<'d> {
170 pub fn enable_debug_wfe(&mut self, _dbg: &mut peripherals::DBGMCU, enable_dma: bool) { 170 pub fn enable_debug_wfe(&mut self, _dbg: &mut peripherals::DBGMCU, enable_dma: bool) {
171 // NOTE(unsafe) We have exclusive access to the RCC and DBGMCU 171 // NOTE(unsafe) We have exclusive access to the RCC and DBGMCU
172 unsafe { 172 unsafe {
173 pac::RCC.ahbenr().modify(|w| w.set_dmaen(enable_dma)); 173 pac::RCC.ahbenr().modify(|w| w.set_dma1en(enable_dma));
174 174
175 pac::DBGMCU.cr().modify(|w| { 175 pac::DBGMCU.cr().modify(|w| {
176 w.set_dbg_sleep(true); 176 w.set_dbg_sleep(true);
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index c7d1ae615..b7b692f15 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -27,6 +27,9 @@ pub struct Clocks {
27 pub ahb3: Hertz, 27 pub ahb3: Hertz,
28 28
29 #[cfg(any(rcc_h7))] 29 #[cfg(any(rcc_h7))]
30 pub ahb4: Hertz,
31
32 #[cfg(any(rcc_h7))]
30 pub apb4: Hertz, 33 pub apb4: Hertz,
31} 34}
32 35
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 2fa758ecc..ddaed5bb9 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -8,7 +8,6 @@ use crate::peripherals;
8pub use _version::*; 8pub use _version::*;
9 9
10use crate::gpio::Pin; 10use crate::gpio::Pin;
11use crate::pac::usart::Usart;
12use crate::rcc::RccPeripheral; 11use crate::rcc::RccPeripheral;
13 12
14#[derive(Clone, Copy, PartialEq, Eq, Debug)] 13#[derive(Clone, Copy, PartialEq, Eq, Debug)]
@@ -58,6 +57,7 @@ impl Default for Config {
58 57
59/// Serial error 58/// Serial error
60#[derive(Debug, Eq, PartialEq, Copy, Clone)] 59#[derive(Debug, Eq, PartialEq, Copy, Clone)]
60#[cfg_attr(feature = "defmt", derive(defmt::Format))]
61#[non_exhaustive] 61#[non_exhaustive]
62pub enum Error { 62pub enum Error {
63 /// Framing error 63 /// Framing error
@@ -73,11 +73,11 @@ pub enum Error {
73pub(crate) mod sealed { 73pub(crate) mod sealed {
74 use super::*; 74 use super::*;
75 75
76 #[cfg(any(dma, dmamux))] 76 #[cfg(any(dma, bdma, dmamux))]
77 use crate::dma::WriteDma; 77 use crate::dma_traits::WriteDma;
78 78
79 pub trait Instance { 79 pub trait Instance {
80 fn regs(&self) -> Usart; 80 fn regs(&self) -> crate::pac::usart::Usart;
81 } 81 }
82 pub trait RxPin<T: Instance>: Pin { 82 pub trait RxPin<T: Instance>: Pin {
83 fn af_num(&self) -> u8; 83 fn af_num(&self) -> u8;
@@ -95,10 +95,10 @@ pub(crate) mod sealed {
95 fn af_num(&self) -> u8; 95 fn af_num(&self) -> u8;
96 } 96 }
97 97
98 #[cfg(any(dma, dmamux))] 98 #[cfg(any(bdma, dma, dmamux))]
99 pub trait RxDma<T: Instance> {} 99 pub trait RxDma<T: Instance> {}
100 100
101 #[cfg(any(dma, dmamux))] 101 #[cfg(any(bdma, dma, dmamux))]
102 pub trait TxDma<T: Instance>: WriteDma<T> {} 102 pub trait TxDma<T: Instance>: WriteDma<T> {}
103} 103}
104 104
@@ -109,10 +109,10 @@ pub trait CtsPin<T: Instance>: sealed::CtsPin<T> {}
109pub trait RtsPin<T: Instance>: sealed::RtsPin<T> {} 109pub trait RtsPin<T: Instance>: sealed::RtsPin<T> {}
110pub trait CkPin<T: Instance>: sealed::CkPin<T> {} 110pub trait CkPin<T: Instance>: sealed::CkPin<T> {}
111 111
112#[cfg(any(dma, dmamux))] 112#[cfg(any(bdma, dma, dmamux))]
113pub trait RxDma<T: Instance>: sealed::RxDma<T> {} 113pub trait RxDma<T: Instance>: sealed::RxDma<T> {}
114 114
115#[cfg(any(dma, dmamux))] 115#[cfg(any(bdma, dma, dmamux))]
116pub trait TxDma<T: Instance>: sealed::TxDma<T> {} 116pub trait TxDma<T: Instance>: sealed::TxDma<T> {}
117 117
118crate::pac::peripherals!( 118crate::pac::peripherals!(
diff --git a/embassy-stm32/src/usart/v2.rs b/embassy-stm32/src/usart/v2.rs
index 8b1378917..22041b4aa 100644
--- a/embassy-stm32/src/usart/v2.rs
+++ b/embassy-stm32/src/usart/v2.rs
@@ -1 +1,119 @@
1use core::marker::PhantomData;
1 2
3use embassy::util::Unborrow;
4use embassy_extras::unborrow;
5
6use crate::pac::usart::vals;
7
8use super::*;
9
10pub struct Uart<'d, T: Instance> {
11 inner: T,
12 phantom: PhantomData<&'d mut T>,
13}
14
15impl<'d, T: Instance> Uart<'d, T> {
16 pub fn new(
17 inner: impl Unborrow<Target = T>,
18 rx: impl Unborrow<Target = impl RxPin<T>>,
19 tx: impl Unborrow<Target = impl TxPin<T>>,
20 config: Config,
21 ) -> Self {
22 unborrow!(inner, rx, tx);
23
24 T::enable();
25 let pclk_freq = T::frequency();
26
27 // TODO: better calculation, including error checking and OVER8 if possible.
28 let div = pclk_freq.0 / config.baudrate;
29
30 let r = inner.regs();
31
32 unsafe {
33 rx.set_as_af(rx.af_num());
34 tx.set_as_af(tx.af_num());
35
36 r.cr2().write(|_w| {});
37 r.cr3().write(|_w| {});
38
39 r.brr().write(|w| w.set_brr(div as u16));
40 r.cr1().write(|w| {
41 w.set_ue(true);
42 w.set_te(true);
43 w.set_re(true);
44 w.set_m0(vals::M0::BIT8);
45 w.set_m1(vals::M1::M0);
46 w.set_pce(config.parity != Parity::ParityNone);
47 w.set_ps(match config.parity {
48 Parity::ParityOdd => vals::Ps::ODD,
49 Parity::ParityEven => vals::Ps::EVEN,
50 _ => vals::Ps::EVEN,
51 });
52 });
53 }
54
55 Self {
56 inner,
57 phantom: PhantomData,
58 }
59 }
60
61 #[cfg(bdma)]
62 pub async fn write_dma(&mut self, ch: &mut impl TxDma<T>, buffer: &[u8]) -> Result<(), Error> {
63 unsafe {
64 self.inner.regs().cr3().modify(|reg| {
65 reg.set_dmat(true);
66 });
67 }
68 let r = self.inner.regs();
69 let dst = r.tdr().ptr() as *mut u8;
70 ch.transfer(buffer, dst).await;
71 Ok(())
72 }
73
74 pub fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
75 unsafe {
76 let r = self.inner.regs();
77 for b in buffer {
78 loop {
79 let sr = r.isr().read();
80 if sr.pe() {
81 r.rdr().read();
82 return Err(Error::Parity);
83 } else if sr.fe() {
84 r.rdr().read();
85 return Err(Error::Framing);
86 } else if sr.ore() {
87 r.rdr().read();
88 return Err(Error::Overrun);
89 } else if sr.rxne() {
90 break;
91 }
92 }
93 *b = r.rdr().read().0 as u8;
94 }
95 }
96 Ok(())
97 }
98}
99
100impl<'d, T: Instance> embedded_hal::blocking::serial::Write<u8> for Uart<'d, T> {
101 type Error = Error;
102 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
103 unsafe {
104 let r = self.inner.regs();
105 for &b in buffer {
106 while !r.isr().read().txe() {}
107 r.tdr().write(|w| w.set_dr(b as u16));
108 }
109 }
110 Ok(())
111 }
112 fn bflush(&mut self) -> Result<(), Self::Error> {
113 unsafe {
114 let r = self.inner.regs();
115 while !r.isr().read().tc() {}
116 }
117 Ok(())
118 }
119}
diff --git a/embassy-stm32/src/usart/v3.rs b/embassy-stm32/src/usart/v3.rs
index 1e9051443..0071c597a 100644
--- a/embassy-stm32/src/usart/v3.rs
+++ b/embassy-stm32/src/usart/v3.rs
@@ -57,7 +57,7 @@ impl<'d, T: Instance> Uart<'d, T> {
57 } 57 }
58 } 58 }
59 59
60 #[cfg(dma)] 60 #[cfg(any(dma, dmamux))]
61 pub async fn write_dma(&mut self, ch: &mut impl TxDma<T>, buffer: &[u8]) -> Result<(), Error> { 61 pub async fn write_dma(&mut self, ch: &mut impl TxDma<T>, buffer: &[u8]) -> Result<(), Error> {
62 unsafe { 62 unsafe {
63 self.inner.regs().cr3().modify(|reg| { 63 self.inner.regs().cr3().modify(|reg| {
diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs
index 5b6d9eaa1..0b14eeb59 100644
--- a/examples/stm32l4/src/bin/usart.rs
+++ b/examples/stm32l4/src/bin/usart.rs
@@ -82,10 +82,6 @@ fn main() -> ! {
82 w.syscfgen().set_bit(); 82 w.syscfgen().set_bit();
83 w 83 w
84 }); 84 });
85 //pp.RCC.apb1enr.modify(|_, w| {
86 //w.usart3en().enabled();
87 //w
88 //});
89 85
90 unsafe { embassy::time::set_clock(&ZeroClock) }; 86 unsafe { embassy::time::set_clock(&ZeroClock) };
91 87
diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs
new file mode 100644
index 000000000..cc630e0df
--- /dev/null
+++ b/examples/stm32l4/src/bin/usart_dma.rs
@@ -0,0 +1,96 @@
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 cortex_m_rt::entry;
13use embassy::executor::Executor;
14use embassy::time::Clock;
15use embassy::util::Forever;
16use embassy_stm32::usart::{Config, Uart};
17use example_common::*;
18use heapless::String;
19use stm32l4::stm32l4x5 as pac;
20
21#[embassy::task]
22async fn main_task() {
23 let mut p = embassy_stm32::init(Default::default());
24
25 let config = Config::default();
26 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, config);
27
28 for n in 0u32.. {
29 let mut s: String<128> = String::new();
30 core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap();
31
32 usart
33 .write_dma(&mut p.DMA1_3, s.as_bytes())
34 .await
35 .unwrap();
36 info!("wrote DMA");
37 }
38}
39
40struct ZeroClock;
41
42impl Clock for ZeroClock {
43 fn now(&self) -> u64 {
44 0
45 }
46}
47
48static EXECUTOR: Forever<Executor> = Forever::new();
49
50#[entry]
51fn main() -> ! {
52 info!("Hello World!");
53
54 let pp = pac::Peripherals::take().unwrap();
55
56 pp.DBGMCU.cr.modify(|_, w| {
57 w.dbg_sleep().set_bit();
58 w.dbg_standby().set_bit();
59 w.dbg_stop().set_bit()
60 });
61
62 pp.RCC.ahb1enr.modify(|_, w| {
63 unsafe {
64 w.bits( 0x07 );
65 }
66 w
67 //w.dmamuxen().set_bit();
68 //w.dma1en().set_bit();
69 //w.dma2en().set_bit();
70 //w
71 });
72
73 pp.RCC.ahb2enr.modify(|_, w| {
74 w.gpioaen().set_bit();
75 w.gpioben().set_bit();
76 w.gpiocen().set_bit();
77 w.gpioden().set_bit();
78 w.gpioeen().set_bit();
79 w.gpiofen().set_bit();
80 w
81 });
82
83 pp.RCC.apb2enr.modify(|_, w| {
84 w.syscfgen().set_bit();
85 w
86 });
87
88
89 unsafe { embassy::time::set_clock(&ZeroClock) };
90
91 let executor = EXECUTOR.put(Executor::new());
92
93 executor.run(|spawner| {
94 unwrap!(spawner.spawn(main_task()));
95 })
96}
diff --git a/stm32-data b/stm32-data
Subproject 409ed5502c254e462f3e31b0ea5ddee95f818a7 Subproject bc74a98017800aad50dd1448a24e3f54eaec8eb
diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs
index 978f70b92..37254f6f0 100644
--- a/stm32-metapac-gen/src/lib.rs
+++ b/stm32-metapac-gen/src/lib.rs
@@ -141,6 +141,21 @@ macro_rules! peripheral_count {{
141 write!(out, " }}\n").unwrap(); 141 write!(out, " }}\n").unwrap();
142} 142}
143 143
144fn make_dma_channel_counts(out: &mut String, data: &HashMap<String, u8>) {
145 write!(out,
146 "#[macro_export]
147macro_rules! dma_channels_count {{
148 ").unwrap();
149 for (name, count) in data {
150 write!(out,
151 "({}) => ({});\n",
152 name, count,
153 ).unwrap();
154 }
155 write!(out,
156 " }}\n").unwrap();
157}
158
144fn make_table(out: &mut String, name: &str, data: &Vec<Vec<String>>) { 159fn make_table(out: &mut String, name: &str, data: &Vec<Vec<String>>) {
145 write!( 160 write!(
146 out, 161 out,
@@ -252,9 +267,11 @@ pub fn gen(options: Options) {
252 let mut peripheral_pins_table: Vec<Vec<String>> = Vec::new(); 267 let mut peripheral_pins_table: Vec<Vec<String>> = Vec::new();
253 let mut peripheral_rcc_table: Vec<Vec<String>> = Vec::new(); 268 let mut peripheral_rcc_table: Vec<Vec<String>> = Vec::new();
254 let mut dma_channels_table: Vec<Vec<String>> = Vec::new(); 269 let mut dma_channels_table: Vec<Vec<String>> = Vec::new();
270 let mut bdma_channels_table: Vec<Vec<String>> = Vec::new();
255 let mut dma_requests_table: Vec<Vec<String>> = Vec::new(); 271 let mut dma_requests_table: Vec<Vec<String>> = Vec::new();
256 let mut peripheral_dma_channels_table: Vec<Vec<String>> = Vec::new(); 272 let mut peripheral_dma_channels_table: Vec<Vec<String>> = Vec::new();
257 let mut peripheral_counts: HashMap<String, u8> = HashMap::new(); 273 let mut peripheral_counts: HashMap<String, u8> = HashMap::new();
274 let mut dma_channel_counts: HashMap<String, u8> = HashMap::new();
258 275
259 let dma_base = core 276 let dma_base = core
260 .peripherals 277 .peripherals
@@ -266,14 +283,6 @@ pub fn gen(options: Options) {
266 let gpio_base = core.peripherals.get(&"GPIOA".to_string()).unwrap().address; 283 let gpio_base = core.peripherals.get(&"GPIOA".to_string()).unwrap().address;
267 let gpio_stride = 0x400; 284 let gpio_stride = 0x400;
268 285
269 for (id, channel_info) in &core.dma_channels {
270 let mut row = Vec::new();
271 row.push(id.clone());
272 row.push(channel_info.dma.clone());
273 row.push(channel_info.channel.to_string());
274 dma_channels_table.push(row);
275 }
276
277 let number_suffix_re = Regex::new("^(.*?)[0-9]*$").unwrap(); 286 let number_suffix_re = Regex::new("^(.*?)[0-9]*$").unwrap();
278 287
279 for (name, p) in &core.peripherals { 288 for (name, p) in &core.peripherals {
@@ -295,6 +304,11 @@ pub fn gen(options: Options) {
295 if let Some(block) = &p.block { 304 if let Some(block) = &p.block {
296 let bi = BlockInfo::parse(block); 305 let bi = BlockInfo::parse(block);
297 306
307 peripheral_counts.insert(
308 bi.module.clone(),
309 peripheral_counts.get(&bi.module).map_or(1, |v| v + 1),
310 );
311
298 for pin in &p.pins { 312 for pin in &p.pins {
299 let mut row = Vec::new(); 313 let mut row = Vec::new();
300 row.push(name.clone()); 314 row.push(name.clone());
@@ -421,14 +435,16 @@ pub fn gen(options: Options) {
421 clock.to_ascii_lowercase() 435 clock.to_ascii_lowercase()
422 }; 436 };
423 437
424 peripheral_rcc_table.push(vec![ 438 if !name.starts_with("GPIO") {
425 name.clone(), 439 peripheral_rcc_table.push(vec![
426 clock, 440 name.clone(),
427 enable_reg.to_ascii_lowercase(), 441 clock,
428 reset_reg.to_ascii_lowercase(), 442 enable_reg.to_ascii_lowercase(),
429 format!("set_{}", enable_field.to_ascii_lowercase()), 443 reset_reg.to_ascii_lowercase(),
430 format!("set_{}", reset_field.to_ascii_lowercase()), 444 format!("set_{}", enable_field.to_ascii_lowercase()),
431 ]); 445 format!("set_{}", reset_field.to_ascii_lowercase()),
446 ]);
447 }
432 } 448 }
433 (None, Some(_)) => { 449 (None, Some(_)) => {
434 print!("Unable to find enable register for {}", name) 450 print!("Unable to find enable register for {}", name)
@@ -447,6 +463,30 @@ pub fn gen(options: Options) {
447 dev.peripherals.push(ir_peri); 463 dev.peripherals.push(ir_peri);
448 } 464 }
449 465
466 for (id, channel_info) in &core.dma_channels {
467 let mut row = Vec::new();
468 let dma_peri = core.peripherals.get(&channel_info.dma);
469 row.push(id.clone());
470 row.push(channel_info.dma.clone());
471 row.push(channel_info.channel.to_string());
472 if let Some(dma_peri) = dma_peri {
473 if let Some(ref block) = dma_peri.block {
474 let bi = BlockInfo::parse(block);
475 if bi.module == "bdma" {
476 bdma_channels_table.push(row);
477 } else {
478 dma_channels_table.push(row);
479 }
480 }
481 }
482
483 let dma_peri_name = channel_info.dma.clone();
484 dma_channel_counts.insert(
485 dma_peri_name.clone(),
486 dma_channel_counts.get(&dma_peri_name).map_or(1, |v| v + 1),
487 );
488 }
489
450 for (name, &num) in &core.interrupts { 490 for (name, &num) in &core.interrupts {
451 dev.interrupts.push(ir::Interrupt { 491 dev.interrupts.push(ir::Interrupt {
452 name: name.clone(), 492 name: name.clone(),
@@ -493,8 +533,10 @@ pub fn gen(options: Options) {
493 ); 533 );
494 make_table(&mut extra, "peripheral_rcc", &peripheral_rcc_table); 534 make_table(&mut extra, "peripheral_rcc", &peripheral_rcc_table);
495 make_table(&mut extra, "dma_channels", &dma_channels_table); 535 make_table(&mut extra, "dma_channels", &dma_channels_table);
536 make_table(&mut extra, "bdma_channels", &bdma_channels_table);
496 make_table(&mut extra, "dma_requests", &dma_requests_table); 537 make_table(&mut extra, "dma_requests", &dma_requests_table);
497 make_peripheral_counts(&mut extra, &peripheral_counts); 538 make_peripheral_counts(&mut extra, &peripheral_counts);
539 make_dma_channel_counts(&mut extra, &dma_channel_counts);
498 540
499 for (module, version) in peripheral_versions { 541 for (module, version) in peripheral_versions {
500 all_peripheral_versions.insert((module.clone(), version.clone())); 542 all_peripheral_versions.insert((module.clone(), version.clone()));