Hi,
I’m using a NUCLEO-L4R5ZI board with OV2640 camera to capture pictures. Since I’m not familiar with HAL, I tested and modified a UART program which uses DMA. However, after modifying this program to work with DCMI, I cannot obtain any result from my buffer but all the debug outputs are positive. Can anyone help me out?
Here’s my source (codes that are commented using //
are original UART one).
Codes
BufferedSerial pc(USBTX, USBRX, 115200);
Timer t;
/* HW_PWR, HW_RST,
I2C_SDA, I2C_SCL
VSYNC, HSYNC, PCLK,
D0~D7 */
OV2640 camera1(
PB_1, PA_8,
PB_9, PB_8, // I2C1
PB_7, PA_4, PA_6,
PC_6, PC_7, PC_8, PC_9, PE_4, PD_3, PE_5, PE_6
);
DigitalOut flash(LED3);
// UART_HandleTypeDef uartHandle;
DCMI_HandleTypeDef dcmiHandle;
DMA_HandleTypeDef dmaHandle;
#define CAM_DIM_W 16
#define CAM_DIM_H 12
uint8_t captureBuffer[CAM_DIM_W * CAM_DIM_H * 2] = {0};
int main(void)
{
t.start();
printf("[%7lld] Start\n", t.elapsed_time().count()/1000);
/* Enable clocks */
__HAL_RCC_DMA1_CLK_ENABLE();
__HAL_RCC_DMA2_CLK_ENABLE();
__HAL_RCC_DMAMUX1_CLK_ENABLE();
// __HAL_RCC_UART5_CLK_ENABLE();
__HAL_RCC_DCMI_CLK_ENABLE();
// __HAL_RCC_GPIOC_CLK_ENABLE();
// __HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
/* Initialize GPIOs (for DCMI) */
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
// GPIO_InitStruct.Alternate = GPIO_AF8_UART5;
// GPIO_InitStruct.Pull = GPIO_PULLUP;
// GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
// GPIO_InitStruct.Pin = GPIO_PIN_12;
// HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = GPIO_PIN_2;
// HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.Alternate = GPIO_AF10_DCMI;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_4;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_6;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_9;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_3;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_7;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Init OV2640 */
camera1.powerStateSet(CAMERA_PWR_ON) == CAMERA_OK ?
printf("[%7lld] Power on\n", t.elapsed_time().count()/1000):
printf("[%7lld] Power on fail\n", t.elapsed_time().count()/1000);
camera1.hwReset() == CAMERA_OK ?
printf("[%7lld] Hardware reset\n", t.elapsed_time().count()/1000):
printf("[%7lld] Hardware reset fail\n", t.elapsed_time().count()/1000);
camera1.idCheck(OV2640_ADDRESS, 0x7FA2, 0x2642) == CAMERA_OK ?
printf("[%7lld] ID checked\n", t.elapsed_time().count()/1000):
printf("[%7lld] ID check fail\n", t.elapsed_time().count()/1000);
camera1.swReset(OV2640_ADDRESS) == CAMERA_OK ?
printf("[%7lld] Software Reset\n", t.elapsed_time().count()/1000):
printf("[%7lld] Software reset fail\n", t.elapsed_time().count()/1000);
camera1.init(OV2640_ADDRESS, CAMERA_RES_SXGA) == CAMERA_OK ?
printf("[%7lld] Inited\n", t.elapsed_time().count()/1000):
printf("[%7lld] Init fail\n", t.elapsed_time().count()/1000);
camera1.outputFormatSet(OV2640_ADDRESS, CAMERA_FMT_RGB565) == CAMERA_OK ?
printf("[%7lld] Output format set\n", t.elapsed_time().count()/1000):
printf("[%7lld] Output format set fail\n", t.elapsed_time().count()/1000);
camera1.outputResolutionSet(OV2640_ADDRESS, CAM_DIM_W, CAM_DIM_H) == CAMERA_OK ?
printf("[%7lld] Output resolution set\n", t.elapsed_time().count()/1000):
printf("[%7lld] Output resolution set fail\n", t.elapsed_time().count()/1000);
camera1.captureFrameRateSet(OV2640_ADDRESS, 0x0F) == CAMERA_OK ? /* set FPS */
printf("[%7lld] Capture frame rate set\n", t.elapsed_time().count()/1000):
printf("[%7lld] Capture frame rate fail\n", t.elapsed_time().count()/1000);
camera1.outputClockFreqSet(OV2640_ADDRESS, 0x7F) == CAMERA_OK ?
printf("[%7lld] Output frequency set\n", t.elapsed_time().count()/1000):
printf("[%7lld] Output frequency set fail\n", t.elapsed_time().count()/1000);
/* Peripheral handle */
// uartHandle.Instance = UART5;
// uartHandle.Init.BaudRate = 9600;
// uartHandle.Init.WordLength = UART_WORDLENGTH_8B;
// uartHandle.Init.StopBits = 1;
// uartHandle.Init.Parity = UART_PARITY_NONE;
// uartHandle.Init.HwFlowCtl = UART_HWCONTROL_CTS;
// uartHandle.Init.Mode = UART_MODE_TX_RX;
dcmiHandle.Instance = DCMI;
dcmiHandle.Init.SynchroMode = DCMI_SYNCHRO_HARDWARE;
dcmiHandle.Init.PCKPolarity = DCMI_PCKPOLARITY_RISING;
dcmiHandle.Init.VSPolarity = DCMI_VSPOLARITY_LOW;
dcmiHandle.Init.HSPolarity = DCMI_HSPOLARITY_LOW;
dcmiHandle.Init.CaptureRate = DCMI_CR_ALL_FRAME;
dcmiHandle.Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B;
dcmiHandle.Init.ByteSelectMode = DCMI_BSM_ALL;
dcmiHandle.Init.JPEGMode = DCMI_JPEG_DISABLE;
/* DMA handle */
// dmaHandle.Instance = DMA1_Channel1;
// dmaHandle.Init.Request = DMA_REQUEST_UART5_TX;
// dmaHandle.Init.Direction = DMA_MEMORY_TO_PERIPH;
// dmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
// dmaHandle.Init.MemInc = DMA_MINC_ENABLE;
// dmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
// dmaHandle.Init.PeriphInc = DMA_PINC_DISABLE;
// dmaHandle.Init.Mode = DMA_CIRCULAR;
// dmaHandle.Init.Priority = DMA_PRIORITY_HIGH;
dmaHandle.Instance = DMA1_Channel1;
dmaHandle.Init.Request = DMA_REQUEST_DCMI;
dmaHandle.Init.Direction = DMA_PERIPH_TO_MEMORY;
dmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
dmaHandle.Init.PeriphInc = DMA_PINC_DISABLE;
dmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
dmaHandle.Init.MemInc = DMA_MINC_ENABLE;
dmaHandle.Init.Mode = DMA_CIRCULAR;
dmaHandle.Init.Priority = DMA_PRIORITY_HIGH;
/* Init peripheral and DMA */
// __HAL_LINKDMA(&uartHandle, hdmatx, dmaHandle);
__HAL_LINKDMA(&dcmiHandle, DMA_Handle, dmaHandle);
// HAL_UART_Init(&uartHandle) == HAL_OK ?
HAL_DCMI_Init(&dcmiHandle) == HAL_OK ?
printf("[%7lld] DCMI inited\n", t.elapsed_time().count()/1000):
printf("[%7lld] DCMI init fail\n", t.elapsed_time().count()/1000);
HAL_DMA_Init(&dmaHandle) == HAL_OK ?
printf("[%7lld] DMA inited\n", t.elapsed_time().count()/1000):
printf("[%7lld] DMA init fail\n", t.elapsed_time().count()/1000);
/* Start transmission */
// uint8_t msg[] = "test";
// HAL_UART_Transmit_DMA(&uartHandle, msg, 4) == HAL_OK ?
// printf("[%7lld] UART_DMA started\n", t.elapsed_time().count()/1000):
// printf("[%7lld] UART_DMA start fail\n", t.elapsed_time().count()/1000);
HAL_DCMI_Start_DMA(&dcmiHandle, DCMI_MODE_SNAPSHOT, (uint32_t)captureBuffer, CAM_DIM_W * CAM_DIM_H * 2) == HAL_OK ?
printf("[%7lld] DCMI_DMA started\n", t.elapsed_time().count()/1000):
printf("[%7lld] DCMI_DMA start fail\n", t.elapsed_time().count()/1000);
while (true)
{
/* Determine transmission state */
// HAL_UART_Transmit(&uartHandle, msg, 6, 1000);
// if (__HAL_DMA_GET_FLAG(&dmaHandle, DMA_FLAG_TC1))
// {
// HAL_UART_DMAStop(&uartHandle);
// break;
// }
if (__HAL_DMA_GET_FLAG(&dmaHandle, DMA_FLAG_TC1))
{
HAL_DCMI_Stop(&dcmiHandle);
break;
}
flash = !flash;
ThisThread::sleep_for(1s);
}
flash = 1;
/* Send obtained data to computer */
for (int i=0; i<CAM_DIM_W*CAM_DIM_H*2; i+=2)
{
// printf("%02X ", cap[i]);
printf("%02X %02X %02X FF ", (
captureBuffer[i]&0x1F)<<3,
(captureBuffer[i+1]&0x07)<<5 | (captureBuffer[i]&0xE0)>>3,
captureBuffer[i+1]&0xF8);
}
printf("\n");
printf("[%7lld] Finished\n", t.elapsed_time().count()/1000);
flash = 0;
}
By the way, the OV2640 class was written by myself and was tested working well. I can capture small images (tested that no larger than 112*84 px when minimal clock frequency applied) using another approch. Greater resolutions result in unexpected missing pixel.
Codes
// DigitalIn sig_v, sig_h, sig_c;
// BusIn dat;
uint32_t OV2640::capture(uint8_t* cap)
{
uint32_t length = 0;
abandonFrames(1); // throw the first (not complete) frame
while(sig_v == 1) // start collecting
{
while(sig_h == 1)
{
while(sig_c == 0);
cap[length] = dat;
while(sig_c == 1);
length++;
}
}
return length;
}
Thank you for replying in advance.