Capturing images using the Digital Camera Interface | STM32L4 | DCMI | CMSIS
Digital Camera Interface
DCMI Registers
The DCMI peripheral has Control and Status registers for the DCMI Core and Interrupts. It also has a few registers for handling Data synchronization, Cropping, and at last a Data Register. The ones used in this blog are:
- DCMI Control Register (DCMI_CR)
- DCMI Status Register (DCMI_SR)
- DCMI Interrupt Enable Register (DCMI_IER)
- DCMI Raw Interrupt Status Register (DCMI_RIS)
- DCMI Interrupt Clear Register (DCMI_ICR)
- DCMI Data Register (DCMI_DR)
Configuration of DCMI Peripheral
This driver is written specifically for interfacing with an OV7670 CMOS Camera Module from Omni Vision. So, we will configure the DCMI for an 8-bit Parallel interface. The Pixel Clock Polarity is set to the Rising Edge to capture the data. Hardware Synchronisation is used instead of Embedded Synchronisation mode and JPEG Compression is opted. We will configure the driver to operate the camera in Snapshot mode and not the Continous Grab mode. The rest of the options are set to the reset state.
Walkthrough
Definitions and Headers
Initializing GPIO Pins
HSYNC PH8
Configuring DMAMUX and DMA Controller
Once the DCMI peripheral starts capturing a frame, the data is added to an 8-word* FIFO and then fed into the DCMI Data Register (DCMI_DR). Since the DCMI peripheral acquires data at high speed, we have to use DMA to read the data from the DCMI_DR register rather than using the Software method.
In the STM32F4, we had some fixed peripherals for a DMA Channel and the inputs were multiplexed. But in the STM32L4, this is different. We can configure which peripheral can use which DMA Channel using the DMA Request Multiplexer (DMAMUX) peripheral.
We start off by enabling the clock to DMA1 and DMAMUX peripherals and waiting for the clock to be active. We set the DMAMUX's Channel 0 to the DCMI Peripheral, which is DMAMUX Input Request 90. So, we write 90 to the DCMI_CCR register. Then, we configure the DMA Controller's Channel 1, Source, and the Destination address to the DCMI_DR register and the character array, imageDataBuffer respectively. Then, we set the NDTR value to the BUFFER_SIZE macro, configure DMA to Memory Increment Mode, Enable Transfer Complete Interrupt, Set Transfer Direction to Read from Memory, and Set the Priority to High.
Configuring DCMI Core
From this function, we call the DCMI_InitGPIO() and DCMI_InitDMA() functions. In the DCMI Control Register, we set the DCMI peripheral to 8-bit input, with Hardware Synchronization, JPEG Compression, PXCLK Polarity to Rising Edge, and Capture Mode in Snapshot Mode. Then, we enable all the Interrupts available to the DCMI Peripheral in the DCMI_IER register. Finally, we enable the DCMI peripheral by setting the EN bit in the DCMI_CR register. But this does not start sampling the data from the camera, for that we have to set the CAPTURE bit.
De-initializing the DCMI Peripheral
When we want to De-Initialize the DCMI peripheral, we can do so by cutting off the clock signal to the DCMI peripheral in the RCC_AHB2ENR register.
Enabling and Disabling Capture
Once we need to capture a particular frame, we set the CAPTURE bit in the DCMI_CR register, Along with that, we will also enable Channel 1 of DMA1 to transfer data from DCMI_DR to the imageDataBuffer array. In the Snapshot mode, we don't need to Disable Capture, the hardware will reset the CAPTURE bit in the DCMI_CR register when a complete frame has been captured.
Polling DCMI Status
The DCMI Status Register can poll the status of three conditions,
- If FIFO is empty
- If in between Frames
- If in between Lines
DCMI Interrupt Handler
The DCMI Interrupt Request Handler is used to handle the Interrupts that occur due to any of the five previously enabled Interrupts in the DCMI_IER register. The five interrupts of the DCMI peripheral are;
- End of Line Interrupt
- Frame Synchronization Interrupt
- Embedded Synchronization Code Error Interrupt
- Data Overrun Interrupt
- End of Frame Interrupt
For the time being, we can just print the name of the interrupt fired to the Serial Terminal. We also have to clear the corresponding interrupt in the DCMI_ICR register, or else the Interrupt will be marked as pending.
Checkout my GitHub repository for example code and projects.