尹加豹,朱 濤,崔凱華
(江蘇自動化研究所,江蘇 連云港 222061)
控制器局域網(Controller Area Network,CAN)總線是一種多主機半雙工異步串行通信總線,具有實時性好、抗干擾性強、數據傳輸率高和成本低等優(yōu)點,是應用最廣泛的現場總線之一[1]。VxWorks系統(tǒng)在眾多嵌入式實時操作系統(tǒng)中具有強大的競爭力和非常重要的地位,在通信、航空航天、軍工等領域具有廣泛應用[2]。VxWorks系統(tǒng)下的CAN總線通信應用于各行各業(yè),在多種硬件平臺上都有成熟的設計方案。文獻[3]介紹了基于SPARC V8架構的S698系列處理器內CAN模塊的驅動設計方法,文獻[4-5]給出ARM及X86平臺獨立CAN控制器驅動的設計及優(yōu)化方法,上述CAN驅動都是基于國外先進處理器設計,且CAN通道路數在兩路以內。由于在國內一些關鍵領域,需要使用自主可控的硬件方案,在一些特殊領域,甚至需要使用多達數十路CAN通道,因此現有的驅動設計方案無法滿足應用要求。
本文在龍芯3A3000主板上研究開發(fā)CAN總線驅動程序,龍芯系列處理器是自主化程度最高的國產處理器,其中,3A3000/3B3000采用28 nm工藝制造,配置為單節(jié)點4核,工作主頻為1.2 GHz~1.5 GHz[6]。在MIPS平臺上,基于VxWorks系統(tǒng)的CAN驅動研究成果甚少,在龍芯3A3000主板上進行多板多通道CAN通信時,CAN驅動程序的中斷頻率過高、運行效率較低,且CAN板之間未進行故障隔離。針對上述問題,本文在發(fā)送、接收及設備創(chuàng)建等環(huán)節(jié)進行了一系列優(yōu)化設計,以提高系統(tǒng)的運行效率和健壯性。
CAN通信板共有8路獨立的CAN總線接口,其硬件結構主要由6個部分構成,分別為CPCI總線接口單元、PCI橋接單元、FPGA可編程邏輯單元、電平轉換單元、CAN總線單元以及供電單元,其組成及原理框圖如圖1所示。
圖1 CAN通信板組成及原理框圖
由圖1可知,CAN總線單元主要由CAN總線控制器、高速光隔離器、CAN總線收發(fā)器構成。CAN總線控制器選用SJA1000T,該芯片具有BasicCAN和PeliCAN兩種工作模式[7],其中,PeliCAN模式支持CAN2.0B協(xié)議,本文使用PeliCAN模式[8]。
驅動程序用于控制某個硬件完成其固有功能,它直接與硬件設備交互,主要操作就是配置硬件相關寄存器,驅動程序作為接口層,對上要匹配操作系統(tǒng)提供的一套規(guī)范接口,對下要驅動硬件設備完成工作[9]。
在VxWorks操作系統(tǒng)中,大部分設備使用文件方式進行管理,應用程序通過I/O請求訪問設備文件,進而操作對應的硬件設備,系統(tǒng)將應用程序的I/O請求傳遞給設備專用的I/O函數,而驅動程序的主要作用就是為這些設備提供專用的I/O函數[10]。具體的過程依靠3張表,即文件描述表、設備列表與驅動程序列表實現。
VxWorks操作系統(tǒng)的所有驅動程序的入口函數地址均由驅動程序列表負責維護,驅動程序列表中的每一行對應一個設備驅動程序,每行包含7列,對應7個函數指針,這些函數就是要實現的設備驅動程序,當設備執(zhí)行 creat、delete、open、close、read、write和ioctl函數時,需回調對應的驅動函數。VxWorks系統(tǒng)通過iosDrvInstall函數將驅動程序的函數入口地址注冊到驅動程序列表中, iosDrvInstall函數定義如下:
int iosDrvInstall(FUNCPTR create,FUNCPTR remove,FUNCPTR open,FUNCPTR close,FUNCPTR read,FUNCPTR write,FUNCPTR ioctl)。
在驅動程序中,每一個設備都有一個數據結構,被稱為設備描述符,用于存儲相關數據。每個設備的設備描述符都有一個結構相同的起始部分,即設備頭數據結構,I/O系統(tǒng)通過設備頭將所有設備描述符鏈接在一起構成設備列表。驅動程序通過iosDevAdd函數創(chuàng)建設備,并在設備列表中新建節(jié)點,iosDevAdd函數定義如下:
int iosDevAdd(DEV_HDR * p_hdr,const char * dev_name,int drv_num)。
以打開設備為例,驅動程序的工作流程如圖2所示[11]。
圖2 驅動程序的工作流程
VxWorks下CAN驅動的設計工作主要包括I/O接口函數設計、中斷處理函數設計、驅動初始化函數設計和設備創(chuàng)建函數[12]設計。
I/O接口函數需要實現can_open、can_close、can_read、can_write和can_ioctl 5個函數。創(chuàng)建CAN設備結構體,針對SJA1000T控制器設計的結構體如下:
typedef struct {
DEV_HDR can_hdr;/*設備頭*/
BOOL opened;/*打開標識*/
MSG_Q_ID msg_id;/*消息隊列*/
unsigned char index; /*通道序號*/
unsigned char mode; /*濾波方式*/
unsigned long baudrate;/*波特率*/
unsigned long acc_code;/*接收代碼值*/
unsigned long acc_mask;/*接收屏蔽值*/
}CAN_DEV;
I/O接口函數設計包括以下5個部分:
1)can_open函數設計
函數原型為int can_open (DEV_HDR *dev,int option,int flags),主要用于配置CAN控制器為工作模式,并執(zhí)行一些配置操作,最后返回設備結構體指針[13]。
2)can_close函數設計
函數原型為int can_close (DEV_HDR *dev),主要用于配置CAN控制器為復位模式,并清除一些狀態(tài)參數。
3)can_read函數設計
函數原型為int can_read (int dev_id,char *pBuf,int nBytes),主要用于接收總線上的CAN數據幀,SJA1000T收到CAN幀后會提起中斷,中斷處理程序接收CAN幀并發(fā)送到消息隊列,can_read則直接讀取消息隊列,若消息隊列中有數據則讀取至緩沖區(qū),若無數據則進行阻塞。
4)can_write函數設計
函數原型為int can_write (int dev_id,char *pBuf,int nBytes),主要用于向總線發(fā)送CAN數據幀,為降低通信板提起的中斷頻率,SJA1000T的發(fā)送中斷被禁用,改用查詢方式,發(fā)送先前查詢SJA1000T狀態(tài)寄存器的發(fā)送緩沖器狀態(tài),若為釋放狀態(tài)則立即發(fā)送CAN幀,若為鎖定狀態(tài)則循環(huán)判斷狀態(tài),直至超時返回。具體發(fā)送流程如圖3所示。
圖3 函數的發(fā)送流程
5)can_ioctl函數設計
函數原型為int can_ioctl(int dev_id,int cmd,int arg),主要用于配置CAN通道參數,如波特率、濾波方式及參數等。
VxWorks作為一個嵌入式實時操作系統(tǒng),采用中斷的方式來滿足系統(tǒng)實時性要求,中斷服務程序的高效執(zhí)行至關重要[14]。SJA1000T有多種中斷類型,包括發(fā)送中斷、接收中斷、錯誤報警中斷、數據溢出中斷、總線錯誤中斷等[15]。中斷處理函數首先判斷中斷狀態(tài)再進行相應處理,CAN通信板的8個SJA1000T芯片共享一個中斷號,中斷方式為低電平中斷。對于接收中斷,在釋放完SJA1000T接收緩沖器中的CAN幀后會自動清除中斷。
龍芯3A3000主板的板級支持包在設計時將所有外部中斷都路由到一個CPU,其外部中斷過多,導致系統(tǒng)運行效率降低[16]。為降低CAN通信板的中斷頻率,禁用發(fā)送中斷,僅使用錯誤報警中斷和接收中斷并對中斷處理函數進行優(yōu)化。當接收到數據后,中斷處理函數對CAN通信板的8個SJA1000T芯片的狀態(tài)寄存器進行遍歷查詢,若發(fā)現接收緩沖區(qū)有數據則接收這些數據,優(yōu)化后的處理流程如圖4所示。
圖4 優(yōu)化后的中斷處理流程
驅動初始化函數的主要工作是調用iosDrvInstall函數,將can_open、can_close、can_read、can_write和can_ioctl函數注冊到驅動程序列表中[17]。在此之前,要先確定系統(tǒng)正常工作時每一塊CAN通信板的PCI總線信息,并為其分配通道號,本文系統(tǒng)共有3塊CAN通信板、24路CAN通道,PCI總線信息和通道分配如表 1所示。
表1 CAN通信板PCI總線信息及通道分配
Table 1 PCI bus information and channel allocation of CAN bus board
板號PCI總線信息busdevfunc通道號0111300~71111408~1521115016~23
驅動初始化函數,通過pciFindDevice函數查找所有的CAN通信板[18],并將其PCI總線信息與表 1信息進行對比,以確定每個通信板的狀態(tài),具體代碼如下:
STATUS can_drv (void)
{
int i,j;
if (can_drv_num>0)/*驅動程序已安裝*/
return OK;
/*查找CAN板*/
for(i=0;(OK == pciFindDevice(VENDER_ID,DEVICE_ID,i,&bus,&slot,&func)) && (i<3);i++)
{
for(j=0;j<3;j++)
{/*查找該CAN板對應的板號并進行標記*/
if((pci_bus_info[i].bus == bus) && (pci_bus_info[i].slot == slot) && (pci_bus_info[i].func == func))
can_board_found[i] = TRUE;
}
}
/*將驅動程序添加到驅動程序描述表中*/
if((can_drv_num = iosDrvInstall(can_open,(FUNCPTR)NULL,can_open,can_close,can_read,can_write,can_ioctl)) == ERROR)
return ERROR;
return OK;
}
CAN驅動的設備創(chuàng)建函數的輸入參數為設備名和通道號。該函數首先要判斷該通道號對應的CAN通信板是否存在,若存在則初始化該CAN通道并調用iosDevAdd函數,將CAN設備添加到設備列表中[19],具體代碼如下:
STATUS can_dev_create(char * name,int i)
{
if((name==NULL) || (i < 0) || (i > 23) || (can_dev_created[i]==TRUE))
return ERROR;
/*判斷該通道號對應的CAN通信板是否存在*/
if(can_board_found[i/8] == FALSE)
return ERROR;
p_can_dev[i] = (CAN_DEV*)malloc (sizeof(CAN_DEV));
…
/*初始化SJA1000T,并將其添加到設備列表*/
if((SJA1000T_init(p_can_dev[i],i) == ERROR) || (iosDevAdd(& p_can_dev[i]->can_hdr,name,can_drv_num) == NULL))
{
free((char*)p_can_dev[i]);
return ERROR;
}
can_dev_created[i] = TRUE;
return OK;
}
本文在龍芯3A3000主板上對CAN通信板進行測試,測試內容包括CAN總線并行工作時CAN幀的傳輸效率和驅動程序的健壯性。
傳輸效率主要通過CAN幀的收發(fā)速度和中斷的提起頻率進行衡量。計算機系統(tǒng)運行期間,各個模塊均占用系統(tǒng)資源,若各模塊中斷頻率過高,會使系統(tǒng)性能下降,甚至造成系統(tǒng)“假死機”[20]。通過優(yōu)化,在高速通信時,CAN通信板的中斷頻率顯著下降,具體結果見表2。
表2 CAN通信板傳輸效率對比
Table 2 Comparison of transmission efficiency of CAN communication board
板號波特率/103Baud傳輸速度/(幀·s-1·通道-1)中斷頻率/(次·s-1)優(yōu)化前優(yōu)化后1502003 2001 60021255007 9962 038325080012 8003 19445001 00015 0833 99551 0002 00020 6184 182
驅動程序健壯性主要是測試部分CAN板異常時系統(tǒng)的運行情況,具體方法是任意拔下1~2塊CAN通信板,造成CAN通信板異常。以第1號CAN通信板異常為例,驅動程序優(yōu)化前后的通道號分配如表3所示。優(yōu)化前,第1號板卡異常,使得第2號板卡的CAN通道號變?yōu)?~15,在使用過程中可能會造成嚴重后果;優(yōu)化后,第1號板卡異常不可用,但第0號和第2號板卡可正常使用,異常板卡被成功隔離。
表3 1號CAN通信板損壞后的通道號對比
Table 3 Comparison of channel numbers after the CAN communication board No.1 is damaged
板號PCI信息通道號busdevfunc優(yōu)化前優(yōu)化后0111300~70~71111402111508~1516~23
測試結果表明,針對CAN接收中斷進行優(yōu)化后,有效降低了高速通信時系統(tǒng)的中斷頻率,提高了系統(tǒng)性能。針對多通信板進行的優(yōu)化能夠有效隔離問題板卡,提高系統(tǒng)的健壯性,保證計算機系統(tǒng)穩(wěn)定可靠運行。
本文以龍芯3A3000主板為硬件平臺,在VxWorks系統(tǒng)下提出一種CAN控制器驅動的設計與優(yōu)化方案。在初始化時,使用PCI信息標記各個模塊,在發(fā)送環(huán)節(jié),使用查詢方式進行發(fā)送,并通過對所有通道進行查詢遍歷來接收數據。實驗結果表明,該驅動程序工作穩(wěn)定,性能可靠。本文主要針對龍芯3A3000主板進行設計和優(yōu)化,下一步將把優(yōu)化方案推廣到2K1000等其他龍芯主板上,拓展其應用范圍。