配置总共分以下几步:
一:硬件初始化
OV5640_HW_Init();
void OV5640_HW_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStruct;
/***DCMI引脚配置***/
/* 使能DCMI时钟 */
RCC_AHB1PeriphClockCmd(DCMI_PWDN_GPIO_CLK|DCMI_RST_GPIO_CLK|DCMI_VSYNC_GPIO_CLK | DCMI_HSYNC_GPIO_CLK | DCMI_PIXCLK_GPIO_CLK|
DCMI_D0_GPIO_CLK| DCMI_D1_GPIO_CLK| DCMI_D2_GPIO_CLK| DCMI_D3_GPIO_CLK|
DCMI_D4_GPIO_CLK| DCMI_D5_GPIO_CLK| DCMI_D6_GPIO_CLK| DCMI_D7_GPIO_CLK, ENABLE);
/*控制/同步信号线*/
GPIO_InitStructure.GPIO_Pin = DCMI_VSYNC_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
GPIO_Init(DCMI_VSYNC_GPIO_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(DCMI_VSYNC_GPIO_PORT, DCMI_VSYNC_PINSOURCE, DCMI_VSYNC_AF);
GPIO_InitStructure.GPIO_Pin = DCMI_HSYNC_GPIO_PIN ;
GPIO_Init(DCMI_HSYNC_GPIO_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(DCMI_HSYNC_GPIO_PORT, DCMI_HSYNC_PINSOURCE, DCMI_HSYNC_AF);
GPIO_InitStructure.GPIO_Pin = DCMI_PIXCLK_GPIO_PIN ;
GPIO_Init(DCMI_PIXCLK_GPIO_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(DCMI_PIXCLK_GPIO_PORT, DCMI_PIXCLK_PINSOURCE, DCMI_PIXCLK_AF);
/*数据信号*/
GPIO_InitStructure.GPIO_Pin = DCMI_D0_GPIO_PIN ;
GPIO_Init(DCMI_D0_GPIO_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(DCMI_D0_GPIO_PORT, DCMI_D0_PINSOURCE, DCMI_D0_AF);
GPIO_InitStructure.GPIO_Pin = DCMI_D1_GPIO_PIN ;
GPIO_Init(DCMI_D1_GPIO_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(DCMI_D1_GPIO_PORT, DCMI_D1_PINSOURCE, DCMI_D1_AF);
GPIO_InitStructure.GPIO_Pin = DCMI_D2_GPIO_PIN ;
GPIO_Init(DCMI_D2_GPIO_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(DCMI_D2_GPIO_PORT, DCMI_D2_PINSOURCE, DCMI_D2_AF);
GPIO_InitStructure.GPIO_Pin = DCMI_D3_GPIO_PIN ;
GPIO_Init(DCMI_D3_GPIO_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(DCMI_D3_GPIO_PORT, DCMI_D3_PINSOURCE, DCMI_D3_AF);
GPIO_InitStructure.GPIO_Pin = DCMI_D4_GPIO_PIN ;
GPIO_Init(DCMI_D4_GPIO_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(DCMI_D4_GPIO_PORT, DCMI_D4_PINSOURCE, DCMI_D4_AF);
GPIO_InitStructure.GPIO_Pin = DCMI_D5_GPIO_PIN ;
GPIO_Init(DCMI_D5_GPIO_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(DCMI_D5_GPIO_PORT, DCMI_D5_PINSOURCE, DCMI_D5_AF);
GPIO_InitStructure.GPIO_Pin = DCMI_D6_GPIO_PIN ;
GPIO_Init(DCMI_D6_GPIO_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(DCMI_D6_GPIO_PORT, DCMI_D6_PINSOURCE, DCMI_D6_AF);
GPIO_InitStructure.GPIO_Pin = DCMI_D7_GPIO_PIN ;
GPIO_Init(DCMI_D7_GPIO_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(DCMI_D7_GPIO_PORT, DCMI_D7_PINSOURCE, DCMI_D7_AF);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = DCMI_PWDN_GPIO_PIN ;
GPIO_Init(DCMI_PWDN_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = DCMI_RST_GPIO_PIN ;
GPIO_Init(DCMI_RST_GPIO_PORT, &GPIO_InitStructure);
/*PWDN引脚,高电平关闭电源,低电平供电*/
GPIO_ResetBits(DCMI_RST_GPIO_PORT,DCMI_RST_GPIO_PIN);
GPIO_SetBits(DCMI_PWDN_GPIO_PORT,DCMI_PWDN_GPIO_PIN);
Delay(10);
GPIO_ResetBits(DCMI_PWDN_GPIO_PORT,DCMI_PWDN_GPIO_PIN);
//先拉低RST, 关闭电源10ms,然后打开电源, 等待10ms,此时复位完毕,然后RST拉高开始工作!
Delay(10);
GPIO_SetBits(DCMI_RST_GPIO_PORT,DCMI_RST_GPIO_PIN);
/****** 配置I2C,使用I2C与摄像头的SCCB接口通讯*****/
/* 使能I2C时钟 */
RCC_APB1PeriphClockCmd(CAMERA_I2C_CLK, ENABLE);
/* 使能I2C使用的GPIO时钟 */
RCC_AHB1PeriphClockCmd(CAMERA_I2C_SCL_GPIO_CLK|CAMERA_I2C_SDA_GPIO_CLK, ENABLE);
/* 配置引脚源 */
GPIO_PinAFConfig(CAMERA_I2C_SCL_GPIO_PORT, CAMERA_I2C_SCL_SOURCE, CAMERA_I2C_SCL_AF);
GPIO_PinAFConfig(CAMERA_I2C_SDA_GPIO_PORT, CAMERA_I2C_SDA_SOURCE, CAMERA_I2C_SDA_AF);
/* 初始化GPIO */
GPIO_InitStructure.GPIO_Pin = CAMERA_I2C_SCL_PIN ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(CAMERA_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(CAMERA_I2C_SCL_GPIO_PORT, CAMERA_I2C_SCL_SOURCE, CAMERA_I2C_SCL_AF);
GPIO_InitStructure.GPIO_Pin = CAMERA_I2C_SDA_PIN ;
GPIO_Init(CAMERA_I2C_SDA_GPIO_PORT, &GPIO_InitStructure);
/*初始化I2C模式 */
I2C_DeInit(CAMERA_I2C);
I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStruct.I2C_OwnAddress1 = 0xFE;
I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStruct.I2C_ClockSpeed = 400000;
/* 写入配置 */
I2C_Init(CAMERA_I2C, &I2C_InitStruct);
/* 使能I2C */
I2C_Cmd(CAMERA_I2C, ENABLE);
Delay(50);
}
二:判断摄像头是否已经挂载
OV5640_ReadID(&OV5640_IDStruct);
if(OV5640_IDStruct.PIDH == 0x56)
{
printf("OV5640 IS MOUNTED!\r\n");
}
三:颜色配置
void OV5640_RGB565Config(void)
{
uint32_t i;
/*摄像头复位*/
OV5640_Reset();
/* 写入寄存器配置 */
/* Initialize OV5640 Set to output RGB565 */
for(i=0; i<(sizeof(RGB565_Init)/4); i++)
{
OV5640_WriteReg(RGB565_Init[i][0], RGB565_Init[i][1]);
sensor_reg[i] = OV5640_ReadReg(RGB565_Init[i][0]);
CAMERA_DEBUG("sensor_reg[0x%x]:%x-%x\n",RGB565_Init[i][0],RGB565_Init[i][1],sensor_reg[i]);
}
Delay_ms(500);
if(img_width == 320)
ImageFormat=BMP_320x240;
else if(img_width == 640)
ImageFormat=BMP_640x480;
else if(img_width == 800)
ImageFormat=BMP_800x480;
switch(ImageFormat)
{
case BMP_320x240:
{
for(i=0; i<(sizeof(RGB565_QVGA)/2); i++)
{
OV5640_WriteReg(RGB565_QVGA[i][0], RGB565_QVGA[i][1]);
}
break;
}
case BMP_640x480:
{
for(i=0; i<(sizeof(RGB565_VGA)/2); i++)
{
OV5640_WriteReg(RGB565_VGA[i][0], RGB565_VGA[i][1]);
}
break;
}
case BMP_800x480:
{
for(i=0; i<(sizeof(RGB565_WVGA)/2); i++) //?
{
OV5640_WriteReg(RGB565_WVGA[i][0], RGB565_WVGA[i][1]);
}
break;
}
default:
{
for(i=0; i<(sizeof(RGB565_WVGA)/2); i++)
{
OV5640_WriteReg(RGB565_WVGA[i][0], RGB565_WVGA[i][1]);
}
break;
}
}
}
四:性能参数设置
void OV5640_USER_Config(void)
{
OV5640_FrameRate_Set(cam_mode.frame_rate);
Delay_ms(100);
// OV5640_ISPSize_Set(cam_mode.cam_isp_sx,
// cam_mode.cam_isp_sy,
// cam_mode.cam_isp_width,
// cam_mode.cam_isp_height);
// Delay(100);
OV5640_OutSize_Set(cam_mode.scaling,
cam_mode.cam_out_sx,
cam_mode.cam_out_sy,
cam_mode.cam_out_width,
cam_mode.cam_out_height);
Delay(100);
OV5640_BrightnessConfig(cam_mode.brightness);
Delay(100);
OV5640_Color_Saturation(cam_mode.saturation);
Delay(100);
OV5640_ContrastConfig(cam_mode.contrast);
Delay(100);
OV5640_Exposure(cam_mode.exposure);
Delay(100);
OV5640_LightMode(cam_mode.light_mode);
Delay(100);
OV5640_SpecialEffects(cam_mode.effect);
Delay(100);
// Delay(500);
}
五:DCMI以及DMA配置
void OV5640_Init(void)
{
DCMI_InitTypeDef DCMI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_DCMI, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
DCMI_InitStructure.DCMI_CaptureMode = DCMI_CaptureMode_Continuous;
DCMI_InitStructure.DCMI_SynchroMode = DCMI_SynchroMode_Hardware;
DCMI_InitStructure.DCMI_PCKPolarity = DCMI_PCKPolarity_Rising;
DCMI_InitStructure.DCMI_VSPolarity = DCMI_VSPolarity_High;
DCMI_InitStructure.DCMI_HSPolarity = DCMI_HSPolarity_Low;
DCMI_InitStructure.DCMI_CaptureRate = DCMI_CaptureRate_All_Frame;
DCMI_InitStructure.DCMI_ExtendedDataMode = DCMI_ExtendedDataMode_8b;
DCMI_Init(&DCMI_InitStructure);
OV5640_Start_DMA((uint32_t)LCD_MemoryAdd,160 * 800 * 2 / 4);//每次传输160行
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream1_IRQn ;//DMA数据流中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_ITConfig(DMA2_Stream1,DMA_IT_TC,ENABLE);
/* 配置帧中断,接收到帧同步信号就进入中断 */
NVIC_InitStructure.NVIC_IRQChannel = DCMI_IRQn ; //帧中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DCMI_ITConfig (DCMI_IT_FRAME,ENABLE);
}
六:配置DMA发送完成中断和DCMI帧中断
void DMA2_Stream1_IRQHandler(void)
{
if(DMA_GetITStatus(DMA2_Stream1, DMA_IT_TCIF1) == SET)
{
//DMA_ClearITPendingBit(DMA2_Stream1, DMA_IT_TCIF1);//放在这里不行,不知道为啥
linenum++;
if(3 == linenum)
{
linenum = 0;
}
OV5640_Start_DMA(LCD_MemoryAdd + 160*(800 *2*linenum), 160*800 * 2 /4);
DMA_ClearITPendingBit(DMA2_Stream1, DMA_IT_TCIF1);
}
}
void DCMI_IRQHandler(void)
{
if(DCMI_GetITStatus(DCMI_IT_FRAME) == SET)
{
DCMI_ClearITPendingBit(DCMI_IT_FRAME);
linenum = 0;
}
//OV5640_Start_DMA(LCD_MemoryAdd, 800 * 2 /4);
}
因为DMA每次发送的项数不能超过65535, 每一项的大小为数据源的宽度,即PSIZE = 字,因此每次控制传输不能超过65535字,而每一行的大小为800 x 2 / 4(字),那么160 x 800 x 2 / 4 = 64000(字) < 65535(字), 这样分三次传输完一帧(480行), 每次传输160行,有效减少了出入DMA中断的次数,每帧进入DMA中断三次,然后在DCMI帧中断里重新开始新的一帧传输,保证同步。
六:开始捕捉
DCMI_Cmd(ENABLE);
DCMI_CaptureCmd(ENABLE);
注:
这里我的LCD第一层设置像素格式为RGB565,第二层设置为ARGB1555(可以实现字幕在画面上方的效果),
LTDC时钟经测试25M合适
效果图:
来源:CSDN
作者:一个人的团队
链接:https://blog.csdn.net/weixin_43527214/article/details/104728612