Camera模块解析.docx

上传人:b****4 文档编号:3999096 上传时间:2022-11-27 格式:DOCX 页数:21 大小:24.77KB
下载 相关 举报
Camera模块解析.docx_第1页
第1页 / 共21页
Camera模块解析.docx_第2页
第2页 / 共21页
Camera模块解析.docx_第3页
第3页 / 共21页
Camera模块解析.docx_第4页
第4页 / 共21页
Camera模块解析.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

Camera模块解析.docx

《Camera模块解析.docx》由会员分享,可在线阅读,更多相关《Camera模块解析.docx(21页珍藏版)》请在冰豆网上搜索。

Camera模块解析.docx

Camera模块解析

手机摄像头功能由多个功能模块组成,主要三个部分,采集,加工,显示。

(1)采集部分由感光的sensor完成,通过CAMIF接口与手机芯片内的CAM连接。

(2)CAM对CAMIF数据进行加工,主要是格式转换,特殊效果等。

最终处理出来的一帧数据,存在内存中。

(3)手机的刷新线程,使用手机内部的DMA功能,或者OVERLAY技术,把处理好的camera图像,显示到LCD上。

刷新部分,不在camera框架范围内,后面只做简单讨论。

图1:

Camera典型硬件模块图

2 Sensor简介

Sensor是对图像的采集系统,通常采用的是ov系列的芯片。

如ov2655等。

通常包含两路接口:

(1)控制总线:

Sensor也是一个智能嵌入式系统,一般通过I2C总线与手机芯片通信。

手机可以通过I2C读写Sensor的寄存器,改变Sensor的参数,从而改变其工作方式。

(2)数据总线:

Sensor通过CAMIF接口与CAM联系。

 

图2:

sensor硬件连接图

 

由图可知,sensor工作的条件需要:

(1)电压供应,一般模拟电压,数字电压。

(2)工作时钟,通常为24MHZ的正弦波。

一般为手机芯片产生

(3)SDA,SCL,i2c总线连接,sensor通常为从设备。

(4)standby控制线,手机芯片通过这条GPIO控制线,控制sensor的工作是否开启。

(5)Sensor输出给手机芯片的接口,CAMIF接口:

(6)并行数据线,通常8位,10位。

分辨率高的sensor数据线需要更多。

(7)提供给手机芯片内集成的camera模块的PCLK,HCLK,VCLK.(像素同步信号,行同步信号,帧同步信号)。

Sensor通常产出稳定频率的数据图像流,手机芯片可以通过I2C总线接口,修改寄存器,改变帧频率。

也可以改变sensor的输出流的格式,通常采用yuv422格式。

3 CAM简介

CAM就是将Sensor采集过来的数据,转换相应格式,及其他加工,最后存放到内存中。

CAM核心就是个DSP。

这个阶段,dsp可以做很多图像处理的事情。

比如颜色纠正,自动对焦,scaler等。

不同平台会有不同。

由于Sensor的核心也是dsp,对于这些特效工作,一般Sensor中也会提供。

高通平台的Sensor的特效(反色)就可以在Sensor中设置。

由图可知

CAMconsistsofthefollowingelements:

•ImageSignalProcessing(ISP)1

•ColorProcessing

•Imageeffects

•Luminance/ChrominanceSplitter(Y/CSplit)

•Resize(Down/Up-Scalers)

•JPEGEncoder

•YCbCrtoRGBconversionforpreview

•MemoryInterface

•ControlUnit

具体详解,可见ste6715datesheet。

这些模块看似很复杂,对于我们开发者来说,也不复杂。

我们知道它们相应的流程,并且知道每个子模块提供了什么功能。

这些模块的功能可以通过相应模块的寄存器进行相应调整的]。

这同sensor的参数调整的思想是一样的。

硬件提供功能,通过寄存器进行参数调整。

 

Camera的native层软件接口,在Camera在native层中,提供了/dev/video*的设备节点。

Native层通过打开设备文件,关联上camera,申请一串帧缓冲区,建立循环队列,并把这些内存地址传给内核的camera模块,并等待内核camera的处理结束。

Camera模块一帧处理结束,native层就会返回。

4 LCD显示

LCD的显示,就是将lcd的framebuffer的数据映射到LCD屏上,而我们camera的数据要在屏幕上显示,就只需建立camera帧buffer到framebuffer的映射关系。

可以使用内核的DMA,也可以使用overlay。

通常的preview过程都是在native层以上开个线程,waitingkernel的处理完成,然后push到lcd屏上,如此循环。

(1)软件设计思想

5 V4l2驱动框架:

关联文件:

V4l2-dev.c(src\linux\kernel\linux\drivers\media\video)

Videodev2.h(src\linux\kernel\linux\include\linux)Cam-core分析

V4l2.c(src/linux/modules/v4l2cam)

V4L2是linux的标准接口,提供了众多的标准IOCTL接口,这样不管内核驱动如何改变,风格各异,都可以让应用程序native程序稳定工作。

IOCTL接口标准定义于Videodev2.h,这个文件也会被android系统所引用。

V4L2层的意义在于:

让平台的驱动,通过char字符设备层能够与应用关联起来。

首先对v4l2.c和v4l2-dev.c两个文件的内容做个简单介绍:

(1)V4l2.c文件主要工作:

在模块加载的时候,调用v4l2_init()函数,该函数完成camera_sensor的获取和对video_device设备的创建,初始化和注册。

实际上完成一个video_device设备驱动,最重要的是v4l2_ioctrl()函数的实现,根据android的HAL层传下来的操作类型调用不同的控制函数,而这些控制函数通过调用cameraa_sensor和camIF接口来实现。

(2)V4l2-dev.c文件的主要工作:

完成一个字符设备驱动,并实现了video_device注册的工作。

字符设备驱动中的主要工作是通过调用video_device设备驱动来完成的。

这里请注意:

camera驱动分为三个部分,最后生成cam.ko,v4l2cam.ko和sensor.ko三个模块,v4l2cam.ko依赖于cam.ko和sensor.ko模块,因此,v4l2cam.ko后于cam.ko和sensor.ko模块加载。

下面来分析v4l2框架的工作流程。

(1)v4l2-dev.c

v4l2-dev.c文件中初始化函数申请了v4l2的字符设备号,但是并没有注册和关联具体驱动。

staticint__initvideodev_init(void)

{

 dev_tdev=MKDEV(VIDEO_MAJOR,0);

 intret;

……

 ret=register_chrdev_region(dev,VIDEO_NUM_DEVICES,VIDEO_NAME); //申请一组设备号

……

 ret=class_register(&video_class);             //注册一个类设备

}

 

提供了2个函数供其他具体驱动进行注册

video_register_device_index();

video_register_device();

intvideo_register_device_index(structvideo_device*vdev,inttype,intnr,

                             intindex)

{

……

 vdev->cdev=cdev_alloc();

 if(vdev->cdev==NULL){

        ret=-ENOMEM;

        gotocleanup;

 }

 if(vdev->fops->unlocked_ioctl)

        vdev->cdev->ops=&v4l2_unlocked_fops;

 else

        vdev->cdev->ops=&v4l2_fops;

 vdev->cdev->owner=vdev->fops->owner;

 ret=cdev_add(vdev->cdev,MKDEV(VIDEO_MAJOR,vdev->minor),1); //注册一个字符设备

……

memset(&vdev->dev,0,sizeof(vdev->dev));

 /*Thememsetaboveclearedthedevice'sdrvdata,so

   putbackthecopywemadeearlier.*/

 video_set_drvdata(vdev,priv);

 vdev->dev.class=&video_class;

 vdev->dev.devt=MKDEV(VIDEO_MAJOR,vdev->minor);

 if(vdev->parent)

        vdev->dev.parent=vdev->parent;

 dev_set_name(&vdev->dev,"%s%d",name_base,vdev->num);

 ret=device_register(&vdev->dev); //注册video_deice设备,将其添加到sysfs文件系统

……

mutex_lock(&videodev_lock);

 video_device[vdev->minor]=vdev;  //本地管理的一个video_device数组

 mutex_unlock(&videodev_lock);

……

}

该文件中核心对象为:

staticstructvideo_device*video_device[VIDEO_NUM_DEVICES];设备文件就是根据index与相应的video_device[index]指针关联。

      在videodev_init()初始化函数中,申请了一组设备号,并注册了一个类video_class,在注册视频设备时,首先注册了一个字符设备,然后用相同的设备号注册了一个设备节点。

这里的字符设备是让平台的驱动通过char字符设备层能够与应用关联起来,V4l2框架核心文件为v4l2-dev.c。

 

v4l2-dev.c文件的核心对象为:

staticstructvideo_device*video_device[VIDEO_NUM_DEVICES],它维护每个注册了的video_device设备,设备文件就是根据index与相应的video_device[index]指针关联。

所以,这个文件的主要工作就是:

字符设备的驱动内容。

字符设备驱动最后还是调用video_device的fops来实现的,这个fops就是v4l2.c中的cam_fops结构体,不过它只实现了打开,关闭,映射和io控制四个函数。

这里要注意的是:

在注册video_device前是通过config_a_device()来初始化video_device的fops的成员的。

 

(2)V4l2.c:

文件中重要的数据对象:

structacq_device_t{

      structvideo_device*vfd;          //视频设备对象指针

#defineNAME_LENGTH16

   charname[NAME_LENGTH];

      ……

       */

      structacq_session_cxt_t*streaming;             //打开camera的一个上下文

      video_frame_t*stream_vdf[V4L2_MAX_VDF];

 

      /*Hardwaredependantparts*/

      /*TheCameraobjectpluggedtoourCAMIF*/

      structcamera_sensor*camera;       //sensor对象指针

      /*specifictosensor*/

      void*camera_priv_data;

      ……

};

 

structacq_session_cxt_t{  //代表一个打开的camera设备

      structacq_device_t*dev;

      /*handletocontrolsessionofCAMhardwarebloc*/

      void*camhdl;

      /*datapoolhandle(framemem)*/

      void*pool_hdl;

      /*jpegbuffers*/

#ifdefCONFIG_V4L2CAM_PMEM

      memblock_tblocks[V4L2_MAX_BUF];

#else

      structv4l2_bufferbufs[V4L2_MAX_BUF];

#endif

      /*CameraPixfmtdefinesthesizeandpixelformatofthesensor.*/

      structv4l2_pix_formatCameraPixfmt;

      /*CamPixfmtdefinesthesizeandpixelformatattheoutputofCAMbloc*/

      structv4l2_pix_formatCamPixfmt;

      /*CamPixfmtdefinesthesizeandpixelformatofthumbnailattheoutputofCAMbloc*/

      structv4l2_pix_formatCamThumbfmt;

      /*videoframeusetopreviewsession*/

      video_frame_t*cur_vdf;

      video_frame_t*next_vdf;

      intcount;

};

 

V4l2cam驱动模块的初始化函数流程如下:

intv4l2_init(void)

{

……

 while

(1){

        dev=kzalloc(sizeof(structacq_device_t),GFP_KERNEL);

        dev->camera=v4l2_detect(dev);            //检测并获得camera_sensor设备

        /*openthecamblocinterface*/

        cam_open(&hdl);

        /*wegotacameraplugged!

*/

        /*initialiseprivatefieldsofthesensor,forcmoscoprocessorwetrytofindthecamerapluggedtoit*/

        dev->camera_priv_data=dev->camera->init();

 

        /*closethecamblocinterface*/

        cam_close(hdl);

        dev->vfd=video_device_alloc();             //为video_device分配内存

        if(config_a_device(dev)){               //初始化video_device设备结构,包括fops成员

               unconfig_a_device(dev);

               ret=-ENODEV;

               gotobail;

        }

 

        if(video_register_device(dev->vfd,VFL_TYPE_GRABBER,dev->vfd->minor)!

=0){                               //注册video_device设备

               CRITICAL("Couldn'tregistervideodriver.");

               unconfig_a_device(dev);

               ret=-ENODEV;

               gotobail;

        }

        dev->is_registered=1;

        dev->preview_running=FALSE;

        dev->snapshot_running=FALSE;

        dev->snapshot_done=FALSE;

 

        /*initcompletion*/

        init_completion(&dev->complete);

 

        video_set_drvdata(dev->vfd,dev);

}

}

该函数中出现一个config_a_device(dev)函数,这个函数是video_device设备的初始化配置函数,包括对文件操作指针的赋值,这里是一个初始化封装。

先来看看v4l2_detect()函数:

structcamera_sensor*v4l2_detect(structacq_device_t*dev)

{

      structcamera_sensor**Cams=NULL;

      structcamera_sensor*cam=NULL;

      void*hdl=0;

      inti=0;

      PROLOG("");

 

      dev->camera=NULL;

      cam_open(&hdl);

 

      Cams=sensor_get_cameras();        //获取camera_sensor数组

      if(Cams){

             while(Cams[i]!

=NULL){

                    cam=Cams[i];

                    if(!

cam->isProbed){

                           cam->isProbed=1;

                           if(cam->detect()==0){           //创建和初始化camera_sensor就在这里,这是sensor驱动部分的内容,后面会有详细的介绍

                                  gotodetect_exit;

                           }

                    }

                    i++;

             }

      }

      dev->camera=NULL;

      cam=NULL;

 

     detect_exit:

      cam_close(hdl);

      EPILOG("");

      returncam;

}

该函数中调用了cam->detect()函数,这个函数在camera的sensor部分被实现,后面会有详细说明,下面看看如何注册video_device设备的,video_register_device()函数,该函数代码在前面已经列出,这里简单描述:

intvideo_register_device(structvideo_device*vdev,inttype,intnr)

{

      return__video_register_device(vdev,type,nr,1);

}

 

staticint__video_register_device(structvideo_device*vdev,inttype,intnr,

             intwarn_if_nr_in_use)

{

      ……

      ret=cdev_add(vdev->cdev,MKDEV(VIDEO_MAJOR,vdev->minor),1);

      ……

      ret=device_register(&vdev->dev);

      ……

      video_device[vdev->minor]=vdev;

      ……

}

该文件中核心对象为:

staticstructvideo_device*video_device[VIDEO_NUM_DEVICES];设备文件就是根据index与相应的video_device[index]指针关联。

由驱动框架我们了解到,平台驱动就是初始化video_device结构,然后注册到V4L2框架中。

在V4l2框架中有几个重要内容有必要提出来:

(1)capture_callback()

voidcapture_callback(void*userdata)

{

structacq_session_cxt_t*acq_cxt=(structacq_session_cxt_t*)userdata;

structacq_device_t*dev;

BUG_ON(!

acq_cxt);

dev=acq_cxt->dev;

BUG_ON(!

dev);

dev->it_frame_nb++;

 

if(dev->wait_end_of_frame){

 

       dev->wait_end_of_frame=0;

       complete(&dev->complete);

}else{

       if(dev->wait_first_frame){

              dev->wait_first_frame=0;

              complete(&dev->complete);

       }

}

}

这是一个回调函数,当一帧数据完成时候,中断函数会响应,从而callback函数也会被调用,唤醒comple等待的函数。

此callback函数通过cam_streaming_start函数,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 农林牧渔 > 林学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1