📄 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 <windows.h>
#include <ceddk.h>
#include "Cs.h"
#include "Csmedia.h"
#include "CameraPDDProps.h"
#include "dstruct.h"
#include "dbgsettings.h"
#include <Camera.h>
#include "CameraDriver.h"
#include "PinDriver.h"
#include "SensorFormats.h"
#include "monahans.h"
#include "ov7660.h"
#include "ov7660_hw.h"
#include "Camera_SOC.h"
#include "GPIO_SOC.h"
#include "I2C_SOC.h"
#include "GPX_API.h"
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_11, 400, -294, 12, 30);
MAKE_STREAM_MODE_YV12(DCAM_StreamMode_12, 800, -600, 12, 30);
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);
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);
static qci_interface_t ov7660_interface =
{
PXA_CI_MODE_MP,
PXA_CI_DATA_WIDTH8,
2600,
FALSE,
FALSE,
FALSE
};
static camera_cfg_t strQCIFYV12 =
{
&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 strVGAYV12 =
{
&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,
};
#define SENSOR_INIT_WAIT 150
#ifdef DEBUG
static void dump_ov7660();
#endif
void Ov7660::DeInitialize()
{
return;
}
bool Ov7660::Initialize()
{
qci_interface = &ov7660_interface;
timing.BFW = 0x01;
timing.BLW = 0x00;
m_SkipFrames = 2;
return TRUE;
}
enum SensorPowerPins
{
DOVDD = 0x13,// ov7660 sensor power pin name, PMIC LDO Regs
AVDD = 0x14,
DVDD = 0x92
};
#define PMIC_REG_CTRL 0x17
void Ov7660::set_voltage(UCHAR camera_ana, UCHAR camera_io, UCHAR camera_core, BOOL is_on)
{
UCHAR reg;
pic_read_reg(AVDD, ®);
if ((reg & 0xf) != camera_ana)
pic_write_reg(AVDD, (reg & 0xf0) | camera_ana);
#ifdef SETUP_IO_CORE_VOLTAGE
pic_read_reg(DOVDD, ®);
pic_write_reg(DOVDD, (reg & 0xf0) | camera_io);
pic_read_reg(DVDD, ®);
if ((reg & 0xf) != camera_core)
pic_write_reg(DVDD, (reg & 0xf0) | camera_core);
#endif
const UCHAR ldo_en = 0x80;
UCHAR set_value = is_on? ldo_en : 0;
pic_read_reg(PMIC_REG_CTRL, ®);
if ((reg & ldo_en) != set_value)
{
reg &= ~ldo_en;
pic_write_reg(PMIC_REG_CTRL, reg | set_value);
}
}
bool Ov7660::detect()
{
UINT8 pid = 0, rev = 0;
OV7660VersionRevision(&pid, &rev);
RETAILMSG(1, (TEXT("CAM: Detect OV7660 sensor 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();
//For CETK "Video capture filter and camera driver component test" 1104 sub-case "PinFlowingTests".
//OV7660 sends out the first frame too slow, it takes about 70ms to send out after starting OV7660.
//So, a trick is to delay some time here, to shorten the interval between the next "RUN" command and receiving the first frame.
Sleep(40);
}
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 &strQCIFYV12;
else
return &strVGAYV12;
}
extern void fill_buffer_yv12(PUCHAR* dest_plane, frame_t* frame);
DWORD 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;
DWORD dwRetVal = 0;
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);
return dwRetVal;
}
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"CAM: OV7660 reg 0x%x = 0x%x", i, buf[i]));
}
#endif
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;
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);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -