廖建尚,曹成濤,楊志偉
(廣東交通職業(yè)技術(shù)學(xué)院 計算機工程學(xué)院,廣東 廣州 510650)
隨著社會的發(fā)展,汽車不斷增多,高速公路上違章的車輛也逐漸增多,為了構(gòu)建一個平安交通和智能交通,視頻監(jiān)控系統(tǒng)在交通行業(yè)的應(yīng)用也越來越多,為了能對高速公路進行監(jiān)控,高清視頻監(jiān)控也應(yīng)用越來越廣泛[1]。
文中將研究詳細分析RX8025和I2C的工作原理和通信協(xié)議和Linux的I2C總線驅(qū)動程序,設(shè)計一個應(yīng)用在高速公路視頻監(jiān)控的基于I2C的RX-8025實時時鐘控制系統(tǒng),為高速公路的高清視頻監(jiān)控提供一個設(shè)計方案。
本研究課題的高速公路高清視頻監(jiān)控系統(tǒng)采用TI公司的TMS320DM368,DM368是一款面向多媒體技術(shù)應(yīng)用的高性能芯片,功能強大,集成了ARM9、硬件編碼協(xié)處理引擎(HDVICP)、圖像處理子系統(tǒng)(VPSS)。DM368最高可以支持H.264編碼 1080P格式 30幀/s的速度。該處理器有I2C總線等外圍接口等,其中ARM9運行性能穩(wěn)定的Linux嵌入式操作系統(tǒng)[2]。
視頻監(jiān)控系統(tǒng)中實時時鐘控制的設(shè)計采用DM368的I2C總線接口,設(shè)計基于ARM9的I2C云臺電機,完成驅(qū)動程序設(shè)計和應(yīng)用程序設(shè)計,以及應(yīng)用程序控制RX-8025實時時鐘,應(yīng)用于視頻監(jiān)控系統(tǒng)中,達到全方位的高速公路視頻監(jiān)控。
RX-8025是一種具有高精度,包括32.768 kHz晶振時鐘I2C總線接口的實時時鐘芯片,該芯片提供的功能有6個中斷,2個系統(tǒng)鬧鐘功能、電源電壓監(jiān)測和數(shù)字時鐘精度調(diào)節(jié)功能來滿足不同精度要求,其中計時功能可以進行至陽歷二位數(shù)和年、月、日、時、分、秒為止的數(shù)據(jù)設(shè)定,包括計時和讀取,當(dāng)陽歷的下二位數(shù)為4的倍數(shù)時,可自動識別至2099年。因此RX-8025適用于高清視頻監(jiān)控的嵌入式系統(tǒng),用于計時同步[5]。
SCL:I2C通信用的串行時鐘輸入,與時鐘信號同步,SDA SDA:與I2C通信串行時鐘同步,進行地址、數(shù)據(jù)、應(yīng)答等的輸入輸出。
圖1 RX-8025內(nèi)部時鐘信號圖Fig.1 Internal clock signal of RX-8025
FOUT:由FOE控制的32.768 kHZ時鐘輸出端;
FOE:控制FOUT輸出時鐘信號的輸入腳內(nèi)置,當(dāng)它接高電平時,F(xiàn)OUT腳輸出時鐘信號;
RX-8025使用I2C和外圍芯片進行數(shù)據(jù)通信,因此,本系統(tǒng)中ARM9和RX-8025通信需要通過I2C總線,因此需要完成Linux在ARM9的I2C驅(qū)動。
I2C總線是由雙向數(shù)據(jù)線和時鐘線構(gòu)成的二線制串行總線,總線采用主從雙向通信,即總線上在某一時刻只有一個主設(shè)備總線上的其他設(shè)備都作為從設(shè)備,任何能夠進行發(fā)送和接收的設(shè)備都可以成為主設(shè)備,但是在同一時間內(nèi)只能有一個設(shè)備作為主設(shè)備,通常為處理器,其他器件作為從設(shè)備與主設(shè)備進行通信,采用唯一的I2C地址識別[5]。
圖2 I2c工作時序Fig.2 Working sequence of I2c
如圖2所示I2C的工作時序圖所示,I2C總線在傳送數(shù)據(jù)過程中使用了3種信號。1)開始信號:SCL為高電平時,SDA由高電平向低電平跳變,表示將要開始傳送數(shù)據(jù);2)應(yīng)答信號:從設(shè)備在接收到1個字節(jié)數(shù)據(jù)后向主設(shè)備發(fā)出一個低電平脈沖應(yīng)答信號,表示已收到數(shù)據(jù),主設(shè)備根據(jù)從設(shè)備的應(yīng)答信號做出是否繼續(xù)傳輸數(shù)據(jù)的操作;3)結(jié)束信號:為低電平時由低電平向高電平跳變,表示數(shù)據(jù)傳送結(jié)束[4-5]。
總線具體的通信工作原理:主設(shè)備首先發(fā)出開始信號,接著發(fā)送的1個字節(jié)的數(shù)據(jù),其由高7位地址碼和最低1位方向位組成。系統(tǒng)中所有從設(shè)備將自己的地址與主設(shè)備發(fā)送到總線上的地址進行比較,如果從設(shè)備地址與總線上的地址相同,該設(shè)備就是與主設(shè)備進行數(shù)據(jù)傳輸?shù)脑O(shè)備。接著進行數(shù)據(jù)傳輸,根據(jù)方向位,主設(shè)備接收從設(shè)備數(shù)據(jù)或發(fā)送數(shù)據(jù)到從設(shè)備。當(dāng)數(shù)據(jù)傳送完成后,主設(shè)備發(fā)出一個停止信號,釋放I2C總線,然后所有從設(shè)備等待下一個開始信號的到來[4-5]。
I2C由主設(shè)備和從設(shè)備構(gòu)成,通信上通過識別I2C地址進行通信,即可以存在多個i2c adapter適配器和多個外設(shè)i2c device,Linux的I2C驅(qū)動采用分層設(shè)計實現(xiàn)的思想,層與層之間不存在耦合,增加adapter和增加device不會影響其他驅(qū)動,具體分層如下。
第一層:提供i2c adapter的硬件驅(qū)動,探測、初始化i2c adapter(如申請I2C地址和中斷號),驅(qū)動處理器控制的i2c adapter在硬件上產(chǎn)生信號(開始、停止、應(yīng)答)以及處理i2c中斷,涉及圖2中的硬件實現(xiàn)層;
第二層:提供i2c adapter的algorithm,用具體適配器的函數(shù)來填充i2c_algorithm的master_xfer函數(shù)指針,并把賦值后的i2c_algorithm,再賦值給i2c_adapter的成員指針,主要涉及圖2中訪問抽象層、i2c核心層;
第三層:實現(xiàn)i2c設(shè)備驅(qū)動中的i2c_driver接口,用具體的 i2c device 設(shè)備的 i2c_add_driver()、i2c_del_driver()方法賦值給i2c_driver的成員函數(shù)指針,采用Probe探尋方式實現(xiàn)設(shè)備device與總線的掛接,涉及圖2中的driver驅(qū)動層,此層是本文實現(xiàn)的驅(qū)動部分;
第四層:實現(xiàn)i2c設(shè)備所對應(yīng)的具體device的驅(qū)動,i2c_driver只是實現(xiàn)設(shè)備與總線的掛接,掛接在總線上的設(shè)備千差萬別的,所以要實現(xiàn)具體設(shè)備device的write()、read()、ioctl()等方法,賦值給file_operations,然后注冊字符設(shè)備,涉及圖2中的driver驅(qū)動層,此層是本文實現(xiàn)的驅(qū)動部分。
第一層和第二層又叫i2c總線驅(qū)動(bus driver),第三層和第四層屬于i2c設(shè)備驅(qū)動(device driver)。在Linux驅(qū)動架構(gòu)中,不需要再開發(fā)總線驅(qū)動,因為Linux內(nèi)核幾乎集成所有總線驅(qū)動,驅(qū)動設(shè)計主要是實現(xiàn)第三層和第四層的設(shè)備驅(qū)動。
圖3 I2c驅(qū)動架構(gòu)圖Fig.3 Driven architecture of I2c
Linux中的I2C驅(qū)動分層設(shè)計涉及了多個數(shù)據(jù)結(jié)構(gòu),數(shù)據(jù)結(jié)構(gòu)的設(shè)計在I2C分層設(shè)計中起了非常重要的作用,數(shù)據(jù)結(jié)構(gòu)有i2c_driver、i2c_client、i2c_adapter,下面具體分析這三個數(shù)據(jù)結(jié)構(gòu)之間的關(guān)系。
1)i2c_driver與i2c_client
i2c_driver對應(yīng)Linux的一種驅(qū)動方法,它不對應(yīng)于任何的物理實體。
i2c_client對應(yīng)于真實的物理設(shè)備,每個I2C設(shè)備都需要一個 i2c_client來描述,i2c_client代表一個掛載到I2C總線上的I2C從設(shè)備,該設(shè)備所需要的數(shù)據(jù)結(jié)構(gòu),包括該I2C從設(shè)備所依附的I2C主設(shè)備i2c_adapter,I2C從設(shè)備的驅(qū)動程序i2c_driver,作為i2c從設(shè)備所通用的成員變量;
struct i2c_client{
unsigned shortaddr; /* chip address -NOTE:7bit */
struct i2c_adapter*adapter;/*該i2c從設(shè)備所依附的i2c主設(shè)備*/
struct i2c_driver*driver;/*該i2c從設(shè)備的驅(qū)動程序*/
intusage_count; /*目前掛接I2C從設(shè)備的數(shù)量 */
struct device dev; /*該i2c從設(shè)備驅(qū)動所特有的數(shù)據(jù)*/
struct list_head list;/*鏈表*/
char name[I2C_NAME_SIZE];/**/
}
i2c_driver與 i2c_client發(fā)生關(guān)聯(lián)的時刻在 i2c_driver的attach_adapter()函數(shù)被運行時,attach_adapter()會探測物理設(shè)備,當(dāng)確定一個I2C從設(shè)備存在時,把該 client使用的i2c_client數(shù)據(jù)結(jié)構(gòu)的 adapter指針指向?qū)?yīng)的i2c_adapter。
2)i2c_adpater與i2c_client
i2c_adpater與 i2c_client的關(guān)系與 I2C硬件體系中適配器和設(shè)備的關(guān)系一致,即 i2c_client依附于 i2c_adpater,一個i2c_adpater上可以連接多個 I2C設(shè)備,i2c_adpater中包括依附于它的i2c_client的鏈表。
3)結(jié)構(gòu)體i2c_msg解析
i2c_msg用于I2C驅(qū)動第三層和第二層的數(shù)據(jù)交換,i2c_transfer通過調(diào)用master_xfer函數(shù)傳遞i2c_msg結(jié)構(gòu)體,結(jié)構(gòu)體包括成員變量有設(shè)備地址addr,消息長度len和消息數(shù)據(jù)buf以及讀寫標(biāo)志的宏定義,具體如下:
struct i2c_msg{
__u16 addr;/*設(shè)備地址*/
__u16 flags;/*標(biāo)志 */
__u16 len;?/*消息長度*/
__u8*buf;?/*消息數(shù)據(jù)*/
#define I2C_M_TEN 0x10 /*we have Aten bit chip address */
#define I2C_M_RD 0x01
#define I2C_M_NOSTART 0x4000
#define I2C_M_REV_DIR_ADDR 0x2000
#define I2C_M_IGNORE_NAK 0x1000
#define I2C_M_NO_RD_ACK 0x0800};
根據(jù)Linux2.6.32的驅(qū)動分層設(shè)計[3,5,7],驅(qū)動的第一層和第二層在Linux-2.6.32中以及集成了成熟驅(qū)動,文中重點講述第三層和第四層驅(qū)動程序的設(shè)計。
驅(qū)動設(shè)計采用字符設(shè)備方式來實現(xiàn),RX8025_I2C_Init()和RX8025_I2C_Exit()實現(xiàn)驅(qū)動的初始化以及退出,初始化最后調(diào)用cdev_add()實現(xiàn)字符設(shè)備的添加,添加過程中通過完善file_operations的結(jié)構(gòu)體,填充了以下4個結(jié)構(gòu)體變量。
Struct file_operations i2c_dev_ops={
.open=RX8025_Open,
.close=RX8025_Close,
.read=RX8025_Read,
.write=RX8025_Write
};
這4個用戶空間接口驅(qū)動函數(shù),完成注冊后,用戶空間可以采用文件讀寫的方式來操作I2C設(shè)備了,RX8025_Open函數(shù)實現(xiàn)打開實時時鐘字符設(shè)備,RX8025_Close函數(shù)實現(xiàn)關(guān)閉實時時鐘字符設(shè)備,數(shù)據(jù)交換通過接口RX8025_Read和RX8025_Write來實現(xiàn),主要實現(xiàn)設(shè)備的數(shù)據(jù)讀取和數(shù)據(jù)寫入,從而完成用戶空間和驅(qū)動程序以及硬件設(shè)備的數(shù)據(jù)交換,i2c_board_info結(jié)構(gòu)體中,“RX8025-i2c” 定義為 RX8025的I2C名字,0x32為RX8025的地址,該數(shù)據(jù)結(jié)構(gòu)的填充在Board-dm368-evm.c文件,Board-dm368-evm.c文件包含了大部分驅(qū)動的數(shù)據(jù)信息,系統(tǒng)啟動會自動加載相關(guān)驅(qū)動信息。一個i2c_client就代表著一個位于adapter適配器上,地址為client->addr,使用設(shè)備驅(qū)動的一個i2c設(shè)備。
static struct i2c_board_info i2c_info[]={
{I2C_BOARD_INFO("RX8025-i2c",0x32),
},};
本設(shè)計主要完整時鐘數(shù)據(jù)的讀取,用于同步到系統(tǒng)中,因此重點實現(xiàn)RX8025_Read接口函數(shù),RX8025_Read利用i2c_transfer函數(shù)調(diào)用master_xfer實現(xiàn)時鐘數(shù)據(jù)的讀取,具體實現(xiàn)過程如圖4所示,其中i2c_probe和RX8025_Read實現(xiàn)部分代碼如下:
struct i2c_client*rx8025_client=NULL;
static int i2c_probe(struct i2c_client*client, const struct i2c_device_id*id){……
rx8025_client=client;……}
int I2C_read (struct file*file,unsigned char*buffer,unsigned char count){
client=( struct i2c_client*)file->private_data;for(i=0;i msg->addr=((client->addr)>>1); msg->flags=0; msg->len =1; msg->buf=data; data[0] =reg[i]; err=i2c_transfer(client->adapter,msg,1);}//end of for } 圖4 RX8025_Read驅(qū)動的實現(xiàn)過程Fig.4 Driven implementation process of RX8025_read 根據(jù)I2C驅(qū)動程序設(shè)計[7],要正確調(diào)用驅(qū)動程序,需要實現(xiàn)驅(qū)動的用戶空間調(diào)用函數(shù),主要是實現(xiàn)open、read和write等函數(shù),因此在應(yīng)用層的接口函數(shù)中也需要實現(xiàn)此函數(shù)。 i2c_Init()函數(shù)實現(xiàn)open函數(shù),調(diào)用驅(qū)動函數(shù)打開該設(shè)備驅(qū)動,定義一個數(shù)據(jù)結(jié)構(gòu)體為: int Rx_8025(){ fd_rx8025=open(I2C_RX8025_NAME,O_RDWR);if(fd_rx8025<0) { printf("open/dev/rx8025_i2c error!"); return-1; } return 0; } 設(shè)備通過open函數(shù)正確打開后,就能通過讀寫函數(shù)進行數(shù)據(jù)交換了,該結(jié)構(gòu)體主要用來實現(xiàn)用戶空間和內(nèi)核空間的調(diào)用的數(shù)據(jù)交換,下面通過read數(shù)據(jù)讀取函數(shù)說明具體的實現(xiàn)過程,其中buf用于保存讀取數(shù)據(jù),count用于讀取數(shù)據(jù)的字節(jié)數(shù)。 int RX8025_read(uint8_t*buf,uint8_t count){ unsigned char ret ret=read(fd_rx8025,buf,count);if(status<0) printf("RX8025 read error!
"); return reg;} 如圖5所示,可以通過人機交互設(shè)置實時時鐘或讀取實時時鐘、同步系統(tǒng)時鐘,調(diào)用setTime()和synTime()接口函數(shù)來調(diào)用write()和read()文件IO讀寫文件,最終調(diào)用write()和read()的字符驅(qū)動函數(shù)實現(xiàn)對I2C驅(qū)動的調(diào)用。 圖5 云臺電機控制應(yīng)用程序設(shè)計圖Fig.5 Application design of PTZmotor control 實時時鐘在本系統(tǒng)中有兩個功能,一是通過QT圖形界面軟件輸入時間信息來設(shè)置實時時鐘的時間,可以在界面年月日時分秒信息,通過調(diào)用應(yīng)用程序函數(shù)達到時間設(shè)置的目的,二是從而帶動視頻監(jiān)控的攝像頭朝不同方位轉(zhuǎn)動以及定位,如圖所示。根據(jù)協(xié)議,應(yīng)用程序設(shè)計主要實現(xiàn)以下操作: 1)設(shè)置當(dāng)前的時鐘信息,函數(shù)接口為setTime(); 2)同步實時時鐘的時鐘信息到系統(tǒng),函數(shù)接口為synTime(); 下面通過時鐘同步函數(shù)的接口函數(shù)synTime(),詳細RX8025實時時鐘應(yīng)用程序接口函數(shù)的實現(xiàn)過程,通過調(diào)用用戶空間和內(nèi)核空間的read()函數(shù)實現(xiàn)對驅(qū)動的調(diào)用,最終通過I2C總線設(shè)置時鐘和讀取時鐘數(shù)據(jù)。 通過實現(xiàn)人機交互操作程序,實現(xiàn)設(shè)置當(dāng)前的時鐘信息和同步實時時鐘的時鐘信息到系統(tǒng),通過調(diào)用相應(yīng)的接口函數(shù),實現(xiàn)對I2C應(yīng)用程序的調(diào)用,最后通過read、write函數(shù)實現(xiàn)對RX-8025的控制,具體實現(xiàn)如圖5所示。 本系統(tǒng)設(shè)計實現(xiàn)了一款基于TMS320DM368的高清視頻監(jiān)控系統(tǒng)中的實時時鐘系統(tǒng)控制設(shè)計,完成了實時時鐘RX8025的I2C驅(qū)動程序的分析以及設(shè)計,并且完成了i2c應(yīng)用程序的設(shè)計和實時時鐘RX8025控制應(yīng)用程序設(shè)計,達到了應(yīng)用目的。 [1]張志.高速公路高清視頻監(jiān)控系統(tǒng)的構(gòu)建[J].中國交通信息化,2011(4):99-102.ZHANG Zhi.Construction of the highway high-definition video surveillance system[J].China ITSJoural,2011(4):99-102. [2]Texas Instruments Incorporated.TMS320DM368 digitalmedia sys-tem-on-Chip(DMSoC).[EB/OL](2014-03)http://www.ti.com/lit/ds/sym link/tms320dm368.pdf. [3]TMS320DM36x Digital Media System-on-Chip(DMSoC)Inter-Integrated Circuit(I2C)Module User's Guide[EB/OL].[2014-03].http://software-dl.ti.com/dsps/dsps_public_sw/sdo_sb/targetcontent/dvsdk/DVSDK_4_00/latest/index_FDS.html. [4]高非非.ARM-Linux中I2C總線驅(qū)動開發(fā)[J].微型機與應(yīng)用,2012(5):57-58.GAO Fei-fei.Design of I2C bus driver based on ARM-Linux[J].Network and Comunication,2012(5):57-58. [5]Philips Corp.The I2C-BUSSpecification Version 2.1[Z],2000. [6]Real time clock module RX-8025SA/NB applicationmannual[M].EPSON Toyocom,2002. [7]Jonahan Corbet.Linux device drivers[M].北京:中國電力出版社,2006.4 RX8025實時時鐘I2C應(yīng)用程序設(shè)計
5 RX8025實時時鐘應(yīng)用程序設(shè)計
6 結(jié)束語