diff options
| author | Matous Hybl <[email protected]> | 2021-11-10 14:47:16 +0100 |
|---|---|---|
| committer | Matous Hybl <[email protected]> | 2021-12-09 12:56:39 +0100 |
| commit | 1dd5a71c07d2ab9aec1d9af7b4c87d5b1b969bd8 (patch) | |
| tree | 206f031c4d2c6857e40e9fbc1da9e607617c2928 | |
| parent | 8ad8e3b718d0f66e2d6e52c4beb112977c6a73b4 (diff) | |
Add DCMI peripheral support.
| -rw-r--r-- | embassy-stm32/src/dcmi.rs | 481 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/h7/mod.rs | 5 |
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 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | use core::task::Poll; | ||
| 3 | |||
| 4 | use crate::gpio::sealed::Pin as __GpioPin; | ||
| 5 | use crate::gpio::Pin as GpioPin; | ||
| 6 | use embassy::interrupt::{Interrupt, InterruptExt}; | ||
| 7 | use embassy::util::Unborrow; | ||
| 8 | use embassy::waitqueue::AtomicWaker; | ||
| 9 | use embassy_hal_common::unborrow; | ||
| 10 | use 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)] | ||
| 14 | pub 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)] | ||
| 21 | pub enum HSyncDataInvalidLevel { | ||
| 22 | Low, | ||
| 23 | High, | ||
| 24 | } | ||
| 25 | |||
| 26 | #[derive(Clone, Copy, PartialEq)] | ||
| 27 | pub enum PixelClockPolarity { | ||
| 28 | RisingEdge, | ||
| 29 | FallingEdge, | ||
| 30 | } | ||
| 31 | |||
| 32 | pub struct State { | ||
| 33 | waker: AtomicWaker, | ||
| 34 | } | ||
| 35 | impl State { | ||
| 36 | const fn new() -> State { | ||
| 37 | State { | ||
| 38 | waker: AtomicWaker::new(), | ||
| 39 | } | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | static STATE: State = State::new(); | ||
| 44 | |||
| 45 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] | ||
| 46 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 47 | #[non_exhaustive] | ||
| 48 | pub enum Error { | ||
| 49 | Overrun, | ||
| 50 | PeripheralError, | ||
| 51 | } | ||
| 52 | |||
| 53 | pub struct Dcmi<'d, T: Instance, Dma: FrameDma> { | ||
| 54 | inner: T, | ||
| 55 | dma: Dma, | ||
| 56 | phantom: PhantomData<&'d mut T>, | ||
| 57 | } | ||
| 58 | |||
| 59 | impl<'d, T, Dma> Dcmi<'d, T, Dma> | ||
| 60 | where | ||
| 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 | |||
| 254 | mod 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 | |||
| 302 | pub trait Instance: sealed::Instance + 'static { | ||
| 303 | type Interrupt: Interrupt; | ||
| 304 | } | ||
| 305 | |||
| 306 | pub trait FrameDma: sealed::FrameDma + crate::dma::Channel {} | ||
| 307 | |||
| 308 | macro_rules! pin { | ||
| 309 | ($name:ident) => { | ||
| 310 | pub trait $name: sealed::$name + 'static {} | ||
| 311 | }; | ||
| 312 | } | ||
| 313 | |||
| 314 | pin!(D0Pin); | ||
| 315 | pin!(D1Pin); | ||
| 316 | pin!(D2Pin); | ||
| 317 | pin!(D3Pin); | ||
| 318 | pin!(D4Pin); | ||
| 319 | pin!(D5Pin); | ||
| 320 | pin!(D6Pin); | ||
| 321 | pin!(D7Pin); | ||
| 322 | pin!(D8Pin); | ||
| 323 | pin!(D9Pin); | ||
| 324 | pin!(D10Pin); | ||
| 325 | pin!(D11Pin); | ||
| 326 | pin!(D12Pin); | ||
| 327 | pin!(D13Pin); | ||
| 328 | |||
| 329 | pin!(HSyncPin); | ||
| 330 | pin!(VSyncPin); | ||
| 331 | pin!(PixClkPin); | ||
| 332 | |||
| 333 | // allow unused as U5 sources do not contain interrupt nor dma data | ||
| 334 | #[allow(unused)] | ||
| 335 | macro_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 | |||
| 349 | crate::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)] | ||
| 357 | macro_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 | |||
| 381 | crate::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 | |||
| 390 | macro_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 | |||
| 411 | macro_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 | |||
| 420 | impl_no_pin!(D8Pin); | ||
| 421 | impl_no_pin!(D9Pin); | ||
| 422 | impl_no_pin!(D10Pin); | ||
| 423 | impl_no_pin!(D11Pin); | ||
| 424 | impl_no_pin!(D12Pin); | ||
| 425 | impl_no_pin!(D13Pin); | ||
| 426 | impl_no_pin!(HSyncPin); | ||
| 427 | impl_no_pin!(VSyncPin); | ||
| 428 | |||
| 429 | crate::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; | |||
| 32 | pub mod dac; | 32 | pub mod dac; |
| 33 | #[cfg(dbgmcu)] | 33 | #[cfg(dbgmcu)] |
| 34 | pub mod dbgmcu; | 34 | pub mod dbgmcu; |
| 35 | #[cfg(dcmi)] | ||
| 36 | pub mod dcmi; | ||
| 35 | #[cfg(all(eth, feature = "net"))] | 37 | #[cfg(all(eth, feature = "net"))] |
| 36 | pub mod eth; | 38 | pub 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 | ||
| 78 | pub struct Rcc<'d> { | 79 | pub 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), |
