Camera硬件及基于V4L2驱动源码分析

时间:2024-02-24 15:38:24

Camera硬件及基于V4L2驱动源码分析

Jorgen Quan

2012-12-18

 

 

摘要:本文主要描述camera的硬件工作原理以及基于V4l2驱动框架的SC8810平台camera源码进行分析,从而弄懂camera整个底层部分的工作原理。为今后工作准备好扎实的理论基础。

 

疑问:

1. v4l2_device_register和video_register_device的区别,为什么这两个都要注册起来??

 

2. 视频缓存队列是如何管理的?驱动中在哪里申请分配内存?怎么入列出列?

 

3. 展讯平台中如何与硬件操作关联起来?

 

 

一、Camera硬件工作原理

 

1.  摄像头模组介绍

摄像头模组,全称CameraCompact Module,以下简写为CCM,是影像捕捉至关重要

的电子器件。主要组成部分:lens和Sensor IC,其中有些Sensor IC是集成了DSP,有些是没有集成DSP,没有集成DSP的module需要外部外挂DSP。

 

2.  摄像头工作原理、camera的组成和各组件的作用

 

 

                             图1-1.摄像头模组结构示意图

 

2.1、工作原理:

物体通过镜头(lens)聚集的光,通过CMOS或CCD集成电路,把光信号转换成电信号,再经过内部图像处理器(ISP)转换成数字图像信号输出到数字信号处理器(DSP)加工处理,转换成标准的GRB、YUV等格式图像数据。

2.2、CCM包含四大组件:

镜头(lens)、传感器(sensor)、软板(FPC)、图像处理芯片(DSP)。决定一个摄像头好坏的重要部件是:镜头(lens)、图像处理芯片(DSP)、传感器(sensor)。CCM的关键技术为:光学设计技术、非球面镜制作技术、光学镀膜技术。

镜头(lens)是相机的灵魂,仅次于CMOS芯片影响画质的第二要素,镜头(lens)是利用透镜的折射原理,景物光线通过镜头,在聚焦平面上形成清晰的影像,通过感光材料CMOS或CCD感光器记录景物的影像。其组成是透镜结构,由几片透镜组成,一般可分为塑胶透镜(plastic)或玻璃透镜(glass)。当然,所谓塑胶透镜也非纯粹塑料,而是树脂镜片,当然其透光率感光性之类的光学指标是比不上镀膜镜片的。通常摄像头用的镜头构造有:1P、2P、1G1P、1G2P、2G2P、2G3P、4G、5G等。透镜越多,成本越高,相对成像效果会更出色,镜头厂家主要集中在*、日本和韩国,镜头这种光学技术含量高的产业有比较高的门槛,业内比较知名的企业如富士精机、柯尼卡美能达、大立光、Enplas等。

 

传感器(sensor)是CCM的核心模块.摄像头的主要组件中,最重要的就是图像传感器了,因为感光器件对成像质量的重要性不言而喻。Sensor将从lens上传导过来的光线转换为电信号,再通过内部的DA转换为数字信号。由于Sensor的每个pixel只能感光R光或者B光或者G光,因此每个像素此时存贮的是单色的,我们称之为RAW DATA数据。要想将每个像素的RAW DATA数据还原成三基色,就需要ISP来处理。目前广泛使用的有两种:一种是广泛使用的CCD(电荷藕合)元件;另一种是CMOS(互补金属氧化物导体)器件。

 

图像处理芯片(DSP)是CCM的重要组成部分,由ISP和JPEGdecoder组成。它的作用是将感光芯片获得的数据及时快速地传递*处理器并刷新感光芯片,因此DSP芯片的好坏,直接影响画面品质(比如色彩饱和度,清晰度等)。

FPC绕性电路板

 

2.3.摄像头的常用技术指标

 

    A. 图像解析度/分辨率(resolution):常见摄像头为130W(1280x1024)、500W(2592x1944)、800W(3264x2448)

    B.图像格式(ImageFormat/colorspace):RGB24和YUV420是常用的两种图像格式。RGB24表示RGB三种颜色各8位,最多可表现256级浓度,从而可以再现256*256*256种颜色;420是YUV格式之一,这种格式可以避免相互干扰,还可以降低色度的采样率而不会对图像质量影响太大。此外还有类似,RGB565,YUV422等格式。

    YUV知识链接:http://blog.csdn.net/searchsun/article/details/2443867

              http://baike.baidu.com/view/189685.htm

 

    C.自动白平衡调整(Auto White Balance):

    定义:要求在不同色温环境下,照白色的物体,屏幕中的图像应也是白色的。色温表示光谱成份,光的颜色。色温低表示长波光成分多。当色温改变时,光源中三基色(红、绿、蓝)的比例会发生变化,需要调节三基色的比例来达到彩色的平衡,这就是白平衡调节的实际。

    D.图像压缩方式:JPEG:(joint photo graphicexpert group)静态图像压缩方式。一种有损图像的压缩方式。压缩比越大,图像质量也就越差。当图像精度要求不高存储空间有限时,可以选择这种格式。目前大部分数码相机都使用JPEG格式。

       E.彩色深度(色彩位数):反映对色彩的识别能力和成像的色彩表现能力,实际就是A/D转换器的量化精度,是指将信号分成多少个等级。常用色彩位数(bit)表示。彩色深度越高,获得的影像色彩就越艳丽动人。现在市场上的摄像头均已达到24位,有的甚至是32位.

       F.图像噪音:指的是图像中的杂点干挠。表现为图像中有固定的彩色杂点。

G.输出/输入接口
串行接口(RS232/422):传输速率慢,为115kbit/s
并行接口(PP):速率可以达到1Mbit/s
红外接口(IrDA):速率也是115kbit/s,一般笔记本电脑有此接口
通用串行总线USB:即插即用的接口标准,支持热插拔。USB1.1速率可达12Mbit/s,USB2.0可达480Mbit/s
IEEE1394(火线)接口(亦称ilink):其传输速率可达100M~400Mbit/s 

 

2.4、CCM内部工作原理:

    A.Sensor内部工作原理:外部光线穿过lens后,经过colorfilter滤波后照射到Sensor面上, Sensor将从lens上传导过来的光线转换为电信号,再通过内部的DA转换为数字信号。如果Sensor没有集成DSP,则通过DVP的方式传输到baseband,此时的数据格式是RAW RGB。

 

    如果集成了DSP,则RAW DATA 数据经过AWB、color matrix、lensshading、gamma、sharpness、AE和de-noise处理,后输出YUV或者RGB格式的数据.下图是ov5640的硬件框图:

   

 

    B.DVP传输方式简介:

    DVP分为三个部分:1)输出总线;2)输入总线;3)电源总线。如下图:

           

    1)输入总线介绍

    a、PWD为camera的使能管脚。当camera处于PWD模式时,一切对camera的操作都是无效的。因此,在RESET之前,一定要将PWD管脚置为normal模式。

    b、RESET为camera的复位管脚。此方式为硬复位模式,一般管脚置为低,camera处于硬复位状态,camera的各个IO口恢复到出厂默认状态。只有在MCLK开启后,将RESET置为低,硬复位才有效,否则复位无效。

    c、MCLK为camera工作时钟管脚。此管脚为BB提供camera的工作时钟。

    d、I2C为camera与BB通信管脚。BB与camera的通信总线。

    2)输出总线介绍

    a、data为camera的数据管脚。此数据脚可以输出的格式有YUV、RGB、JPEG。

    b、VSYNC为camera的帧同步信号管脚。一个VYSNC信号结束表示一帧(即一个画面)的数据已经输出完毕。

    c、HSYNC为camera行同步信号管脚。一个HSYNC信号结束表示一行的数据已经输出完毕。

d、PCLK为像素同步信号管脚。一个PCLK信号结束表示一个数据已经输出完毕。

Data,VSYNC,HSYNC,PCLK时序图如下:

           

    3)Power线介绍

    a、AVDD为camera的模拟电压。

    b、DOVDD为camera的GPIO口数字电压。

    c、DVDD为camera的核工作电压。

   

    一般来说,要求先提供sensor的GPIO口电压,接着提供模拟电压,最后提供工作电压。时序如下图:

           

 

2.5、摄像头外部工作原理:

    采用DVP方式传输数据的camera(OV系列摄像头),主要硬件接口可以进行如下划分:

l  控制接口:PWD、MCLK、RESET、SDA/SCL;

l  供电引脚:AVDD、DVDD、DOVDD;

l  数据输出接口:DATA(8bit或者10bit)、PCLK、VSYNC、HSYNC;

使camera进入工作状态的步骤:

1. 按照手册上面的供电时序给camera的各路供电引脚上电;

2. 打开MCLK时钟;

3. 拉低PWD信号线(PWD引脚在camera工作时始终保持低电平);

4. 复位camera,使能RESET引脚,或者通过I2C总线发送RESETB给sensorIC;

 

PCLK是像素时钟,HREF是行参考信号,VSYNC是场同步信号。一旦给摄像头提供了时钟,并且复位摄像头,

摄像头就开始工作了,通过HREF,VSYNC和PCLK同步传输数字图像信号。 数据是通过D0~D7这八根数据线并行送出的

       Camera调试主要要点:

l  I2C:camera相关寄存器的数据都是通过I2C总线传输的。如果I2C不能正常工作,就初始化camera相关寄存器;

l  MCLK:Camera要正常工作,必须由主控芯片(SOC芯片)给它提供时钟信号,没有时钟信号,Camera是一定不会干活的;

l  上下电时序:camera需要按照datasheet提供的上下点时序,为Camera进行上电操作;

l  PCLK/DATA1-7:数据传输信号和时钟同步信号;

l  主要寄存器设置:分辨率、YUV顺序、X轴、Y轴、镜像、翻转;

 

3.展讯SC8810平台DCAM模块工作原理:

3.1Multi_SubSystemàDcam

   

4.OV5640 Camera简要描述:

    4.1.

 

二、Dcam_v4l2.c源码分析

 

1.展讯video_device的定义和注册:

static struct video_devicedcam_template = {

.name = "dcam",

.fops = &dcam_fops,

.ioctl_ops = &dcam_ioctl_ops,

.minor = -1,

.release = video_device_release,

.tvnorms = V4L2_STD_525_60,

.current_norm = V4L2_STD_NTSC_M,

};

Dcam_template是展讯camera的video_device设备,在dcam_probe函数中被video_register_device()所调用,用来注册一个video设备。Dcam_fops和dcam_ioctl_ops分别是对应的v4l2文件操作方法和IOCTL操作方法;

 

2.文件操作指针:

2.1、V4l2文件操作的定义:

static const structv4l2_file_operations dcam_fops = {

.owner = THIS_MODULE,

.open = open,

.write = video_write,

.release = close,

.ioctl = video_ioctl2,  /* V4L2ioctl handler */

};

V4l2文件操作指针,这里只定义了open,video_write,close,video_ioctl2函数,其中,video_ioctl2是videodev.c中是实现的。video_ioctl2中会根据ioctl不同的cmd来调用video_device中ioctl_ops的操作方法.

 

 

2.1、open函数

static int open(struct file *file)

{

    struct dcam_dev *dev =video_drvdata(file);

    struct dcam_fh *fh =NULL;

    int retval = 0;

 

  if (atomic_inc_return(&dev->users) > 1) {//增加引用计数,当前只能有一个用

atomic_dec_return(&dev->users);     户进程打开video_device设备。

        return -EBUSY;

    }

    dprintk(dev, 1,"open /dev/video%d type=%s users=%d\n", dev->vfd->num,

        v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE],dev->users.counter);

 

    /* allocate +initialize per filehandle data */

    fh =kzalloc(sizeof(*fh), GFP_KERNEL); //为dcam_fh对象fh分配内存空间

    if (NULL == fh) {

        atomic_dec_return(&dev->users);

        retval = -ENOMEM;

    }

    if (retval)

        return retval;

 

    file->private_data =fh; //将dcam_fh对象赋值给file文件结构的

                            private_data,以便在后续的ioctl等操作中调用fh

    //初始化fh结构体:{

    fh->dev = dev;

    fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    fh->fmt =&formats[0];

    fh->width = 640;

    fh->height = 480;

    /* Resets framecounters */

    dev->h = 0;

    dev->m = 0;

    dev->s = 0;

    dev->ms = 0;

    dev->mv_count = 0;

    dev->jiffies =jiffies;

    sprintf(dev->timestr,"%02d:%02d:%02d:%03d",

        dev->h,dev->m, dev->s, dev->ms);

    videobuf_queue_vmalloc_init(&fh->vb_vidq,&dcam_video_qops, //初始化

                    NULL, &dev->slock, fh->type,                //视频缓存

                    V4L2_FIELD_INTERLACED,                      //队列

                    sizeof(struct dcam_buffer), fh,&dev->lock);

    }

    g_fh = fh;

    //初始化DCAM_INFO_T结构体,该结构体保存dcam和sensor的配置信息,如预览模式,图片效果,闪光灯状态,对焦,对比度,亮度等参数。

    g_dcam_info.wb_param =INVALID_VALUE;

    g_dcam_info.brightness_param= INVALID_VALUE;

    g_dcam_info.contrast_param= INVALID_VALUE;

    g_dcam_info.saturation_param= INVALID_VALUE;

    g_dcam_info.imageeffect_param= INVALID_VALUE;

    g_dcam_info.hflip_param= INVALID_VALUE;

    g_dcam_info.vflip_param= INVALID_VALUE;

    g_dcam_info.previewmode_param= INVALID_VALUE;

    g_dcam_info.ev_param =INVALID_VALUE;

    g_dcam_info.focus_param= 0;

    g_dcam_info.power_freq= INVALID_VALUE;

    g_dcam_info.flash_mode= FLASH_CLOSE;

    g_dcam_info.recording_start= 0;

    g_dcam_info.sensor_work_mode= DCAM_PREVIEW_MODE;

    s_auto_focus =DCAM_AF_IDLE;

    //打开摄像头相关服务

    if (0 != dcam_open()) {

        return 1;

    }

    s_dcam_err_info.is_stop= DCAM_THREAD_END_FLAG;

    dcam_create_thread();

    dcam_init_timer(&s_dcam_err_info.dcam_timer);

    DCAM_V4L2_PRINT("###DCAM:OK to open dcam.\n");

    init_MUTEX(&s_dcam_err_info.dcam_start_sem);

    down(&s_dcam_err_info.dcam_start_sem);

    /*dcam_callback_fun_register(DCAM_CB_SENSOR_SOF,dcam_cb_ISRSensorSOF); */

    dcam_callback_fun_register(DCAM_CB_CAP_SOF,dcam_cb_ISRCapSOF);

    /*dcam_callback_fun_register(DCAM_CB_CAP_EOF,dcam_cb_ISRCapEOF); */

    dcam_callback_fun_register(DCAM_CB_PATH1_DONE,dcam_cb_ISRPath1Done);

    /*dcam_callback_fun_register(DCAM_CB_PATH2_DONE,dcam_cb_ISRPath2Done);*/

    dcam_callback_fun_register(DCAM_CB_CAP_FIFO_OF,dcam_cb_ISRCapFifoOF);

    dcam_callback_fun_register(DCAM_CB_SENSOR_LINE_ERR,

                   dcam_cb_ISRSensorLineErr);

    dcam_callback_fun_register(DCAM_CB_SENSOR_FRAME_ERR,

                   dcam_cb_ISRSensorFrameErr);

    dcam_callback_fun_register(DCAM_CB_JPEG_BUF_OF,dcam_cb_ISRJpegBufOF);

    return 0;

}