/* 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; }