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