引言:近年來高性能,、低功耗的ARM處理器成為嵌入式應(yīng)用的主流,;開源的嵌入式Linux操作系統(tǒng)由于系統(tǒng)穩(wěn)定、兼容性和移植性好,、網(wǎng)絡(luò)功能強(qiáng)等優(yōu)點(diǎn)也成為首選嵌入式操作系統(tǒng)之一,,但目前嵌入式Linux支持的USB攝像頭(如OV511)市場上已淘汰,使用現(xiàn)有USB攝像頭需開發(fā)相關(guān)驅(qū)動程序,,由于采用中芯微公司的USB攝像頭在市場中的占有率很高,,可高效壓縮后輸出JPEG圖像,,所以本文針對這類USB攝像頭設(shè)計(jì)了基于AT91RM9200處理器的圖像采集處理平臺,實(shí)現(xiàn)了JPEG圖像的采集和網(wǎng)絡(luò)傳輸,。
1.硬件系統(tǒng)設(shè)計(jì)
?。?) AT91RM9200簡介
AT91RM9200是ATMEL公司生產(chǎn)的基于ARM920T的工業(yè)級SOC芯片,不僅有豐富的片上資源和標(biāo)準(zhǔn)接口,,而且有低功耗,、低成本、高性能,、支持多種主要的嵌入式操作系統(tǒng)等特點(diǎn),,其采用5級整數(shù)流水線結(jié)構(gòu)性能高達(dá)200 MIPS, 具有標(biāo)準(zhǔn)的ARMv4存儲器管理單元(MMU),內(nèi)部集成有兩個(gè)USB 2.0 全速(12 M比特/秒) 主機(jī)端口和10/100 Base-T 型以
太網(wǎng)接口,該芯片具有多種工作模式,其低功耗待機(jī)模式下電流僅3.1 mA[1],。
?。?) AT91RM9200的USB主機(jī)端口(UHP)
AT91RM9200集成有一個(gè)USB器件端口(UDP)和一個(gè)USB主機(jī)端口(UHP),均符合USB V2.0 全速及低速規(guī)范,。UHP內(nèi)部集成一個(gè)根集線器和2個(gè)收發(fā)器,,可連接127個(gè)USB 器件,UHP控制器與OHCI Rev 1.0規(guī)范完全兼容,,標(biāo)準(zhǔn)分類驅(qū)動可以自動檢測并在用戶程序中使用[1]。
?。?) 硬件系統(tǒng)結(jié)構(gòu)
圖像采集平臺的硬件系統(tǒng)結(jié)構(gòu)設(shè)計(jì)如圖1所示,,主要包括AT91RM9200處理器、JTAG接口,、網(wǎng)絡(luò)模塊,、32M SDRAM、16M FLASH,、串口,、USB主從口等部分。其中網(wǎng)絡(luò)模塊通過外接DM9161實(shí)現(xiàn)10M/100M自適應(yīng)網(wǎng)絡(luò)連接,,通過處理器內(nèi)置的4個(gè)通用同步(異步)收發(fā)器(USART) 可實(shí)現(xiàn)4路數(shù)據(jù)傳輸與控制,。另外,處理器內(nèi)置的雙主機(jī)收發(fā)器可連接USB攝像頭和USB存儲設(shè)備,,也可經(jīng)USB集線器連接更多USB設(shè)備,,提高了系統(tǒng)的擴(kuò)展性。
圖1.硬件系統(tǒng)結(jié)構(gòu)
2.軟件系統(tǒng)設(shè)計(jì)
(1) 嵌入式Linux軟件架構(gòu)
Linux工作模式分為內(nèi)核模式和用戶模式,,其軟件系統(tǒng)架構(gòu)由硬件控制器,、Linux內(nèi)核、系統(tǒng)調(diào)用接口和用戶進(jìn)程4層組成,。一個(gè)用戶進(jìn)程就是一個(gè)用戶程序,,操作系統(tǒng)支持多進(jìn)程并發(fā),;內(nèi)核是操作系統(tǒng)的中心組件,有進(jìn)程管理,、內(nèi)存管理,、文件系統(tǒng)管理、設(shè)備控制,、網(wǎng)絡(luò)控制等功能,,它通過底層接口層以一致的方式管理硬件,通過高層抽象層為用戶進(jìn)程提供與硬件無關(guān)的API控制硬件資源,;系統(tǒng)調(diào)用接口負(fù)責(zé)為應(yīng)用程序調(diào)用內(nèi)核中特定的過程,,從而實(shí)現(xiàn)特定服務(wù),一般認(rèn)為這些調(diào)用和服務(wù)也是操作系統(tǒng)內(nèi)核的一部分,。
(2) USB驅(qū)動程序系統(tǒng)框架
圖2.USB驅(qū)動程序系統(tǒng)框架
USB驅(qū)動程序的系統(tǒng)框架如圖2所示,,包括客戶驅(qū)動程序、通用總線驅(qū)動程序,、主機(jī)控制器驅(qū)動程序幾部分,。其中,客戶驅(qū)動程序是特定USB設(shè)備的驅(qū)動程序,,提供了USB設(shè)備的功能操作及特定子類協(xié)議封裝[6],;通用總線驅(qū)動程序(USBD)擁有特定操作系統(tǒng)上抽象出的主機(jī)控制器驅(qū)動程序的共有特性,是整個(gè)USB驅(qū)動程序的核心,,主要實(shí)現(xiàn)USB總線管理,、URB管理、為客戶驅(qū)動程序提供相關(guān)接口等功能,,它還負(fù)責(zé)維護(hù)設(shè)備的加載和卸載,、設(shè)備配置、客戶端驅(qū)動程序的安裝和卸載等工作[2],;主機(jī)控制器驅(qū)動程序是直接與硬件交互的軟件模塊,,主要實(shí)現(xiàn)主機(jī)控制器硬件初始化、負(fù)責(zé)總線的注冊,、為USBD層提供相應(yīng)的接口函數(shù),、完成4種類型的數(shù)據(jù)傳輸?shù)裙δ躘2]。
Linux通過定義了統(tǒng)一的URB(Universal Request Block)結(jié)構(gòu),,在客戶驅(qū)動程序和USBD之間,,以及USBD和HCD之間進(jìn)行消息傳遞,為USB驅(qū)動程序的開發(fā)帶來了很大方便[3],。我們開發(fā)USB驅(qū)動程序主要是編寫USB客戶軟件層的程序,,即如何將數(shù)據(jù)封裝成URB和如何從URB中得到數(shù)據(jù)。
(3) V4L簡介與攝像頭驅(qū)動程序開發(fā)
Video for Linux(簡V4L)是Linux中關(guān)于視頻設(shè)備的內(nèi)核驅(qū)動,它為編寫視頻應(yīng)用程序提供一系列接口函數(shù),,內(nèi)核,、驅(qū)動程序和應(yīng)用程序以它為標(biāo)準(zhǔn)進(jìn)行交流,因此視頻類驅(qū)動程序的開發(fā)必須遵循此標(biāo)準(zhǔn),,應(yīng)用V4L API函數(shù)進(jìn)行設(shè)計(jì)[4],。
設(shè)備驅(qū)動程序是Linux內(nèi)核與應(yīng)用程序之間的接口,通過USB客戶驅(qū)動程序提供的USBD接口和應(yīng)用程序接口,,屏蔽了硬件實(shí)現(xiàn)的細(xì)節(jié),。應(yīng)用程序?qū)⑼獠吭O(shè)備看成是一類特殊文件__設(shè)備文件,可以使用像操作普通文件一樣的系統(tǒng)調(diào)用接口函數(shù)來完成對外部設(shè)備的打開,、關(guān)閉,、讀寫和I/O控制操作。陷于篇幅原因只對驅(qū)動程序的重要部分進(jìn)行闡述,。
l 驅(qū)動程序的注冊,、注銷:所有的USB設(shè)備類驅(qū)動程序都要在USBD中進(jìn)行注冊和注銷,Linux中的驅(qū)動程序通常采用模塊方式編寫,,使用函數(shù)module_init注冊設(shè)備,,使用函數(shù)module_ exit注銷設(shè)備。
module_init(usb_gfkd_init); /*加載模塊入口,調(diào)用函數(shù)usb_register()注冊設(shè)備*/
module_exit(usb_gfkd_exit); /*注銷模塊入口,調(diào)用函數(shù)usb_deregister()注銷設(shè)備*/
l 驅(qū)動程序與USBD的接口:USBD為每個(gè)設(shè)備驅(qū)動程序維護(hù)一個(gè)相關(guān)的usb_
driver的數(shù)據(jù)結(jié)構(gòu),,負(fù)責(zé)設(shè)備的初始化和卸載,。當(dāng)總線上有設(shè)備連接操作時(shí),USBD通過該結(jié)構(gòu)來查找相關(guān)的驅(qū)動程序,,并調(diào)用初始化函數(shù)probe()對設(shè)備初始化,;當(dāng)設(shè)備斷開時(shí),USBD也通過該結(jié)構(gòu)來查找相關(guān)的驅(qū)動程序,,并調(diào)用設(shè)備卸載函數(shù)disconnect ()對設(shè)備卸載。USBD接口的數(shù)據(jù)結(jié)構(gòu)定義為:
static struct usb_driver gfkd_driver = { "gfkd",gfkd_probe,gfkd_disconnect},;
初始化函數(shù)static void * gfkd_probe(…)首先讀取設(shè)備的Usb dev結(jié)構(gòu),,根據(jù)設(shè)備的配置描述符判斷該設(shè)備是否被驅(qū)動程序所支持, 判斷使用接口是否正確,然后為驅(qū)動申請一塊內(nèi)存,,再探測使用的攝像頭,,完成對攝像頭的初始化,最后創(chuàng)建攝像頭的設(shè)備文件結(jié)點(diǎn)[5],。
卸載函數(shù)static void gfkd_disconnect (struct usb_device *dev, void *ptr)的作用是終止數(shù)據(jù)傳輸,、刪除攝像頭的設(shè)備文件結(jié)點(diǎn)、釋放接口,、將驅(qū)動占用的內(nèi)存釋放,。
l 驅(qū)動程序與應(yīng)用程序接口:攝像頭驅(qū)動程序在static struct file_operations gfkd_fops中給應(yīng)用程序提供了統(tǒng)一的外設(shè)操作函數(shù)接口,當(dāng)應(yīng)用程序?qū)z像頭進(jìn)行open 、release,、read,、內(nèi)存映射mmap以及IO控制等系統(tǒng)調(diào)用操作時(shí)將通過該結(jié)構(gòu)訪問驅(qū)動程序提供的函數(shù)。
static struct file_operations gfkd_fops = {
.owner = THIS_MODULE, .open = gfkd_open,
.release = gfkd_close, .read = gfkd_read,
.mmap = gfkd_mmap, .ioctl = gfkd_ioctl,
.llseek = no_llseek, };
打開攝像頭函數(shù)static int gfkd_open(struct inode *inode, struct file *file)作用是打開攝像頭的設(shè)備文件結(jié)點(diǎn),,并為數(shù)據(jù)傳輸做好必要的準(zhǔn)備工作,。它先調(diào)用函數(shù)gfkd _alloc()分配用于視頻解碼的臨時(shí)數(shù)據(jù)緩沖區(qū)、幀緩沖區(qū)和數(shù)據(jù)緩沖區(qū),;然后初始化攝像頭,,用函數(shù)gfkd _setMode()設(shè)置輸出的視頻格式和分辨率;再用函數(shù)gfkd _setFrameDecoder()設(shè)置幀緩沖區(qū)接收的視頻幀的格式和分辨率,;最后調(diào)用函數(shù)gfkd _init_isoc()初始化等時(shí)數(shù)據(jù)傳輸設(shè)置,、打開攝像頭和分配提交URB。
關(guān)閉攝像頭函數(shù)static int gfkd_close(struct inode *inode, struct file *file)作用是關(guān)閉攝像頭的設(shè)備文件結(jié)點(diǎn),。它先調(diào)用函數(shù)gfkd _stop_isoc()終止等時(shí)數(shù)據(jù)傳輸,;再調(diào)用函數(shù)CameraShutDown()關(guān)閉攝像頭;最后使用函數(shù)gfkd _dealloc( )釋放分配的各種緩沖區(qū),。
內(nèi)存映射函數(shù)static int gfkd_mmap(struct file *file, struct vm_area_struct *vma)實(shí)現(xiàn)內(nèi)核空間與用戶空間的內(nèi)存映射,。先通過函數(shù)vmalloc()申請分配足夠大的內(nèi)核態(tài)內(nèi)存作為圖像幀緩沖區(qū),并能存儲兩個(gè)URB采集的圖像,;然后用函數(shù)remap_page_range()將其映射到用戶空間中,。這樣提高了用戶程序獲取內(nèi)核態(tài)圖像幀緩沖區(qū)數(shù)據(jù)的速度。
讀函數(shù)static long gfkd_read(struct video_device *dev, char *buf, unsigned long count, int noblock)通過調(diào)用函數(shù)copy_to_user()將圖像數(shù)據(jù)從內(nèi)核態(tài)的幀緩沖區(qū)拷貝到用戶態(tài)的數(shù)據(jù)緩沖區(qū),。
IO控制函數(shù)static int gfkd_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)的功能是接收應(yīng)用程序的各種命令,,實(shí)現(xiàn)對攝像頭的控制操作,如獲得攝像頭的參數(shù),、設(shè)置攝像頭的分辨率
,、開始采集圖圖像和設(shè)置幀同步。
由于Linux中任何USB傳輸都是通過URB實(shí)現(xiàn)的,,每次URB傳輸都包括URB的建立,、發(fā)出、回收,、數(shù)據(jù)整理等階段不產(chǎn)生有效數(shù)據(jù),,因此在具體實(shí)現(xiàn)中采用等時(shí)傳輸方式,通過建立兩個(gè)URB,,使用雙URB輪流通信的方法來提高圖像的采集速度,。
本驅(qū)動程序開發(fā)是基于ATMEL最新版Linux-2.4.27-vrs1-Atmel,在驅(qū)動程序開發(fā)完后需重新配置內(nèi)核,,讓內(nèi)核支持usb-ohci 和video for linux,,再把驅(qū)動程序配置成module,然后重新編譯內(nèi)核生成.o文件。將編譯好的驅(qū)動放入文件系統(tǒng),,建立設(shè)備文件,,然后將文件系統(tǒng)燒入flash,再連接USB攝像頭(如內(nèi)置中芯微Zc301P DSP),,把模塊加載進(jìn)內(nèi)核并注冊就可以找到該攝像頭并顯示:
gfkd _core.c: USB gfkd camera found. Type Vimicro Zc301P 0x301b
gfkd _core.c: gfkd driver 00.57.06LE registered
(4) 圖像采集的實(shí)現(xiàn)與性能分析
服務(wù)端應(yīng)用程序的實(shí)現(xiàn)是基于C/S模式,,使用了3個(gè)線程,其中一個(gè)主線程,,一個(gè)圖像采集線程負(fù)責(zé)從驅(qū)動程序獲取圖像,,可根據(jù)變量grabMethod選擇采用read方式或內(nèi)存映射方式獲取圖像;另有一個(gè)圖像發(fā)送線程負(fù)責(zé)圖像發(fā)送,,程序通過建立帶共享鎖的4幀圖像循環(huán)隊(duì)列做為圖像采集線程和圖像發(fā)送線程進(jìn)行數(shù)據(jù)交換的公共緩沖區(qū),。服務(wù)端還使用了兩個(gè)socket,一個(gè)用于和服務(wù)端口綁定后偵聽是否有服務(wù)請求,,另外一個(gè)用于發(fā)送圖像數(shù)據(jù),,主線程流程如圖3所示。
程序首先設(shè)置采集圖像的相關(guān)參數(shù)(如設(shè)備號,、圖像大小,、初始化圖像幀緩沖區(qū)等),然后通過函數(shù) int init_videoIn()獲取攝像頭參數(shù),,設(shè)置采集圖像寬度,、高度、格式,、采集方式等參數(shù),,并分配4幀采集圖像緩存vd->ptframe[i] =(unsigned char *) realloc (vd->ptframe[i], sizeof(struct frame_t) + (size_t) vd->framesizeIn ),再啟動圖像采集線程 pthread_create (&w1, NULL, (void *) grab, NULL)進(jìn)行圖像采集,;創(chuàng)建服務(wù)端socket,,與服務(wù)端口綁定后偵聽服務(wù)請求;如果有新連接進(jìn)來,,函數(shù)accept()返回一個(gè)新的發(fā)送socket,,并啟動新的圖像發(fā)送線程,pthread_create(&server_th, NULL, (void *)service, &new_sock); 如果采集結(jié)束或連接產(chǎn)生錯(cuò)誤,,調(diào)用pthread_join (w1, NULL)和close(serv_sock)關(guān)閉圖像采集線程和圖像發(fā)送線程,,釋放有關(guān)資源后退出,。
圖3.主程序流程
使用奧尼銀色天使S900攝像頭分別對640×480和320×240兩種分辨率用read方式和內(nèi)存映射方式進(jìn)行了圖像采集和發(fā)送,,實(shí)驗(yàn)結(jié)果如表1所示,應(yīng)用程序采用內(nèi)存映射方式圖像獲取的實(shí)時(shí)性較高,,達(dá)到實(shí)時(shí)視頻的要求,。
4結(jié)束語
本文針對市場主流USB攝像頭開發(fā)了驅(qū)動程序,實(shí)現(xiàn)了基于AT91RM9200的嵌入式圖像采集和網(wǎng)絡(luò)傳輸??朔似渌鼒D像采集方案采集BMP圖像數(shù)據(jù)量大和實(shí)時(shí)性差的問題,,并解決了目前嵌入式Linux缺乏USB攝像頭驅(qū)動程序的問題,具有集成度和性價(jià)比高,、實(shí)時(shí)性 好,、支持多種USB攝像頭和充分利用USB帶寬的優(yōu)點(diǎn)。實(shí)驗(yàn)表明適于高質(zhì)量實(shí)時(shí)圖像監(jiān)控場所和智能圖像監(jiān)控應(yīng)用,,具有很好的廣泛應(yīng)用前景,。
參考文獻(xiàn):
[1]ATMEL, AT91RM9200 DATA,[Z]. America, Atmel Corporation , 2003.
[2](美)科比特,、魯賓尼,、哈特曼主編,LINUX設(shè)備驅(qū)動程序[M],,東南大學(xué)出版社,,2004
[3]周力功 主編 ,USB編程與驅(qū)動程序開發(fā)[M],,北京航空航天大學(xué),,2004
[4]李侃,基于S3C2410平臺與嵌入式Linux圖像采集應(yīng)用[J],微計(jì)算機(jī)信息,2006,第3-2期
[5]Don Anderson、Dave Dzatko 著,,USB系統(tǒng)體系[M],,中國電力出版社,2003
[6]倪繼利著,,LINUX 內(nèi)核分析及編程[M],,電子工業(yè)出版社,2005