史小燕,朱建鴻
(江南大學 物聯網工程學院,無錫 214122)
控制器局部網(CAN-CONTROLLER AREA NETWORK)是BOSCH公司推出的一種多主機局部網[1].它是一種非常有效的分布式控制串行通信網絡,并且具有傳輸速度快、可靠性高、通信方式靈活等特點,因此在工業控制現場被廣泛應用[2].CAN總線工作時要求通訊雙方波特率一致,實現CAN波特率自適應將有效提高CAN總線的靈活性和使用效率.本文實現了一種基于嵌入式Linux的波特率自適應方法,該方法通過融合直接測量法和波特率表輪詢法來加快波特率的配適速度;同時,加入波特率優先級的概念,保存用戶選擇數據并將其利用到波特率初始值設置中,增加了一次性命中正確波特率的概率.
硬件平臺采用三星S3C2410芯片作為系統微控制器.CAN總線規范定義了OSI模型的數據鏈路層和物理層.這兩層通常由CAN總線控制器和CAN總線收發器實現[3].本文CAN總線控制器和收發器分別采用Microchip的MCP2510和Philips的P82C50,二者通過SPI總線實現與控制器的數據傳輸.
S3C241X系列是由Samsung公司設計生產的低功耗,高集成微處理器芯片,能夠對WINCE,EPOC32,LINUX系統提供支持.芯片接口資源豐富,可通過SPI同步串行接口和MCP2510相連.MCP2510是帶有SPI接口的CAN總線控制器,支持回環、正常、監聽、睡眠、配置5種工作模式,滿足CAN總線使用需求.P82C50是Philips公司生產的can總線收發器,芯片作為CAN控制器與物理總線間的接口,提供對總線的差動發送和接收功能.當使用P82C50作為CAN收發器時,同一網絡中允許掛接110個節點.CAN收發器,控制器與微控制單元之間的關系如圖1所示.

圖1 CAN總線器件示意圖
Linux設備驅動是硬件設備和應用程序之間的接口,它為用戶提供了統一的設備訪問方式.Linux內核一般把驅動程序分為4種類型,而CAN總線設備屬于其中的字符型設備,它以設備文件的方式建立在文件系統中的/dev目錄下,并且可以像文件一樣被訪問[4].
Linux下設備驅動程序可以以模塊的形式動態的加載和卸載,字符設備驅動程序一般包含5個部分:頭文件、file_operation結構體變量、中斷函數、加載函數以及卸載函數.file_operation結構體變量存儲驅動內核模塊提供的對設備進行各種操作的函數的指針,該結構體的每個域都對應著驅動內核模塊用來處理某個被請求的事務的函數的地址.<linux/fs.h>對file_operations數據結構中各個變量做了詳細定義[5].當用戶調用如open(),read()等API接口時,系統將參數傳遞給file_operation結構體的成員函數,最終獲得參數實控權的將是系統調用函數.
加載函數以及卸載函數為驅動提供了動態使用模式,系統通過調用module_init()來加載驅動,通過調用module_exit()來卸載驅動.module_exit()只在動態編譯時有意義,因為靜態加載時驅動已經被編譯進內核,無法進行卸載.
中斷函數即中斷服務程序,它響應系統中斷并作出相應的處理.本文所設計的波特率自適應方式就是通過中斷服務程序來實現.Linux中斷處理程序可以分為上半部和下半部[6].上部中斷處理緊急中斷任務,它應該盡量短小簡單以便程序能迅速處理完中斷并及時返回.底部中斷用來處理較長的非緊急任務,linux2.6版本內核提供了三種底部中斷處理方式:softirq、tasklet和work queue.tasklet和softirq都是基于軟中斷機制實現,而work queue則是依靠內核線程實現.這三種處理方式各有優缺點,如果專注性能提高應使用softirq,對底部中斷處理的調度有特殊要求則必須使用work queue,除此之外,最優選擇tasklet處理方式.
CAN波特率自適應的一般方法有兩種:輪詢法和探測法.本方案將結合這兩種常用檢測法來設計自適應CAN驅動.
輪詢法即將常用波特率記錄進一張波特率輪詢表中,然后將測試波特率按序填入CAN驅動,通過判斷能否正確接收CAN數據幀決定是否進行下一次輪詢.
探測法即對接收數據進行采樣,通過采樣數據來獲得正確波特率.由于CAN波特率有一定容錯空間,所以當MCU自帶捕捉功能時,即使采樣波特率有一定誤差,很大程度上也能獲得正確波特率.
這兩種方法各有利弊,前者可以保證在波特率表范圍內找到正確值,但因為要對數據依次輪詢,所以往往耗時較長.后者雖然時耗短,但對設備有特殊要求,且如果偏差值超過波特率容錯范圍,則會造成無法獲得正確波特率的錯誤.基于此本文將兩種方法相結合,實現一種平均耗時短、匹配成功率高的波特率自適應CAN驅動.
MCP2510是一款獨立CAN控制器,它的存在大大降低了軟件開發的難度.MCP2510具有8個中斷源,寄存器CANINTE是中斷使能寄存器,它包含了各個中斷源的中斷使能位;寄存器CANINTF是中斷標志寄存器,它包含了各個中斷源的中斷標志位.寄存器各個位設置如表1所示.

表1 中斷寄存器CANINTE,CANINTF
Bit0–Bit1:接收中斷位.MCP2510有兩個接收緩沖寄存器,緩存器0和緩存器1,驅動將接收數據讀入這兩個寄存器再傳遞進用戶層.在這兩個位使能的情況下,若RX0IF置位,則緩存器0已滿;若RX1IF置位則緩存器1已滿.
Bit2–Bit4:發送中斷位.MCP2510有三個發送緩存器,緩存器0,1和2.在這三個位使能的情況下,若TX0IF置位,則發送緩存器0是空;以此類推.
Bit5–Bit6:錯誤中斷位和喚醒總線活動位.
Bit7:報文錯誤中斷位.如果報文發送和接收過程中發生錯誤,將觸發該位中斷.該中斷功能在與監聽模式聯用時被用來加快波特率的確定.
MCP2510提供五種工作模式:配置模式,正常模式,睡眠模式,監聽模式,回環模式.這五種模式通過設置CANTCRL寄存器的值來切換,其中波特率必須在配置模式下才能成功設置;CAN總線的通信運行在正常模式下;監聽模式僅接受數據幀而不能發送數據,應該在該模式下進行波特率自適應.
本文所使用的硬件平臺將外部中斷4作為CAN專用中斷引腳,SPI 總線將差分信號傳輸到 MCU 的外部中斷引腳,驅動對該中斷做出一系列響應從而得到傳輸數據.首先對MCP2510 的CANINIE進行設置,使能中斷.當信號來臨時會根據相應中斷對中斷標志寄存器進行設置,在中斷服務程序中讀取CANINIF寄存器的值并進行判斷,完成中斷響應.通訊雙方波特率相匹配時,中斷服務程序將會設置工作模式為正常模式并接收數據;波特率設置有誤時,中斷服務程序將會設置工作模式為正常模式并進入波特率自適應階段.
在波特率自適應階段,驅動首先對數據進行采樣以獲得預判波特率.中斷觸發方式有邊沿觸發和電平觸發,邊緣觸發分為高電平觸發和低電平觸發.驅動中可調用set_irq_type函數對觸發方式進行設置,do_gettimeofday函數可在高低電平觸發時分別獲得一個當前時間值.do_gettimeofday是系統函數,用戶層函數gettimeofday實際調用的便是該函數,它可以實現微秒級的時間獲取.將獲得的當前時間與前一次獲得的時間相減并不斷比較可獲得一個最小時間差Tmin.由于CAN總線采用反向不歸零編碼(NRZ),該種編碼方式采用位填充的方法確保至少每6位時間發生一次跳變,即Tmin可以是實際碼元長度的1–5倍.從提高驅動效率的角度出發,實際出現長時間不跳變的情況較少,所以本文僅考慮Tmin就是實際碼元長度的情況.
獲得預判波特率以后即使用該波特率進行測試,若再次進入報文錯誤中斷,則依據該波特率所在位置對其周圍波特率進行左右輪詢直至波特率最終匹配成功.波特率自適應流程圖如圖2.

圖2 CAN波特率自適應流程圖
當產生報文錯誤中斷后,首先獲取波特率預測值并對該波特率進行測試.該預測值往往有一定的誤差,將波特率表中的各值之間的中間值作為判定該值的邊界,可使獲得的波特率歸束到波特率表中存在的值中.若再次進入報文錯誤中斷,則進行波特率輪詢.確定該波特率在波特率表中的位置,根據錯誤計數值的奇偶性向左右兩個方向進行輪詢,即一回合向左,下一回合向右.若一方先達到邊界值,則專注向另一方向輪詢直至找到正確值.輪詢部分交由Linux底部中斷完成.波特率匹配成功后進入接收中斷,對CANINIF寄存器的接收緩存標志位進行問詢,若緩存器0,1有空閑空間,則讀取數據;若緩存器滿,則喚醒等待隊列,將數據傳遞到用戶層.在中斷服務程序執行完畢后,需要手動清除中斷標志位,否則中斷會一直響應陷入死循環.清除中斷標志位最好使用按位清除的方式,以防未被響應的中斷標志被一并清除.
CAN波特率的設置與距離有關,波特率越高,能夠穩定通信的距離越短.即在距離一定的情況下,往往波特率的設置區間也受到了一定的限制.CAN總線在不同波特率下允許的最大通訊距離是:6.7 km(10 Kbps)、1.3 km(50 Kbps)、620 m(100 Kbps)、530 m(125 Kbps)、270 m(250 Kbps)、130 m(500 Kbps)、40 m(1Mbps)[7].在CAN驅動中,波特率初值固定地設置為波特率表的第一個值,這對于波特率自適應來說是一種資源的浪費.基于此,本文將用戶使用頻率的影響添進波特率初始值的設置,增加了一次碰撞即可獲得正確波特率的概率,提高了波特率匹配效率.
用戶數據需要具有能夠反復讀取、即使驅動關閉也能繼續存留數據的功能,因此僅將其作為變量寫入驅動是不夠的.在本方法中用戶數據被寫入文件,在驅動打開時讀入數據,接收中斷里進行優先級判定,驅動關閉時保存數據.驅動層調用讀寫程序之前需要使用set_fs()函數對內核空間進行保護.
用戶數據中保存一個二維數組,該數組放置了波特率表中的各波特率及其所屬優先級,程序每進入一次接受中斷,證明該次波特率匹配成功,對該波特率進行判斷并將其對應的優先級增加1,再進行排序后便可獲得一個新的波特率優先級表.該表存放在一個掉電不擦除的目錄下,每次初始化時讀取到驅動中的數組里,使用后在關閉驅動時原路保存.
本設計方案為用戶設定了16個常見波特率,滿足一般情況下的通訊需求.通過實驗平臺串口調試功能檢測驅動運行情況,驅動初始化階段打印優先級信息,userlist是波特率枚舉值,priority為對應優先級信息.用戶層運行CAN數據收發程序,進入波特率調試階段,驅動首先獲得波特率探測值再根據該值進行輪詢.
圖3首先以十六進制形式向ARM開發板發送一組隨機數據AA 76 07 54 65 34 53 55,成功匹配波特率后順利接收;然后ARM端向PC端發送如圖4所示三組數據.
圖4接收數據為ASSIC碼轉換而成.經過測試,本文所設計CAN驅動匹配時間基本維持在3秒以內,而僅使用輪訓方式匹配波特率會有首尾波特率輪詢時間差距大的情況出現,如文獻[6]中波特率自適應時間從4 s到12 s時間不等.且本設計增加了用戶選擇頻率的影響,當所設置波特率為常用波特率時,有很大幾率會一次命中正確波特率.在實際實驗中,當用戶優先級第一的波特率被選中時,匹配時間會被縮短到1 s以內,驅動能夠在毫秒級時間內完成波特率匹配,這進一步提高了波特率匹配效率.

圖3 驅動匹配測試圖

圖4 驅動數據收發測試圖
本文在對CAN驅動結構進行分析的基礎上設計了一款可以實現CAN波特率自適應的驅動.以S3C2410微處理器為主控制器、MCP2510芯片為CAN控制器的嵌入式設備為實驗硬件平臺.設計方案融合了兩種常用波特率自適應方法并增加了用戶使用頻率對波特率自適應的影響,文章對這部分內容進行了詳細的解釋.經過實驗驗證了該方案比原本的方法耗時更短,該驅動正常工作時數據能正確傳輸.
1 馮軍,王耀南,劉宏立.Linux系統下CAN總線通信的設計及實現.微計算機信息,2008,24(32):71–72,81.[doi:10.3969/j.issn.1008-0570.2008.32.031]
2 田小剛,蔡啟仲,鄔軍偉.基于嵌入式Linux下CAN設備驅動程序設計.微計算機信息,2009,25(17):155–157.
3 黃輝,范霽月,張明.CAN總線接口設計與應用.輕工科技,2013,(1):61–62.
4 陳在平,許東輝.Linux下S3C2440微控制器的CAN驅動設計與實現.化工自動化及儀表,2011,38(8):985–988.
5 張雪松,王鴻磊,徐釗.嵌入式Linux2.6內核的CAN驅動設計與實現.計算機工程與設計,2010,31(15):3396–3398,3426.
6 曾祥文,宋樹祥,賓相邦.嵌入式Linux下波特率自適應的CAN總線驅動的實現.測控技術,2015,34(8):104–107.
7 謝云山,楊安種,龔建宇,等.自適應CAN總線波特率轉換器設計.自動化與儀器儀表,2013,(5):62–63.