aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatous Hybl <[email protected]>2021-11-10 14:47:16 +0100
committerMatous Hybl <[email protected]>2021-12-09 12:56:39 +0100
commit1dd5a71c07d2ab9aec1d9af7b4c87d5b1b969bd8 (patch)
tree206f031c4d2c6857e40e9fbc1da9e607617c2928
parent8ad8e3b718d0f66e2d6e52c4beb112977c6a73b4 (diff)
Add DCMI peripheral support.
-rw-r--r--embassy-stm32/src/dcmi.rs481
-rw-r--r--embassy-stm32/src/lib.rs2
-rw-r--r--embassy-stm32/src/rcc/h7/mod.rs5
3 files changed, 488 insertions, 0 deletions
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs
new file mode 100644
index 000000000..2d2ad72e4
--- /dev/null
+++ b/embassy-stm32/src/dcmi.rs
@@ -0,0 +1,481 @@
1use core::marker::PhantomData;
2use core::task::Poll;
3
4use crate::gpio::sealed::Pin as __GpioPin;
5use crate::gpio::Pin as GpioPin;
6use embassy::interrupt::{Interrupt, InterruptExt};
7use embassy::util::Unborrow;
8use embassy::waitqueue::AtomicWaker;
9use embassy_hal_common::unborrow;
10use futures::future::poll_fn;
11
12/// The level on the VSync pin when the data is not valid on the parallel interface.
13#[derive(Clone, Copy, PartialEq)]
14pub enum VSyncDataInvalidLevel {
15 Low,
16 High,
17}
18
19/// The level on the VSync pin when the data is not valid on the parallel interface.
20#[derive(Clone, Copy, PartialEq)]
21pub enum HSyncDataInvalidLevel {
22 Low,
23 High,
24}
25
26#[derive(Clone, Copy, PartialEq)]
27pub enum PixelClockPolarity {
28 RisingEdge,
29 FallingEdge,
30}
31
32pub struct State {
33 waker: AtomicWaker,
34}
35impl State {
36 const fn new() -> State {
37 State {
38 waker: AtomicWaker::new(),
39 }
40 }
41}
42
43static STATE: State = State::new();
44
45#[derive(Debug, Eq, PartialEq, Copy, Clone)]
46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47#[non_exhaustive]
48pub enum Error {
49 Overrun,
50 PeripheralError,
51}
52
53pub struct Dcmi<'d, T: Instance, Dma: FrameDma> {
54 inner: T,
55 dma: Dma,
56 phantom: PhantomData<&'d mut T>,
57}
58
59impl<'d, T, Dma> Dcmi<'d, T, Dma>
60where
61 T: Instance,
62 Dma: FrameDma,
63{
64 pub fn new(
65 peri: impl Unborrow<Target = T> + 'd,
66 dma: impl Unborrow<Target = Dma> + 'd,
67 vsync_level: VSyncDataInvalidLevel,
68 hsync_level: HSyncDataInvalidLevel,
69 pixclk_polarity: PixelClockPolarity,
70 use_embedded_synchronization: bool,
71 irq: impl Unborrow<Target = T::Interrupt> + 'd,
72 d0: impl Unborrow<Target = impl D0Pin> + 'd,
73 d1: impl Unborrow<Target = impl D1Pin> + 'd,
74 d2: impl Unborrow<Target = impl D2Pin> + 'd,
75 d3: impl Unborrow<Target = impl D3Pin> + 'd,
76 d4: impl Unborrow<Target = impl D4Pin> + 'd,
77 d5: impl Unborrow<Target = impl D5Pin> + 'd,
78 d6: impl Unborrow<Target = impl D6Pin> + 'd,
79 d7: impl Unborrow<Target = impl D7Pin> + 'd,
80 d8: impl Unborrow<Target = impl D8Pin> + 'd,
81 d9: impl Unborrow<Target = impl D9Pin> + 'd,
82 d10: impl Unborrow<Target = impl D10Pin> + 'd,
83 d11: impl Unborrow<Target = impl D11Pin> + 'd,
84 d12: impl Unborrow<Target = impl D12Pin> + 'd,
85 d13: impl Unborrow<Target = impl D13Pin> + 'd,
86 v_sync: impl Unborrow<Target = impl VSyncPin> + 'd,
87 h_sync: impl Unborrow<Target = impl HSyncPin> + 'd,
88 pixclk: impl Unborrow<Target = impl PixClkPin> + 'd,
89 ) -> Self {
90 T::reset();
91 T::enable();
92
93 unborrow!(
94 peri, dma, irq, d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, v_sync,
95 h_sync, pixclk
96 );
97
98 d0.configure();
99 d1.configure();
100 d2.configure();
101 d3.configure();
102 d4.configure();
103 d5.configure();
104 d6.configure();
105 d7.configure();
106 d8.configure();
107 d9.configure();
108 d10.configure();
109 d11.configure();
110 d12.configure();
111 d13.configure();
112
113 v_sync.configure();
114 h_sync.configure();
115 pixclk.configure();
116
117 let edm = match (
118 d8.pin().is_some(),
119 d9.pin().is_some(),
120 d10.pin().is_some(),
121 d11.pin().is_some(),
122 d12.pin().is_some(),
123 d13.pin().is_some(),
124 ) {
125 (true, true, true, true, true, true) => 0b11, // 14 bits
126 (true, true, true, true, false, false) => 0b10, // 12 bits
127 (true, true, false, false, false, false) => 0b01, // 10 bits
128 (false, false, false, false, false, false) => 0b00, // 8 bits
129 _ => {
130 panic!("Invalid pin configuration.");
131 }
132 };
133
134 unsafe {
135 peri.regs().cr().modify(|r| {
136 r.set_cm(true); // disable continuous mode (snapshot mode)
137 r.set_ess(use_embedded_synchronization);
138 r.set_pckpol(pixclk_polarity == PixelClockPolarity::RisingEdge);
139 r.set_vspol(vsync_level == VSyncDataInvalidLevel::High);
140 r.set_hspol(hsync_level == HSyncDataInvalidLevel::High);
141 r.set_fcrc(0x00); // capture every frame
142 r.set_edm(edm); // extended data mode
143 });
144 }
145
146 irq.set_handler(Self::on_interrupt);
147 irq.unpend();
148 irq.enable();
149
150 Self {
151 inner: peri,
152 dma,
153 phantom: PhantomData,
154 }
155 }
156
157 unsafe fn on_interrupt(_: *mut ()) {
158 let ris = crate::pac::DCMI.ris().read();
159 if ris.err_ris() {
160 error!("DCMI IRQ: Error.");
161 crate::pac::DCMI.ier().modify(|ier| ier.set_err_ie(false));
162 }
163 if ris.ovr_ris() {
164 error!("DCMI IRQ: Overrun.");
165 crate::pac::DCMI.ier().modify(|ier| ier.set_ovr_ie(false));
166 }
167 if ris.frame_ris() {
168 info!("DCMI IRQ: Frame captured.");
169 crate::pac::DCMI.ier().modify(|ier| ier.set_frame_ie(false));
170 }
171 STATE.waker.wake();
172 }
173
174 unsafe fn toggle(enable: bool) {
175 crate::pac::DCMI.cr().modify(|r| {
176 r.set_enable(enable);
177 r.set_capture(enable);
178 })
179 }
180
181 fn enable_irqs() {
182 unsafe {
183 crate::pac::DCMI.ier().modify(|r| {
184 r.set_err_ie(true);
185 r.set_ovr_ie(true);
186 r.set_frame_ie(true);
187 });
188 }
189 }
190
191 fn clear_interrupt_flags() {
192 unsafe {
193 crate::pac::DCMI.icr().write(|r| {
194 r.set_ovr_isc(true);
195 r.set_err_isc(true);
196 r.set_frame_isc(true);
197 })
198 }
199 }
200
201 /// This method starts the capture and finishes when both the dma transfer and DCMI finish the frame transfer.
202 /// The implication is that the input buffer size must be exactly the size of the captured frame.
203 pub async fn capture(&mut self, buffer: &mut [u32]) -> Result<(), Error> {
204 let channel = &mut self.dma;
205 let request = channel.request();
206
207 let r = self.inner.regs();
208 let src = r.dr().ptr() as *mut u32;
209 let dma_read = crate::dma::read(channel, request, src, buffer);
210
211 Self::clear_interrupt_flags();
212 Self::enable_irqs();
213
214 unsafe { Self::toggle(true) };
215
216 let result = poll_fn(|cx| {
217 STATE.waker.register(cx.waker());
218
219 let ris = unsafe { crate::pac::DCMI.ris().read() };
220 if ris.err_ris() {
221 unsafe {
222 crate::pac::DCMI.icr().write(|r| {
223 r.set_err_isc(true);
224 })
225 };
226 Poll::Ready(Err(Error::PeripheralError))
227 } else if ris.ovr_ris() {
228 unsafe {
229 crate::pac::DCMI.icr().write(|r| {
230 r.set_ovr_isc(true);
231 })
232 };
233 Poll::Ready(Err(Error::Overrun))
234 } else if ris.frame_ris() {
235 unsafe {
236 crate::pac::DCMI.icr().write(|r| {
237 r.set_frame_isc(true);
238 })
239 };
240 Poll::Ready(Ok(()))
241 } else {
242 Poll::Pending
243 }
244 });
245
246 let (_, result) = futures::future::join(dma_read, result).await;
247
248 unsafe { Self::toggle(false) };
249
250 result
251 }
252}
253
254mod sealed {
255 use super::*;
256 use crate::rcc::RccPeripheral;
257
258 pub trait Instance: RccPeripheral {
259 fn regs(&self) -> crate::pac::dcmi::Dcmi;
260 }
261
262 pub trait FrameDma {
263 fn request(&self) -> crate::dma::Request;
264 }
265
266 macro_rules! pin {
267 ($name:ident) => {
268 pub trait $name: GpioPin {
269 fn configure(&mut self);
270 }
271 };
272 }
273
274 macro_rules! optional_pin {
275 ($name:ident) => {
276 pub trait $name: crate::gpio::OptionalPin {
277 fn configure(&mut self);
278 }
279 };
280 }
281
282 pin!(D0Pin);
283 pin!(D1Pin);
284 pin!(D2Pin);
285 pin!(D3Pin);
286 pin!(D4Pin);
287 pin!(D5Pin);
288 pin!(D6Pin);
289 pin!(D7Pin);
290 optional_pin!(D8Pin);
291 optional_pin!(D9Pin);
292 optional_pin!(D10Pin);
293 optional_pin!(D11Pin);
294 optional_pin!(D12Pin);
295 optional_pin!(D13Pin);
296
297 optional_pin!(HSyncPin);
298 optional_pin!(VSyncPin);
299 pin!(PixClkPin);
300}
301
302pub trait Instance: sealed::Instance + 'static {
303 type Interrupt: Interrupt;
304}
305
306pub trait FrameDma: sealed::FrameDma + crate::dma::Channel {}
307
308macro_rules! pin {
309 ($name:ident) => {
310 pub trait $name: sealed::$name + 'static {}
311 };
312}
313
314pin!(D0Pin);
315pin!(D1Pin);
316pin!(D2Pin);
317pin!(D3Pin);
318pin!(D4Pin);
319pin!(D5Pin);
320pin!(D6Pin);
321pin!(D7Pin);
322pin!(D8Pin);
323pin!(D9Pin);
324pin!(D10Pin);
325pin!(D11Pin);
326pin!(D12Pin);
327pin!(D13Pin);
328
329pin!(HSyncPin);
330pin!(VSyncPin);
331pin!(PixClkPin);
332
333// allow unused as U5 sources do not contain interrupt nor dma data
334#[allow(unused)]
335macro_rules! impl_peripheral {
336 ($inst:ident, $irq:ident) => {
337 impl sealed::Instance for crate::peripherals::$inst {
338 fn regs(&self) -> crate::pac::dcmi::Dcmi {
339 crate::pac::$inst
340 }
341 }
342
343 impl Instance for crate::peripherals::$inst {
344 type Interrupt = crate::interrupt::$irq;
345 }
346 };
347}
348
349crate::pac::interrupts! {
350 ($inst:ident, dcmi, $block:ident, GLOBAL, $irq:ident) => {
351 impl_peripheral!($inst, $irq);
352 };
353}
354
355// allow unused as U5 sources do not contain interrupt nor dma data
356#[allow(unused)]
357macro_rules! impl_dma {
358 ($inst:ident, {dmamux: $dmamux:ident}, $signal:ident, $request:expr) => {
359 impl<T> sealed::$signal for T
360 where
361 T: crate::dma::MuxChannel<Mux = crate::dma::$dmamux>,
362 {
363 fn request(&self) -> crate::dma::Request {
364 $request
365 }
366 }
367
368 impl<T> $signal for T where T: crate::dma::MuxChannel<Mux = crate::dma::$dmamux> {}
369 };
370 ($inst:ident, {channel: $channel:ident}, $signal:ident, $request:expr) => {
371 impl sealed::$signal for crate::peripherals::$channel {
372 fn request(&self) -> crate::dma::Request {
373 $request
374 }
375 }
376
377 impl $signal for crate::peripherals::$channel {}
378 };
379}
380
381crate::pac::peripheral_dma_channels! {
382 ($peri:ident, dcmi, $kind:ident, PSSI, $channel:tt, $request:expr) => {
383 impl_dma!($peri, $channel, FrameDma, $request);
384 };
385 ($peri:ident, dcmi, $kind:ident, DCMI, $channel:tt, $request:expr) => {
386 impl_dma!($peri, $channel, FrameDma, $request);
387 };
388}
389
390macro_rules! impl_pin {
391 ($pin:ident, $signal:ident, $af:expr) => {
392 impl sealed::$signal for crate::peripherals::$pin {
393 fn configure(&mut self) {
394 // NOTE(unsafe) Exclusive access to the registers
395 critical_section::with(|_| unsafe {
396 self.set_as_af($af, crate::gpio::sealed::AFType::Input);
397 self.block().ospeedr().modify(|w| {
398 w.set_ospeedr(
399 self.pin() as usize,
400 crate::pac::gpio::vals::Ospeedr::VERYHIGHSPEED,
401 )
402 });
403 })
404 }
405 }
406
407 impl $signal for crate::peripherals::$pin {}
408 };
409}
410
411macro_rules! impl_no_pin {
412 ($signal:ident) => {
413 impl sealed::$signal for crate::gpio::NoPin {
414 fn configure(&mut self) {}
415 }
416 impl $signal for crate::gpio::NoPin {}
417 };
418}
419
420impl_no_pin!(D8Pin);
421impl_no_pin!(D9Pin);
422impl_no_pin!(D10Pin);
423impl_no_pin!(D11Pin);
424impl_no_pin!(D12Pin);
425impl_no_pin!(D13Pin);
426impl_no_pin!(HSyncPin);
427impl_no_pin!(VSyncPin);
428
429crate::pac::peripheral_pins!(
430 ($inst:ident, dcmi, DCMI, $pin:ident, D0, $af:expr) => {
431 impl_pin!($pin, D0Pin, $af);
432 };
433 ($inst:ident, dcmi, DCMI, $pin:ident, D1, $af:expr) => {
434 impl_pin!($pin, D1Pin, $af);
435 };
436 ($inst:ident, dcmi, DCMI, $pin:ident, D2, $af:expr) => {
437 impl_pin!($pin, D2Pin, $af);
438 };
439 ($inst:ident, dcmi, DCMI, $pin:ident, D3, $af:expr) => {
440 impl_pin!($pin, D3Pin, $af);
441 };
442 ($inst:ident, dcmi, DCMI, $pin:ident, D4, $af:expr) => {
443 impl_pin!($pin, D4Pin, $af);
444 };
445 ($inst:ident, dcmi, DCMI, $pin:ident, D5, $af:expr) => {
446 impl_pin!($pin, D5Pin, $af);
447 };
448 ($inst:ident, dcmi, DCMI, $pin:ident, D6, $af:expr) => {
449 impl_pin!($pin, D6Pin, $af);
450 };
451 ($inst:ident, dcmi, DCMI, $pin:ident, D7, $af:expr) => {
452 impl_pin!($pin, D7Pin, $af);
453 };
454 ($inst:ident, dcmi, DCMI, $pin:ident, D8, $af:expr) => {
455 impl_pin!($pin, D8Pin, $af);
456 };
457 ($inst:ident, dcmi, DCMI, $pin:ident, D9, $af:expr) => {
458 impl_pin!($pin, D9Pin, $af);
459 };
460 ($inst:ident, dcmi, DCMI, $pin:ident, D10, $af:expr) => {
461 impl_pin!($pin, D10Pin, $af);
462 };
463 ($inst:ident, dcmi, DCMI, $pin:ident, D11, $af:expr) => {
464 impl_pin!($pin, D11Pin, $af);
465 };
466 ($inst:ident, dcmi, DCMI, $pin:ident, D12, $af:expr) => {
467 impl_pin!($pin, D12Pin, $af);
468 };
469 ($inst:ident, dcmi, DCMI, $pin:ident, D13, $af:expr) => {
470 impl_pin!($pin, D13Pin, $af);
471 };
472 ($inst:ident, dcmi, DCMI, $pin:ident, HSYNC, $af:expr) => {
473 impl_pin!($pin, HSyncPin, $af);
474 };
475 ($inst:ident, dcmi, DCMI, $pin:ident, VSYNC, $af:expr) => {
476 impl_pin!($pin, VSyncPin, $af);
477 };
478 ($inst:ident, dcmi, DCMI, $pin:ident, PIXCLK, $af:expr) => {
479 impl_pin!($pin, PixClkPin, $af);
480 };
481);
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 649b25f10..425516a3f 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -32,6 +32,8 @@ pub mod can;
32pub mod dac; 32pub mod dac;
33#[cfg(dbgmcu)] 33#[cfg(dbgmcu)]
34pub mod dbgmcu; 34pub mod dbgmcu;
35#[cfg(dcmi)]
36pub mod dcmi;
35#[cfg(all(eth, feature = "net"))] 37#[cfg(all(eth, feature = "net"))]
36pub mod eth; 38pub mod eth;
37#[cfg(exti)] 39#[cfg(exti)]
diff --git a/embassy-stm32/src/rcc/h7/mod.rs b/embassy-stm32/src/rcc/h7/mod.rs
index dc458a8a3..be7f440a1 100644
--- a/embassy-stm32/src/rcc/h7/mod.rs
+++ b/embassy-stm32/src/rcc/h7/mod.rs
@@ -73,6 +73,7 @@ pub struct Config {
73 pub pll2: PllConfig, 73 pub pll2: PllConfig,
74 pub pll3: PllConfig, 74 pub pll3: PllConfig,
75 pub enable_dma1: bool, 75 pub enable_dma1: bool,
76 pub enable_dma2: bool,
76} 77}
77 78
78pub struct Rcc<'d> { 79pub struct Rcc<'d> {
@@ -334,6 +335,10 @@ impl<'d> Rcc<'d> {
334 RCC.ahb1enr().modify(|w| w.set_dma1en(true)); 335 RCC.ahb1enr().modify(|w| w.set_dma1en(true));
335 } 336 }
336 337
338 if self.config.enable_dma2 {
339 RCC.ahb1enr().modify(|w| w.set_dma2en(true));
340 }
341
337 CoreClocks { 342 CoreClocks {
338 hclk: Hertz(rcc_hclk), 343 hclk: Hertz(rcc_hclk),
339 pclk1: Hertz(rcc_pclk1), 344 pclk1: Hertz(rcc_pclk1),