add camera driver and examples for edu-riscv64

This commit is contained in:
wuzheng
2022-11-18 20:20:34 +08:00
parent f22fbc3c94
commit 06ed03337a
36 changed files with 7038 additions and 351 deletions
@@ -0,0 +1,46 @@
if BSP_USING_CAMERA
config DVP_XCLK_RATE
int "Camera interface clk rate"
default 24000000
config IMAGE_WIDTH
int "Camera photo width"
default 320
config IMAGE_HEIGHT
int "Camera photo height"
default 240
config DVP_BURST_ENABLE
bool "brust mode enable"
default y
config DVP_AUTO_ENABLE
bool "auto recv image mode enable"
default n
config DVP_AI_OUTPUT
bool "ai output enable"
default n
config DVP_INTERRUPT_ENABLE
bool "interrupt enable"
default y
config CAMERA_BUS_NAME
string "camera bus name"
default "camera"
config CAMERA_DRV_NAME
string "camera driver name"
default "camera_drv"
config CAMERA_DEVICE_NAME
string "camera device name"
default "camera_dev"
choice
prompt "set camera framesize and fps"
default SVGA_25FPS_MODE
config UXGA_15FPS_MODE
bool "using uxga in 15fps"
config SVGA_25FPS_MODE
bool "using svag in 25fps"
endchoice
endif
@@ -0,0 +1,4 @@
SRC_FILES := connect_dvp.c dvp.c ov2640.c
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,242 @@
#include <connect_dvp.h>
#include <dvp.h>
#include <board.h>
#include "sysctl.h"
#include "bsp.h"
#include "plic.h"
#include <ov2640.h>
#define REG_SCCB_READ 0x12U
#define REG_SCCB_WRITE 0x13U
#define SCCB_REG_LENGTH 0x08U
// irq interrupt function
static int on_irq_dvp(int irq, void *arg)
{
if (dvp_get_interrupt(DVP_STS_FRAME_FINISH))
{
dvp_clear_interrupt(DVP_STS_FRAME_FINISH);
}
else
{
dvp_start_convert();
dvp_clear_interrupt(DVP_STS_FRAME_START);
}
return 0;
}
struct DvpRegConfigureInfo
{
uint8_t device_addr;
uint16_t reg_addr;
uint8_t reg_value;
};
static struct CameraCfg sensor_config = {
.output_h = IMAGE_HEIGHT,//will be resize from window below in ov2640
.output_w = IMAGE_WIDTH,
.window_h = 600, //register configure in ov2640.h
.window_w = 800, //to make window as large as cmos selected size
.window_xoffset = 0,
.window_yoffset = 0,
.gain_manu_enable = 0,
.gain = 0x00
};
static uint32 dvpDrvInit(void)
{
x_err_t ret = EOK;
dvp_init(SCCB_REG_LENGTH);
dvp_set_xclk_rate(DVP_XCLK_RATE);
dvp_set_image_format(DVP_CFG_RGB_FORMAT);
dvp_set_image_size(IMAGE_WIDTH, IMAGE_HEIGHT);
dvp_set_output_enable(DVP_OUTPUT_DISPLAY, 0);
dvp_set_output_enable(DVP_OUTPUT_AI, 0);
ov2640_init();
sensorConfigure(&sensor_config);
sysctl_set_spi0_dvp_data(1);
#ifdef DVP_BURST_ENABLE
dvp_enable_burst();
#endif
#ifdef DVP_AUTO_ENABLE
dvp_disable_auto();
#endif
#ifdef DVP_AI_OUTPUT
dvp_set_output_enable(DVP_OUTPUT_AI, 1);
dvp_set_ai_addr((uint32_t)DVP_AI_RED_ADRESS, (uint32_t)DVP_AI_GREEN_ADRESS, (uint32_t)DVP_AI_BLUE_ADRESS);
#endif
#ifdef DVP_INTERRUPT_ENABLE
dvp_config_interrupt(DVP_CFG_START_INT_ENABLE | DVP_CFG_FINISH_INT_ENABLE, 0);
isrManager.done->registerIrq(IRQN_DVP_INTERRUPT, (IsrHandlerType)on_irq_dvp, NULL);
isrManager.done->enableIrq(IRQN_DVP_INTERRUPT);
dvp_clear_interrupt(DVP_STS_FRAME_START | DVP_STS_FRAME_FINISH);
dvp_config_interrupt(DVP_CFG_START_INT_ENABLE | DVP_CFG_FINISH_INT_ENABLE, 1);
KPrintf("camera interrupt has open!\n");
#endif
return ret;
}
static uint32 readDvpReg(void *drv, struct DvpRegConfigureInfo *reg_info)
{
x_err_t ret = EOK;
reg_info->reg_value = dvp_sccb_receive_data(reg_info->device_addr, reg_info->reg_addr);
return ret;
}
static uint32 writeDvpReg(void *drv, struct DvpRegConfigureInfo *reg_info)
{
x_err_t ret = EOK;
dvp_sccb_send_data(reg_info->device_addr, reg_info->reg_addr, reg_info->reg_value);
return ret;
}
static uint32 dvpOpen(void *dev)
{
x_err_t ret = EOK;
dvpDrvInit();
return ret;
}
static uint32 dvpClose(void *dev)
{
x_err_t ret = EOK;
dvp_config_interrupt(DVP_CFG_START_INT_ENABLE | DVP_CFG_FINISH_INT_ENABLE, 0);
dvp_set_output_enable(DVP_OUTPUT_AI, 0);
dvp_set_output_enable(DVP_OUTPUT_DISPLAY, 0);
return ret;
}
static uint32 dvpRead(void *dev, struct BusBlockReadParam *read_param)
{
x_err_t ret = EOK;
// change the output buff address by read
dvp_set_output_enable(DVP_OUTPUT_DISPLAY, 0);
dvp_set_display_addr((uintptr_t)read_param->buffer);
dvp_set_output_enable(DVP_OUTPUT_DISPLAY, 1);
return ret;
}
static uint32 dvpDrvConfigure(void *drv, struct BusConfigureInfo *args)
{
x_err_t ret = EOK;
int cmd_type = args->configure_cmd;
struct CameraCfg* tmp_cfg;
switch (cmd_type)
{
case OPE_INT:
break;
case OPE_CFG:
tmp_cfg = (struct CameraCfg *)args->private_data;
sensorConfigure(tmp_cfg);
dvp_set_image_size(tmp_cfg->output_w, tmp_cfg->output_h);
break;
case REG_SCCB_READ:
readDvpReg(drv, (struct DvpRegConfigureInfo *)args->private_data);
break;
case REG_SCCB_WRITE:
writeDvpReg(drv, (struct DvpRegConfigureInfo *)args->private_data);
break;
default:
break;
}
return ret;
}
/*manage the camera device operations*/
static const struct CameraDevDone camera_dev_done =
{
.dev_open = dvpOpen,
.dev_close = dvpClose,
.dev_write = NONE,
.dev_read = dvpRead,
};
/*Init camera bus*/
static int BoardCameraBusInit(struct CameraBus *camera_bus, struct CameraDriver *camera_driver)
{
x_err_t ret = EOK;
/*Init the camera bus */
camera_bus->private_data = (void *)&camera_dev_done;
ret = CameraBusInit(camera_bus, CAMERA_BUS_NAME);
if (EOK != ret)
{
KPrintf("board_camera_init CameraBusInit error %d\n", ret);
return ERROR;
}
/*Init the camera driver*/
camera_driver->private_data = (void *)&camera_dev_done;
ret = CameraDriverInit(camera_driver, CAMERA_DRV_NAME);
if (EOK != ret)
{
KPrintf("board_camera_init CameraDriverInit error %d\n", ret);
return ERROR;
}
/*Attach the camera driver to the camera bus*/
ret = CameraDriverAttachToBus(CAMERA_DRV_NAME, CAMERA_BUS_NAME);
if (EOK != ret)
{
KPrintf("board_camera_init CameraDriverAttachToBus error %d\n", ret);
return ERROR;
}
return ret;
}
/*Attach the camera device to the camera bus*/
static int BoardCameraDevBend(void)
{
x_err_t ret = EOK;
static struct CameraHardwareDevice camera_device;
memset(&camera_device, 0, sizeof(struct CameraHardwareDevice));
camera_device.camera_dev_done = &camera_dev_done;
ret = CameraDeviceRegister(&camera_device, NONE, CAMERA_DEVICE_NAME);
if (EOK != ret)
{
KPrintf("board_camera_init CameraDeviceInit device %s error %d\n", CAMERA_DEVICE_NAME, ret);
return ERROR;
}
ret = CameraDeviceAttachToBus(CAMERA_DEVICE_NAME, CAMERA_BUS_NAME);
if (EOK != ret)
{
KPrintf("board_camera_init CameraDeviceAttachToBus device %s error %d\n", CAMERA_DEVICE_NAME, ret);
return ERROR;
}
return ret;
}
int HwDvpInit(void)
{
x_err_t ret = EOK;
static struct CameraBus camera_bus;
memset(&camera_bus, 0, sizeof(struct CameraBus));
static struct CameraDriver camera_driver;
memset(&camera_driver, 0, sizeof(struct CameraDriver));
camera_driver.configure = dvpDrvConfigure;
ret = BoardCameraBusInit(&camera_bus, &camera_driver);
if (EOK != ret)
{
KPrintf("board_camera_Init error ret %u\n", ret);
return ERROR;
}
ret = BoardCameraDevBend();
if (EOK != ret)
{
KPrintf("board_camera_Init error ret %u\n", ret);
return ERROR;
}
return ret;
}
@@ -0,0 +1,288 @@
/* 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 <stddef.h>
#include <stdint.h>
#include "dvp.h"
#include "utils.h"
#include "fpioa.h"
#include "sysctl.h"
#include <math.h>
#include <sleep.h>
volatile dvp_t* const dvp = (volatile dvp_t*)DVP_BASE_ADDR;
static uint8_t g_sccb_reg_len = 8;
static void dvp_sccb_clk_init(void)
{
uint32_t tmp;
tmp = dvp->sccb_cfg & (~(DVP_SCCB_SCL_LCNT_MASK | DVP_SCCB_SCL_HCNT_MASK));
tmp |= DVP_SCCB_SCL_LCNT(255) | DVP_SCCB_SCL_HCNT(255);
dvp->sccb_cfg = tmp;
}
uint32_t dvp_sccb_set_clk_rate(uint32_t clk_rate)
{
uint32_t tmp;
uint32_t v_sccb_freq = SysctlClockGetFreq(SYSCTL_CLOCK_APB1);
uint16_t v_period_clk_cnt = round(v_sccb_freq / clk_rate / 2.0);
if(v_period_clk_cnt > 255)
{
return 0;
}
tmp = dvp->sccb_cfg & (~(DVP_SCCB_SCL_LCNT_MASK | DVP_SCCB_SCL_HCNT_MASK));
tmp |= DVP_SCCB_SCL_LCNT(v_period_clk_cnt) | DVP_SCCB_SCL_HCNT(v_period_clk_cnt);
dvp->sccb_cfg = tmp;
return SysctlClockGetFreq(SYSCTL_CLOCK_DVP) / (v_period_clk_cnt * 2);
}
static void dvp_sccb_start_transfer(void)
{
while (dvp->sts & DVP_STS_SCCB_EN)
;
dvp->sts = DVP_STS_SCCB_EN | DVP_STS_SCCB_EN_WE;
while (dvp->sts & DVP_STS_SCCB_EN)
;
}
void dvp_sccb_send_data(uint8_t dev_addr, uint16_t reg_addr, uint8_t reg_data)
{
uint32_t tmp;
tmp = dvp->sccb_cfg & (~DVP_SCCB_BYTE_NUM_MASK);
(g_sccb_reg_len == 8) ? (tmp |= DVP_SCCB_BYTE_NUM_3) : (tmp |= DVP_SCCB_BYTE_NUM_4);
dvp->sccb_cfg = tmp;
if (g_sccb_reg_len == 8)
{
dvp->sccb_ctl = DVP_SCCB_WRITE_DATA_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr) | DVP_SCCB_WDATA_BYTE0(reg_data);
}
else
{
dvp->sccb_ctl = DVP_SCCB_WRITE_DATA_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr >> 8) | DVP_SCCB_WDATA_BYTE0(reg_addr & 0xff) | DVP_SCCB_WDATA_BYTE1(reg_data);
}
dvp_sccb_start_transfer();
}
uint8_t dvp_sccb_receive_data(uint8_t dev_addr, uint16_t reg_addr)
{
uint32_t tmp;
tmp = dvp->sccb_cfg & (~DVP_SCCB_BYTE_NUM_MASK);
if (g_sccb_reg_len == 8)
tmp |= DVP_SCCB_BYTE_NUM_2;
else
tmp |= DVP_SCCB_BYTE_NUM_3;
dvp->sccb_cfg = tmp;
if (g_sccb_reg_len == 8)
{
dvp->sccb_ctl = DVP_SCCB_WRITE_DATA_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr);
}
else
{
dvp->sccb_ctl = DVP_SCCB_WRITE_DATA_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr >> 8) | DVP_SCCB_WDATA_BYTE0(reg_addr & 0xff);
}
dvp_sccb_start_transfer();
dvp->sccb_ctl = DVP_SCCB_DEVICE_ADDRESS(dev_addr);
dvp_sccb_start_transfer();
return (uint8_t) DVP_SCCB_RDATA_BYTE(dvp->sccb_cfg);
}
static void dvp_reset(void)
{
/* First power down */
dvp->cmos_cfg |= DVP_CMOS_POWER_DOWN;
msleep(200);
dvp->cmos_cfg &= ~DVP_CMOS_POWER_DOWN;
msleep(200);
/* Second reset */
dvp->cmos_cfg &= ~DVP_CMOS_RESET;
msleep(200);
dvp->cmos_cfg |= DVP_CMOS_RESET;
msleep(200);
}
void dvp_init(uint8_t reg_len)
{
g_sccb_reg_len = reg_len;
sysctl_clock_enable(SYSCTL_CLOCK_DVP);
sysctl_reset(SYSCTL_RESET_DVP);
dvp->cmos_cfg &= (~DVP_CMOS_CLK_DIV_MASK);
dvp->cmos_cfg |= DVP_CMOS_CLK_DIV(3) | DVP_CMOS_CLK_ENABLE;
dvp_sccb_clk_init();
dvp_reset();
}
uint32_t dvp_set_xclk_rate(uint32_t xclk_rate)
{
uint32_t v_apb1_clk = SysctlClockGetFreq(SYSCTL_CLOCK_APB1);
uint32_t v_period;
if(v_apb1_clk > xclk_rate * 2)
v_period = round(v_apb1_clk / (xclk_rate * 2.0)) - 1;
else
v_period = 0;
if(v_period > 255)
v_period = 255;
dvp->cmos_cfg &= (~DVP_CMOS_CLK_DIV_MASK);
dvp->cmos_cfg |= DVP_CMOS_CLK_DIV(v_period) | DVP_CMOS_CLK_ENABLE;
dvp_reset();
return v_apb1_clk / ((v_period + 1) * 2);
}
void dvp_set_image_format(uint32_t format)
{
uint32_t tmp;
tmp = dvp->dvp_cfg & (~DVP_CFG_FORMAT_MASK);
dvp->dvp_cfg = tmp | format;
}
void dvp_enable_burst(void)
{
dvp->dvp_cfg |= DVP_CFG_BURST_SIZE_4BEATS;
dvp->axi &= (~DVP_AXI_GM_MLEN_MASK);
dvp->axi |= DVP_AXI_GM_MLEN_4BYTE;
}
void dvp_disable_burst(void)
{
dvp->dvp_cfg &= (~DVP_CFG_BURST_SIZE_4BEATS);
dvp->axi &= (~DVP_AXI_GM_MLEN_MASK);
dvp->axi |= DVP_AXI_GM_MLEN_1BYTE;
}
void dvp_set_image_size(uint32_t width, uint32_t height)
{
uint32_t tmp;
tmp = dvp->dvp_cfg & (~(DVP_CFG_HREF_BURST_NUM_MASK | DVP_CFG_LINE_NUM_MASK));
tmp |= DVP_CFG_LINE_NUM(height);
if (dvp->dvp_cfg & DVP_CFG_BURST_SIZE_4BEATS)
tmp |= DVP_CFG_HREF_BURST_NUM(width / 8 / 4);
else
tmp |= DVP_CFG_HREF_BURST_NUM(width / 8 / 1);
dvp->dvp_cfg = tmp;
}
void dvp_set_ai_addr(uint32_t r_addr, uint32_t g_addr, uint32_t b_addr)
{
dvp->r_addr = r_addr;
dvp->g_addr = g_addr;
dvp->b_addr = b_addr;
}
void dvp_set_display_addr(uint32_t addr)
{
dvp->rgb_addr = addr;
}
void dvp_start_frame(void)
{
while (!(dvp->sts & DVP_STS_FRAME_START))
;
dvp->sts = (DVP_STS_FRAME_START | DVP_STS_FRAME_START_WE);
}
void dvp_start_convert(void)
{
dvp->sts = DVP_STS_DVP_EN | DVP_STS_DVP_EN_WE;
}
void dvp_finish_convert(void)
{
while (!(dvp->sts & DVP_STS_FRAME_FINISH))
;
dvp->sts = DVP_STS_FRAME_FINISH | DVP_STS_FRAME_FINISH_WE;
}
void dvp_get_image(void)
{
while (!(dvp->sts & DVP_STS_FRAME_START))
;
dvp->sts = DVP_STS_FRAME_START | DVP_STS_FRAME_START_WE;
while (!(dvp->sts & DVP_STS_FRAME_START))
;
dvp->sts = DVP_STS_FRAME_FINISH | DVP_STS_FRAME_FINISH_WE | DVP_STS_FRAME_START | DVP_STS_FRAME_START_WE | DVP_STS_DVP_EN | DVP_STS_DVP_EN_WE;
while (!(dvp->sts & DVP_STS_FRAME_FINISH))
;
}
void dvp_config_interrupt(uint32_t interrupt, uint8_t enable)
{
if (enable)
dvp->dvp_cfg |= interrupt;
else
dvp->dvp_cfg &= (~interrupt);
}
int dvp_get_interrupt(uint32_t interrupt)
{
if (dvp->sts & interrupt)
return 1;
return 0;
}
void dvp_clear_interrupt(uint32_t interrupt)
{
interrupt |= (interrupt << 1);
dvp->sts |= interrupt;
}
void dvp_enable_auto(void)
{
dvp->dvp_cfg |= DVP_CFG_AUTO_ENABLE;
}
void dvp_disable_auto(void)
{
dvp->dvp_cfg &= (~DVP_CFG_AUTO_ENABLE);
}
void dvp_set_output_enable(dvp_output_mode_t index, int enable)
{
configASSERT(index < 2);
if (index == 0)
{
if (enable)
dvp->dvp_cfg |= DVP_CFG_AI_OUTPUT_ENABLE;
else
dvp->dvp_cfg &= ~DVP_CFG_AI_OUTPUT_ENABLE;
}
else
{
if (enable)
dvp->dvp_cfg |= DVP_CFG_DISPLAY_OUTPUT_ENABLE;
else
dvp->dvp_cfg &= ~DVP_CFG_DISPLAY_OUTPUT_ENABLE;
}
}
@@ -0,0 +1,457 @@
/* 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 "ov2640.h"
#include "dvp.h"
#include "plic.h"
#include "board.h"
#if defined SVGA_25FPS_MODE
const uint8_t ov2640_config[][2]=
{
{0xff, 0x01},
{0x12, 0x80},
{0xff, 0x00},
{0x2c, 0xff},
{0x2e, 0xdf},
{0xff, 0x01},
{0x3c, 0x32},
{0x11, 0x00},
{0x09, 0x02},
{0x04, 0x58},
{0x13, 0xe5},
{0x14, 0x48},
{0x2c, 0x0c},
{0x33, 0x78},
{0x3a, 0x33},
{0x3b, 0xfb},
{0x3e, 0x00},
{0x43, 0x11},
{0x16, 0x10},
{0x39, 0x92},
{0x35, 0xda},
{0x22, 0x1a},
{0x37, 0xc3},
{0x23, 0x00},
{0x34, 0xc0},
{0x36, 0x1a},
{0x06, 0x88},
{0x07, 0xc0},
{0x0d, 0x87},
{0x0e, 0x41},
{0x4c, 0x00},
{0x48, 0x00},
{0x5b, 0x00},
{0x42, 0x03},
{0x4a, 0x81},
{0x21, 0x99},
{0x24, 0x40},
{0x25, 0x38},
{0x26, 0x82},
{0x5c, 0x00},
{0x63, 0x00},
{0x46, 0x22},
{0x0c, 0x3c},
{0x61, 0x70},
{0x62, 0x80},
{0x7c, 0x05},
{0x20, 0x80},
{0x28, 0x30},
{0x6c, 0x00},
{0x6d, 0x80},
{0x6e, 0x00},
{0x70, 0x02},
{0x71, 0x94},
{0x73, 0xc1},
{0x3d, 0x34},
{0x5a, 0x57},
{0x12, 0x40},
{0x17, 0x11},
{0x18, 0x43},
{0x19, 0x00},
{0x1a, 0x97},
{0x32, 0x09},
{0x37, 0xc0},
{0x4f, 0xca},
{0x50, 0xa8},
{0x5a, 0x23},
{0x6d, 0x00},
{0x3d, 0x38},
{0xff, 0x00},
{0xe5, 0x7f},
{0xf9, 0xc0},
{0x41, 0x24},
{0xe0, 0x14},
{0x76, 0xff},
{0x33, 0xa0},
{0x42, 0x20},
{0x43, 0x18},
{0x4c, 0x00},
{0x87, 0xd5},
{0x88, 0x3f},
{0xd7, 0x03},
{0xd9, 0x10},
{0xd3, 0x82},
{0xc8, 0x08},
{0xc9, 0x80},
{0x7c, 0x00},
{0x7d, 0x00},
{0x7c, 0x03},
{0x7d, 0x48},
{0x7d, 0x48},
{0x7c, 0x08},
{0x7d, 0x20},
{0x7d, 0x10},
{0x7d, 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, 0x05},
{0x93, 0x05},
{0x93, 0x00},
{0x93, 0x04},
{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},
{0xc3, 0xed},
{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},
{0xc0, 0x64},
{0xc1, 0x4b},
{0x8c, 0x00},
{0x86, 0x3d},
{0x50, 0x00},
{0x51, 0xc8},
{0x52, 0x96},
{0x53, 0x00},
{0x54, 0x00},
{0x55, 0x00},
{0x5a, 0xc8},
{0x5b, 0x96},
{0x5c, 0x00},
{0xd3, 0x02},
{0xc3, 0xed},
{0x7f, 0x00},
{0xda, 0x08},
{0xe5, 0x1f},
{0xe1, 0x67},
{0xe0, 0x00},
{0xdd, 0x7f},
{0x05, 0x00},
{0xff, 0x00},
{0xe0, 0x04},
{0x5a, 0x50},
{0x5b, 0x3c},
{0x5c, 0x00},
{0xe0, 0x00},
{0x00, 0x00}
};
#elif defined UXGA_15FPS_MODE
const uint8_t ov2640_config[][2]=
{
{0xFF, 0x00},
{0x2C, 0xFF},
{0x2E, 0xDF},
{0xFF, 0x01},
{0x3C, 0x32},
{0x11, 0x00},
{0x09, 0x02},
{0x04, 0xA8},
{0x13, 0xE5},
{0x14, 0x48},
{0x2C, 0x0C},
{0x33, 0x78},
{0x3A, 0x33},
{0x3B, 0xFB},
{0x3E, 0x00},
{0x43, 0x11},
{0x16, 0x10},
{0x39, 0x92},
{0x35, 0xDA},
{0x22, 0x1A},
{0x37, 0xC3},
{0x23, 0x00},
{0x34, 0xC0},
{0x36, 0x1A},
{0x06, 0x88},
{0x07, 0xC0},
{0x0D, 0x87},
{0x0E, 0x41},
{0x4C, 0x00},
{0x48, 0x00},
{0x5B, 0x00},
{0x42, 0x03},
{0x4A, 0x81},
{0x21, 0x99},
{0x24, 0x40},
{0x25, 0x38},
{0x26, 0x82},
{0x5C, 0x00},
{0x63, 0x00},
{0x46, 0x00},
{0x0C, 0x3C},
{0x61, 0x70},
{0x62, 0x80},
{0x7C, 0x05},
{0x20, 0x80},
{0x28, 0x30},
{0x6C, 0x00},
{0x6D, 0x80},
{0x6E, 0x00},
{0x70, 0x02},
{0x71, 0x94},
{0x73, 0xC1},
{0x3D, 0x34},
{0x5A, 0x57},
{0x12, 0x00},
{0x17, 0x11},
{0x18, 0x75},
{0x19, 0x01},
{0x1A, 0x97},
{0x32, 0x36},
{0x03, 0x0F},
{0x37, 0x40},
{0x4F, 0xCA},
{0x50, 0xA8},
{0x5A, 0x23},
{0x6D, 0x00},
{0x6D, 0x38},
{0xFF, 0x00},
{0xE5, 0x7F},
{0xF9, 0xC0},
{0x41, 0x24},
{0xE0, 0x14},
{0x76, 0xFF},
{0x33, 0xA0},
{0x42, 0x20},
{0x43, 0x18},
{0x4C, 0x00},
{0x87, 0xD5},
{0x88, 0x3F},
{0xD7, 0x03},
{0xD9, 0x10},
{0xD3, 0x82},
{0xC8, 0x08},
{0xC9, 0x80},
{0x7C, 0x00},
{0x7D, 0x00},
{0x7C, 0x03},
{0x7D, 0x48},
{0x7D, 0x48},
{0x7C, 0x08},
{0x7D, 0x20},
{0x7D, 0x10},
{0x7D, 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, 0x05},
{0x93, 0x05},
{0x93, 0x00},
{0x93, 0x04},
{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},
{0xC3, 0xEF},
{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},
{0xC0, 0xC8},
{0xC1, 0x96},
{0x8C, 0x00},
{0x86, 0x3D},
{0x50, 0x00},
{0x51, 0x90},
{0x52, 0x2C},
{0x53, 0x00},
{0x54, 0x00},
{0x55, 0x88},
{0x5A, 0x90},
{0x5B, 0x2C},
{0x5C, 0x05},
{0xD3, 0x02},
{0xC3, 0xED},
{0x7F, 0x00},
{0xDA, 0x08},
{0xE5, 0x1F},
{0xE1, 0x67},
{0xE0, 0x00},
{0xDD, 0x7F},
{0x00, 0x00}
};
#else
const uint8_t ov2640_config[][2]=
{
{0x00,x00}
}
#endif
int ov2640_init(void)
{
uint16_t v_manuf_id;
uint16_t v_device_id;
ov2640_read_id(&v_manuf_id, &v_device_id);
printf("manuf_id:0x%04x,device_id:0x%04x\n", v_manuf_id, v_device_id);
uint16_t index = 0;
for (index = 0; ov2640_config[index][0]; index++)
dvp_sccb_send_data(OV2640_ADDR, ov2640_config[index][0], ov2640_config[index][1]);
return 0;
}
int ov2640_read_id(uint16_t *manuf_id, uint16_t *device_id)
{
dvp_sccb_send_data(OV2640_ADDR, 0xFF, 0x01);
*manuf_id = (dvp_sccb_receive_data(OV2640_ADDR, 0x1C) << 8) | dvp_sccb_receive_data(OV2640_ADDR, 0x1D);
*device_id = (dvp_sccb_receive_data(OV2640_ADDR, 0x0A) << 8) | dvp_sccb_receive_data(OV2640_ADDR, 0x0B);
return 0;
}
int sensorConfigure(struct CameraCfg *cfg_info)
{
uint8_t reg_tmp;
//set reg mode to sensor
dvp_sccb_send_data(OV2640_ADDR, 0xFF, 0x00);
//configure the window size and position
dvp_sccb_send_data(OV2640_ADDR, 0x51, cfg_info->window_w>>2);
dvp_sccb_send_data(OV2640_ADDR, 0x52, cfg_info->window_h>>2);
dvp_sccb_send_data(OV2640_ADDR, 0x53, (uint8_t)(cfg_info->window_xoffset&0xFF));
dvp_sccb_send_data(OV2640_ADDR, 0x54, (uint8_t)(cfg_info->window_yoffset&0xFF));
dvp_sccb_send_data(OV2640_ADDR, 0x55, (((cfg_info->window_h/4)&0x100)>>1)+
((cfg_info->window_yoffset&0x700)>>4)+
(((cfg_info->window_w/4)&0x100)>>5)+
((cfg_info->window_xoffset&0x700)>>8));
dvp_sccb_send_data(OV2640_ADDR, 0x57, ((cfg_info->window_w/4)&0x200)>>2);
dvp_sccb_send_data(OV2640_ADDR, 0x5A, cfg_info->output_w>>2);
dvp_sccb_send_data(OV2640_ADDR, 0x5B, cfg_info->output_h>>2);
//set reg mode to dsp
dvp_sccb_send_data(OV2640_ADDR, 0xFF, 0x01);
//configure dsp gain
if(cfg_info->gain_manu_enable){
reg_tmp = dvp_sccb_receive_data(OV2640_ADDR, 0x13);
dvp_sccb_send_data(OV2640_ADDR, 0x13, reg_tmp&0xFB);
dvp_sccb_send_data(OV2640_ADDR, 0x00, cfg_info->gain);
}else{
reg_tmp = dvp_sccb_receive_data(OV2640_ADDR, 0x13);
dvp_sccb_send_data(OV2640_ADDR, 0x13, reg_tmp|0x04);
}
return 1;
}