2022-04-05 03:44 PM
I have started with the DCMI example, but I am trying to modify it to improve performance. The DCMI example calls BSP_CAMERA_Suspend/BSP_CAMERA_Resume for every frame. From my testing, this seems to reduce the framerate by half. I would like to continuously run the DCMI, using the double buffer DMA to ping pong buffer each frame into two separate full-frame buffer locations in the SDRAM.
I have this ping pong buffering working, however, whenever I try to use one of the SDRAM frame buffers - copy them to another area in SDRAM or push them to the LCD SDRAM Frame buffer, I get a HAL_DCMI_ERROR_OVR
Is there perhaps a conflict with using the SDRAM for the LCD while the DCMI is DMA buffering to the SDRAM? Any suggested solutions?
2022-04-05 10:42 PM
I have DCMI project working with DMA+circular mode+mem2mem DMA (dcmiCplt and dcmiHalfCplt interrupts). Some copy-paste from the project:
// ...
hdma_dcmi.Instance = DMA2_Stream1;
hdma_dcmi.Init.Channel = DMA_CHANNEL_1;
hdma_dcmi.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_dcmi.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_dcmi.Init.MemInc = DMA_MINC_ENABLE;
hdma_dcmi.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_dcmi.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_dcmi.Init.Mode = DMA_CIRCULAR;
hdma_dcmi.Init.Priority = DMA_PRIORITY_LOW;
hdma_dcmi.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
// ...
__HAL_DCMI_ENABLE(&hdcmi);
hdcmi.Instance->CR &= ~(DCMI_CR_CM);
hdcmi.Instance->CR |= (uint32_t) (DCMI_MODE_SNAPSHOT);
hdcmi.DMA_Handle->XferHalfCpltCallback = &dcmiHalfCplt;
hdcmi.DMA_Handle->XferCpltCallback = &dcmiCplt;
hdcmi.DMA_Handle->XferErrorCallback = NULL;
hdcmi.DMA_Handle->XferAbortCallback = NULL;
HAL_DMA_Start_IT(hdcmi.DMA_Handle, (uint32_t) &hdcmi.Instance->DR,
(uint32_t) jpegBuffer, JPEG_BUFFER_SIZE / 2);
hdcmi.Instance->CR |= DCMI_CR_CAPTURE;
// ...
void dcmiHalfCplt(DMA_HandleTypeDef *hdma)
{
if (HAL_DMA_Start(&hdma_memtomem_dma2_stream0, (uint32_t)&jpegBuffer[0],
(uint32_t)&jpegCopy[0], sizeof(jpegBuffer)/4/2)!=HAL_OK)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7,GPIO_PIN_SET);
}
}
void dcmiCplt(DMA_HandleTypeDef *hdma)
{
// ...
My suggestion is to use DCMI in circular DMA mode. Because of high data rate data must be copied very fast, I've used another DMA to initiate MEM2MEM transfers on each DCMI DMA complete interrupt.
2022-04-06 12:07 AM
Georgy,
Thanks for the example. A couple of quick follow-ups. Are both jpegbuffer and jpegCopy in SDRAM? Also, what resolution are you doing? I am trying to do VGA (640x480 @ 25+ fps). It seems the DCMI DMA requires double buffer mode for any data sizes larger than 0xFFFF words.
I have it working DMA double buffer to System RAM, copying RAM to SDRAM, then pushing SDRAM Frame copy to the display FRAME buffer (SDRAM). This uses a lot of system ram though (307.2kb!). I would rather use the bulk SDRAM.
2022-04-06 12:58 AM
no external SDRAM in my project, I use small buffer in internal ram and push data to external IC in endless loop. Also I tested with 12bit parallel ADC (frame of infinite size, HSYNC and VSYNC are emulated using GPIO outputs). Maybe you can use smaller buffer too, for example 1024 bytes for DCMI+DMA, and transfer frame of any size to SDRAM by small 512 byte chunks (dcmiCplt and dcmiHalfCplt interrupts will be automatically called each 512 bytes if DMA is configured for 1024 bytes circular mode buffer). Last time I've used HAL DCMI functions DMA half complete callback was not implemented. To make this work, HAL DMA function must be copy-pasted to main.c and modified:
hdcmi.DMA_Handle->XferHalfCpltCallback = &dcmiHalfCplt;
hdcmi.DMA_Handle->XferCpltCallback = &dcmiCplt;
DCMI+DMA is started single time by calling HAL_DMA_Start_IT(hdcmi.DMA_Handle... before main loop.