⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ov7660.cpp

📁 windows ce 6.0 camera driver
💻 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, &reg);

    if ((reg & 0xf) != camera_ana)
        pic_write_reg(AVDD, (reg & 0xf0) | camera_ana);

#ifdef SETUP_IO_CORE_VOLTAGE  

    pic_read_reg(DOVDD, &reg);
    pic_write_reg(DOVDD, (reg & 0xf0) | camera_io);

    pic_read_reg(DVDD, &reg);
    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, &reg);

    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);

    reg = (UCHAR)((exposure >> 10) & 0xff);
    OV7660WriteSensorReg(OV7660_AECHH, &reg);
}

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, &reg);
}    

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, &reg);
    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 + -