1use core::future::poll_fn;
3use core::marker::PhantomData;
4use core::task::Poll;
5
6use embassy_hal_internal::PeripheralType;
7use embassy_sync::waitqueue::AtomicWaker;
8
9use crate::dma::Transfer;
10use crate::gpio::{AfType, Pull};
11use crate::interrupt::typelevel::Interrupt;
12use crate::{interrupt, rcc, Peri};
13
14pub struct InterruptHandler<T: Instance> {
16 _phantom: PhantomData<T>,
17}
18
19impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
20 unsafe fn on_interrupt() {
21 let ris = crate::pac::DCMI.ris().read();
22 if ris.err_ris() {
23 trace!("DCMI IRQ: Error.");
24 crate::pac::DCMI.ier().modify(|ier| ier.set_err_ie(false));
25 }
26 if ris.ovr_ris() {
27 trace!("DCMI IRQ: Overrun.");
28 crate::pac::DCMI.ier().modify(|ier| ier.set_ovr_ie(false));
29 }
30 if ris.frame_ris() {
31 trace!("DCMI IRQ: Frame captured.");
32 crate::pac::DCMI.ier().modify(|ier| ier.set_frame_ie(false));
33 }
34 STATE.waker.wake();
35 }
36}
37
38#[allow(missing_docs)]
40#[derive(Clone, Copy, PartialEq)]
41pub enum VSyncDataInvalidLevel {
42 Low,
43 High,
44}
45
46#[allow(missing_docs)]
48#[derive(Clone, Copy, PartialEq)]
49pub enum HSyncDataInvalidLevel {
50 Low,
51 High,
52}
53
54#[derive(Clone, Copy, PartialEq)]
55#[allow(missing_docs)]
56pub enum PixelClockPolarity {
57 RisingEdge,
58 FallingEdge,
59}
60
61struct State {
62 waker: AtomicWaker,
63}
64
65impl State {
66 const fn new() -> State {
67 State {
68 waker: AtomicWaker::new(),
69 }
70 }
71}
72
73static STATE: State = State::new();
74
75#[derive(Debug, Eq, PartialEq, Copy, Clone)]
77#[cfg_attr(feature = "defmt", derive(defmt::Format))]
78#[non_exhaustive]
79pub enum Error {
80 Overrun,
82 PeripheralError,
84}
85
86#[non_exhaustive]
88pub struct Config {
89 pub vsync_level: VSyncDataInvalidLevel,
91 pub hsync_level: HSyncDataInvalidLevel,
93 pub pixclk_polarity: PixelClockPolarity,
95}
96
97impl Default for Config {
98 fn default() -> Self {
99 Self {
100 vsync_level: VSyncDataInvalidLevel::High,
101 hsync_level: HSyncDataInvalidLevel::Low,
102 pixclk_polarity: PixelClockPolarity::RisingEdge,
103 }
104 }
105}
106
107macro_rules! config_pins {
108 ($($pin:ident),*) => {
109 critical_section::with(|_| {
110 $(
111 $pin.set_as_af($pin.af_num(), AfType::input(Pull::None));
112 )*
113 })
114 };
115}
116
117pub struct Dcmi<'d, T: Instance, Dma: FrameDma<T>> {
119 inner: Peri<'d, T>,
120 dma: Peri<'d, Dma>,
121}
122
123impl<'d, T, Dma> Dcmi<'d, T, Dma>
124where
125 T: Instance,
126 Dma: FrameDma<T>,
127{
128 pub fn new_8bit(
130 peri: Peri<'d, T>,
131 dma: Peri<'d, Dma>,
132 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
133 d0: Peri<'d, impl D0Pin<T>>,
134 d1: Peri<'d, impl D1Pin<T>>,
135 d2: Peri<'d, impl D2Pin<T>>,
136 d3: Peri<'d, impl D3Pin<T>>,
137 d4: Peri<'d, impl D4Pin<T>>,
138 d5: Peri<'d, impl D5Pin<T>>,
139 d6: Peri<'d, impl D6Pin<T>>,
140 d7: Peri<'d, impl D7Pin<T>>,
141 v_sync: Peri<'d, impl VSyncPin<T>>,
142 h_sync: Peri<'d, impl HSyncPin<T>>,
143 pixclk: Peri<'d, impl PixClkPin<T>>,
144 config: Config,
145 ) -> Self {
146 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7);
147 config_pins!(v_sync, h_sync, pixclk);
148
149 Self::new_inner(peri, dma, config, false, 0b00)
150 }
151
152 pub fn new_10bit(
154 peri: Peri<'d, T>,
155 dma: Peri<'d, Dma>,
156 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
157 d0: Peri<'d, impl D0Pin<T>>,
158 d1: Peri<'d, impl D1Pin<T>>,
159 d2: Peri<'d, impl D2Pin<T>>,
160 d3: Peri<'d, impl D3Pin<T>>,
161 d4: Peri<'d, impl D4Pin<T>>,
162 d5: Peri<'d, impl D5Pin<T>>,
163 d6: Peri<'d, impl D6Pin<T>>,
164 d7: Peri<'d, impl D7Pin<T>>,
165 d8: Peri<'d, impl D8Pin<T>>,
166 d9: Peri<'d, impl D9Pin<T>>,
167 v_sync: Peri<'d, impl VSyncPin<T>>,
168 h_sync: Peri<'d, impl HSyncPin<T>>,
169 pixclk: Peri<'d, impl PixClkPin<T>>,
170 config: Config,
171 ) -> Self {
172 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9);
173 config_pins!(v_sync, h_sync, pixclk);
174
175 Self::new_inner(peri, dma, config, false, 0b01)
176 }
177
178 pub fn new_12bit(
180 peri: Peri<'d, T>,
181 dma: Peri<'d, Dma>,
182 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
183 d0: Peri<'d, impl D0Pin<T>>,
184 d1: Peri<'d, impl D1Pin<T>>,
185 d2: Peri<'d, impl D2Pin<T>>,
186 d3: Peri<'d, impl D3Pin<T>>,
187 d4: Peri<'d, impl D4Pin<T>>,
188 d5: Peri<'d, impl D5Pin<T>>,
189 d6: Peri<'d, impl D6Pin<T>>,
190 d7: Peri<'d, impl D7Pin<T>>,
191 d8: Peri<'d, impl D8Pin<T>>,
192 d9: Peri<'d, impl D9Pin<T>>,
193 d10: Peri<'d, impl D10Pin<T>>,
194 d11: Peri<'d, impl D11Pin<T>>,
195 v_sync: Peri<'d, impl VSyncPin<T>>,
196 h_sync: Peri<'d, impl HSyncPin<T>>,
197 pixclk: Peri<'d, impl PixClkPin<T>>,
198 config: Config,
199 ) -> Self {
200 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11);
201 config_pins!(v_sync, h_sync, pixclk);
202
203 Self::new_inner(peri, dma, config, false, 0b10)
204 }
205
206 pub fn new_14bit(
208 peri: Peri<'d, T>,
209 dma: Peri<'d, Dma>,
210 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
211 d0: Peri<'d, impl D0Pin<T>>,
212 d1: Peri<'d, impl D1Pin<T>>,
213 d2: Peri<'d, impl D2Pin<T>>,
214 d3: Peri<'d, impl D3Pin<T>>,
215 d4: Peri<'d, impl D4Pin<T>>,
216 d5: Peri<'d, impl D5Pin<T>>,
217 d6: Peri<'d, impl D6Pin<T>>,
218 d7: Peri<'d, impl D7Pin<T>>,
219 d8: Peri<'d, impl D8Pin<T>>,
220 d9: Peri<'d, impl D9Pin<T>>,
221 d10: Peri<'d, impl D10Pin<T>>,
222 d11: Peri<'d, impl D11Pin<T>>,
223 d12: Peri<'d, impl D12Pin<T>>,
224 d13: Peri<'d, impl D13Pin<T>>,
225 v_sync: Peri<'d, impl VSyncPin<T>>,
226 h_sync: Peri<'d, impl HSyncPin<T>>,
227 pixclk: Peri<'d, impl PixClkPin<T>>,
228 config: Config,
229 ) -> Self {
230 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13);
231 config_pins!(v_sync, h_sync, pixclk);
232
233 Self::new_inner(peri, dma, config, false, 0b11)
234 }
235
236 pub fn new_es_8bit(
238 peri: Peri<'d, T>,
239 dma: Peri<'d, Dma>,
240 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
241 d0: Peri<'d, impl D0Pin<T>>,
242 d1: Peri<'d, impl D1Pin<T>>,
243 d2: Peri<'d, impl D2Pin<T>>,
244 d3: Peri<'d, impl D3Pin<T>>,
245 d4: Peri<'d, impl D4Pin<T>>,
246 d5: Peri<'d, impl D5Pin<T>>,
247 d6: Peri<'d, impl D6Pin<T>>,
248 d7: Peri<'d, impl D7Pin<T>>,
249 pixclk: Peri<'d, impl PixClkPin<T>>,
250 config: Config,
251 ) -> Self {
252 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7);
253 config_pins!(pixclk);
254
255 Self::new_inner(peri, dma, config, true, 0b00)
256 }
257
258 pub fn new_es_10bit(
260 peri: Peri<'d, T>,
261 dma: Peri<'d, Dma>,
262 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
263 d0: Peri<'d, impl D0Pin<T>>,
264 d1: Peri<'d, impl D1Pin<T>>,
265 d2: Peri<'d, impl D2Pin<T>>,
266 d3: Peri<'d, impl D3Pin<T>>,
267 d4: Peri<'d, impl D4Pin<T>>,
268 d5: Peri<'d, impl D5Pin<T>>,
269 d6: Peri<'d, impl D6Pin<T>>,
270 d7: Peri<'d, impl D7Pin<T>>,
271 d8: Peri<'d, impl D8Pin<T>>,
272 d9: Peri<'d, impl D9Pin<T>>,
273 pixclk: Peri<'d, impl PixClkPin<T>>,
274 config: Config,
275 ) -> Self {
276 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9);
277 config_pins!(pixclk);
278
279 Self::new_inner(peri, dma, config, true, 0b01)
280 }
281
282 pub fn new_es_12bit(
284 peri: Peri<'d, T>,
285 dma: Peri<'d, Dma>,
286 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
287 d0: Peri<'d, impl D0Pin<T>>,
288 d1: Peri<'d, impl D1Pin<T>>,
289 d2: Peri<'d, impl D2Pin<T>>,
290 d3: Peri<'d, impl D3Pin<T>>,
291 d4: Peri<'d, impl D4Pin<T>>,
292 d5: Peri<'d, impl D5Pin<T>>,
293 d6: Peri<'d, impl D6Pin<T>>,
294 d7: Peri<'d, impl D7Pin<T>>,
295 d8: Peri<'d, impl D8Pin<T>>,
296 d9: Peri<'d, impl D9Pin<T>>,
297 d10: Peri<'d, impl D10Pin<T>>,
298 d11: Peri<'d, impl D11Pin<T>>,
299 pixclk: Peri<'d, impl PixClkPin<T>>,
300 config: Config,
301 ) -> Self {
302 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11);
303 config_pins!(pixclk);
304
305 Self::new_inner(peri, dma, config, true, 0b10)
306 }
307
308 pub fn new_es_14bit(
310 peri: Peri<'d, T>,
311 dma: Peri<'d, Dma>,
312 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
313 d0: Peri<'d, impl D0Pin<T>>,
314 d1: Peri<'d, impl D1Pin<T>>,
315 d2: Peri<'d, impl D2Pin<T>>,
316 d3: Peri<'d, impl D3Pin<T>>,
317 d4: Peri<'d, impl D4Pin<T>>,
318 d5: Peri<'d, impl D5Pin<T>>,
319 d6: Peri<'d, impl D6Pin<T>>,
320 d7: Peri<'d, impl D7Pin<T>>,
321 d8: Peri<'d, impl D8Pin<T>>,
322 d9: Peri<'d, impl D9Pin<T>>,
323 d10: Peri<'d, impl D10Pin<T>>,
324 d11: Peri<'d, impl D11Pin<T>>,
325 d12: Peri<'d, impl D12Pin<T>>,
326 d13: Peri<'d, impl D13Pin<T>>,
327 pixclk: Peri<'d, impl PixClkPin<T>>,
328 config: Config,
329 ) -> Self {
330 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13);
331 config_pins!(pixclk);
332
333 Self::new_inner(peri, dma, config, true, 0b11)
334 }
335
336 fn new_inner(
337 peri: Peri<'d, T>,
338 dma: Peri<'d, Dma>,
339 config: Config,
340 use_embedded_synchronization: bool,
341 edm: u8,
342 ) -> Self {
343 rcc::enable_and_reset::<T>();
344
345 peri.regs().cr().modify(|r| {
346 r.set_cm(true); r.set_ess(use_embedded_synchronization);
348 r.set_pckpol(config.pixclk_polarity == PixelClockPolarity::RisingEdge);
349 r.set_vspol(config.vsync_level == VSyncDataInvalidLevel::High);
350 r.set_hspol(config.hsync_level == HSyncDataInvalidLevel::High);
351 r.set_fcrc(0x00); r.set_edm(edm); });
354
355 T::Interrupt::unpend();
356 unsafe { T::Interrupt::enable() };
357
358 Self { inner: peri, dma }
359 }
360
361 fn toggle(enable: bool) {
362 crate::pac::DCMI.cr().modify(|r| {
363 r.set_enable(enable);
364 r.set_capture(enable);
365 })
366 }
367
368 fn enable_irqs() {
369 crate::pac::DCMI.ier().modify(|r| {
370 r.set_err_ie(true);
371 r.set_ovr_ie(true);
372 r.set_frame_ie(true);
373 });
374 }
375
376 fn clear_interrupt_flags() {
377 crate::pac::DCMI.icr().write(|r| {
378 r.set_ovr_isc(true);
379 r.set_err_isc(true);
380 r.set_frame_isc(true);
381 })
382 }
383
384 pub async fn capture(&mut self, buffer: &mut [u32]) -> Result<(), Error> {
387 let r = self.inner.regs();
388 let src = r.dr().as_ptr() as *mut u32;
389 let request = self.dma.request();
390 let dma_read = unsafe { Transfer::new_read(self.dma.reborrow(), request, src, buffer, Default::default()) };
391
392 Self::clear_interrupt_flags();
393 Self::enable_irqs();
394
395 Self::toggle(true);
396
397 let result = poll_fn(|cx| {
398 STATE.waker.register(cx.waker());
399
400 let ris = crate::pac::DCMI.ris().read();
401 if ris.err_ris() {
402 crate::pac::DCMI.icr().write(|r| r.set_err_isc(true));
403 Poll::Ready(Err(Error::PeripheralError))
404 } else if ris.ovr_ris() {
405 crate::pac::DCMI.icr().write(|r| r.set_ovr_isc(true));
406 Poll::Ready(Err(Error::Overrun))
407 } else if ris.frame_ris() {
408 crate::pac::DCMI.icr().write(|r| r.set_frame_isc(true));
409 Poll::Ready(Ok(()))
410 } else {
411 Poll::Pending
412 }
413 });
414
415 let (_, result) = embassy_futures::join::join(dma_read, result).await;
416
417 Self::toggle(false);
418
419 result
420 }
421}
422
423trait SealedInstance: crate::rcc::RccPeripheral {
424 fn regs(&self) -> crate::pac::dcmi::Dcmi;
425}
426
427#[allow(private_bounds)]
429pub trait Instance: SealedInstance + PeripheralType + 'static {
430 type Interrupt: interrupt::typelevel::Interrupt;
432}
433
434pin_trait!(D0Pin, Instance);
435pin_trait!(D1Pin, Instance);
436pin_trait!(D2Pin, Instance);
437pin_trait!(D3Pin, Instance);
438pin_trait!(D4Pin, Instance);
439pin_trait!(D5Pin, Instance);
440pin_trait!(D6Pin, Instance);
441pin_trait!(D7Pin, Instance);
442pin_trait!(D8Pin, Instance);
443pin_trait!(D9Pin, Instance);
444pin_trait!(D10Pin, Instance);
445pin_trait!(D11Pin, Instance);
446pin_trait!(D12Pin, Instance);
447pin_trait!(D13Pin, Instance);
448pin_trait!(HSyncPin, Instance);
449pin_trait!(VSyncPin, Instance);
450pin_trait!(PixClkPin, Instance);
451
452#[allow(unused)]
454macro_rules! impl_peripheral {
455 ($inst:ident, $irq:ident) => {
456 impl SealedInstance for crate::peripherals::$inst {
457 fn regs(&self) -> crate::pac::dcmi::Dcmi {
458 crate::pac::$inst
459 }
460 }
461
462 impl Instance for crate::peripherals::$inst {
463 type Interrupt = crate::interrupt::typelevel::$irq;
464 }
465 };
466}
467
468foreach_interrupt! {
469 ($inst:ident, dcmi, $block:ident, GLOBAL, $irq:ident) => {
470 impl_peripheral!($inst, $irq);
471 };
472}
473
474dma_trait!(FrameDma, Instance);