Camera driver&V4L2驅動架構介紹

基於Mavell Pxa920 linux

1.Camera相關介紹

1.1.  手機Camera介紹

手機的數碼相機功能指的是手機經過內置數碼相機進行拍攝靜態圖片或短片拍攝,做爲手機的一項新的附加功能,手機的數碼相機功能獲得了迅速的發展。 緩存

手機攝像頭分爲內置與外置,內置攝像頭是指攝像頭在手機內部,更方便。外置手機經過數據線或者手機下部接口與數碼相機相連,來完成數碼相機的一切拍攝功能。 架構

處於發展階段的手機的數碼相機的性能應該也處於初級階段,帶有光學變焦的手機目前國內銷售的尚未這個功能,不過相信隨着手機數碼相機功能的發展,帶有光學變焦的手機也會逐漸上市,但大部分都擁有數碼變焦功能。 ide

目前手機的數碼相機功能主要包括拍攝靜態圖像,連拍功能,短片拍攝,鏡頭可旋轉,自動白平衡,內置閃光燈等等。手機的拍攝功能是與其屏幕材質、屏幕的分辨率、攝像頭像素、攝像頭材質有直接關係。 函數

1.2.  Camera技術指標

1.2.1.    圖像壓縮方式JPEG

(joint photographic expert group)靜態圖像壓縮方式。一種有損圖像的壓縮方式。壓縮比越大,圖像質量也就越差。當圖像精度要求不高存儲空間有限時,能夠選擇這種格式。目前大部分數碼相機都使用JPEG格式。 性能

1.2.2.   圖像噪音

指的是圖像中的雜點干擾,表現爲圖像中有固定的彩色雜點。 ui

1.2.3.    視角

與人的眼睛成像是類似原理,簡單說就是成像範圍。 spa

1.2.4.   白平衡處理技術(AWB)

要求在不一樣色溫環境下,照白色的物體,屏幕中的圖像應也是白色的。色溫表示光譜成份,光的顏色。色溫低表示長波光成分多。當色溫改變時,光源中三基色(紅、綠、藍)的比例會發生變化,須要調節三基色的比例來達到彩色的平衡,這就是白平衡調節的實際。 code

圖象傳感器的圖象數據被讀取後,系統將對其進行鍼對鏡頭的邊緣畸變的運算修正,而後通過壞像處理後被系統送進去進行白平衡處理(在不一樣的環境光照 下,人類的眼睛能夠把一些「白」色的物體都當作白色,是由於人眼進行了修正。可是SENSOR沒有這種功能,所以須要對SENSOR輸出的信號進行必定的 修正,這就是白平衡處理技術)。 orm

1.2.5.   電源

好的攝像頭內部電源也是保證攝像頭穩定工做的一個因素。

1.2.6.   彩色深度(色彩位數)

反映對色彩的識別能力和成像的色彩表現能力,就是用多少位的二進制數字來記錄三種原色。實際就是A/D轉換器的量化精度,是指將信號分紅多少個等級,經常使用 色彩位數(bit)表示。彩色深度越高,得到的影像色彩就越豔麗動人。非專業的SENSOR通常是24位;專業型SENSOR至少是36位。24位的 SENSOR,感光單元能記錄的光亮度值最多有2^8=256級,每一種原色用一個8位的二進制數字來記錄,最多記錄的色彩是256×256×256約 16,77萬種。

36位的SENSOR,感光單元能記錄的光亮度值最多有2^12=4096級,每一種原色用一個12位的二進制數字來記錄,最多記錄的色彩是4096×4096×4096約68.7億種。

1.2.7.   輸出/輸入接口(IO)

串行接口(RS232/422):傳輸速率慢,爲115kbit/s。

並行接口(PP):速率能夠達到1Mbit/s。

紅外接口(IrDA):速率也是115kbit/s,通常筆記本電腦有此接口。

通用串行總線USB:即插即用的接口標準,支持熱插拔。USB1.1速率可12Mbit/s,USB2.0可達480bit/s。

IEEE1394(火線)接口(亦稱ilink):其傳輸速率可達100M~400Mbit/s。

 

1.2.8.   圖像格式(image Format/ Color space)

 RGB24,I420是目前最經常使用的兩種圖像格式。

RGB24:表示R、G、B三種顏色各8bit,最多可表現色。

 I420:YUV格式之一。

 其它格式有: RGB565,RGB444,YUV4:2:2等。

1.2.9.   分辨率(Resolution)

所謂分辨率就是指畫面的解析度,由多少象素構成的數值越大,圖像也就越清晰。分辨率不只與顯示尺寸有關,還會受到顯像管點距、視頻帶寬等因素的影 響。咱們一般所看到的分辨率都以乘法形式表現的,好比1024*768,其中的1024表示屏幕上水平方向顯示的點數,768表示垂直方向的點數。

QXGA (2048 X 1536)又稱300萬像素

UXGA (1600X 1200)又稱200萬像素

SXGA(1280 x1024)又稱130萬像素

XGA(1024 x768)又稱80萬像素

SVGA(800 x600)又稱50萬像素

VGA(640x480)又稱30萬像素(35萬是指648X488)

CIF(352x288) 又稱10萬像素

SIF/QVGA(320x240)

QCIF(176x144)

QSIF/QQVGA(160x120)

1.3.  備註

1.3.1.   Mipi接口介紹:

MIPI=Mobile Industry Processor Interface, 是相似SMIA的一個LVDS的一種接口,主要用在手機Camera Module上居多。

就CameraModule而言,如今Micorn和OV均推出支持MIPI接口的Sensor如Micorn的MT9D112,MT9T111和 OV的OV2650等,對於低像素的Sensor彷佛MIPI的優點不是很明顯哦,可是在3MP以上就可能有些優點了。

  • 優點-1,Camera的佈線大大減小。並口的數據接口,若是是YUV輸出至少爲8個數據Bit、2個Clock(MCLK和PCLK)、I2C兩個、同 步信號2個,再加地和電源等,若是換成MIPI的串口,能夠減小2個同步信號,8個數據Bit變爲DOUT_P、DOUT_N、CLK_P、 CLK_N,PCLK也能夠不要,卓實少了不少,佈線天然方便許多。
  • 優點-2,Noise的減小。走線越多被幹擾的可能就越多,走線少了因而干擾就少了,同時MIPI信號是DOUT_N和DOUT_P成對走線,須要考慮 impedance,兩根線從波形看是成反相,因此有外部干擾過來,就會被抵消很大部分,同時MIPI的信號屬於LVDS(Low Voltage Differential Signaling:低壓差分信號傳輸)底到MV的等級,因而他自己對於外部的干擾也是很小的。
  • 優點-3,傳輸速度極快,從並口到串口,固然要足夠大的速度,MIPI的理論上的速度能夠到80MB/s-1GB/s,實際也在600-800MB/s,而傳統的並口再高也不過600MB/s了吧。
  • 優點-4,功耗低。並口的Camera,只要上電,給Clock因而PCLK就有輸出,Data也會由輸出,抓不到同步就成不了像,可是數據仍是輸出,因而就要功耗。而MIPI理論上靜態是沒有功耗的。

2.Linux Camera Driver

2.1.代碼結構

其中以ov5640爲例,其餘carmera相關carmere driver 同理。

 

2.2.  重要接口實現說明

ov5640_mipi_probe()
{
    …
    ccic_set_clock_mipi();  //ccic mipi clock 設置
    pdata->power_on(1, 1);  //power on camera
    i2c_set_clientdata(client, info); //初始化I2c資源
    ov5640_mipi_detect(client);  //camera檢測
    ccic_sensor_attach(client);  //ccic host端與sensor driver綁定
    …
}




說明:camera 驅動啓動時調用的初始化操做函數,包括camera上電、ccic控制器mpi clock設置、i2c端口初始化、camera檢測與綁定等。

ov5640_mipi_comman()
{
    v4l2_chip_ident_i2c_client () 
    ov5640_mipi_reset()
    ov5640_mipi_enum_fmsize () 
    ov5640_mipi_querycap ()   
    ov5640_mipi_enum_fmt () 
    ov5640_mipi_try_fmt ()
    ov5640_mipi_s_fmt()
    ov5640_mipi_queryctrl()
    ov5640_mipi_s_ctrl()
    ov5640_mipi_g_ctrl()
    ov5640_mipi_s_input()
    ov5640_mipi_streamon()
    ov5640_mipi_streamoff()
    ov5640_mipi_g_register()
    ov5640_mipi_s_register()
}




說明:camera iocontorl函數

v4l2_chip_ident_i2c_client() //爲攝像頭分配一個獨立字段,因爲雙攝像頭區分之用

ov5640_mipi_reset   //camera重啓功能

ov5640_mipi_enum_fmsize  // 枚舉camera支持的priver and capture 的圖像大小

ov5640_mipi_querycap   //對應hal層識別的camera device的關鍵字符串賦值

ov5640_mipi_enum_fmt  //枚舉camera支持的圖像格式

ov5640_mipi_try_fmt ()   //根據傳入的圖像格式及大小,計算圖像的寬和高佔用的字節數

ov5640_mipi_s_fmt()  //根據傳入的圖像格式及大小,對camera寄存器進行相應的設置

ov5640_mipi_s_ctrl() //預留函數,對camera的一些特效設置,進行對應的寄存器設置,如今這部分功能已經在hal層實現。

ov5640_mipi_g_ctrl()//預留函數,獲取camera的一些特效設置對應的寄存器設置值,如今這部分功能已經在hal層實現。

ov5640_mipi_s_input() //camera寄存器初始化

ov5640_mipi_streamon()  //camera 數據流開

ov5640_mipi_streamoff()  //camera 數據關

ov5640_mipi_g_register()  //讀取camera某一寄存器的值

ov5640_mipi_s_register()  //設置 camera某一寄存器的值

3. Host控制器實現(基於V4L2)

3.1. V4L2知識

Video4linux2(簡稱V4L2),是linux中關於視頻設備的內核驅動。在Linux中,視頻設備是設備文件,能夠像訪問普通文件同樣對其進行讀寫,攝像頭在/dev/video0下

3.1.1.   通常操做流程(視頻設備):

1.打開設備文件。 int fd=open(」/dev/video0″,O_RDWR);

2.取得設備的capability,看看設備具備什麼功能,好比是否具備視頻輸入,或者音頻輸入輸出等。VIDIOC_QUERYCAP,struct v4l2_capability

3.設置視頻的制式和幀格式,制式包括PAL,NTSC,幀的格式個包括寬度和高度等。

VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format

4.向驅動申請幀緩衝,通常不超過5個。struct v4l2_requestbuffers

5.將申請到的幀緩衝映射到用戶空間,這樣就能夠直接操做採集到的幀了,而沒必要去複製。mmap

6.將申請到的幀緩衝所有入隊列,以便存放採集到的數據.VIDIOC_QBUF,struct v4l2_buffer

7.開始視頻的採集。VIDIOC_STREAMON

8.出隊列以取得已採集數據的幀緩衝,取得原始採集數據。VIDIOC_DQBUF

9.將緩衝從新入隊列尾,這樣能夠循環採集。VIDIOC_QBUF

10.中止視頻的採集。VIDIOC_STREAMOFF

11.關閉視頻設備。close(fd);

3.1.2.   在進行V4L2開發中,通常會用到如下的命令標誌符:

1 VIDIOC_REQBUFS:分配內存

2 VIDIOC_QUERYBUF:把VIDIOC_REQBUFS中分配的數據緩存轉換成物理地址

3 VIDIOC_QUERYCAP:查詢驅動功能

4 VIDIOC_ENUM_FMT:獲取當前驅動支持的視頻格式

5 VIDIOC_S_FMT:設置當前驅動的頻捕獲格式

6 VIDIOC_G_FMT:讀取當前驅動的頻捕獲格式

7 VIDIOC_TRY_FMT:驗證當前驅動的顯示格式

8 VIDIOC_CROPCAP:查詢驅動的修剪能力

9 VIDIOC_S_CROP:設置視頻信號的邊框

10 VIDIOC_G_CROP:讀取視頻信號的邊框

11 VIDIOC_QBUF:把數據從緩存中讀取出來

12 VIDIOC_DQBUF:把數據放回緩存隊列

13 VIDIOC_STREAMON:開始視頻顯示函數

14 VIDIOC_STREAMOFF:結束視頻顯示函數

15 VIDIOC_QUERYSTD:檢查當前視頻設備支持的標準,例如PAL或NTSC。

這些IO調用,有些是必須的,有些是可選擇的。

3.2.  Host控制器(video device)代碼結構

這裏主要介紹920 host端 camera video控制器實現,主要基於v4l2架構,code文件見pxa910_camera.c。

 

3.3.  部分重要接口實現說明

如3.2中結構圖所示,camera host端是被看成標準的v4l2架構來註冊的的,也就是說是按照 struct video_device 結構體(標準的視頻設置)來向系統註冊設備的。

pxa910_camera_probe()
{
    ……
    platform_set_drvdata(pdev, cam);
    init_waitqueue_head()
    request_irq()  // ccic irq 中斷註冊
    ccic_ctlr_init()    //ccic 控制器初始化
    video_register_device()
    ……
}



說明:camera video 設備啓動時調用的初始化操做函數

platform_set_drvdata(pdev, cam) //鏈接設備對象與設備驅動

init_waitqueue_head()  //申明等待事件,處理見ccic_v4l_poll函數

request_irq()ccic irq 中斷註冊,對應中斷處理函數見 ccic_irq()函數

ccic_ctlr_init() ccic 控制器初始化

video_register_device //v4l2 video 設備註冊

 

v4l2 video主要需實現ccic_v4l_fops : (struct v4l2_file_operations) ccic_ioctl_ops : (struct v4l2_ioctl_ops)

static const struct v4l2_file_operations ccic_v4l_fops = {
    .owner = THIS_MODULE,
    .open = ccic_v4l_open,  //open files
    .release = ccic_v4l_release, //release files resource
    .poll = ccic_v4l_poll,  //files poll 功能對於接口
    .mmap = ccic_v4l_mmap, //files 內存映射接口
    .ioctl = ccic_v4l_ioctl, //files 對應iocontorl操做接口
};




說明:v4l2 video做爲文件接口對應的相關操做

struct v4l2_ioctl_ops ccic_ioctl_ops = { .vidioc_querycap = ccic_vidioc_querycap, .vidioc_enum_fmt_vid_cap= ccic_vidioc_enum_fmt_cap, .vidioc_try_fmt_vid_cap = ccic_vidioc_try_fmt_cap, .vidioc_s_fmt_vid_cap = ccic_vidioc_s_fmt_cap, .vidioc_g_fmt_vid_cap = ccic_vidioc_g_fmt_cap, .vidioc_enum_input = ccic_vidioc_enum_input, .vidioc_g_input = ccic_vidioc_g_input, .vidioc_s_input = ccic_vidioc_s_input, .vidioc_s_std = ccic_vidioc_s_std, .vidioc_reqbufs = ccic_vidioc_reqbufs, .vidioc_querybuf = ccic_vidioc_querybuf, .vidioc_qbuf = ccic_vidioc_qbuf, .vidioc_dqbuf = ccic_vidioc_dqbuf, .vidioc_streamon = ccic_vidioc_streamon, .vidioc_streamoff = ccic_vidioc_streamoff, .vidioc_queryctrl = ccic_vidioc_queryctrl, .vidioc_g_ctrl = ccic_vidioc_g_ctrl, .vidioc_s_ctrl = ccic_vidioc_s_ctrl, .vidioc_g_parm = ccic_vidioc_g_parm, .vidioc_s_parm = ccic_vidioc_s_parm, .vidioc_cropcap = ccic_vidioc_cropcap, .vidioc_g_register = ccic_vidioc_g_register, .vidioc_s_register = ccic_vidioc_s_register, }



 

說明:v4l2 video設備io contorl對應的處理函數。

ccic_vidioc_querycap() //查詢驅動功能,獲取camera屬性

ccic_vidioc_enum_fmt_cap()  獲取當前驅動支持的視頻格式

ccic_vidioc_try_fmt_cap()  //對應調用ov5640_mipi_try_fmt ()的接口,功能見上一章

ccic_vidioc_s_fmt_cap()  //設置當前驅動的頻捕獲格式

ccic_vidioc_g_fmt_cap()  //讀取當前驅動的頻捕獲格式

ccic_vidioc_enum_input()   //支持的camera檢測,容錯處理

ccic_vidioc_g_input()  //獲取camera id(30萬sensor_selected 爲0 ,500萬sensor_selected爲1)

ccic_vidioc_s_input()  //設置要切換的camera id

ccic_vidioc_reqbufs()   //分配buf內存

ccic_vidioc_querybuf, //把ccic_vidioc_reqbufs中分配的數據緩存轉換成物理地址

ccic_vidioc_qbuf()  //把緩衝放回緩存隊列

ccic_vidioc_dqbuf()  //把數據從緩存中讀取出來

ccic_vidioc_streamon()  //開始視頻顯示函數

ccic_vidioc_streamoff() // 結束視頻顯示函數

ccic_vidioc_queryctrl()  //對應調用ov5640_mipi_queryctrl()的接口,功能見上一章

ccic_vidioc_g_ctrl()  //對應調用ov5640_mipi_ g_ctrl ()的接口,功能見上一章

ccic_vidioc_s_ctrl()  //對應調用ov5640_mipi_ s_ctrl ()的接口,功能見上一章

ccic_vidioc_cropcap()   //預留接口,查詢驅動的修剪能力

ccic_vidioc_g_register()  //對應調用ov5640_mipi_g_registe ()的接口,功能見上一章

ccic_vidioc_s_register()  //對應調用ov5640_mipi_ s_register()的接口,功能見上一章

3.4. 備註

Camera視頻數據流流動有如下主要相關函數:

ccic_vidioc_reqbufs()   //分配部份內存

ccic_vidioc_querybuf, //把ccic_vidioc_reqbufs中分配的數據緩存轉換成物理地址

ccic_vidioc_qbuf() //把緩衝放回緩存隊列

ccic_vidioc_dqbuf()  //把數據從緩存中讀取出來

ccic_irq() //ccic中斷處理函數

ccic_v4l_poll,  //files poll 功能對於接口

check_jpeg_header //檢測抓取數據是否爲jpeg文件

具體數據如何流動,見下圖:(來自marrvel提供的PXA920 CCIC sensor bring up guide.pdf)

說明:VIDIOC_QBUF對應函數ccic_vidioc_qbuf()

      VIDIOC_QBUF對應函數ccic_vidioc_dqbuf()

      Dma_map_page //將dma buffer 數據映射到kernel內存空間

相關文章
相關標籤/搜索