DSP

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

2019-07-13 19:49发布

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等。透镜越多,成本越高,相对成像效果会更出 {MOD},镜头厂家主要集中在台湾、日本和韩国,镜头这种光学技术含量高的产业有比较高的门槛,业内比较知名的企业如富士精机、柯尼卡美能达、大立光、Enplas等。 传感器(sensor)是CCM的核心模块.摄像头的主要组件中,最重要的就是图像传感器了,因为感光器件对成像质量的重要性不言而喻。Sensor将从lens上传导过来的光线转换为电信号,再通过内部的DA转换为数字信号。由于Sensor的每个pixel只能感光R光或者B光或者G光,因此每个像素此时存贮的是单 {MOD}的,我们称之为RAW DATA数据。要想将每个像素的RAW DATA数据还原成三基 {MOD},就需要ISP来处理。目前广泛使用的有两种:一种是广泛使用的CCD(电荷藕合)元件;另一种是CMOS(互补金属氧化物导体)器件。 图像处理芯片(DSP)是CCM的重要组成部分,由ISP和JPEGdecoder组成。它的作用是将感光芯片获得的数据及时快速地传递中央处理器并刷新感光芯片,因此DSP芯片的好坏,直接影响画面品质(比如 {MOD}彩饱和度,清晰度等)。 FPC绕性电路板   2.3.摄像头的常用技术指标       A. 图像解析度/分辨率(resolution):常见摄像头为130W(1280x1024)、500W(2592x1944)、800W(3264x2448)     B.图像格式(ImageFormat/colorspace):RGB24和YUV420是常用的两种图像格式。RGB24表示RGB三种颜 {MOD}各8位,最多可表现256级浓度,从而可以再现256*256*256种颜 {MOD};420是YUV格式之一,这种格式可以避免相互干扰,还可以降低 {MOD}度的采样率而不会对图像质量影响太大。此外还有类似,RGB565,YUV422等格式。     YUV知识链接:http://blog.csdn.net/searchsun/article/details/2443867               http://baike.baidu.com/view/189685.htm       C.自动白平衡调整(Auto White Balance):     定义:要求在不同 {MOD}温环境下,照白 {MOD}的物体,屏幕中的图像应也是白 {MOD}的。 {MOD}温表示光谱成份,光的颜 {MOD}。 {MOD}温低表示长波光成分多。当 {MOD}温改变时,光源中三基 {MOD}(红、绿、蓝)的比例会发生变化,需要调节三基 {MOD}的比例来达到彩 {MOD}的平衡,这就是白平衡调节的实际。     D.图像压缩方式:JPEG:(joint photo graphicexpert group)静态图像压缩方式。一种有损图像的压缩方式。压缩比越大,图像质量也就越差。当图像精度要求不高存储空间有限时,可以选择这种格式。目前大部分数码相机都使用JPEG格式。        E.彩 {MOD}深度( {MOD}彩位数):反映对 {MOD}彩的识别能力和成像的 {MOD}彩表现能力,实际就是A/D转换器的量化精度,是指将信号分成多少个等级。常用 {MOD}彩位数(bit)表示。彩 {MOD}深度越高,获得的影像 {MOD}彩就越艳丽动人。现在市场上的摄像头均已达到24位,有的甚至是32位.        F.图像噪音:指的是图像中的杂点干挠。表现为图像中有固定的彩 {MOD}杂点。 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 ", 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. ");     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; }       3.