From e2e66d92405c18f19fc5630fe31c3e4db58ba246 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 21 Feb 2014 23:32:25 +0200 Subject: [PATCH] Add OV2640 driver --- src/ov2640.c | 360 ++++++++++++++++++++++++++++++++++++++++++++++ src/ov2640.h | 5 + src/ov2640_regs.h | 196 +++++++++++++++++++++++++ 3 files changed, 561 insertions(+) create mode 100644 src/ov2640.c create mode 100644 src/ov2640.h create mode 100644 src/ov2640_regs.h diff --git a/src/ov2640.c b/src/ov2640.c new file mode 100644 index 000000000..ec67b3db3 --- /dev/null +++ b/src/ov2640.c @@ -0,0 +1,360 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sccb.h" +#include "ov2640.h" +#include "systick.h" +#include "ov2640_regs.h" +static const uint8_t default_regs[][2] = { + { BANK_SEL, BANK_SEL_DSP}, + { 0x2c, 0xff }, + { 0x2e, 0xdf }, + + { BANK_SEL, BANK_SEL_SENSOR }, + { 0x3c, 0x32 }, + { CLKRC, 0x01 }, /* Set PCLK divider */ + { COM2, COM2_OUT_DRIVE_2x }, /* Output drive x2 */ + { REG04, REG04_SET(0x00)}, /* Mirror/VFLIP/AEC[1:0]*/ + { COM7, COM7_RES_UXGA | COM7_ZOOM_EN }, + { COM8, COM8_SET(COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN) }, + { COM9, COM9_AGC_SET(COM9_AGC_GAIN_8x)}, + { 0x2c, 0x0c }, + { 0x33, 0x78 }, + { 0x3a, 0x33 }, + { 0x3b, 0xfb }, + { 0x3e, 0x00 }, + { 0x43, 0x11 }, + { 0x16, 0x10 }, + { 0x39, 0x02 }, + { 0x35, 0x88 }, + { 0x22, 0x0a }, + { 0x37, 0x40 }, + { 0x23, 0x00 }, + { ARCOM2, 0xa0 }, + { 0x06, 0x02 }, + { 0x06, 0x88 }, + { 0x07, 0xc0 }, + { 0x0d, 0xb7 }, + { 0x0e, 0x01 }, + { 0x4c, 0x00 }, + { 0x4a, 0x81 }, + { 0x21, 0x99 }, + /* AGC/AEC operating region */ + { AEW, 0x40 }, + { AEB, 0x38 }, + /* AGC/AEC fast mode operating region */ + { VV, VV_AGC_TH_SET(0x08, 0x02) }, + { 0x5c, 0x00 }, + { 0x63, 0x00 }, + { FLL, 0x00 }, //TODO + { FLH, 0x00 }, + /* Set banding filter */ + { COM3, COM3_BAND_SET(COM3_BAND_AUTO) }, + { REG5D, 0x55 }, + { REG5E, 0x7d }, + { REG5F, 0x7d }, + { REG60, 0x55 }, + { HISTO_LOW, 0x70 }, + { HISTO_HIGH, 0x80 }, + { 0x7c, 0x05 }, + { 0x20, 0x80 }, + { 0x28, 0x30 }, + { 0x6c, 0x00 }, + { 0x6d, 0x80 }, + { 0x6e, 0x00 }, + { 0x70, 0x02 }, + { 0x71, 0x94 }, + { 0x73, 0xc1 }, + { 0x3d, 0x34 }, + { 0x5a, 0x57 }, + { BD50, 0xbb }, + { BD60, 0x9c }, + + { BANK_SEL, BANK_SEL_DSP }, + { 0xe5, 0x7f }, + { MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL }, + { 0x41, 0x24 }, + { RESET, RESET_JPEG | RESET_DVP }, + { 0x76, 0xff }, + { 0x33, 0xa0 }, + { 0x42, 0x20 }, + { 0x43, 0x18 }, + { 0x4c, 0x00 }, + { CTRL3, CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10 }, + { 0x88, 0x3f }, + { 0xd7, 0x03 }, + { 0xd9, 0x10 }, + { R_DVP_SP, R_DVP_SP_AUTO_MODE}, + { 0xc8, 0x08 }, + { 0xc9, 0x80 }, + { BPADDR, 0x00 }, + { BPDATA, 0x00 }, + { BPADDR, 0x03 }, + { BPDATA, 0x48 }, + { BPDATA, 0x48 }, + { BPADDR, 0x08 }, + { BPDATA, 0x20 }, + { BPDATA, 0x10 }, + { BPDATA, 0x0e }, + { 0x90, 0x00 }, + { 0x91, 0x0e }, + { 0x91, 0x1a }, + { 0x91, 0x31 }, + { 0x91, 0x5a }, + { 0x91, 0x69 }, + { 0x91, 0x75 }, + { 0x91, 0x7e }, + { 0x91, 0x88 }, + { 0x91, 0x8f }, + { 0x91, 0x96 }, + { 0x91, 0xa3 }, + { 0x91, 0xaf }, + { 0x91, 0xc4 }, + { 0x91, 0xd7 }, + { 0x91, 0xe8 }, + { 0x91, 0x20 }, + { 0x92, 0x00 }, + { 0x93, 0x06 }, + { 0x93, 0xe3 }, + { 0x93, 0x03 }, + { 0x93, 0x03 }, + { 0x93, 0x00 }, + { 0x93, 0x02 }, + { 0x93, 0x00 }, + { 0x93, 0x00 }, + { 0x93, 0x00 }, + { 0x93, 0x00 }, + { 0x93, 0x00 }, + { 0x93, 0x00 }, + { 0x93, 0x00 }, + { 0x96, 0x00 }, + { 0x97, 0x08 }, + { 0x97, 0x19 }, + { 0x97, 0x02 }, + { 0x97, 0x0c }, + { 0x97, 0x24 }, + { 0x97, 0x30 }, + { 0x97, 0x28 }, + { 0x97, 0x26 }, + { 0x97, 0x02 }, + { 0x97, 0x98 }, + { 0x97, 0x80 }, + { 0x97, 0x00 }, + { 0x97, 0x00 }, + { 0xa4, 0x00 }, + { 0xa8, 0x00 }, + { 0xc5, 0x11 }, + { 0xc6, 0x51 }, + { 0xbf, 0x80 }, + { 0xc7, 0x10 }, + { 0xb6, 0x66 }, + { 0xb8, 0xA5 }, + { 0xb7, 0x64 }, + { 0xb9, 0x7C }, + { 0xb3, 0xaf }, + { 0xb4, 0x97 }, + { 0xb5, 0xFF }, + { 0xb0, 0xC5 }, + { 0xb1, 0x94 }, + { 0xb2, 0x0f }, + { 0xc4, 0x5c }, + { 0xa6, 0x00 }, + { 0xa7, 0x20 }, + { 0xa7, 0xd8 }, + { 0xa7, 0x1b }, + { 0xa7, 0x31 }, + { 0xa7, 0x00 }, + { 0xa7, 0x18 }, + { 0xa7, 0x20 }, + { 0xa7, 0xd8 }, + { 0xa7, 0x19 }, + { 0xa7, 0x31 }, + { 0xa7, 0x00 }, + { 0xa7, 0x18 }, + { 0xa7, 0x20 }, + { 0xa7, 0xd8 }, + { 0xa7, 0x19 }, + { 0xa7, 0x31 }, + { 0xa7, 0x00 }, + { 0xa7, 0x18 }, + { 0x7f, 0x00 }, + { 0xe5, 0x1f }, + { 0xe1, 0x77 }, + { 0xdd, 0x7f }, + /* Enable AEC/AEC_SEL/YUV/YUV422/RGB */ + { CTRL0, CTRL0_YUV422 | CTRL0_YUV_EN | CTRL0_RGB_EN }, + + /* Set DSP input image size to 1600x1200 and offset to 0. + The sensor output image can be scaled with OUTW/OUTH */ + { BANK_SEL, BANK_SEL_DSP }, + { RESET, RESET_DVP }, + { HSIZE8, (1600>>3)}, /* Image Horizontal Size HSIZE[10:3] */ + { VSIZE8, (1200>>3)}, /* Image Horizontal Size VSIZE[10:3] */ + { SIZEL, 0x00 }, /* {HSIZE[11], HSIZE[2:0], VSIZE[2:0]} */ + + { XOFFL, 0x00 }, /* OFFSET_X[7:0] */ + { YOFFL, 0x00 }, /* OFFSET_Y[7:0] */ + { HSIZE, ((1600>>2)&0xFF) }, /* H_SIZE[7:0] real/4 */ + { VSIZE, ((1200>>2)&0xFF) }, /* V_SIZE[7:0] real/4 */ + /* V_SIZE[8]/OFFSET_Y[10:8]/H_SIZE[8]/OFFSET_X[10:8] */ + { VHYX, ((1600>>3)&0x80) | ((1200>>7)&0x08) }, + { TEST, 0x00 }, /* H_SIZE[9] */ + + { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN | + CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN }, + { CTRLI, CTRLI_LP_DP | 0x1B }, /* H_DIVIDER/V_DIVIDER */ + { R_BYPASS, R_BYPASS_USE_DSP }, + {0x00, 0x00} +}; + +static const uint8_t yuv422_regs[][2] = { + { BANK_SEL, BANK_SEL_DSP }, + { IMAGE_MODE, IMAGE_MODE_YUV422 }, + { 0xD7, 0x01 }, + { 0x33, 0xa0 }, + { 0xe1, 0x67 }, + { RESET, 0x00 }, + {0, 0}, +}; + +static const uint8_t rgb565_regs[][2] = { + { BANK_SEL, BANK_SEL_DSP }, + { IMAGE_MODE, IMAGE_MODE_RGB565 }, + { 0xd7, 0x03 }, + { RESET, 0x00 }, + {0, 0}, +}; + +static const uint8_t br_regs[NUM_BR_LEVELS + 1][5] = { + { BPADDR, BPDATA, BPADDR, BPDATA, BPDATA }, + { 0x00, 0x04, 0x09, 0x00, 0x00 }, /* -2 */ + { 0x00, 0x04, 0x09, 0x10, 0x00 }, /* -1 */ + { 0x00, 0x04, 0x09, 0x20, 0x00 }, /* 0 */ + { 0x00, 0x04, 0x09, 0x30, 0x00 }, /* +1 */ + { 0x00, 0x04, 0x09, 0x40, 0x00 }, /* +2 */ +}; + +static int reset() +{ + int i=0; + const uint8_t (*regs)[2]; + + /* Reset all registers */ + SCCB_Write(BANK_SEL, BANK_SEL_SENSOR); + SCCB_Write(COM7, COM7_SRST); + + /* delay n ms */ + systick_sleep(10); + + i = 0; + regs = default_regs; + /* Write initial regsiters */ + while (regs[i][0]) { + SCCB_Write(regs[i][0], regs[i][1]); + i++; + } + + return 0; +} + +static int set_pixformat(enum sensor_pixformat pixformat) +{ + int i=0; + const uint8_t (*regs)[2]=NULL; + + /* read pixel format reg */ + switch (pixformat) { + case PIXFORMAT_RGB565: + regs = rgb565_regs; + break; + case PIXFORMAT_YUV422: + case PIXFORMAT_GRAYSCALE: + regs = yuv422_regs; + break; + case PIXFORMAT_JPEG: + return -1; + break; + default: + return -1; + } + + /* Write initial regsiters */ + while (regs[i][0]) { + SCCB_Write(regs[i][0], regs[i][1]); + i++; + } + return 0; +} + +static int set_framesize(enum sensor_framesize framesize) +{ + int ret=0; + uint16_t w=res_width[framesize]; + uint16_t h=res_height[framesize]; + + /* Write output width */ + ret |= SCCB_Write(ZMOW, (w>>2)&0xFF); /* OUTW[7:0] (real/4) */ + ret |= SCCB_Write(ZMOH, (h>>2)&0xFF); /* OUTH[7:0] (real/4) */ + ret |= SCCB_Write(ZMHH, ((h>>8)&0x04)|((w>>10)&0x03)); /* OUTW[9:8] */ + return ret; +} + +static int set_framerate(enum sensor_framerate framerate) +{ + return 0; +} + +static int set_brightness(uint8_t level) +{ + int i; + + level += (NUM_BR_LEVELS / 2 + 1); + if (level < 0 || level > NUM_BR_LEVELS) { + return -1; + } + + /* Switch to DSP register bank */ + SCCB_Write(BANK_SEL, BANK_SEL_SENSOR); + + /* Write brightness registers */ + for (i=0; ivsync_pol = DCMI_VSPolarity_Low; + sensor->hsync_pol = DCMI_HSPolarity_Low; + sensor->pixck_pol = DCMI_PCKPolarity_Rising; + + /* set function pointers */ + sensor->reset = reset; + sensor->set_pixformat = set_pixformat; + sensor->set_framesize = set_framesize; + sensor->set_framerate = set_framerate; + sensor->set_brightness= set_brightness; + sensor->set_exposure = set_exposure; + sensor->set_gainceiling = set_gainceiling; + return 0; +} diff --git a/src/ov2640.h b/src/ov2640.h new file mode 100644 index 000000000..eb0118940 --- /dev/null +++ b/src/ov2640.h @@ -0,0 +1,5 @@ +#ifndef __OV2640_H__ +#define __OV2640_H__ +#include "sensor.h" +int ov2640_init(struct sensor_dev *sensor); +#endif /* __OV2640_H__ */ diff --git a/src/ov2640_regs.h b/src/ov2640_regs.h new file mode 100644 index 000000000..ce3482e99 --- /dev/null +++ b/src/ov2640_regs.h @@ -0,0 +1,196 @@ +#ifndef __REG_REGS_H__ +#define __REG_REGS_H__ +/* OV2640 Registers definition */ +/* DSP register bank FF=0x00*/ +#define Q 0x44 +#define HSIZE 0x51 +#define VSIZE 0x52 +#define XOFFL 0x53 +#define YOFFL 0x54 +#define VHYX 0x55 +#define DPRP 0x56 +#define TEST 0x57 +#define ZMOW 0x5A +#define ZMOH 0x5B +#define ZMHH 0x5C +#define BPADDR 0x7C +#define BPDATA 0x7D +#define SIZEL 0x8C +#define HSIZE8 0xC0 +#define VSIZE8 0xC1 +#define CTRL1 0xC3 +#define MS_SP 0xF0 +#define SS_ID 0xF7 +#define SS_CTRL 0xF7 +#define MC_AL 0xFA +#define MC_AH 0xFB +#define MC_D 0xFC +#define P_CMD 0xFD +#define P_STATUS 0xFE + +#define CTRLI 0x50 +#define CTRLI_LP_DP 0x80 +#define CTRLI_ROUND 0x40 + +#define CTRL0 0xC2 +#define CTRL0_AEC_EN 0x80 +#define CTRL0_AEC_SEL 0x40 +#define CTRL0_STAT_SEL 0x20 +#define CTRL0_VFIRST 0x10 +#define CTRL0_YUV422 0x08 +#define CTRL0_YUV_EN 0x04 +#define CTRL0_RGB_EN 0x02 +#define CTRL0_RAW_EN 0x01 + +#define CTRL2 0x86 +#define CTRL2_DCW_EN 0x20 +#define CTRL2_SDE_EN 0x10 +#define CTRL2_UV_ADJ_EN 0x08 +#define CTRL2_UV_AVG_EN 0x04 +#define CTRL2_CMX_EN 0x01 + +#define CTRL3 0x87 +#define CTRL3_BPC_EN 0x80 +#define CTRL3_WPC_EN 0x40 +#define R_DVP_SP 0xD3 +#define R_DVP_SP_AUTO_MODE 0x80 + +#define R_BYPASS 0x05 +#define R_BYPASS_DSP_EN 0x00 +#define R_BYPASS_DSP_BYPAS 0x01 +#define R_BYPASS_USE_DSP 0x00 + +#define IMAGE_MODE 0xDA +#define IMAGE_MODE_Y8_DVP_EN 0x40 +#define IMAGE_MODE_JPEG_EN 0x10 +#define IMAGE_MODE_YUV422 0x00 +#define IMAGE_MODE_RAW10 0x04 +#define IMAGE_MODE_RGB565 0x08 +#define IMAGE_MODE_HREF_VSYNC 0x02 +#define IMAGE_MODE_LBYTE_FIRST 0x01 + +#define RESET 0xE0 +#define RESET_MICROC 0x40 +#define RESET_SCCB 0x20 +#define RESET_JPEG 0x10 +#define RESET_DVP 0x04 +#define RESET_IPU 0x02 +#define RESET_CIF 0x01 + +#define MC_BIST 0xF9 +#define MC_BIST_RESET 0x80 +#define MC_BIST_BOOT_ROM_SEL 0x40 +#define MC_BIST_12KB_SEL 0x20 +#define MC_BIST_12KB_MASK 0x30 +#define MC_BIST_512KB_SEL 0x08 +#define MC_BIST_512KB_MASK 0x0C +#define MC_BIST_BUSY_BIT_R 0x02 +#define MC_BIST_MC_RES_ONE_SH_W 0x02 +#define MC_BIST_LAUNCH 0x01 + +#define BANK_SEL 0xFF +#define BANK_SEL_DSP 0x00 +#define BANK_SEL_SENSOR 0x01 + +/* Sensor register bank FF=0x01*/ +#define GAIN 0x00 +#define COM1 0x03 +#define REG_PID 0x0A +#define REG_VER 0x0B +#define COM4 0x0D +#define AEC 0x10 +#define CLKRC 0x11 +#define COM10 0x15 +#define ARCOM2 0x34 +#define HSTART 0x17 +#define HSTOP 0x18 +#define VSTART 0x19 +#define VSTOP 0x1A +#define MIDH 0x1C +#define MIDL 0x1D +#define AEW 0x24 +#define AEB 0x25 +#define REG2A 0x2A +#define FRARL 0x2B +#define ADDVSL 0x2D +#define ADDVSH 0x2E +#define YAVG 0x2F +#define HSDY 0x30 +#define HEDY 0x31 +#define ARCOM2 0x34 +#define REG45 0x45 +#define FLL 0x46 +#define FLH 0x47 +#define COM19 0x48 +#define ZOOMS 0x49 +#define COM22 0x4B +#define COM25 0x4E +#define BD50 0x4F +#define BD60 0x50 +#define REG5D 0x5D +#define REG5E 0x5E +#define REG5F 0x5F +#define REG60 0x60 +#define HISTO_LOW 0x61 +#define HISTO_HIGH 0x62 + +#define REG04 0x04 +#define REG04_DEFAULT 0x20 +#define REG04_HFLIP_IMG 0x80 +#define REG04_VFLIP_IMG 0x40 +#define REG04_VREF_EN 0x10 +#define REG04_HREF_EN 0x08 +#define REG04_SET(x) (REG04_DEFAULT|x) + +#define REG08 0x08 +#define COM2 0x09 +#define COM2_STDBY 0x10 +#define COM2_OUT_DRIVE_1x 0x00 +#define COM2_OUT_DRIVE_2x 0x01 +#define COM2_OUT_DRIVE_3x 0x02 +#define COM2_OUT_DRIVE_4x 0x03 + +#define COM3 0x0C +#define COM3_DEFAULT 0x38 +#define COM3_BAND_50Hz 0x04 +#define COM3_BAND_60Hz 0x00 +#define COM3_BAND_AUTO 0x02 +#define COM3_BAND_SET(x) (COM3_DEFAULT|x) + +#define COM7 0x12 +#define COM7_SRST 0x80 +#define COM7_RES_UXGA 0x00 /* UXGA */ +#define COM7_RES_SVGA 0x40 /* SVGA */ +#define COM7_RES_CIF 0x20 /* CIF */ +#define COM7_ZOOM_EN 0x04 /* Enable Zoom */ +#define COM7_COLOR_BAR 0x02 /* Enable Color Bar Test */ + +#define COM8 0x13 +#define COM8_DEFAULT 0xC0 +#define COM8_BNDF_EN 0x20 /* Enable Banding filter */ +#define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */ +#define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */ +#define COM8_SET(x) (COM8_DEFAULT|x) + +#define COM9 0x14 /* AGC gain ceiling */ +#define COM9_DEFAULT 0x08 +#define COM9_AGC_GAIN_2x 0x00 /* AGC: 2x */ +#define COM9_AGC_GAIN_4x 0x01 /* AGC: 4x */ +#define COM9_AGC_GAIN_8x 0x02 /* AGC: 8x */ +#define COM9_AGC_GAIN_16x 0x03 /* AGC: 16x */ +#define COM9_AGC_GAIN_32x 0x04 /* AGC: 32x */ +#define COM9_AGC_GAIN_64x 0x05 /* AGC: 64x */ +#define COM9_AGC_GAIN_128x 0x06 /* AGC: 128x */ +#define COM9_AGC_SET(x) (COM9_DEFAULT|(x<<5)) + +#define VV 0x26 +#define VV_AGC_TH_SET(h,l) ((h<<4)|(l&0x0F)) + +#define REG32 0x32 +#define REG32_UXGA 0x36 +#define REG32_SVGA 0x09 +#define REG32_CIF 0x00 + +/* Misc */ +#define NUM_BR_LEVELS 5 +#endif //__REG_REGS_H__