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