摘 要: 目前的嵌入式系統(tǒng)中,USB攝像頭使用比較普遍,但其應(yīng)用會受到傳輸速度的限制。本文采用一款高速CMOS攝像頭,其驅(qū)動利用S3C6410內(nèi)置的FIMC接口技術(shù),采用DMA和ping-pong緩沖池機(jī)制,結(jié)合內(nèi)存共享策略,有效提高了傳輸速率并充分利用了有限的內(nèi)存資源。深入分析了該驅(qū)動的原理和實(shí)現(xiàn)細(xì)節(jié),并提出了改進(jìn)設(shè)計(jì),最終應(yīng)用在嵌入式圖像采集系統(tǒng)中,能夠?yàn)閼?yīng)用程序提供高清、高速圖像。
關(guān)鍵詞: FIMC接口;OV9650;;內(nèi)存共享;DMA
0 引言
嵌入式系統(tǒng)具有體積小、功耗低和成本低等天然性的優(yōu)勢,因而得到廣泛應(yīng)用,甚至在許多場合得以取代傳統(tǒng)工控機(jī),比如視頻監(jiān)控系統(tǒng)和安防系統(tǒng)。目前嵌入式系統(tǒng)中最常用、嵌入式Linux內(nèi)核支持最廣泛的是USB攝像頭。然而受到嵌入式處理器性能的限制,USB攝像頭接口的傳輸速率限制為12 Mb/s,對于常用的640×480分辨率的YUV圖像,其最高幀率為3.75幀/s,無法滿足實(shí)時(shí)性要求。因此,基于CMOS圖像傳感器的高速攝像頭正在被推廣應(yīng)用。CMOS高速攝像頭可以為嵌入式系統(tǒng)實(shí)時(shí)地提供高分辨率圖像[1],很適合進(jìn)行識別、跟蹤等實(shí)時(shí)圖像處理作業(yè)。采集640×480的VGA圖像,CMOS攝像頭最高幀率可以達(dá)到30幀/s?;贠V系列的CMOS攝像頭應(yīng)用很多,比如監(jiān)控[2]和人數(shù)檢測[3]都使用了OmniVision公司的OV9650攝像頭。參考文獻(xiàn)[4]介紹了基于S3C6410和OV9650的V4L2圖像采集系統(tǒng)的設(shè)計(jì),參考文獻(xiàn)[5]和[6]介紹了基于S3C2440中相機(jī)接口(Camera Interface,CAMIF)的OV9650攝像頭驅(qū)動設(shè)計(jì)。
本文涉及的S3C6410[7]的完全交互式移動相機(jī)(Fully Integrated Mobile Camera,F(xiàn)IMC)接口是由S3C2440的CAMIF發(fā)展而來,但是目前關(guān)于FIMC驅(qū)動的原理分析和設(shè)計(jì)實(shí)現(xiàn)的文獻(xiàn)仍然很少。本文對OV9650及FIMC接口驅(qū)動的原理和實(shí)現(xiàn)細(xì)節(jié)作了深入分析,并對原有驅(qū)動進(jìn)行了改進(jìn),使之適用于視線檢測系統(tǒng)。
本文首先分析攝像頭驅(qū)動所依賴的硬件接口,然后重點(diǎn)分析其驅(qū)動軟件設(shè)計(jì)原理和實(shí)現(xiàn)細(xì)節(jié),并給出改進(jìn)設(shè)計(jì),最后對下一步的改進(jìn)工作提出展望。
1 攝像頭驅(qū)動系統(tǒng)的硬件接口
本文所涉及的驅(qū)動系統(tǒng)基于OK6410嵌入式開發(fā)板,采用S3C6410作為中央處理器。S3C6410內(nèi)置的FIMC接口為開發(fā)板與CMOS攝像頭的連接提供了可靠便利的接口。該驅(qū)動系統(tǒng)的硬件結(jié)構(gòu)如圖1所示。
如圖1,攝像頭為130萬像素、20引腳的OV9650,通過FIMC接口接入S3C6410。OV9650與FIMC對應(yīng)管腳連接如圖2所示。其中,CAMYDATA7~CAMYDATA0負(fù)責(zé)圖像數(shù)據(jù)傳輸,CAMRSTN為復(fù)位信號,CAMSYNC為同步信號。OV9650的配置接口為SCCB接口。由于S3C6410沒有專用的SCCB接口,因此使用GPB6、GPB5分別模擬SIO_D、SIO_C,即數(shù)據(jù)和時(shí)鐘信號。SCCB協(xié)議與I2C協(xié)議的區(qū)別僅在于設(shè)備地址不同,因此,驅(qū)動中直接用I2C代替。
2 攝像頭驅(qū)動系統(tǒng)軟件
2.1 Linux驅(qū)動模型
在Linux操作系統(tǒng)中,設(shè)備驅(qū)動為應(yīng)用程序提供訪問接口,屏蔽了底層硬件細(xì)節(jié)。從Linux2.6內(nèi)核開始,設(shè)備被驅(qū)動和內(nèi)核映射為文件,應(yīng)用程序可以像訪問普通文件一樣訪問這些掛載在/dev目錄下的設(shè)備,訪問接口被定義在驅(qū)動中file_operations結(jié)構(gòu)體對象內(nèi)。每一個接口函數(shù)其實(shí)都是一個系統(tǒng)調(diào)用,其具體實(shí)現(xiàn)由驅(qū)動程序完成。Linux內(nèi)核中驅(qū)動模型包括總線(Bus)、設(shè)備(Device)和驅(qū)動(Driver)三個要素,即設(shè)備和驅(qū)動作為對象掛載在相同的總線上,由總線對設(shè)備和驅(qū)動進(jìn)行一一匹配。
Linux驅(qū)動模型將所有外設(shè)分為字符設(shè)備、塊設(shè)備和網(wǎng)絡(luò)設(shè)備三種。攝像頭屬于字符設(shè)備,其驅(qū)動遵循著字符設(shè)備驅(qū)動的框架,包括設(shè)備號、設(shè)備注冊和最重要的文件操作函數(shù)的實(shí)現(xiàn)。特別地,針對攝像頭設(shè)備,V4L2[8]接口為驅(qū)動程序提供了一套完備的文件操作標(biāo)準(zhǔn)接口和緩沖池管理策略,目前大多數(shù)的攝像頭驅(qū)動都遵循V4L2接口標(biāo)準(zhǔn)。
2.2 V4L2驅(qū)動
V4L2是Video For Linux 2的簡稱,是Linux內(nèi)核中關(guān)于視頻設(shè)備的虛擬驅(qū)動,它不涉及硬件,僅僅為應(yīng)用程序提供一套完備的操作接口,這些接口的具體實(shí)現(xiàn)都由遵守V4L2協(xié)議的驅(qū)動程序來完成,比如常用的ioctl接口。V4L2的存在極大地方便了應(yīng)用程序的編寫,使得同一套應(yīng)用程序可以應(yīng)用于多種攝像頭。V4L2層次示意圖如圖3。
基于V4L2的基本圖像采集流程如下:
?。?)打開視頻設(shè)備文件(一般為dev/video0),初始化采集格式等參數(shù);
?。?)在內(nèi)核空間申請若干視頻采集的幀緩沖區(qū);
?。?)地址映射,使得用戶空間的應(yīng)用程序?qū)彌_區(qū)有讀寫權(quán)限;
?。?)幀緩沖區(qū)在視頻采集輸入隊(duì)列排隊(duì),并啟動視頻采集;
?。?)從緩沖隊(duì)列取出幀緩沖區(qū),獲得數(shù)據(jù)進(jìn)行處理;
(6)處理完,將幀緩沖區(qū)重新放入視頻采集輸入隊(duì)列,循環(huán)往復(fù)采集連續(xù)視頻數(shù)據(jù)。
V4L2為圖像采集程序維持一個環(huán)形緩沖隊(duì)列,如圖4。該緩沖區(qū)隊(duì)列為ping-pong操作模式,應(yīng)用程序需要使用的圖像數(shù)據(jù)會通過ioctl接口使對應(yīng)的緩沖區(qū)出隊(duì),緩沖隊(duì)列的其余緩沖區(qū)繼續(xù)接收圖像數(shù)據(jù),并在一個循環(huán)之后覆蓋掉原有的緩沖區(qū)數(shù)據(jù),以保證緩沖區(qū)隊(duì)列中圖像數(shù)據(jù)的實(shí)時(shí)性。
2.3 關(guān)鍵模塊驅(qū)動的設(shè)計(jì)與實(shí)現(xiàn)
OV9650通過FIMC接口與S3C6410連接,F(xiàn)IMC為輸入圖像進(jìn)行格式轉(zhuǎn)換、剪裁等預(yù)處理,最后傳輸?shù)絻?nèi)核中開辟的圖像緩沖區(qū),供應(yīng)用程序讀取。攝像頭驅(qū)動分為兩個部分:OV9650驅(qū)動和FIMC驅(qū)動。
2.3.1 OV9650驅(qū)動
OV9650驅(qū)動的主要作用是掛載驅(qū)動和配置寄存器,其中.h文件定義了寄存器配置數(shù)據(jù),并由.c文件調(diào)用。由于FIMC接口的存在,應(yīng)用程序不需要直接操作OV9650攝像頭,因此OV9650驅(qū)動不需要為應(yīng)用程序提供訪問接口,不需要定義file_operations結(jié)構(gòu)體。
從Mach-smdk6410.c文件中可以知道,內(nèi)核在啟動時(shí),將OV9650作為一個I2C設(shè)備掛載到內(nèi)核樹的I2C總線上。之后內(nèi)核找到OV9650驅(qū)動,執(zhí)行其入口函數(shù)——ov965x_init(),將OV9650.c文件中定義的i2c_driver驅(qū)動對象也添加到內(nèi)核樹中,最后由總線根據(jù)其name將設(shè)備和驅(qū)動進(jìn)行匹配。在匹配工作完成之后,內(nèi)核會調(diào)用其探測函數(shù)ov965x_probe(),將OV9650的配置數(shù)據(jù)傳遞給FIMC驅(qū)動中的一個全局參數(shù)s3c_fimc,用于配置FIMC寄存器,然后,初始化OV9650寄存器。
2.3.2 FIMC驅(qū)動
FIMC是s3c6410芯片為攝像頭設(shè)備提供的一個接口,用來對所采集的圖像進(jìn)行裁剪、放縮等預(yù)處理。FIMC為輸出圖像提供兩個DMA通道:preivew通道和codec通道,并為每個通道分配四個ping-pong緩沖區(qū),以提高圖像傳輸速度和內(nèi)存使用效率。如圖5所示。
FIMC接收OV9650圖像數(shù)據(jù),并向上傳遞。因此,F(xiàn)IMC驅(qū)動最重要的作用就是向應(yīng)用層提供標(biāo)準(zhǔn)的操作接口,供應(yīng)用程序使用。
FIMC驅(qū)動主要包括三個部分:(1)platform驅(qū)動注冊;(2)file_operations接口定義;(3)V4L2接口實(shí)現(xiàn)。
2.3.2.1 platform驅(qū)動注冊
platform是Linux 2.6內(nèi)核所引進(jìn)的一種新型驅(qū)動管理和注冊機(jī)制。目前Linux內(nèi)核中大部分的設(shè)備驅(qū)動都采用platform架構(gòu)。在platform架構(gòu)中,設(shè)備用platform_device表示,驅(qū)動用platform_driver表示。Linux platform driver機(jī)制與傳統(tǒng)的device driver機(jī)制(通過drivce_register函數(shù)進(jìn)行注冊)相比,一個十分明顯的優(yōu)勢在于platform機(jī)制將設(shè)備本身的資源注冊進(jìn)內(nèi)核,由內(nèi)核統(tǒng)一管理,在驅(qū)動程序使用這些資源時(shí)通過platform device提供的標(biāo)準(zhǔn)接口進(jìn)行申請并使用,提高了驅(qū)動和資源管理的獨(dú)立性,并且擁有較好的可移植性和安全性(這些標(biāo)準(zhǔn)接口是安全的)。
FIMC驅(qū)動入口函數(shù)是s3c_fimc_core.c中的s3c_fimc_register(),該函數(shù)將platform_driver類型的s3c_fimc_driver掛載到platform虛擬總線。由mach-smdk6410.c文件可知,內(nèi)核啟動時(shí)將所有platform_device(包括s3c_device_fimc0)掛載到platform總線。platform總線的match函數(shù)將device和driver匹配之后,會自動調(diào)用s3c_fimc_driver中指定的probe函數(shù)探測設(shè)備、申請內(nèi)存資源、申請中斷等,并將最終形成的platform_device類型數(shù)據(jù)保存到內(nèi)核中,供后續(xù)使用。最后,調(diào)用video_register_device函數(shù)將對應(yīng)的video_device注冊到內(nèi)核。
video_device結(jié)構(gòu)體包括fops、ioctl_ops、release、name、vf_type幾個成員變量,其中,最重要的是file_operations類型的fops和v4l2_ioctl_ops類型的ioctl_ops,分別實(shí)現(xiàn)文件操作接口和V4L2接口。
2.3.2.2 file_operations接口
FIMC驅(qū)動遵循V4L2接口標(biāo)準(zhǔn),其file_operations接口定義如下:
static const struct v4l2_file_operations s3c_fimc_fops=
{
.owner=THIS_MODULE,
.open=s3c_fimc_open,
.release=s3c_fimc_release,
.unlocked_ioctl=video_ioctl2,
.read=s3c_fimc_read,
.write=s3c_fimc_write,
.mmap=s3c_fimc_mmap,
.poll=s3c_fimc_poll,
};
當(dāng)應(yīng)用程序通過系統(tǒng)調(diào)用open()打開攝像頭設(shè)備時(shí),內(nèi)核會最終找到s3c_fimc_open()函數(shù)來打開攝像頭。
應(yīng)用程序通過read()獲取圖像數(shù)據(jù),該函數(shù)通過copy_to_user()將內(nèi)核空間所申請緩沖區(qū)中圖像數(shù)據(jù)拷貝到用戶空間中開辟的圖像數(shù)據(jù)區(qū)。該函數(shù)沒有充分利用FIMC接口提供的ping-pong緩沖區(qū),按字進(jìn)行拷貝(memcpy),十分耗時(shí)。
mmap函數(shù)將內(nèi)核空間中申請到的圖像緩沖區(qū)映射到應(yīng)用程序所在的用戶空間,這樣,應(yīng)用程序申請到的buffer將指向內(nèi)核空間的圖像緩沖區(qū),應(yīng)用程序可以(不拷貝)直接對圖像進(jìn)行操作。該函數(shù)配合V4L2標(biāo)準(zhǔn)中的環(huán)形緩沖區(qū)隊(duì)列,節(jié)省了應(yīng)用程序讀取圖像數(shù)據(jù)所消耗的時(shí)間。
2.3.2.3 V4L2接口
V4L2接口功能強(qiáng)大,為應(yīng)用程序提供了完備的操作接口,包括設(shè)置格式、幀率、白平衡、曝光模式、申請緩沖區(qū)、取數(shù)據(jù)、剪裁圖像等。此處僅列舉幾個重要接口。
const struct v4l2_ioctl_ops s3c_fimc_v4l2_ops=
{
.vidioc_s_fmt_vid_cap=
s3c_fimc_v4l2_s_fmt_vid_cap,
.vidioc_s_ctrl=s3c_fimc_v4l2_s_ctrl,
.vidioc_streamon=s3c_fimc_v4l2_streamon,
.vidioc_streamoff=s3c_fimc_v4l2_streamoff,
.vidioc_reqbufs=s3c_fimc_v4l2_reqbufs,
.vidioc_querybuf=s3c_fimc_v4l2_querybuf,
.vidioc_qbuf=s3c_fimc_v4l2_qbuf,
.vidioc_dqbuf=s3c_fimc_v4l2_dqbuf,
.vidioc_s_parm=s3c_fimc_v4l2_s_parm,
};
應(yīng)用程序通過ioctl接口使用這些函數(shù),比如ioctl(fd,VIDIOC_S_FMT,&fmt)用來設(shè)置圖像格式,此時(shí)V4L2會將VIDIOC_S_FMT命令映射為s3c_fimc_v4l2_s_fmt_vid_cap()函數(shù),并將fmt指定的格式告知FIMC接口,F(xiàn)IMC會將OV9650傳遞過來的原始圖像數(shù)據(jù)經(jīng)過類型轉(zhuǎn)換傳遞回應(yīng)用程序。
s3c_fimc_v4l2_reqbufs()用于申請圖像緩沖區(qū),該函數(shù)為應(yīng)用程序在內(nèi)核空間開辟ping-pong緩沖區(qū)。s3c_fimc_v4l2_qbuf()函數(shù)將緩沖區(qū)組成環(huán)形緩沖隊(duì)列,當(dāng)應(yīng)用程序需要調(diào)用圖像數(shù)據(jù)時(shí),使用s3c_fimc_v4l2_dqbuf()使指定的緩沖區(qū)出隊(duì),緩沖區(qū)在出隊(duì)期間,不會被新來的圖像數(shù)據(jù)覆蓋,新到的圖像數(shù)據(jù)會被傳送到環(huán)形隊(duì)列中指定緩沖區(qū)的下一個緩沖區(qū)。由于FIMC控制器為P通道和C通道分別開辟了4個緩沖區(qū),在內(nèi)核初始化時(shí)已經(jīng)申請到,因此FIMC驅(qū)動中并不需要再重新申請。
2.4 驅(qū)動錯誤分析與改進(jìn)設(shè)計(jì)
在驅(qū)動主體框架正確的情況下,開發(fā)板(OK6410A)自帶的驅(qū)動并不能直接使用。同一套V4L2圖像采集程序可以應(yīng)用在USB攝像頭上,應(yīng)用在OV9650上卻無法獲得圖像,并且先后報(bào)出兩個錯誤:
(1)tx or ty is lower than zero and this is a invalid target size
?。?)VIDIOC_QUERYBUF error
上述錯誤出現(xiàn)之后,LCD屏幕沒有圖像,緊接著串口會顯示display 0,表示程序無法讀出圖像數(shù)據(jù),導(dǎo)致程序終止。下面分別對兩個錯誤進(jìn)行分析并改進(jìn)。
2.4.1 錯誤1的分析與改進(jìn)
由于ov9650驅(qū)動僅僅將ov9650設(shè)備注冊進(jìn)入系統(tǒng),并沒有其他處理,因此ov965x.h和ov965x.c兩個文件不用修改和調(diào)試。
FIMC采用DMA通道向內(nèi)核緩沖區(qū)傳送數(shù)據(jù),需要專門的函數(shù)打開DMA輸出通道。通過函數(shù)跟蹤得知,原有s3c_fimc_v4l2_s_fmt_vid_cap()函數(shù)并沒有打開輸出DMA通道,因此CMOS攝像頭的數(shù)據(jù)并沒有傳送到內(nèi)核開辟的緩沖區(qū)中,導(dǎo)致V4L2也無法獲取這些圖像數(shù)據(jù)。而且由于沒有打開輸出DMA通道,out_frame參數(shù)也沒有設(shè)置,導(dǎo)致其對應(yīng)的尺寸參數(shù)也為0,所以報(bào)出第一個錯誤。
在s3c_fimc_v4l2_s_fmt_vid_cap()中通過調(diào)用s3c_fimc_ set_output_frame()函數(shù),打開輸出DMA通道,解決了該問題。
2.4.2 錯誤2的分析與改進(jìn)
該錯誤由s3c_fimc_v4l2_querybuf()函數(shù)報(bào)出,報(bào)錯條件是:
if(b->type!=V4L2_BUF_TYPE_VIDEO_OVERLAY&&b
->type!=V4L2_BUF_TYPE_VIDEO_CAPTURE)
該函數(shù)用于配置所申請圖像緩沖區(qū)的長度、偏移量等屬性,從而使所申請的環(huán)形隊(duì)列緩沖區(qū)生效。由于本系統(tǒng)中攝像頭僅用于圖像捕獲,因此在該函數(shù)開頭可以將b->type進(jìn)行強(qiáng)制設(shè)定,即:b->type=V4L2_BUF_ TYPE_VIDEO_CAPTURE,從而解決圖像緩沖區(qū)申請的問題,該錯誤不再出現(xiàn)。
至此,修正后的FIMC驅(qū)動程序可以正常工作,圖像數(shù)據(jù)得以傳輸?shù)絻?nèi)核中為FIMC驅(qū)動開辟的圖像緩沖區(qū),應(yīng)用程序可以通過read()系統(tǒng)調(diào)用或者ioctl()的VIDIOC_DQBUF命令獲取圖像數(shù)據(jù)。
圖像捕獲效果如圖6所示。
3 結(jié)論
本文深入分析了CMOS攝像頭驅(qū)動的原理和實(shí)現(xiàn)細(xì)節(jié)。FIMC驅(qū)動向內(nèi)核申請四個ping-pong緩沖區(qū),通過DMA方式傳入圖像數(shù)據(jù),提高了圖像數(shù)據(jù)傳輸速率。內(nèi)存共享策略使得應(yīng)用程序在訪問圖像緩沖區(qū)時(shí)免去了內(nèi)存拷貝的步驟,大大縮減了圖像獲取的時(shí)間。但是目前的FIMC驅(qū)動在緩沖區(qū)出隊(duì)和入隊(duì)時(shí)的保護(hù)機(jī)制仍不夠完善,需要在今后的工作當(dāng)中對這一部分不斷進(jìn)行優(yōu)化。
參考文獻(xiàn)
[1] OminiVision Technologies Inc. OV9650 color CMOS SXGA (1.3MegaPixel)camerachipTM implementation guide[EB/OL].(2004-12-07)[2015-01-31]. http://www.ovt.com.
[2] 胡哲光.基于S3C2440與OV9650的嵌入式監(jiān)控設(shè)計(jì)[J].輕工機(jī)械,2012,30(2):50-53.
[3] 官志平.基于ARM9的Linux系統(tǒng)移植以及在電梯轎廂內(nèi)人數(shù)檢測的應(yīng)用[D].廈門:廈門大學(xué),2014.
[4] Lu Yinli, Yu Hongli, Zhang Pengpeng. The implementation of embedded image acquisition based on V4L2[C]. Proceedings of the 2011 International Conference on Electronics, Communications and Control (ICECC), 2011:549-552.
[5] Zhang Min, Sun Jinguang, Wang Shi. Research and implementation of the CMOS camera device driver based on S3C2440[C]. Proceedings of the 2010 International Conference on Intelligent Computation Technology and Automation (ICICTA),2010:1039-1042.
[6] Kuang Shunming, He Xiaojian. Included in your digital subscription design and application of CMOS device driver based on S3C2440[C]. Proceedings of the 2011 10th International Conference on Electronic Measurement & Instruments (ICEMI),2011:342-343.
[7] Samsung. S3C6410x RISC microprocessor user′s manual (revision 1.2)[EB/OL].(2009-02-13)[2015-01-31]. http://www.samsung.com.
[8] DIRKS B. Video for Linux two API specification (revision 3.9)[EB/OL].(2012-12-03)[2015-01-31]. http://www.linuxtv.org/downloads/v4l-dvb-apis/v4l2spec.html.