esp_hal/lcd_cam/
cam.rs

1//! # Camera - Master or Slave Mode
2//!
3//! ## Overview
4//! The camera module is designed to receive parallel video data signals, and
5//! its bus supports DVP 8-/16-bit modes in master or slave mode.
6//!
7//! ## Configuration
8//! In master mode, the peripheral provides the master clock to drive the
9//! camera, in slave mode it does not. This is configured with the
10//! `with_master_clock` method on the camera driver. The driver (due to the
11//! peripheral) mandates DMA (Direct Memory Access) for efficient data transfer.
12//!
13//! ## Examples
14//! ## Master Mode
15//! Following code shows how to receive some bytes from an 8 bit DVP stream in
16//! master mode.
17//! ```rust, no_run
18#![doc = crate::before_snippet!()]
19//! # use esp_hal::lcd_cam::{cam::{Camera, Config}, LcdCam};
20//! # use esp_hal::dma_rx_stream_buffer;
21//!
22//! # let dma_buf = dma_rx_stream_buffer!(20 * 1000, 1000);
23//!
24//! let mclk_pin = peripherals.GPIO15;
25//! let vsync_pin = peripherals.GPIO6;
26//! let href_pin = peripherals.GPIO7;
27//! let pclk_pin = peripherals.GPIO13;
28//!
29//! let config = Config::default().with_frequency(Rate::from_mhz(20));
30//!
31//! let lcd_cam = LcdCam::new(peripherals.LCD_CAM);
32//! let mut camera = Camera::new(
33//!     lcd_cam.cam,
34//!     peripherals.DMA_CH0,
35//!     config,
36//! )?
37//! .with_master_clock(mclk_pin) // Remove this for slave mode
38//! .with_pixel_clock(pclk_pin)
39//! .with_vsync(vsync_pin)
40//! .with_h_enable(href_pin)
41//! .with_data0(peripherals.GPIO11)
42//! .with_data1(peripherals.GPIO9)
43//! .with_data2(peripherals.GPIO8)
44//! .with_data3(peripherals.GPIO10)
45//! .with_data4(peripherals.GPIO12)
46//! .with_data5(peripherals.GPIO18)
47//! .with_data6(peripherals.GPIO17)
48//! .with_data7(peripherals.GPIO16);
49//!
50//! let transfer = camera.receive(dma_buf).map_err(|e| e.0)?;
51//!
52//! # Ok(())
53//! # }
54//! ```
55
56use core::{
57    mem::ManuallyDrop,
58    ops::{Deref, DerefMut},
59};
60
61use crate::{
62    Blocking,
63    clock::Clocks,
64    dma::{ChannelRx, DmaError, DmaPeripheral, DmaRxBuffer, PeripheralRxChannel, RxChannelFor},
65    gpio::{
66        InputConfig,
67        InputSignal,
68        OutputConfig,
69        OutputSignal,
70        interconnect::{PeripheralInput, PeripheralOutput},
71    },
72    lcd_cam::{BitOrder, ByteOrder, ClockError, calculate_clkm},
73    pac,
74    peripherals::LCD_CAM,
75    system::{self, GenericPeripheralGuard},
76    time::Rate,
77};
78
79/// Generation of GDMA SUC EOF
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81#[cfg_attr(feature = "defmt", derive(defmt::Format))]
82pub enum EofMode {
83    /// Generate GDMA SUC EOF by data byte length
84    ByteLen,
85    /// Generate GDMA SUC EOF by the vsync signal
86    VsyncSignal,
87}
88
89/// Vsync Filter Threshold
90#[derive(Debug, Clone, Copy, PartialEq, Eq)]
91#[cfg_attr(feature = "defmt", derive(defmt::Format))]
92pub enum VsyncFilterThreshold {
93    /// Requires 1 valid VSYNC pulse to trigger synchronization.
94    One,
95    /// Requires 2 valid VSYNC pulse to trigger synchronization.
96    Two,
97    /// Requires 3 valid VSYNC pulse to trigger synchronization.
98    Three,
99    /// Requires 4 valid VSYNC pulse to trigger synchronization.
100    Four,
101    /// Requires 5 valid VSYNC pulse to trigger synchronization.
102    Five,
103    /// Requires 6 valid VSYNC pulse to trigger synchronization.
104    Six,
105    /// Requires 7 valid VSYNC pulse to trigger synchronization.
106    Seven,
107    /// Requires 8 valid VSYNC pulse to trigger synchronization.
108    Eight,
109}
110
111/// Vsync/Hsync or Data Enable Mode
112#[derive(Debug, Clone, Copy, PartialEq, Eq)]
113#[cfg_attr(feature = "defmt", derive(defmt::Format))]
114pub enum VhdeMode {
115    /// VSYNC + HSYNC mode is selected, in this mode,
116    /// the signals of VSYNC, HSYNC and DE are used to control the data.
117    /// For this case, users need to wire the three signal lines.
118    VsyncHsync,
119
120    /// DE mode is selected, the signals of VSYNC and
121    /// DE are used to control the data. For this case, wiring HSYNC signal
122    /// line is not a must. But in this case, the YUV-RGB conversion
123    /// function of camera module is not available.
124    De,
125}
126
127/// Vsync Filter Threshold
128#[derive(Debug, Clone, Copy, PartialEq)]
129#[cfg_attr(feature = "defmt", derive(defmt::Format))]
130pub enum ConfigError {
131    /// The frequency is out of range.
132    Clock(ClockError),
133}
134
135/// Represents the camera interface.
136pub struct Cam<'d> {
137    /// The LCD_CAM peripheral reference for managing the camera functionality.
138    pub(crate) lcd_cam: LCD_CAM<'d>,
139    pub(super) _guard: GenericPeripheralGuard<{ system::Peripheral::LcdCam as u8 }>,
140}
141
142/// Represents the camera interface with DMA support.
143pub struct Camera<'d> {
144    lcd_cam: LCD_CAM<'d>,
145    rx_channel: ChannelRx<Blocking, PeripheralRxChannel<LCD_CAM<'d>>>,
146    _guard: GenericPeripheralGuard<{ system::Peripheral::LcdCam as u8 }>,
147}
148
149impl<'d> Camera<'d> {
150    /// Creates a new `Camera` instance with DMA support.
151    pub fn new(
152        cam: Cam<'d>,
153        channel: impl RxChannelFor<LCD_CAM<'d>>,
154        config: Config,
155    ) -> Result<Self, ConfigError> {
156        let rx_channel = ChannelRx::new(channel.degrade());
157
158        let mut this = Self {
159            lcd_cam: cam.lcd_cam,
160            rx_channel,
161            _guard: cam._guard,
162        };
163
164        this.apply_config(&config)?;
165
166        Ok(this)
167    }
168
169    fn regs(&self) -> &pac::lcd_cam::RegisterBlock {
170        self.lcd_cam.register_block()
171    }
172
173    /// Applies the configuration to the camera interface.
174    ///
175    /// # Errors
176    ///
177    /// [`ConfigError::Clock`] will be returned if the frequency passed in
178    /// `Config` is too low.
179    pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> {
180        let clocks = Clocks::get();
181        let (i, divider) = calculate_clkm(
182            config.frequency.as_hz() as _,
183            &[
184                clocks.xtal_clock.as_hz() as _,
185                clocks.cpu_clock.as_hz() as _,
186                clocks.crypto_pwm_clock.as_hz() as _,
187            ],
188        )
189        .map_err(ConfigError::Clock)?;
190
191        self.regs().cam_ctrl().write(|w| {
192            // Force enable the clock for all configuration registers.
193            unsafe {
194                w.cam_clk_sel().bits((i + 1) as _);
195                w.cam_clkm_div_num().bits(divider.div_num as _);
196                w.cam_clkm_div_b().bits(divider.div_b as _);
197                w.cam_clkm_div_a().bits(divider.div_a as _);
198                if let Some(threshold) = config.vsync_filter_threshold {
199                    w.cam_vsync_filter_thres().bits(threshold as _);
200                }
201                w.cam_byte_order()
202                    .bit(config.byte_order != ByteOrder::default());
203                w.cam_bit_order()
204                    .bit(config.bit_order != BitOrder::default());
205                w.cam_vs_eof_en().set_bit();
206                w.cam_line_int_en().clear_bit();
207                w.cam_stop_en().clear_bit()
208            }
209        });
210        self.regs().cam_ctrl1().write(|w| unsafe {
211            w.cam_2byte_en().bit(config.enable_2byte_mode);
212            w.cam_vh_de_mode_en()
213                .bit(matches!(config.vh_de_mode, VhdeMode::VsyncHsync));
214            w.cam_rec_data_bytelen().bits(0);
215            w.cam_line_int_num().bits(0);
216            w.cam_vsync_filter_en()
217                .bit(config.vsync_filter_threshold.is_some());
218            w.cam_clk_inv().clear_bit();
219            w.cam_de_inv().clear_bit();
220            w.cam_hsync_inv().clear_bit();
221            w.cam_vsync_inv().clear_bit()
222        });
223
224        self.regs()
225            .cam_rgb_yuv()
226            .write(|w| w.cam_conv_bypass().clear_bit());
227
228        self.regs()
229            .cam_ctrl()
230            .modify(|_, w| w.cam_update().set_bit());
231
232        Ok(())
233    }
234}
235
236impl<'d> Camera<'d> {
237    /// Configures the master clock (MCLK) pin for the camera interface.
238    pub fn with_master_clock(self, mclk: impl PeripheralOutput<'d>) -> Self {
239        let mclk = mclk.into();
240
241        mclk.apply_output_config(&OutputConfig::default());
242        mclk.set_output_enable(true);
243
244        OutputSignal::CAM_CLK.connect_to(&mclk);
245
246        self
247    }
248
249    /// Configures the pixel clock (PCLK) pin for the camera interface.
250    pub fn with_pixel_clock(self, pclk: impl PeripheralInput<'d>) -> Self {
251        let pclk = pclk.into();
252
253        pclk.apply_input_config(&InputConfig::default());
254        pclk.set_input_enable(true);
255        InputSignal::CAM_PCLK.connect_to(&pclk);
256
257        self
258    }
259
260    /// Configures the Vertical Sync (VSYNC) pin for the camera interface.
261    pub fn with_vsync(self, pin: impl PeripheralInput<'d>) -> Self {
262        let pin = pin.into();
263
264        pin.apply_input_config(&InputConfig::default());
265        pin.set_input_enable(true);
266        InputSignal::CAM_V_SYNC.connect_to(&pin);
267
268        self
269    }
270
271    /// Configures the Horizontal Sync (HSYNC) pin for the camera interface.
272    pub fn with_hsync(self, pin: impl PeripheralInput<'d>) -> Self {
273        let pin = pin.into();
274
275        pin.apply_input_config(&InputConfig::default());
276        pin.set_input_enable(true);
277        InputSignal::CAM_H_SYNC.connect_to(&pin);
278
279        self
280    }
281
282    /// Configures the Horizontal Enable (HENABLE) pin for the camera interface.
283    ///
284    /// Also known as "Data Enable".
285    pub fn with_h_enable(self, pin: impl PeripheralInput<'d>) -> Self {
286        let pin = pin.into();
287
288        pin.apply_input_config(&InputConfig::default());
289        pin.set_input_enable(true);
290        InputSignal::CAM_H_ENABLE.connect_to(&pin);
291
292        self
293    }
294
295    fn with_data_pin(self, signal: InputSignal, pin: impl PeripheralInput<'d>) -> Self {
296        let pin = pin.into();
297
298        pin.apply_input_config(&InputConfig::default());
299        pin.set_input_enable(true);
300        signal.connect_to(&pin);
301
302        self
303    }
304
305    /// Configures the DATA 0 pin for the camera interface.
306    pub fn with_data0(self, pin: impl PeripheralInput<'d>) -> Self {
307        self.with_data_pin(InputSignal::CAM_DATA_0, pin)
308    }
309
310    /// Configures the DATA 1 pin for the camera interface.
311    pub fn with_data1(self, pin: impl PeripheralInput<'d>) -> Self {
312        self.with_data_pin(InputSignal::CAM_DATA_1, pin)
313    }
314
315    /// Configures the DATA 2 pin for the camera interface.
316    pub fn with_data2(self, pin: impl PeripheralInput<'d>) -> Self {
317        self.with_data_pin(InputSignal::CAM_DATA_2, pin)
318    }
319
320    /// Configures the DATA 3 pin for the camera interface.
321    pub fn with_data3(self, pin: impl PeripheralInput<'d>) -> Self {
322        self.with_data_pin(InputSignal::CAM_DATA_3, pin)
323    }
324
325    /// Configures the DATA 4 pin for the camera interface.
326    pub fn with_data4(self, pin: impl PeripheralInput<'d>) -> Self {
327        self.with_data_pin(InputSignal::CAM_DATA_4, pin)
328    }
329
330    /// Configures the DATA 5 pin for the camera interface.
331    pub fn with_data5(self, pin: impl PeripheralInput<'d>) -> Self {
332        self.with_data_pin(InputSignal::CAM_DATA_5, pin)
333    }
334
335    /// Configures the DATA 6 pin for the camera interface.
336    pub fn with_data6(self, pin: impl PeripheralInput<'d>) -> Self {
337        self.with_data_pin(InputSignal::CAM_DATA_6, pin)
338    }
339
340    /// Configures the DATA 7 pin for the camera interface.
341    pub fn with_data7(self, pin: impl PeripheralInput<'d>) -> Self {
342        self.with_data_pin(InputSignal::CAM_DATA_7, pin)
343    }
344
345    /// Configures the DATA 8 pin for the camera interface.
346    pub fn with_data8(self, pin: impl PeripheralInput<'d>) -> Self {
347        self.with_data_pin(InputSignal::CAM_DATA_8, pin)
348    }
349
350    /// Configures the DATA 9 pin for the camera interface.
351    pub fn with_data9(self, pin: impl PeripheralInput<'d>) -> Self {
352        self.with_data_pin(InputSignal::CAM_DATA_9, pin)
353    }
354
355    /// Configures the DATA 10 pin for the camera interface.
356    pub fn with_data10(self, pin: impl PeripheralInput<'d>) -> Self {
357        self.with_data_pin(InputSignal::CAM_DATA_10, pin)
358    }
359
360    /// Configures the DATA 11 pin for the camera interface.
361    pub fn with_data11(self, pin: impl PeripheralInput<'d>) -> Self {
362        self.with_data_pin(InputSignal::CAM_DATA_11, pin)
363    }
364
365    /// Configures the DATA 12 pin for the camera interface.
366    pub fn with_data12(self, pin: impl PeripheralInput<'d>) -> Self {
367        self.with_data_pin(InputSignal::CAM_DATA_12, pin)
368    }
369
370    /// Configures the DATA 13 pin for the camera interface.
371    pub fn with_data13(self, pin: impl PeripheralInput<'d>) -> Self {
372        self.with_data_pin(InputSignal::CAM_DATA_13, pin)
373    }
374
375    /// Configures the DATA 14 pin for the camera interface.
376    pub fn with_data14(self, pin: impl PeripheralInput<'d>) -> Self {
377        self.with_data_pin(InputSignal::CAM_DATA_14, pin)
378    }
379
380    /// Configures the DATA 15 pin for the camera interface.
381    pub fn with_data15(self, pin: impl PeripheralInput<'d>) -> Self {
382        self.with_data_pin(InputSignal::CAM_DATA_15, pin)
383    }
384
385    /// Starts a DMA transfer to receive data from the camera peripheral.
386    pub fn receive<BUF: DmaRxBuffer>(
387        mut self,
388        mut buf: BUF,
389    ) -> Result<CameraTransfer<'d, BUF>, (DmaError, Self, BUF)> {
390        // Reset Camera control unit and Async Rx FIFO
391        self.regs()
392            .cam_ctrl1()
393            .modify(|_, w| w.cam_reset().set_bit());
394        self.regs()
395            .cam_ctrl1()
396            .modify(|_, w| w.cam_reset().clear_bit());
397        self.regs()
398            .cam_ctrl1()
399            .modify(|_, w| w.cam_afifo_reset().set_bit());
400        self.regs()
401            .cam_ctrl1()
402            .modify(|_, w| w.cam_afifo_reset().clear_bit());
403
404        // Start DMA to receive incoming transfer.
405        let result = unsafe {
406            self.rx_channel
407                .prepare_transfer(DmaPeripheral::LcdCam, &mut buf)
408                .and_then(|_| self.rx_channel.start_transfer())
409        };
410
411        if let Err(e) = result {
412            return Err((e, self, buf));
413        }
414
415        // Start the Camera unit to listen for incoming DVP stream.
416        self.regs().cam_ctrl().modify(|_, w| {
417            // Automatically stops the camera unit once the GDMA Rx FIFO is full.
418            w.cam_stop_en().set_bit();
419
420            w.cam_update().set_bit()
421        });
422        self.regs()
423            .cam_ctrl1()
424            .modify(|_, w| w.cam_start().set_bit());
425
426        Ok(CameraTransfer {
427            camera: ManuallyDrop::new(self),
428            buffer_view: ManuallyDrop::new(buf.into_view()),
429        })
430    }
431}
432
433/// Represents an ongoing (or potentially stopped) transfer from the Camera to a
434/// DMA buffer.
435pub struct CameraTransfer<'d, BUF: DmaRxBuffer> {
436    camera: ManuallyDrop<Camera<'d>>,
437    buffer_view: ManuallyDrop<BUF::View>,
438}
439
440impl<'d, BUF: DmaRxBuffer> CameraTransfer<'d, BUF> {
441    /// Returns true when [Self::wait] will not block.
442    pub fn is_done(&self) -> bool {
443        // This peripheral doesn't really "complete". As long the camera (or anything
444        // pretending to be :D) sends data, it will receive it and pass it to the DMA.
445        // This implementation of is_done is an opinionated one. When the transfer is
446        // started, the CAM_STOP_EN bit is set, which tells the LCD_CAM to stop
447        // itself when the DMA stops emptying its async RX FIFO. This will
448        // typically be because the DMA ran out descriptors but there could be other
449        // reasons as well.
450
451        // In the future, a user of esp_hal may not want this behaviour, which would be
452        // a reasonable ask. At which point is_done and wait would go away, and
453        // the driver will stop pretending that this peripheral has some kind of
454        // finish line.
455
456        // For now, most people probably want this behaviour, so it shall be kept for
457        // the sake of familiarity and similarity with other drivers.
458
459        self.camera
460            .regs()
461            .cam_ctrl1()
462            .read()
463            .cam_start()
464            .bit_is_clear()
465    }
466
467    /// Stops this transfer on the spot and returns the peripheral and buffer.
468    pub fn stop(mut self) -> (Camera<'d>, BUF) {
469        self.stop_peripherals();
470        let (camera, view) = self.release();
471        (camera, BUF::from_view(view))
472    }
473
474    /// Waits for the transfer to stop and returns the peripheral and buffer.
475    ///
476    /// Note: The camera doesn't really "finish" its transfer, so what you're
477    /// really waiting for here is a DMA Error. You typically just want to
478    /// call [Self::stop] once you have the data you need.
479    pub fn wait(mut self) -> (Result<(), DmaError>, Camera<'d>, BUF) {
480        while !self.is_done() {}
481
482        // Stop the DMA as it doesn't know that the camera has stopped.
483        self.camera.rx_channel.stop_transfer();
484
485        // Note: There is no "done" interrupt to clear.
486
487        let (camera, view) = self.release();
488
489        let result = if camera.rx_channel.has_error() {
490            Err(DmaError::DescriptorError)
491        } else {
492            Ok(())
493        };
494
495        (result, camera, BUF::from_view(view))
496    }
497
498    fn release(mut self) -> (Camera<'d>, BUF::View) {
499        // SAFETY: Since forget is called on self, we know that self.camera and
500        // self.buffer_view won't be touched again.
501        let result = unsafe {
502            let camera = ManuallyDrop::take(&mut self.camera);
503            let view = ManuallyDrop::take(&mut self.buffer_view);
504            (camera, view)
505        };
506        core::mem::forget(self);
507        result
508    }
509
510    fn stop_peripherals(&mut self) {
511        // Stop the LCD_CAM peripheral.
512        self.camera
513            .regs()
514            .cam_ctrl1()
515            .modify(|_, w| w.cam_start().clear_bit());
516
517        // Stop the DMA
518        self.camera.rx_channel.stop_transfer();
519    }
520}
521
522impl<BUF: DmaRxBuffer> Deref for CameraTransfer<'_, BUF> {
523    type Target = BUF::View;
524
525    fn deref(&self) -> &Self::Target {
526        &self.buffer_view
527    }
528}
529
530impl<BUF: DmaRxBuffer> DerefMut for CameraTransfer<'_, BUF> {
531    fn deref_mut(&mut self) -> &mut Self::Target {
532        &mut self.buffer_view
533    }
534}
535
536impl<BUF: DmaRxBuffer> Drop for CameraTransfer<'_, BUF> {
537    fn drop(&mut self) {
538        self.stop_peripherals();
539
540        // SAFETY: This is Drop, we know that self.camera and self.buffer_view
541        // won't be touched again.
542        unsafe {
543            ManuallyDrop::drop(&mut self.camera);
544            ManuallyDrop::drop(&mut self.buffer_view);
545        }
546    }
547}
548
549#[derive(Debug, Clone, Copy, PartialEq, procmacros::BuilderLite)]
550#[cfg_attr(feature = "defmt", derive(defmt::Format))]
551/// Configuration settings for the Camera interface.
552pub struct Config {
553    /// The pixel clock frequency for the camera interface.
554    frequency: Rate,
555
556    /// Enable 16 bit mode (instead of 8 bit).
557    enable_2byte_mode: bool,
558
559    /// The byte order for the camera data.
560    byte_order: ByteOrder,
561
562    /// The bit order for the camera data.
563    bit_order: BitOrder,
564
565    /// Vsync/Hsync or Data Enable Mode
566    vh_de_mode: VhdeMode,
567
568    /// The Vsync filter threshold.
569    vsync_filter_threshold: Option<VsyncFilterThreshold>,
570}
571
572impl Default for Config {
573    fn default() -> Self {
574        Self {
575            frequency: Rate::from_mhz(20),
576            enable_2byte_mode: false,
577            byte_order: Default::default(),
578            bit_order: Default::default(),
579            vh_de_mode: VhdeMode::De,
580            vsync_filter_threshold: None,
581        }
582    }
583}