張 鵬 郭 芹
[摘要]介紹RTLinux下的設備驅(qū)動模型,以PCI接口的CAN卡為例詳細描述了RTLinux下開發(fā)設備驅(qū)動程序的一般方法。并通過RTLinux與Linux下設備驅(qū)動程序開發(fā)過程的對比,描述兩者的異同,給出將Linux下設備驅(qū)動源碼更改為RTLinux設備驅(qū)動的方法。
[關(guān)鍵詞]RTLinux 設備驅(qū)動 CAN
中圖分類號:TP3文獻標識碼:A文章編號:1671-7597(2009)0520006-02
一、引言
在飛行器控制、機器人控制、數(shù)控加工等應用場合,傳統(tǒng)的Windows、
Linux等桌面操作系統(tǒng)已不能滿足這種高實時性的應用需求,越來越多的控制器開始采用實時操作系統(tǒng)。RTLinux是一個源碼開放的實時操作系統(tǒng),得到了廣泛的應用。對于采用RTLinux作為控制系統(tǒng)軟件開發(fā)平臺的設計者來說,所面臨的一大問題是設備廠商一般不會提供設備在RTLinux下的驅(qū)動程序,需要用戶自行開發(fā)。如何開發(fā)RTLinux下的設備驅(qū)動程序,為RTLinux下的實時應用程序提供操作接口,成為我們利用RTLinux開發(fā)控制系統(tǒng)首先要解決的問題。有些情況下設備廠商會提供Linux下驅(qū)動源碼,我們又該如何將其修改后應用到RTLinux平臺上。CAN總線是工業(yè)控制中應用十分廣泛一種現(xiàn)場總線,CAN接口卡也是在實時控制經(jīng)常用到的典型設備。本文結(jié)合PCI接口CAN控制器的驅(qū)動設計實例,詳細介紹RTLinux下設備驅(qū)動程序的開發(fā)步驟,并與Linux下設備驅(qū)動程序的開發(fā)做出對比。
二、RTLinux設備驅(qū)動程序結(jié)構(gòu)
RTLinux是在Linux的基礎上對進程調(diào)度、中斷處理等方面進行了改進,保證了系統(tǒng)的實時性,使實時任務能在限定的時間內(nèi)得到響應。在RTLinux中,設備驅(qū)動程序是以模塊的形式存在于內(nèi)核中的,用戶通過insmod命令將驅(qū)動模塊載入內(nèi)核。RTLinux提供了符合POSIX標準的設備驅(qū)動設計方式,其設計方法與Linux下設備驅(qū)動程序的開發(fā)類似。所有的設備在RTLinux中都被當作一個文件來看待,所有對設備的操作都可以通過對設備文件進行操作來完成。Linux中的I/O子系統(tǒng)向內(nèi)核中的其他部分提供了統(tǒng)一標準的設備接口file_operations,在RTLinux中,系統(tǒng)提供了類似的接口rtl_file_operations。在驅(qū)動程序初始化時通過rtl_register_chrde
v()對設備進行注冊,這樣當用戶在實時線程中通過open,release,ioctl等標準POSIX I/O接口函數(shù)對設備進行操作時,RTLinux內(nèi)核將會通過rtl_file_operations結(jié)構(gòu)訪問驅(qū)動程序提供的函數(shù)。同樣在RTLinux的rtl_posixio.h中提供了rtl_unregister_chrdev(),rtl_request_irq(),
rtl_free_irq()等與Linux驅(qū)動程序設計相關(guān)操作對應的函數(shù)。但RTLinux設備驅(qū)動程序在開發(fā)時與Linux下的驅(qū)動程序開發(fā)也有很多不同之處,主要包括以下幾點:
1.在RTLinux下用rtl_regiser_chrdev()注冊設備驅(qū)動程序時,是為運行在RTLinux內(nèi)核空間的實時線程提供接口,而不是對用戶空間的程序提供文件系統(tǒng)接口,用戶也不需要根據(jù)注冊的設備號用mknod創(chuàng)建設備節(jié)點。
2.在Linux中,用戶程序與設備驅(qū)動程序分別運行于用戶空間和內(nèi)核空間,驅(qū)動程序在與用戶程序交換數(shù)據(jù)時需要用到copy_from_user(),copy_to_user()等函數(shù)。而在RTLinux中,實時線程與設備驅(qū)動共同運行在內(nèi)核空間,共享同一內(nèi)存空間,他們之間的數(shù)據(jù)交換可以直接使用memcpy之類的函數(shù)來實現(xiàn)。
3.在RTLinux中,有軟中斷和硬中斷之分。所謂軟中斷就是指一般的Linux內(nèi)核中斷,它的優(yōu)點在于可以無限制的使用Linux的內(nèi)核調(diào)用。而硬中斷是直接來自硬件的中斷,有非常短的中斷延遲。對于實時驅(qū)動程序而言,我們?yōu)榱吮WC實時性必須及時響應硬中斷,可以通過rtl_request_irq
()安裝中斷處理程序,并通過rtl_hard_enable_irq()使能中斷。
在下面的CAN接口卡驅(qū)動程序的設計實例中,我們會對這幾個方面做詳細的說明。
三、CAN接口卡的設備驅(qū)動程序設計
(一)CAN卡的硬件結(jié)構(gòu)
CAN總線是一種在汽車電子和工業(yè)控制中得到廣泛應用的現(xiàn)場總線。CAN接口卡擴展了PC設備的CAN接口,實現(xiàn)了PC與其他設備通過CAN總線進行通信。本文中使用的CAN卡為PCI接口的CAN控制器,用來擴展PC機上的CAN接口,實現(xiàn)PC機端CAN數(shù)據(jù)的收發(fā),其硬件結(jié)構(gòu)框圖如下圖1所示。
PCI9052是PLX公司的PCI總線從模式接口芯片,用來把對PCI總線上的操作轉(zhuǎn)換為對局部總線的操作,93LC46是一串行EEPROM,用來存儲初始化信息。SJA1000是PHILIPS公司的CAN總線控制器,它封裝了CAN2.0通訊協(xié)議,功能強大,方便易用。82C250為CAN總線收發(fā)器件,提供對總線的差動發(fā)送能力和對CAN控制器的差動接收能力。
(二)驅(qū)動程序的開發(fā)步驟
我們開發(fā)CAN卡RTLinux下驅(qū)動程序的最終目的是提供能在實時線程調(diào)用的功能函數(shù),如發(fā)送、接收CAN消息、配置CAN網(wǎng)絡等,并提供統(tǒng)一、標準的操作接口。而這些功能的實現(xiàn)是通過對CAN控制芯片SJA1000內(nèi)部寄存器的操作來完成的。這就需要我們首先得到這些寄存器的映射地址,然后對相應功能需要的讀寫操作進行封裝。我們采用的是Linux 2.4.20內(nèi)核,RTLinux的版本為rtlinux-3.2-rc1,驅(qū)動程序的開發(fā)主要有以下步驟:
1.獲取PCI設備的資源配置信息。這一步的操作與Linux下PCI設備驅(qū)動程序的開發(fā)完全一致。當驅(qū)動程序訪問PCI設備的時候,它的內(nèi)存和I/O區(qū)域已經(jīng)被映射到了處理器的地址空間。我們所要做的就是得到這個設備結(jié)構(gòu)指針。Linux內(nèi)核中提供了相應的結(jié)構(gòu)和函數(shù)用來得到設備的資源配置信息。在驅(qū)動程序的初始化階段,我們利用函數(shù)struct pci_dev * pci_
find_device(unsigned int vendor, unsigned int device, struct pci_dev *from)來尋找PCI設備。參數(shù)vendor和device是由設備廠商指定的,并存儲在EEPROM中。當找到設備后,該函數(shù)會返回一個pci_dev結(jié)構(gòu)類型的指針,根據(jù)該結(jié)構(gòu)中resource有關(guān)的域我們就可以得到設備的基地址、中斷號等信息。在接下來的設計中,我們就可以根據(jù)此基地址得到SJA1000內(nèi)部各寄存器的地址,進行相應的I/O操作。
2.注冊中斷處理函數(shù)。由于CAN卡在接收數(shù)據(jù)時必須與系統(tǒng)以中斷的方式交換數(shù)據(jù),而且在發(fā)送數(shù)據(jù)時,當遇到發(fā)送緩沖器忙的時候也需要根據(jù)發(fā)送完成產(chǎn)生的中斷來確定何時發(fā)送下一幀數(shù)據(jù),所以在CAN卡的驅(qū)動程序中我們要注冊中斷處理函數(shù)。為了確保響應硬件中斷的實時性,RTLinux內(nèi)核對Linux的中斷處理做了改進,在硬件中斷控制器和Linux內(nèi)核之間用一層軟中斷模擬器進行隔離,避免了由于Linux關(guān)中斷造成的系統(tǒng)在一段時間內(nèi)無法響應中斷的情況。在RTLinux中我們通過函數(shù)int rtl_requ
est_irq(unsigned int irq, void(*handler)(void))來注冊硬中斷。第一個參數(shù)為設備的中斷號,這個我們在第一步的操作中已經(jīng)得到,第二個參數(shù)就是中斷處理函數(shù)的指針。這里我們定義了函數(shù)CAN_ interrupt_handle
r()。在中斷服務程序中,我們要對發(fā)送和接收中斷分別做出處理,其程序流程如下圖2所示。
3.定義并實現(xiàn)設備操作接口。為了實現(xiàn)在RTLinux的實時線程中通過標準POSIX I/O函數(shù)(如read、write等)對設備進行操作,我們在驅(qū)動程序中定義自己的rtl_file_operation結(jié)構(gòu):
struct rtl_file_operationsrtl_can_fops = {
read: CAN_read, //從CAN總線讀取數(shù)據(jù)
write: CAN_write, //向CAN總線發(fā)送數(shù)據(jù)
ioctl: CAN_ioctl, //對指定寄存器進行操作,實現(xiàn)配置功能
open: CAN_open, //打開設備
close: CAN_close //釋放設備
};
在驅(qū)動程序的入口函數(shù)init_module()中我們通過int rtl_register
_chrdev(unsigned int major, const char* name, struct rtl_file_operations *fops)來注冊設備驅(qū)動程序,第一個參數(shù)為主設備號,第二個參數(shù)為設備名稱,我們?nèi) ?dev/can”,第三個參數(shù)fops即為rtl_can_fops。這樣當我們用open()等POSIX I/O函數(shù)對設備/dev/can進行操作時,rtl_file_operations中對應的CAN_open()等將會執(zhí)行。我們分別定義了函數(shù)CAN_read(),CAN_write(),CAN_ioctl()來完成CAN卡的數(shù)據(jù)接收、發(fā)送和配置功能,函數(shù)的實現(xiàn)就是對相應寄存器進行操作,并與調(diào)用它的實時應用程序交換數(shù)據(jù)。限于篇幅,我們這里不對寄存器級的編程做詳細的介紹。需要注意的是,調(diào)用驅(qū)動程序的實時應用程序和驅(qū)動程序運行于同一地址空間。以int CAN_write(struct rtl_file *filp, cons
t char *buf, size_t count, loff_t* ppos)為例,我們在程序中可以直接對用戶程序傳過來的指針buf指向的內(nèi)存空間進行操作,而不必像在Linux驅(qū)動程序中一樣,用copy_from_user()獲取用戶空間的數(shù)據(jù)。
四、結(jié)束語
RTLinux是性能優(yōu)越的實時多任務操作系統(tǒng),是構(gòu)建實時控制系統(tǒng)的理想平臺,而RTLinux設備驅(qū)動程序是連接實時應用程序與硬件設備的橋梁。本文詳細介紹了在RTLinux下CAN接口卡驅(qū)動程序的開發(fā)過程,并將其應用于一機器人控制系統(tǒng)。實踐證明,該驅(qū)動程序具有良好的實時性和穩(wěn)定性,機器人達到了快速、平穩(wěn)的控制效果。鑒于RTLinux高實時性及源碼開放的特點,其會在工業(yè)控制及其它領域具有更廣泛的應用前景。
參考文獻:
[1]FSM Labs,Geting Started with RTLinux.http://www.fsmlabs.com,2
001.04.20.
[2]Corbet,J.等著,魏永明、耿岳、鐘書毅譯,Linux設備驅(qū)動程序[M].北京:中國電力出版社,2006.
作者簡介:
張鵬(1977-),男,山東水利職業(yè)學院教師,碩士,主要研究方向軟件工程;郭芹(1981-),女,山東水利職業(yè)學院教師,碩士,主要研究方向計算機圖像處理。