基于MCP2515的多路CAN總線接口及驅(qū)動程序設(shè)計
3 驅(qū)動程序設(shè)計
本文引用地址:http://m.butianyuan.cn/article/82980.htm驅(qū)動程序是應(yīng)用程序與硬件之間的中間軟件層,它完全隱蔽了設(shè)備工作的細節(jié)。Linux操作系統(tǒng)根據(jù)設(shè)備中信息傳送方式的不同,將設(shè)備分成3種類型:字符設(shè)備、塊設(shè)備和網(wǎng)絡(luò)設(shè)備。9200與MCP2515的通信都是通過SPI接口以字節(jié)為單位進行的,因此MCP2515屬于字符設(shè)備。由于5個MCP2515共享9200的一個SPI接口,因此采用一個驅(qū)動程序來管理所有的MCP2515,這樣做有利于對所有設(shè)備進行統(tǒng)一管理。
3.1 驅(qū)動程序中定義的主要數(shù)據(jù)結(jié)構(gòu)
CAN總線通信是基于報文幀的,在驅(qū)動程序中,無論發(fā)送數(shù)據(jù)還是接收數(shù)據(jù)都是基于報文幀的操作,因此需要設(shè)計合適的數(shù)據(jù)結(jié)構(gòu)以滿足數(shù)據(jù)操作的需要。
3.1.1 接收與發(fā)送CAN報文幀結(jié)構(gòu)體
其中,node_num為MCP2515的節(jié)點號(0~4),id為CAN報文幀的標識符,dlc為數(shù)據(jù)長度(0~8),data為CAN報文幀的數(shù)據(jù)緩沖區(qū),ext_flag用于標識CAN報文幀是否為擴展幀,rtr_flag用于標識CAN報文幀是否為遠程幀。
3.1.2 設(shè)備配置結(jié)構(gòu)體
(1)波特率和報文濾波配置結(jié)構(gòu)體
其中,node_num為MCP2515的節(jié)點號(0~4),baudrate為CAN總線通信速率,filter為報文濾波配置結(jié)構(gòu),br_flag用于標識波特率配置是否有效,fi_flag用于標識報文濾波配置是否有效。baudrate和filter的數(shù)據(jù)結(jié)構(gòu)類型定義如下:
(2)工作模式配置結(jié)構(gòu)體
其中,node_num意義同上,oper_mode表示該節(jié)點的工作模式。MCP2515共有5種工作模式,分別是配置模式、休眠模式、僅監(jiān)聽模式、回環(huán)模式和正常模式。一般設(shè)備都工作在正常模式。
3.1.3 環(huán)形數(shù)據(jù)接收緩沖區(qū)結(jié)構(gòu)體
其中,can_recv_buf為接收CAN報文幀環(huán)形數(shù)據(jù)緩沖區(qū),recv_pos和read_pos分別表示數(shù)據(jù)存入和讀出緩沖區(qū)的位置;wq定義的是一個等待隊列,用于實現(xiàn)阻塞型read操作。
3.2 驅(qū)動程序接口
驅(qū)動程序的接口主要分為3個部分:初始化與退出函數(shù)接口,完成設(shè)備安裝和卸載等操作;文件系統(tǒng)接口,由file_operations數(shù)據(jù)結(jié)構(gòu)來完成;與設(shè)備的接口,完成對設(shè)備的讀/寫等操作。
3.2.1 初始化與退出函數(shù)
在安裝驅(qū)動程序時,操作系統(tǒng)會調(diào)用初始化函數(shù)進行設(shè)備注冊、設(shè)備初始化以及安裝中斷處理例程等操作。參考文獻[3]詳細論述了設(shè)備注冊的方法,而這里主要討論設(shè)備初始化時的配置方法。在本驅(qū)動程序中,設(shè)備初始化分兩步:一是對9200的SPI控制器初始化,二是對5個MCP2515初始化。
在卸載設(shè)備驅(qū)動程序時會調(diào)用退出函數(shù),退出函數(shù)主要完成設(shè)備的注銷和中斷釋放。
參考文獻[3]詳細論述了中斷處理例程的安裝、設(shè)備注銷和中斷釋放的方法,此處不再詳述。
3.2.2 中斷接收服務(wù)例程
MCP2515收到CAN報文幀后,產(chǎn)生中斷并將INT引腳置低。9200響應(yīng)外部中斷,并調(diào)用和外部中斷相對應(yīng)的中斷處理例程。中斷處理例程共有3個: at91_mcp2515_irq_handler_0響應(yīng)IRQ0的中斷, at91_mcp2515_irq_handler_1_2響應(yīng)IRQ1的中斷, at91_mcp2515_irq_handler_3_4響應(yīng)IRQ2的中斷。其中IRQ0只和一個MCP2515相連,而IRQ1和IRQ2分別被兩個MCP2515所共享。IRQ0和IRQ1的中斷處理流程分別如圖5和圖6所示,IRQ2與IRQ1的中斷處理流程相同。
需要注意的是,在圖5的處理流程中并沒有清中斷操作。這是因為采用了RX讀緩沖區(qū)指令讀取MCP2515RX緩沖區(qū)中的數(shù)據(jù)。該指令操作結(jié)束后,MCP2515會自動清除相應(yīng)的接收中斷標志位。
3.2.3 文件系統(tǒng)接口定義
文件系統(tǒng)接口struct file_operations的成員全部是函數(shù)指針,這些指針指出了設(shè)備驅(qū)動程序所提供的入口點位置。本驅(qū)動程序所定義的file_operations為:
3.2.4 ioctl函數(shù)
ioctl函數(shù)用于對設(shè)備進行配置。我們在ioctl函數(shù)中實現(xiàn)了兩個命令:IOCTRL_CONFIG_CAN_DEV用于配置節(jié)點的CAN總線波特率和報文濾波,IOCTRL_SET_OPER_MODE用于配置節(jié)點的工作模式。這兩種配置命令所對應(yīng)的配置參數(shù)都是指向應(yīng)用層相應(yīng)數(shù)據(jù)結(jié)構(gòu)的指針,兩個配置結(jié)構(gòu)在3.1.2小節(jié)已經(jīng)介紹過了。
用IOCTRL_CONFIG_CAN_DEV命令配置波特率和報文濾波時,在配置完成后,如果節(jié)點處于INACTIVE狀態(tài),則需要使能節(jié)點內(nèi)部的接收中斷,使能節(jié)點所對應(yīng)的外部中斷,并將節(jié)點狀態(tài)設(shè)置為ACTIVE。在通常情況下,通過ioctl函數(shù)對需要配置的節(jié)點執(zhí)行完IOCTRL_CONFIG_CAN_DEV命令后,還要再對配置過的節(jié)點執(zhí)行IOCTRL_SET_OPER_MODE命令,使節(jié)點處于正常的工作模式。
3.2.5 關(guān)于競爭問題
本系統(tǒng)是單CPU系統(tǒng),采用Linux 2.4.19內(nèi)核,且是非搶占式的;同時,此設(shè)計的驅(qū)動程序也只允許一個進程打開并操作該設(shè)備。在這種情況下,驅(qū)動程序中所涉及的競爭問題主要就是中斷處理程序內(nèi)核代碼和其他設(shè)備操作的內(nèi)核代碼之間的資源競爭。在上文中所提到的所有設(shè)備操作中,都要通過9200的SPI接口與MCP2515進行通信。9200與MCP2515進行通信都是以命令字節(jié)開始的,并且在一個命令操作過程中(一般會連續(xù)傳輸多個字節(jié)),片選和時鐘是不能被禁用的,否則操作就會失敗。因此,MCP2515的一個完整的命令操作就是一個臨界區(qū)域,在對MCP2515進行一個命令操作的過程中必須禁用所有的中斷,以保證命令操作的正常執(zhí)行。在驅(qū)動程序中,采用local_irq_save和local_irq_restore函數(shù)對中斷禁用和恢復(fù),在這兩個函數(shù)調(diào)用之間,就是對MCP2515執(zhí)行一個命令操作的代碼。
結(jié) 語
本文針對特有的應(yīng)用需求提出的多路CAN總線接口和驅(qū)動程序設(shè)計,經(jīng)過測試,可以穩(wěn)定正常地運行。關(guān)于驅(qū)動程序的編譯和運行方法,參考文獻[3]有很好的說明。上層的測試程序編寫也比較簡單,但要注意數(shù)據(jù)結(jié)構(gòu)的定義和底層驅(qū)動程序的一致性。本文側(cè)重介紹設(shè)計的基本方法和實現(xiàn)基本的功能。MCP2515本身提供了許多的功能,在實現(xiàn)基本功能的基礎(chǔ)上,也可以根據(jù)自己的應(yīng)用需要再進行功能擴展。
評論