aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/dma
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-07-15 05:42:06 +0200
committerBob McWhirter <[email protected]>2021-07-16 14:41:20 -0400
commit3d1391ef2d634ca6a90c68be7cc69af02e3dc33b (patch)
treeb73e2ca0a00486acff55fc200e2d3087c70b4ba1 /embassy-stm32/src/dma
parent69fb1b5418a4fb355d48b3b4357d0cd7562b5c4d (diff)
stm32/dma: impl all variants
Diffstat (limited to 'embassy-stm32/src/dma')
-rw-r--r--embassy-stm32/src/dma/bdma.rs222
-rw-r--r--embassy-stm32/src/dma/dma.rs210
-rw-r--r--embassy-stm32/src/dma/dmamux.rs61
-rw-r--r--embassy-stm32/src/dma/mod.rs67
-rw-r--r--embassy-stm32/src/dma/v1.rs2
-rw-r--r--embassy-stm32/src/dma/v2.rs331
6 files changed, 553 insertions, 340 deletions
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
new file mode 100644
index 000000000..9449d4bf8
--- /dev/null
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -0,0 +1,222 @@
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 on_drop.defuse();
103
104 // TODO handle error
105 assert!(res == CH_STATUS_COMPLETED);
106}
107
108macro_rules! dma_num {
109 (DMA1) => {
110 0
111 };
112 (DMA2) => {
113 1
114 };
115 (BDMA) => {
116 0
117 };
118}
119
120unsafe fn on_irq() {
121 pac::peripherals! {
122 (bdma, $dma:ident) => {
123 let isr = pac::$dma.isr().read();
124 pac::$dma.ifcr().write_value(isr);
125 let dman = dma_num!($dma);
126
127 for chn in 0..crate::pac::dma_channels_count!($dma) {
128 let n = dman * 8 + 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 crate::interrupt::$irq::steal().enable();
147 };
148 }
149 pac::peripherals! {
150 (bdma, $peri:ident) => {
151 crate::peripherals::$peri::enable();
152 };
153 }
154}
155
156pac::bdma_channels! {
157 ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => {
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::FROMPERIPHERAL,
177 src,
178 buf.as_mut_ptr(),
179 buf.len(),
180 #[cfg(dmamux)]
181 <Self as super::dmamux::MuxChannel>::DMAMUX_REGS,
182 #[cfg(dmamux)]
183 <Self as super::dmamux::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::FROMMEMORY,
201 dst,
202 buf.as_ptr() as *mut u8,
203 buf.len(),
204 #[cfg(dmamux)]
205 <Self as super::dmamux::MuxChannel>::DMAMUX_REGS,
206 #[cfg(dmamux)]
207 <Self as super::dmamux::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/dma.rs b/embassy-stm32/src/dma/dma.rs
new file mode 100644
index 000000000..b0df6ddc5
--- /dev/null
+++ b/embassy-stm32/src/dma/dma.rs
@@ -0,0 +1,210 @@
1use core::task::Poll;
2
3use atomic_polyfill::{AtomicU8, Ordering};
4use core::future::Future;
5use embassy::interrupt::{Interrupt, InterruptExt};
6use embassy::util::AtomicWaker;
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
41pub(crate) async unsafe fn do_transfer(
42 dma: pac::dma::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 // Reset status
57 // Generate a DMB here to flush the store buffer (M7) before enabling the DMA
58 STATE.ch_status[state_number as usize].store(CH_STATUS_NONE, Ordering::Release);
59
60 let ch = dma.st(channel_number as _);
61
62 #[cfg(dmamux)]
63 super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request);
64
65 unsafe {
66 ch.par().write_value(peri_addr as u32);
67 ch.m0ar().write_value(mem_addr as u32);
68 ch.ndtr().write_value(regs::Ndtr(mem_len as _));
69 ch.cr().write(|w| {
70 w.set_dir(dir);
71 w.set_msize(vals::Size::BITS8);
72 w.set_psize(vals::Size::BITS8);
73 w.set_minc(vals::Inc::INCREMENTED);
74 w.set_pinc(vals::Inc::FIXED);
75 w.set_teie(true);
76 w.set_tcie(true);
77 w.set_en(true);
78
79 #[cfg(dma_v2)]
80 w.set_chsel(request);
81 });
82 }
83
84 let res = poll_fn(|cx| {
85 let n = channel_number as usize;
86 STATE.ch_wakers[n].register(cx.waker());
87 match STATE.ch_status[n].load(Ordering::Acquire) {
88 CH_STATUS_NONE => Poll::Pending,
89 x => Poll::Ready(x),
90 }
91 })
92 .await;
93
94 // TODO handle error
95 assert!(res == CH_STATUS_COMPLETED);
96}
97
98macro_rules! dma_num {
99 (DMA1) => {
100 0
101 };
102 (DMA2) => {
103 1
104 };
105}
106
107unsafe fn on_irq() {
108 pac::peripherals! {
109 (dma, $dma:ident) => {
110 for isrn in 0..2 {
111 let isr = pac::$dma.isr(isrn).read();
112 pac::$dma.ifcr(isrn).write_value(isr);
113 let dman = dma_num!($dma);
114
115 for chn in 0..4 {
116 let n = dman * 8 + isrn * 4 + chn;
117 if isr.teif(chn) {
118 STATE.ch_status[n].store(CH_STATUS_ERROR, Ordering::Relaxed);
119 STATE.ch_wakers[n].wake();
120 } else if isr.tcif(chn) {
121 STATE.ch_status[n].store(CH_STATUS_COMPLETED, Ordering::Relaxed);
122 STATE.ch_wakers[n].wake();
123 }
124 }
125 }
126 };
127 }
128}
129
130/// safety: must be called only once
131pub(crate) unsafe fn init() {
132 pac::interrupts! {
133 (DMA, $irq:ident) => {
134 interrupt::$irq::steal().enable();
135 };
136 }
137 pac::peripherals! {
138 (dma, $peri:ident) => {
139 crate::peripherals::$peri::enable();
140 };
141 }
142}
143
144pac::dma_channels! {
145 ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => {
146 impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {}
147 impl Channel for crate::peripherals::$channel_peri
148 {
149 type ReadFuture<'a> = impl Future<Output = ()>;
150 type WriteFuture<'a> = impl Future<Output = ()>;
151
152 fn read<'a>(
153 &'a mut self,
154 request: Request,
155 src: *mut u8,
156 buf: &'a mut [u8],
157 ) -> Self::ReadFuture<'a> {
158 unsafe {
159 do_transfer(
160 crate::pac::$dma_peri,
161 $channel_num,
162 (dma_num!($dma_peri) * 8) + $channel_num,
163 request,
164 vals::Dir::PERIPHERALTOMEMORY,
165 src,
166 buf.as_mut_ptr(),
167 buf.len(),
168 #[cfg(dmamux)]
169 <Self as super::dmamux::MuxChannel>::DMAMUX_REGS,
170 #[cfg(dmamux)]
171 <Self as super::dmamux::MuxChannel>::DMAMUX_CH_NUM,
172 )
173 }
174 }
175
176 fn write<'a>(
177 &'a mut self,
178 request: Request,
179 buf: &'a [u8],
180 dst: *mut u8,
181 ) -> Self::WriteFuture<'a> {
182 unsafe {
183 do_transfer(
184 crate::pac::$dma_peri,
185 $channel_num,
186 (dma_num!($dma_peri) * 8) + $channel_num,
187 request,
188 vals::Dir::MEMORYTOPERIPHERAL,
189 dst,
190 buf.as_ptr() as *mut u8,
191 buf.len(),
192 #[cfg(dmamux)]
193 <Self as super::dmamux::MuxChannel>::DMAMUX_REGS,
194 #[cfg(dmamux)]
195 <Self as super::dmamux::MuxChannel>::DMAMUX_CH_NUM,
196 )
197 }
198 }
199 }
200 };
201}
202
203pac::interrupts! {
204 (DMA, $irq:ident) => {
205 #[crate::interrupt]
206 unsafe fn $irq () {
207 on_irq()
208 }
209 };
210}
diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs
new file mode 100644
index 000000000..ca2879c2e
--- /dev/null
+++ b/embassy-stm32/src/dma/dmamux.rs
@@ -0,0 +1,61 @@
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) trait MuxChannel {
23 const DMAMUX_CH_NUM: u8;
24 const DMAMUX_REGS: pac::dmamux::Dmamux;
25}
26
27macro_rules! dma_num {
28 (DMA1) => {
29 0
30 };
31 (DMA2) => {
32 1
33 };
34 (BDMA) => {
35 0
36 };
37}
38
39macro_rules! dmamux_peri {
40 (DMA1) => {
41 crate::pac::DMAMUX1
42 };
43 (DMA2) => {
44 crate::pac::DMAMUX1
45 };
46 (BDMA) => {
47 crate::pac::DMAMUX1
48 };
49}
50
51pac::bdma_channels! {
52 ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => {
53 impl MuxChannel for peripherals::$channel_peri {
54 const DMAMUX_CH_NUM: u8 = (dma_num!($dma_peri) * 8) + $channel_num;
55 const DMAMUX_REGS: pac::dmamux::Dmamux = dmamux_peri!($dma_peri);
56 }
57 };
58}
59
60/// safety: must be called only once
61pub(crate) unsafe fn init() {}
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index ed080cd16..ebad3d7b6 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -1,9 +1,62 @@
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")] 8use core::future::Future;
4#[cfg_attr(dma_v2, path = "v2.rs")] 9use embassy::util::Unborrow;
5mod _version;
6 10
7#[cfg(dma)] 11#[cfg(any(bdma_v2, dma_v2, dmamux))]
8#[allow(unused)] 12pub type Request = u8;
9pub use _version::*; 13#[cfg(not(any(bdma_v2, dma_v2, dmamux)))]
14pub type Request = ();
15
16pub(crate) mod sealed {
17 pub trait Channel {}
18}
19
20pub trait Channel: sealed::Channel {
21 type ReadFuture<'a>: Future<Output = ()> + 'a
22 where
23 Self: 'a;
24
25 type WriteFuture<'a>: Future<Output = ()> + 'a
26 where
27 Self: 'a;
28
29 fn read<'a>(
30 &'a mut self,
31 request: Request,
32 src: *mut u8,
33 buf: &'a mut [u8],
34 ) -> Self::ReadFuture<'a>;
35
36 fn write<'a>(
37 &'a mut self,
38 request: Request,
39 buf: &'a [u8],
40 dst: *mut u8,
41 ) -> Self::WriteFuture<'a>;
42}
43
44pub struct NoDma;
45
46unsafe impl Unborrow for NoDma {
47 type Target = NoDma;
48
49 unsafe fn unborrow(self) -> Self::Target {
50 self
51 }
52}
53
54// safety: must be called only once at startup
55pub(crate) unsafe fn init() {
56 #[cfg(bdma)]
57 bdma::init();
58 #[cfg(dma)]
59 dma::init();
60 #[cfg(dmamux)]
61 dmamux::init();
62}
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}