www.pudn.com > camera.rar > ov7660.cpp
// // Copyright (c) Microsoft Corporation. All rights reserved. // // // Use of this sample source code is subject to the terms of the Microsoft // license agreement under which you licensed this sample source code. If // you did not accept the terms of the license agreement, you are not // authorized to use this sample source code. For the terms of the license, // please see the license agreement between you and Microsoft or, if applicable, // see the LICENSE.RTF on your install media or the root of your tools installation. // THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES. // // // (C) Copyright 2006 Marvell International Ltd. // All Rights Reserved // #include#include #include "Cs.h" #include "Csmedia.h" #include "CameraPDDProps.h" #include "dstruct.h" #include "dbgsettings.h" #include #include "CameraDriver.h" #include "PinDriver.h" #include "SensorFormats.h" #include "monahans.h" #include "ov7660.h" #include "ov7660_hw.h" #include "Camera_SOC.h" //#include "ost.h" #include "GPIO_SOC.h" #include "I2C_SOC.h" #include "GPX_API.h" #include "PMIC_DRV.h" BOOL pic_read_reg(UCHAR addr, UCHAR* value); BOOL pic_write_reg(UCHAR addr, UCHAR value); static UINT32 get_gain(); static void set_gain(UINT32 gain); static UINT32 get_exposure(); static void set_exposure(UINT32 exposure); static void set_exposure_gain(UINT32 preview_exposure, UINT32 preview_gain); static void get_ae(UCHAR* pre_gain, UCHAR* r_gain, UCHAR* b_gain); static void set_ae(UCHAR pre_gain, UCHAR r_gain, UCHAR b_gain); MAKE_STREAM_MODE_YV12(DCAM_StreamMode_QCIF_YV12, 176, -144, 12, 15); MAKE_STREAM_MODE_YV12(DCAM_StreamMode_QVGA_YV12, 320, -240, 12, 30); MAKE_STREAM_MODE_YV12(DCAM_StreamMode_VGA_YV12, 640, -480, 12, 30); static qci_interface_t ov7660_interface = { PXA_CI_MODE_MP, PXA_CI_DATA_WIDTH8, 2600, FALSE, FALSE, FALSE }; static camera_cfg_t preview_cfg = { &DCAM_StreamMode_QCIF_YV12, PXA_CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR, /* sensor format */ QCIF, /* qci_format_t */ { PXA_CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR, 176, 144 }, 0, }; static camera_cfg_t still_cfg = { &DCAM_StreamMode_VGA_YV12, PXA_CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR, /* sensor format */ VGA, /* qci_format_t */ { PXA_CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR, 640, 480 }, 0, }; MAKE_STREAM_MODE_RGB565(DCAM_StreamMode_0, 160, 120, 16, 30); MAKE_STREAM_MODE_RGB565(DCAM_StreamMode_1, 176, 144, 16, 30); MAKE_STREAM_MODE_RGB565(DCAM_StreamMode_2, 320, 240, 16, 15); MAKE_STREAM_MODE_RGB565(DCAM_StreamMode_3, 320, 240, 16, 30); MAKE_STREAM_MODE_RGB565(DCAM_StreamMode_4, 640, 480, 16, 15); MAKE_STREAM_MODE_YV12(DCAM_StreamMode_11, 400, -294, 12, 30); MAKE_STREAM_MODE_YV12(DCAM_StreamMode_12, 800, -600, 12, 30); //MAKE_STREAM_MODE_YV12(DCAM_StreamMode_UXGA_YV12, 1600, -1200, 12, 15); #define SENSOR_INIT_WAIT 150 //void map_registers(); static void dump_ov7660(); Ov7660::Ov7660() { //map_registers(); qci_interface = &ov7660_interface; timing.BFW = 0x01; timing.BLW = 0x00; DCAM_StreamMode_QCIF_YV12.ConfigCaps.MinFrameInterval = 632911; DCAM_StreamMode_QCIF_YV12.VideoInfoHeader.AvgTimePerFrame = 632911; } void set_voltage(UCHAR camera_ana, UCHAR camera_io, UCHAR camera_core, BOOL is_on) { UCHAR reg; pic_read_reg(0x14, ®); if ((reg & 0xf) != camera_ana) pic_write_reg(0x14, (reg & 0xf0) | camera_ana); #ifdef SETUP_IO_CORE_VOLTAGE pic_read_reg(0x13, ®); pic_write_reg(0x13, (reg & 0xf0) | camera_io); pic_read_reg(0x92, ®); if ((reg & 0xf) != camera_core) pic_write_reg(0x92, (reg & 0xf0) | camera_core); #endif const UCHAR ldo_en = 0x80; UCHAR set_value = is_on? ldo_en : 0; pic_read_reg(0x17, ®); if ((reg & ldo_en) != set_value) { reg &= ~ldo_en; pic_write_reg(0x17, reg | set_value); } //CloseHandle(pic_drv); } bool Ov7660::detect() { UINT8 pid = 0, rev = 0; OV7660VersionRevision(&pid, &rev); DEBUGMSG(ZONE_IOCTL,(L"CAM: Ov7660::detect PID 0x%x, REV 0x%x\r\n",pid, rev)); return pid == PID_OV76XX && rev == PID_7660; } UINT32 Ov7660::get_formats(ULONG type, PCS_DATARANGE_VIDEO** formats) { // Video Format initialization UINT32 nformats = 1; *formats = new PCS_DATARANGE_VIDEO[nformats]; if( NULL == *formats ) { return 0; } switch (type) { case CAPTURE: case PREVIEW: (*formats)[0] = &DCAM_StreamMode_QCIF_YV12; break; case STILL: (*formats)[0] = &DCAM_StreamMode_VGA_YV12; default: break; } return nformats; } void Ov7660::start_capture() { if (frame_size == VGA) { OV7660AutoFunctionOff(); set_exposure_gain(exposure, gain); set_ae(pre_gain, r_gain, b_gain); } else OV7660AutoFunctionOn(); OV7660ViewfinderOn(); } void Ov7660::stop_capture() { if (frame_size != VGA) { gain = get_gain(); exposure = get_exposure(); get_ae(&pre_gain, &r_gain, &b_gain); DEBUGMSG(ZONE_IOCTL,(L"CAM: Ov7660 gain is 0x%x, exposure is 0x%x", gain, exposure)); } OV7660ViewfinderOff(); // put sensor output in tri-state when power down UCHAR com3; OV7660ReadSensorReg(OV7660_COM3, &com3); com3 &= ~0x18; OV7660WriteSensorReg(OV7660_COM3, &com3); } void Ov7660::set_power_mode(bool is_on) { set_voltage(0x7, 0xa, 0x0, is_on); /* Call_GPX */ GPX_SetDirection(GPX_GPIO_CAMERA_LO_PWDN, PXA_GPIO_DIRECTION_OUT); OV7660PowerDown(is_on? PXA_CAMERA_POWER_FULL : PXA_CAMERA_POWER_OFF); if (is_on) Sleep(200); } camera_cfg_t* Ov7660::get_camera_cfg(PCS_VIDEOINFOHEADER pCsVideoInfoHdr, ULONG mode) { UINT32 width = abs(pCsVideoInfoHdr->bmiHeader.biWidth); UINT32 height = abs(pCsVideoInfoHdr->bmiHeader.biHeight); if (width == 176 && height == 144) return &preview_cfg; else return &still_cfg; } extern void fill_buffer_yv12(PUCHAR* dest_plane, frame_t* frame); void Ov7660::handle_frame_interrupt(PUCHAR buf, CS_BITMAPINFOHEADER* info_header, frame_t* qci_frame) { UINT32 width = abs(info_header->biWidth); UINT32 height = abs(info_header->biHeight); UINT32 y_size = width * height; PUCHAR dest[3]; dest[0] = buf; dest[1] = dest[0] + y_size; dest[2] = dest[1] + (y_size >> 2); fill_buffer_yv12(dest, qci_frame); } void Ov7660::set_frame_format(int format, FrameSize size) { int status; UINT32 ovSizeFormat, ovFormat; frame_size = size; // Set the current mode switch(format) { case PXA_CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR: case PXA_CAMERA_IMAGE_FORMAT_YCBCR422_PACKED: ovFormat = OV_FORMAT_YUV_422; break; case PXA_CAMERA_IMAGE_FORMAT_RGB565: ovFormat = OV_FORMAT_RGB_565; break; case PXA_CAMERA_IMAGE_FORMAT_RAW8: ovFormat = OV_FORMAT_RAW8; break; default: ovFormat = OV_FORMAT_YUV_422; break; } switch(size) { case QCIF: ovSizeFormat = OV_SIZE_QCIF; break; case CIF: ovSizeFormat = OV_SIZE_CIF; break; case QQVGA: ovSizeFormat = OV_SIZE_QQVGA; break; case QVGA: ovSizeFormat = OV_SIZE_QVGA; break; case VGA: default: ovSizeFormat = OV_SIZE_VGA; break; } status = OV7660SetFormat(ovSizeFormat, ovFormat, 0); } #ifdef DEBUG static void dump_ov7660() { UCHAR buf[0x8b]; OV7660ReadAllRegs(buf, 0x8b); for (int i = 0; i < 0x8b; i++) DEBUGMSG(ZONE_IOCTL,(L"reg 0x%x = 0x%x", i, buf[i])); } #endif BOOL pic_read_reg(UCHAR addr, UCHAR* value) { PXA_STATUS_T ulStatus = PXA_STATUS_SUCCESS; ulStatus = PMIC_Read((UINT8)addr, (UINT8*)value); if (PXA_STATUS_SUCCESS != ulStatus) { ERRORMSG(1, (TEXT("[Camera]: pic_read_reg Failed in PMIC_Read (ulStatus = %d).\r\n"),ulStatus)); return FALSE; } return TRUE; } BOOL pic_write_reg(UCHAR addr, UCHAR value) { PXA_STATUS_T ulStatus = PXA_STATUS_SUCCESS; ulStatus = PMIC_Write((UINT8)addr, (UINT8)value); if (PXA_STATUS_SUCCESS != ulStatus) { ERRORMSG(1, (TEXT("[Camera]: pic_write_reg Failed in PMIC_Write (ulStatus = %d).\r\n"),ulStatus)); return FALSE; } return TRUE; } static UINT32 get_gain() { UCHAR gain_reg; int gain; OV7660ReadSensorReg(OV7660_GAIN, &gain_reg); gain = (gain_reg & 0x0f) + 16; if (gain_reg & 0x10) gain = gain << 1; if (gain_reg & 0x20) gain = gain << 1; if (gain_reg & 0x40) gain = gain << 1; if (gain_reg & 0x80) gain = gain << 1; return gain; } static UINT32 get_exposure() { UCHAR aechh, aech, com1; OV7660ReadSensorReg(OV7660_AECHH, &aechh); OV7660ReadSensorReg(OV7660_AECH, &aech); OV7660ReadSensorReg(OV7660_COM1, &com1); return ((aechh & 0x3f) << 10) + (aech << 2) + (com1 & 0x03); } static void set_exposure_gain(UINT32 preview_exposure, UINT32 preview_gain) { // the following data are hardcode for zylonite UINT32 capture_maxline = 498; UINT32 preview_maxline = 326; UINT32 capture_f_rate = 10; UINT32 preview_f_rate = 16; BOOL is_50Hz = TRUE; // if your power frequency is 60Hz, set to FALSE UINT32 lines_10ms = 0x4c; UINT32 exposure; UINT32 gain; UINT32 exposure_gain; //Capture_Exposure = Preview_Exposure * Capture_Framerate * Capture_MaxLine / (Preview_Framerate * Preview_MaxLine); exposure = preview_exposure * capture_f_rate * capture_maxline / (preview_f_rate * preview_maxline); exposure_gain = exposure * preview_gain; if (is_50Hz) lines_10ms = capture_f_rate * capture_maxline / 100; else lines_10ms = capture_f_rate * capture_maxline / 120; if (exposure_gain < capture_maxline * 16) { exposure = exposure_gain / 16; if (exposure > lines_10ms) { exposure /= lines_10ms; exposure *= lines_10ms; //Capture_Exposure = n*Lines_10ms, Banding removed } } else { exposure = capture_maxline * lines_10ms / lines_10ms; } gain = (exposure_gain * 100 / exposure + 50) / 100; set_exposure(exposure); set_gain(gain); } static void set_exposure(UINT32 exposure) { UCHAR com1; UCHAR reg; OV7660ReadSensorReg(OV7660_COM1, &com1); com1 = (com1 & 0xfc) | (exposure & 0x03); OV7660WriteSensorReg(OV7660_COM1, &com1); reg = (UCHAR)((exposure >> 2) & 0xff); OV7660WriteSensorReg(OV7660_AECH, ®); reg = (UCHAR)((exposure >> 10) & 0xff); OV7660WriteSensorReg(OV7660_AECHH, ®); } static void set_gain(UINT32 gain) { UCHAR reg = 0; if (gain > 31) { reg |= 0x10; gain = gain >> 1; } if (gain > 31) { reg |= 0x20; gain = gain >> 1; } if (gain > 31) { reg |= 0x40; gain = gain >> 1; } if (gain > 31) { reg |= 0x80; gain = gain >> 1; } if (gain > 16) reg |= (gain -16) & 0x0f; OV7660WriteSensorReg(OV7660_AECHH, ®); } static void get_ae(UCHAR* pre_gain, UCHAR* r_gain, UCHAR* b_gain) { OV7660ReadSensorReg(OV7660_HV, pre_gain); *pre_gain &= 0xf0; OV7660ReadSensorReg(OV7660_RED, r_gain); OV7660ReadSensorReg(OV7660_BLUE, b_gain); } static void set_ae(UCHAR pre_gain, UCHAR r_gain, UCHAR b_gain) { UCHAR reg; OV7660ReadSensorReg(OV7660_HV, ®); pre_gain |= (reg & 0x0f); OV7660WriteSensorReg(OV7660_HV, &pre_gain); OV7660WriteSensorReg(OV7660_RED, &r_gain); OV7660WriteSensorReg(OV7660_BLUE, &b_gain); }