Wednesday, July 9, 2014

Using the STM32 DCMI with JPEG Sensors

If you've been looking for this, chances are you saw Frank's post on the subject, while it contains very useful information and he mentions reading JPEG, he didn't explain his approach in details, so here's my soultion.

First, let me reiterate the issue with JPEG and the STM32, as you already know JPEG images are compressed, so you don't know the exact image size beforehand, you expect to read it after a complete transfer, however, the STM32 DMA data count register (NDTR) counts down, and therein lies the problem, the counter reaches zero after a complete transfer (or gets reloaded in case of a circular mode) either way, you can't find the transfer size after a DMA transfer is complete.

So here's my solution to this problem, first set the DMA stream to transfer the maximum frame size you expect or the absolute max for a DMA transfer (2^16 bits), afterwards, start the DCMI, it will generate a FRAME_IT when a whole frame has been read (VSYNC is asserted high/low depending on the polarity) however, the DMA will never stop, so at this point you should abort the DMA transfer, this will leave the remainder of the transfer size you requested earlier in the NDTR register (it's guaranteed to be there because the transfer was interrupted) now subtract that from the initial transfer size and you have the frame size.

Here's an example code, which uses the STM32Cube (HAL):

uint32_t addr;
uint16_t length;

addr = (uint32_t) image->pixels;
length = MAX_XFER_SIZE;

/* Start the DCMI */
HAL_DCMI_Start_DMA(&DCMIHandle,
        DCMI_MODE_SNAPSHOT, addr, length);

/* Wait for frame */
while ((DCMI->CR & DCMI_CR_CAPTURE) != 0) {

}

/* The frame is finished, but DMA still waiting
   for data because we set max frame size
   so we need to abort the DMA transfer here */
HAL_DMA_Abort(&DMAHandle);

/* Read the number of data items transferred */
image->size = (MAX_XFER_SIZE - DMAHandle.Instance->NDTR)*4;
One issue remains, what if it overflows ? well that would mean you're really cutting it close, but anyway (I haven't tested this) but you should be able read the overflow flag in the DCMI port, or check the JPEG markers.
Read more ...