OV2640
硬件连接
通过开发板的OLED/CAMERA接口与摄像头模块连接。具体引脚连接如上图所示
SCCB时序 外部控制器对OV2640寄存器的配置参数是通过SCCB总线传输过去的,而SCCB总线跟I2C十分类似,在STM32驱动中直接使用片上I2C外设与它通讯。 SCCB与标准的I2C协议的区别是它每次传输只能写入或读取一个字节的数据,而I2C协议是支持突发读写的, 即在一次传输中可以写入多个字节的数据(EEPROM中的页写入时序即突发写)。 SCCB的起始、停止信号及数据有效性 SCCB的起始信号、停止信号及数据有效性与I2C完全一样 起始信号:在SIO_C为高电平时,SIO_D出现一个下降沿,则SCCB开始传输。 停止信号:在SIO_C为高电平时,SIO_D出现一个上升沿,则SCCB停止传输。
数据有效性:除了开始和停止状态,在数据传输过程中,当SIO_C为高电平时,必须保证SIO_D上的数据稳定,即SIO_D上的电平变换只能发生在SIO_C为低电平的时候,SIO_D的信号在SIO_C为高电平时被采集。 SCCB数据读写过程 在SCCB协议中定义的读写操作与I2C一样。它定义了两种写操作,即三步写操作和两步写操作。 三步写操作可向从设备的一个目的寄存器中写入数据 。第一阶段发送从设备的ID地址+W标志(等于I2C的设备地址:7位设备地址+读写方向标志),第二阶段发送从设备目标寄存器的8位地址, 第三阶段发送要写入寄存器的8位数据。图中的“X”数据位可写入1或0,对通讯无影响。(见下图) 而两步写操作没有第三阶段,即只向从器件传输了设备ID+W标志和目的寄存器的地址 。 两步写操作是用来配合后面的读寄存器数据操作的,它与读操作一起使用,实现I2C的复合过程。
两步读操作用于读取从设备目的寄存器中的数据。在第一阶段中发送从设备的设备ID+R标志(设备地址+读方向标志)和自由位, 在第二阶段中读取寄存器中的8位数据和写NA位(非应答信号)。由于两步读操作没有确定目的寄存器的地址, 所以在读操作前,必需有一个两步写操作,以提供读操作中的寄存器地址。
以上介绍的SCCB特性都与I2C无区别,而I2C比SCCB还多出了突发读写的功能,因此我们可以使用STM32的I2C外设来与OV2640进行SCCB通讯。
相关宏
#define CAMERA_I2C I2C1
#define CAMERA_I2C_CLK RCC_APB1Periph_I2C1
#define CAMERA_I2C_SCL_PIN GPIO_Pin_8
#define CAMERA_I2C_SCL_GPIO_PORT GPIOB
#define CAMERA_I2C_SCL_GPIO_CLK RCC_AHB1Periph_GPIOB
#define CAMERA_I2C_SCL_SOURCE GPIO_PinSource8
#define CAMERA_I2C_SCL_AF GPIO_AF_I2C1
#define CAMERA_I2C_SDA_PIN GPIO_Pin_9
#define CAMERA_I2C_SDA_GPIO_PORT GPIOB
#define CAMERA_I2C_SDA_GPIO_CLK RCC_AHB1Periph_GPIOB
#define CAMERA_I2C_SDA_SOURCE GPIO_PinSource9
#define CAMERA_I2C_SDA_AF GPIO_AF_I2C1
#define DCMI_VSYNC_GPIO_PORT GPIOB
#define DCMI_VSYNC_GPIO_CLK RCC_AHB1Periph_GPIOB
#define DCMI_VSYNC_GPIO_PIN GPIO_Pin_7
#define DCMI_VSYNC_PINSOURCE GPIO_PinSource7
#define DCMI_VSYNC_AF GPIO_AF_DCMI
#define DCMI_HSYNC_GPIO_PORT GPIOA
#define DCMI_HSYNC_GPIO_CLK RCC_AHB1Periph_GPIOA
#define DCMI_HSYNC_GPIO_PIN GPIO_Pin_4
#define DCMI_HSYNC_PINSOURCE GPIO_PinSource4
#define DCMI_HSYNC_AF GPIO_AF_DCMI
#define DCMI_PIXCLK_GPIO_PORT GPIOA
#define DCMI_PIXCLK_GPIO_CLK RCC_AHB1Periph_GPIOA
#define DCMI_PIXCLK_GPIO_PIN GPIO_Pin_6
#define DCMI_PIXCLK_PINSOURCE GPIO_PinSource6
#define DCMI_PIXCLK_AF GPIO_AF_DCMI
#define DCMI_PWDN_GPIO_PORT GPIOC
#define DCMI_PWDN_GPIO_CLK RCC_AHB1Periph_GPIOC
#define DCMI_PWDN_GPIO_PIN GPIO_Pin_0
#define DCMI_D0_GPIO_PORT GPIOC
#define DCMI_D0_GPIO_CLK RCC_AHB1Periph_GPIOC
#define DCMI_D0_GPIO_PIN GPIO_Pin_6
#define DCMI_D0_PINSOURCE GPIO_PinSource6
#define DCMI_D0_AF GPIO_AF_DCMI
要点: 1.初始化DCMI时钟,I2C时钟; 2.使用I2C接口向OV2640写入寄存器配置; 3.初始化DCMI工作模式; 4.初始化DMA,用于搬运DCMI的数据到显存空间进行显示; 5.编写测试程序,控制采集图像数据并显示到液晶屏。
初始化DCMI的 GPIO及I2C
void OV2640_HW_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStruct;
RCC_AHB1PeriphClockCmd(DCMI_PWDN_GPIO_CLK|DCMI_VSYNC_GPIO_CLK |
DCMI_HSYNC_GPIO_CLK | DCMI_PIXCLK_GPIO_CLK|
DCMI_D0_GPIO_CLK| DCMI_D1_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_PWDN_GPIO_PIN ;
GPIO_Init(DCMI_PWDN_GPIO_PORT, &GPIO_InitStructure);
GPIO_ResetBits(DCMI_PWDN_GPIO_PORT,DCMI_PWDN_GPIO_PIN);
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);
RCC_APB1PeriphClockCmd(CAMERA_I2C_CLK, ENABLE);
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_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_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 = 40000;
I2C_Init(CAMERA_I2C, &I2C_InitStruct);
I2C_Cmd(CAMERA_I2C, ENABLE);
}
配置DCMI的模式
void OV2640_Init(void)
{
DCMI_InitTypeDef DCMI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_DCMI, 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_Low;
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);
OV2640_DMA_Config(FSMC_LCD_ADDRESS,1);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
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数据传输
void OV2640_DMA_Config(uint32_t DMA_Memory0BaseAddr,uint16_t DMA_BufferSize)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
DMA_Cmd(DMA2_Stream1,DISABLE);
while (DMA_GetCmdStatus(DMA2_Stream1) != DISABLE) {}
DMA_InitStructure.DMA_Channel = DMA_Channel_1;
DMA_InitStructure.DMA_PeripheralBaseAddr = DCMI_DR_ADDRESS;
DMA_InitStructure.DMA_Memory0BaseAddr = DMA_Memory0BaseAddr;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize =DMA_BufferSize;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_INC8;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream1, &DMA_InitStructure);
DMA_Cmd(DMA2_Stream1,ENABLE);
while (DMA_GetCmdStatus(DMA2_Stream1) != ENABLE) {}
配置帧中断
extern uint8_t fps;
void DCMI_IRQHandler(void)
{
if ( DCMI_GetITStatus (DCMI_IT_FRAME) == SET ) {
fps++;
DCMI_ClearITPendingBit(DCMI_IT_FRAME);
}
}
读取摄像头ID
typedef struct
{
uint8_t Manufacturer_ID1;
uint8_t Manufacturer_ID2;
uint8_t PIDH;
uint8_t PIDL;
} OV2640_IDTypeDef;
#define OV2640_DSP_RA_DLMT 0xFF
#define OV2640_SENSOR_MIDH 0x1C
#define OV2640_SENSOR_MIDL 0x1D
#define OV2640_SENSOR_PIDH 0x0A
#define OV2640_SENSOR_PIDL 0x0B
void OV2640_ReadID(OV2640_IDTypeDef *OV2640ID)
{
OV2640_WriteReg(OV2640_DSP_RA_DLMT, 0x01);
OV2640ID->Manufacturer_ID1 = OV2640_ReadReg(OV2640_SENSOR_MIDH);
OV2640ID->Manufacturer_ID2 = OV2640_ReadReg(OV2640_SENSOR_MIDL);
OV2640ID->PIDH = OV2640_ReadReg(OV2640_SENSOR_PIDH);
OV2640ID->PIDL = OV2640_ReadReg(OV2640_SENSOR_PIDL);
}
向OV2640写入寄存器配置
uint16_t img_width=852, img_height=480;
const unsigned char OV2640_UXGA[][2]=
{
0xff, 0x00,
0x2c, 0xff,
0x2e, 0xdf,
0xff, 0x01,
0x3c, 0x32,
0x11, 0x00,
0x09, 0x02,
0x04, 0xD8,
0x13, 0xe5,
}
void OV2640_UXGAConfig(void)
{
uint32_t i;
for (i=0; i<(sizeof(OV2640_UXGA)/2); i++)
{
OV2640_WriteReg(OV2640_UXGA[i][0], OV2640_UXGA[i][1]);
}
OV2640_OutSize_Set(img_width,img_height);
}
|