aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThales Fragoso <[email protected]>2021-07-03 17:58:59 -0300
committerBob McWhirter <[email protected]>2021-07-13 10:08:43 -0400
commitf32caaeaafd77b15005612b6d8d039b101b36975 (patch)
tree112db99ff4183675b286bc8eb7a3adbde5663e97
parent8f28d6b4b1e74b3b3b64fd3a28ce1ea9072b7cbb (diff)
STM: Start working on bdma-v1
-rw-r--r--embassy-stm32/src/bdma/mod.rs69
-rw-r--r--embassy-stm32/src/bdma/v1.rs275
-rw-r--r--embassy-stm32/src/bdma/v2.rs1
-rw-r--r--embassy-stm32/src/lib.rs4
4 files changed, 295 insertions, 54 deletions
diff --git a/embassy-stm32/src/bdma/mod.rs b/embassy-stm32/src/bdma/mod.rs
index e85ade5df..1a49f4e1d 100644
--- a/embassy-stm32/src/bdma/mod.rs
+++ b/embassy-stm32/src/bdma/mod.rs
@@ -7,63 +7,24 @@ mod _version;
7#[allow(unused)] 7#[allow(unused)]
8pub use _version::*; 8pub use _version::*;
9 9
10use crate::pac; 10use core::future::Future;
11use crate::peripherals;
12 11
13pub(crate) mod sealed { 12pub trait WriteDma<T> {
14 use super::*; 13 type WriteDmaFuture<'a>: Future<Output = ()> + 'a
14 where
15 Self: 'a;
15 16
16 pub trait Channel { 17 fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a>
17 fn num(&self) -> u8; 18 where
18 19 T: 'a;
19 fn dma_num(&self) -> u8 {
20 self.num() / 8
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 }
28 }
29} 20}
30 21
31pub trait Channel: sealed::Channel + Sized {} 22pub trait ReadDma<T> {
23 type ReadDmaFuture<'a>: Future<Output = ()> + 'a
24 where
25 Self: 'a;
32 26
33macro_rules! impl_dma_channel { 27 fn transfer<'a>(&'a mut self, src: *const u8, buf: &'a mut [u8]) -> Self::ReadDmaFuture<'a>
34 ($channel_peri:ident, $dma_num:expr, $ch_num:expr) => { 28 where
35 impl Channel for peripherals::$channel_peri {} 29 T: 'a;
36 impl sealed::Channel for peripherals::$channel_peri {
37 #[inline]
38 fn num(&self) -> u8 {
39 $dma_num * 8 + $ch_num
40 }
41 }
42 };
43} 30}
44
45/*
46crate::pac::peripherals!(
47 (dma,DMA1) => {
48 impl_dma_channel!(DMA1_CH0, 0, 0);
49 impl_dma_channel!(DMA1_CH1, 0, 1);
50 impl_dma_channel!(DMA1_CH2, 0, 2);
51 impl_dma_channel!(DMA1_CH3, 0, 3);
52 impl_dma_channel!(DMA1_CH4, 0, 4);
53 impl_dma_channel!(DMA1_CH5, 0, 5);
54 impl_dma_channel!(DMA1_CH6, 0, 6);
55 impl_dma_channel!(DMA1_CH7, 0, 7);
56 };
57
58 (dma,DMA2) => {
59 impl_dma_channel!(DMA2_CH0, 1, 0);
60 impl_dma_channel!(DMA2_CH1, 1, 1);
61 impl_dma_channel!(DMA2_CH2, 1, 2);
62 impl_dma_channel!(DMA2_CH3, 1, 3);
63 impl_dma_channel!(DMA2_CH4, 1, 4);
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 };
68);
69 */
diff --git a/embassy-stm32/src/bdma/v1.rs b/embassy-stm32/src/bdma/v1.rs
new file mode 100644
index 000000000..584d531f7
--- /dev/null
+++ b/embassy-stm32/src/bdma/v1.rs
@@ -0,0 +1,275 @@
1use core::future::Future;
2use core::task::Poll;
3
4use atomic_polyfill::{AtomicU8, Ordering};
5use embassy::interrupt::{Interrupt, InterruptExt};
6use embassy::util::{AtomicWaker, OnDrop};
7use futures::future::poll_fn;
8
9use super::{ReadDma, WriteDma};
10use crate::interrupt;
11use crate::pac;
12use crate::pac::bdma::vals;
13
14const CH_COUNT: usize = pac::peripheral_count!(DMA) * 8;
15const CH_STATUS_NONE: u8 = 0;
16const CH_STATUS_COMPLETED: u8 = 1;
17const CH_STATUS_ERROR: u8 = 2;
18
19struct State {
20 ch_wakers: [AtomicWaker; CH_COUNT],
21 ch_status: [AtomicU8; CH_COUNT],
22}
23
24impl State {
25 const fn new() -> Self {
26 const AW: AtomicWaker = AtomicWaker::new();
27 const AU: AtomicU8 = AtomicU8::new(CH_STATUS_NONE);
28 Self {
29 ch_wakers: [AW; CH_COUNT],
30 ch_status: [AU; CH_COUNT],
31 }
32 }
33}
34
35static STATE: State = State::new();
36
37#[allow(unused)]
38pub(crate) async unsafe fn transfer_p2m(ch: &mut impl Channel, src: *const u8, dst: &mut [u8]) {
39 // ndtr is max 16 bits.
40 assert!(dst.len() <= 0xFFFF);
41
42 let regs: pac::bdma::Ch = ch.regs();
43 let state_number = ch.state_num();
44
45 // Reset status
46 // Generate a DMB here to flush the store buffer (M7) before enabling the DMA
47 STATE.ch_status[state_number].store(CH_STATUS_NONE, Ordering::Release);
48
49 let on_drop = OnDrop::new(|| unsafe {
50 regs.cr().modify(|w| {
51 w.set_tcie(false);
52 w.set_teie(false);
53 w.set_en(false);
54 });
55 while regs.cr().read().en() {}
56 });
57
58 regs.par().write_value(src as u32);
59 regs.mar().write_value(dst.as_mut_ptr() as u32);
60 regs.ndtr().write(|w| w.set_ndt(dst.len() as u16));
61 regs.cr().write(|w| {
62 w.set_psize(vals::Size::BITS8);
63 w.set_msize(vals::Size::BITS8);
64 w.set_minc(vals::Inc::ENABLED);
65 w.set_teie(true);
66 w.set_tcie(true);
67 w.set_en(true);
68 });
69
70 let res = poll_fn(|cx| {
71 STATE.ch_wakers[state_number].register(cx.waker());
72 match STATE.ch_status[state_number].load(Ordering::Acquire) {
73 CH_STATUS_NONE => Poll::Pending,
74 x => Poll::Ready(x),
75 }
76 })
77 .await;
78
79 on_drop.defuse();
80 // TODO handle error
81 assert!(res == CH_STATUS_COMPLETED);
82}
83
84#[allow(unused)]
85pub(crate) async unsafe fn transfer_m2p(ch: &mut impl Channel, src: &[u8], dst: *mut u8) {
86 // ndtr is max 16 bits.
87 assert!(src.len() <= 0xFFFF);
88
89 let regs: pac::bdma::Ch = ch.regs();
90 let state_number = ch.state_num();
91
92 // Reset status
93 // Generate a DMB here to flush the store buffer (M7) before enabling the DMA
94 STATE.ch_status[state_number].store(CH_STATUS_NONE, Ordering::Release);
95
96 let on_drop = OnDrop::new(|| unsafe {
97 regs.cr().modify(|w| {
98 w.set_tcie(false);
99 w.set_teie(false);
100 w.set_en(false);
101 });
102 while regs.cr().read().en() {}
103 });
104
105 regs.par().write_value(dst as u32);
106 regs.mar().write_value(src.as_ptr() as u32);
107 regs.ndtr().write(|w| w.set_ndt(src.len() as u16));
108 regs.cr().write(|w| {
109 w.set_psize(vals::Size::BITS8);
110 w.set_msize(vals::Size::BITS8);
111 w.set_minc(vals::Inc::ENABLED);
112 w.set_dir(vals::Dir::FROMMEMORY);
113 w.set_teie(true);
114 w.set_tcie(true);
115 w.set_en(true);
116 });
117
118 let res = poll_fn(|cx| {
119 STATE.ch_wakers[state_number].register(cx.waker());
120 match STATE.ch_status[state_number].load(Ordering::Acquire) {
121 CH_STATUS_NONE => Poll::Pending,
122 x => Poll::Ready(x),
123 }
124 })
125 .await;
126
127 on_drop.defuse();
128 // TODO handle error
129 assert!(res == CH_STATUS_COMPLETED);
130}
131
132unsafe fn on_irq() {
133 pac::peripherals! {
134 (bdma, $dma:ident) => {
135 let isr = pac::$dma.isr().read();
136 pac::$dma.ifcr().write_value(isr);
137 let dman = <crate::peripherals::$dma as sealed::Dma>::num() as usize;
138
139 for chn in 0..7 {
140 let n = dman * 8 + chn;
141 if isr.teif(chn) {
142 STATE.ch_status[n].store(CH_STATUS_ERROR, Ordering::Relaxed);
143 STATE.ch_wakers[n].wake();
144 } else if isr.tcif(chn) {
145 STATE.ch_status[n].store(CH_STATUS_COMPLETED, Ordering::Relaxed);
146 STATE.ch_wakers[n].wake();
147 }
148 }
149
150 };
151 }
152}
153
154/// safety: must be called only once
155pub(crate) unsafe fn init() {
156 pac::interrupts! {
157 (DMA, $irq:ident) => {
158 crate::interrupt::$irq::steal().enable();
159 };
160 }
161}
162
163pub(crate) mod sealed {
164 use super::*;
165
166 pub trait Dma {
167 fn num() -> u8;
168 }
169
170 pub trait Channel {
171 fn dma_regs() -> &'static pac::bdma::Dma;
172
173 fn state_num(&self) -> usize;
174
175 fn ch_num(&self) -> u8;
176
177 fn regs(&self) -> pac::bdma::Ch {
178 Self::dma_regs().ch(self.ch_num() as usize)
179 }
180 }
181}
182
183pub trait Dma: sealed::Dma + Sized {}
184pub trait Channel: sealed::Channel + Sized {}
185
186macro_rules! impl_dma {
187 ($peri:ident, $num:expr) => {
188 impl Dma for crate::peripherals::$peri {}
189 impl sealed::Dma for crate::peripherals::$peri {
190 fn num() -> u8 {
191 $num
192 }
193 }
194 };
195}
196
197macro_rules! impl_dma_channel {
198 ($channel_peri:ident, $dma_peri:ident, $dma_num:expr, $ch_num:expr) => {
199 impl Channel for crate::peripherals::$channel_peri {}
200 impl sealed::Channel for crate::peripherals::$channel_peri {
201 #[inline]
202 fn dma_regs() -> &'static pac::bdma::Dma {
203 &crate::pac::$dma_peri
204 }
205
206 fn state_num(&self) -> usize {
207 ($dma_num * 8) + $ch_num
208 }
209
210 fn ch_num(&self) -> u8 {
211 $ch_num
212 }
213 }
214
215 impl<T> WriteDma<T> for crate::peripherals::$channel_peri
216 where
217 T: 'static,
218 {
219 type WriteDmaFuture<'a> = impl Future<Output = ()>;
220
221 fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a>
222 where
223 T: 'a,
224 {
225 unsafe { transfer_m2p(self, buf, dst) }
226 }
227 }
228
229 impl<T> ReadDma<T> for crate::peripherals::$channel_peri
230 where
231 T: 'static,
232 {
233 type ReadDmaFuture<'a> = impl Future<Output = ()>;
234
235 fn transfer<'a>(
236 &'a mut self,
237 src: *const u8,
238 buf: &'a mut [u8],
239 ) -> Self::ReadDmaFuture<'a>
240 where
241 T: 'a,
242 {
243 unsafe { transfer_p2m(self, src, buf) }
244 }
245 }
246 };
247}
248
249pac::peripherals! {
250 (bdma, DMA1) => {
251 impl_dma!(DMA1, 0);
252 pac::dma_channels! {
253 ($channel_peri:ident, DMA1, $channel_num:expr) => {
254 impl_dma_channel!($channel_peri, DMA1, 0, $channel_num);
255 };
256 }
257 };
258 (bdma, DMA2) => {
259 impl_dma!(DMA2, 1);
260 pac::dma_channels! {
261 ($channel_peri:ident, DMA2, $channel_num:expr) => {
262 impl_dma_channel!($channel_peri, DMA2, 1, $channel_num);
263 };
264 }
265 };
266}
267
268pac::interrupts! {
269 (DMA, $irq:ident) => {
270 #[crate::interrupt]
271 unsafe fn $irq () {
272 on_irq()
273 }
274 };
275}
diff --git a/embassy-stm32/src/bdma/v2.rs b/embassy-stm32/src/bdma/v2.rs
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/embassy-stm32/src/bdma/v2.rs
@@ -0,0 +1 @@
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 76a6ecd88..35a8d3baf 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -22,6 +22,8 @@ pub mod rcc;
22// Sometimes-present hardware 22// Sometimes-present hardware
23#[cfg(adc)] 23#[cfg(adc)]
24pub mod adc; 24pub mod adc;
25#[cfg(bdma)]
26pub mod bdma;
25#[cfg(timer)] 27#[cfg(timer)]
26pub mod clock; 28pub mod clock;
27#[cfg(dac)] 29#[cfg(dac)]
@@ -86,6 +88,8 @@ pub fn init(config: Config) -> Peripherals {
86 unsafe { 88 unsafe {
87 #[cfg(dma)] 89 #[cfg(dma)]
88 dma::init(); 90 dma::init();
91 #[cfg(bdma)]
92 bdma::init();
89 #[cfg(exti)] 93 #[cfg(exti)]
90 exti::init(); 94 exti::init();
91 rcc::init(config.rcc); 95 rcc::init(config.rcc);