rt-thread-official/bsp/k210/drivers/camera/drv_ov5640.c

309 lines
7.8 KiB
C

/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <unistd.h>
#include "drv_ov5640.h"
#include "ov5640cfg.h"
#include "ov5640af.h"
#include "dvp.h"
static void hal_delay(uint32_t delay)
{
usleep(delay * 1000);
}
static void ov5640_wr_reg(uint16_t reg,uint8_t data)
{
dvp_sccb_send_data(OV5640_ADDR, reg, data);
}
static uint8_t ov5640_rd_reg(uint16_t reg)
{
return dvp_sccb_receive_data(OV5640_ADDR, reg);
}
uint8_t ov5640_init(void)
{
uint16_t i = 0;
uint16_t reg = 0;
reg = ov5640_rd_reg(OV5640_CHIPIDH);
reg <<= 8;
reg |= ov5640_rd_reg(OV5640_CHIPIDL);
if(reg != OV5640_ID)
{
printf("ID: %d \r\n", reg);
return 1;
}
ov5640_wr_reg(0x3103,0X11); /*system clock from pad, bit[1]*/
ov5640_wr_reg(0X3008,0X82);
hal_delay(10);
for(i = 0; i<sizeof(ov5640_init_reg_tbl) / 4; i++)
{
ov5640_wr_reg(ov5640_init_reg_tbl[i][0], ov5640_init_reg_tbl[i][1]);
}
hal_delay(50);
/* Test for flash light*/
ov5640_flash_lamp(1);
hal_delay(50);
ov5640_flash_lamp(0);
return 0x00;
}
void ov5640_flash_lamp(uint8_t sw)
{
ov5640_wr_reg(0x3016, 0X02);
ov5640_wr_reg(0x301C, 0X02);
if(sw)
ov5640_wr_reg(0X3019, 0X02);
else
ov5640_wr_reg(0X3019, 0X00);
}
const static uint8_t OV5640_EXPOSURE_TBL[7][6]=
{
0x10,0x08,0x10,0x08,0x20,0x10,//-3
0x20,0x18,0x41,0x20,0x18,0x10,//-2
0x30,0x28,0x61,0x30,0x28,0x10,//-1
0x38,0x30,0x61,0x38,0x30,0x10,//0
0x40,0x38,0x71,0x40,0x38,0x10,//+1
0x50,0x48,0x90,0x50,0x48,0x20,//+2
0x60,0x58,0xa0,0x60,0x58,0x20,//+3
};
//exposure: 0 - 6,
void OV5640_Exposure(uint8_t exposure)
{
ov5640_wr_reg(0x3212,0x03); //start group 3
ov5640_wr_reg(0x3a0f,OV5640_EXPOSURE_TBL[exposure][0]);
ov5640_wr_reg(0x3a10,OV5640_EXPOSURE_TBL[exposure][1]);
ov5640_wr_reg(0x3a1b,OV5640_EXPOSURE_TBL[exposure][2]);
ov5640_wr_reg(0x3a1e,OV5640_EXPOSURE_TBL[exposure][3]);
ov5640_wr_reg(0x3a11,OV5640_EXPOSURE_TBL[exposure][4]);
ov5640_wr_reg(0x3a1f,OV5640_EXPOSURE_TBL[exposure][5]);
ov5640_wr_reg(0x3212,0x13); //end group 3
ov5640_wr_reg(0x3212,0xa3); //launch group 3
}
const static uint8_t OV5640_LIGHTMODE_TBL[5][7]=
{
0x04,0X00,0X04,0X00,0X04,0X00,0X00,//Auto
0x06,0X1C,0X04,0X00,0X04,0XF3,0X01,//Sunny
0x05,0X48,0X04,0X00,0X07,0XCF,0X01,//Office
0x06,0X48,0X04,0X00,0X04,0XD3,0X01,//Cloudy
0x04,0X10,0X04,0X00,0X08,0X40,0X01,//Home
};
// light mode:
// 0: auto
// 1: sunny
// 2: office
// 3: cloudy
// 4: home
void OV5640_Light_Mode(uint8_t mode)
{
uint8_t i;
ov5640_wr_reg(0x3212,0x03); //start group 3
for(i=0;i<7;i++)ov5640_wr_reg(0x3400+i,OV5640_LIGHTMODE_TBL[mode][i]);
ov5640_wr_reg(0x3212,0x13); //end group 3
ov5640_wr_reg(0x3212,0xa3); //launch group 3
}
const static uint8_t OV5640_SATURATION_TBL[7][6]=
{
0X0C,0x30,0X3D,0X3E,0X3D,0X01,//-3
0X10,0x3D,0X4D,0X4E,0X4D,0X01,//-2
0X15,0x52,0X66,0X68,0X66,0X02,//-1
0X1A,0x66,0X80,0X82,0X80,0X02,//+0
0X1F,0x7A,0X9A,0X9C,0X9A,0X02,//+1
0X24,0x8F,0XB3,0XB6,0XB3,0X03,//+2
0X2B,0xAB,0XD6,0XDA,0XD6,0X04,//+3
};
// Color Saturation:
// sat: 0 - 6
void OV5640_Color_Saturation(uint8_t sat)
{
uint8_t i;
ov5640_wr_reg(0x3212,0x03); //start group 3
ov5640_wr_reg(0x5381,0x1c);
ov5640_wr_reg(0x5382,0x5a);
ov5640_wr_reg(0x5383,0x06);
for(i=0;i<6;i++) ov5640_wr_reg(0x5384+i,OV5640_SATURATION_TBL[sat][i]);
ov5640_wr_reg(0x538b, 0x98);
ov5640_wr_reg(0x538a, 0x01);
ov5640_wr_reg(0x3212, 0x13); //end group 3
ov5640_wr_reg(0x3212, 0xa3); //launch group 3
}
//Brightness
// bright: 0 - 8
void OV5640_Brightness(uint8_t bright)
{
uint8_t brtval;
if(bright<4)brtval=4-bright;
else brtval=bright-4;
ov5640_wr_reg(0x3212,0x03); //start group 3
ov5640_wr_reg(0x5587,brtval<<4);
if(bright<4)ov5640_wr_reg(0x5588,0x09);
else ov5640_wr_reg(0x5588,0x01);
ov5640_wr_reg(0x3212,0x13); //end group 3
ov5640_wr_reg(0x3212,0xa3); //launch group 3
}
//Contrast:
// contrast: 0 - 6
void OV5640_Contrast(uint8_t contrast)
{
uint8_t reg0val=0X00;
uint8_t reg1val=0X20;
switch(contrast)
{
case 0://-3
reg1val=reg0val=0X14;
break;
case 1://-2
reg1val=reg0val=0X18;
break;
case 2://-1
reg1val=reg0val=0X1C;
break;
case 4://1
reg0val=0X10;
reg1val=0X24;
break;
case 5://2
reg0val=0X18;
reg1val=0X28;
break;
case 6://3
reg0val=0X1C;
reg1val=0X2C;
break;
}
ov5640_wr_reg(0x3212,0x03); //start group 3
ov5640_wr_reg(0x5585,reg0val);
ov5640_wr_reg(0x5586,reg1val);
ov5640_wr_reg(0x3212,0x13); //end group 3
ov5640_wr_reg(0x3212,0xa3); //launch group 3
}
// Sharpness:
// sharp: 0 - 33 (0: close , 33: auto , other: Sharpness)
void OV5640_Sharpness(uint8_t sharp)
{
if(sharp<33)
{
ov5640_wr_reg(0x5308,0x65);
ov5640_wr_reg(0x5302,sharp);
}else // auto
{
ov5640_wr_reg(0x5308,0x25);
ov5640_wr_reg(0x5300,0x08);
ov5640_wr_reg(0x5301,0x30);
ov5640_wr_reg(0x5302,0x10);
ov5640_wr_reg(0x5303,0x00);
ov5640_wr_reg(0x5309,0x08);
ov5640_wr_reg(0x530a,0x30);
ov5640_wr_reg(0x530b,0x04);
ov5640_wr_reg(0x530c,0x06);
}
}
const static uint8_t OV5640_EFFECTS_TBL[7][3]=
{
0X06,0x40,0X10, // normal
0X1E,0xA0,0X40,
0X1E,0x80,0XC0,
0X1E,0x80,0X80,
0X1E,0x40,0XA0,
0X40,0x40,0X10,
0X1E,0x60,0X60,
};
void OV5640_Special_Effects(uint8_t eft)
{
ov5640_wr_reg(0x3212,0x03); //start group 3
ov5640_wr_reg(0x5580,OV5640_EFFECTS_TBL[eft][0]);
ov5640_wr_reg(0x5583,OV5640_EFFECTS_TBL[eft][1]);// sat U
ov5640_wr_reg(0x5584,OV5640_EFFECTS_TBL[eft][2]);// sat V
ov5640_wr_reg(0x5003,0x08);
ov5640_wr_reg(0x3212,0x13); //end group 3
ov5640_wr_reg(0x3212,0xa3); //launch group 3
}
uint8_t OV5640_Focus_Init(void)
{
uint16_t i;
uint16_t addr=0x8000;
uint8_t state=0x8F;
ov5640_wr_reg(0x3000, 0x20); //reset
for(i=0;i<sizeof(OV5640_AF_Config);i++)
{
ov5640_wr_reg(addr,OV5640_AF_Config[i]);
addr++;
}
ov5640_wr_reg(0x3022,0x00);
ov5640_wr_reg(0x3023,0x00);
ov5640_wr_reg(0x3024,0x00);
ov5640_wr_reg(0x3025,0x00);
ov5640_wr_reg(0x3026,0x00);
ov5640_wr_reg(0x3027,0x00);
ov5640_wr_reg(0x3028,0x00);
ov5640_wr_reg(0x3029,0x7f);
ov5640_wr_reg(0x3000,0x00);
i=0;
do
{
state=ov5640_rd_reg(0x3029);
hal_delay(5);
i++;
if(i>1000)return 1;
}while(state!=0x70);
return 0;
}
uint8_t OV5640_Auto_Focus(void)
{
uint8_t temp=0;
uint16_t retry=0;
ov5640_wr_reg(0x3023,0x01);
ov5640_wr_reg(0x3022,0x08);
do
{
temp=ov5640_rd_reg(0x3023);
retry++;
if(retry>1000)return 2;
hal_delay(5);
} while(temp!=0x00);
ov5640_wr_reg(0x3023,0x01);
ov5640_wr_reg(0x3022,0x04);
retry=0;
do
{
temp=ov5640_rd_reg(0x3023);
retry++;
if(retry>1000)return 2;
hal_delay(5);
}while(temp!=0x00);
return 0;
}