CAN協議簡介
CAN 是控制器局域網絡(Controller Area Network)的簡稱, 它是由研發和生產汽車電子產品著稱的德國 BOSCH 公司開發的,並最終成為國際標准(ISO11519) , 是國際上應用最廣泛的現場總線之一。
CAN 總線協議已經成為汽車計算機控制系統和嵌入式工業控制局域網的標准總線,並且擁有以 CAN 為底層協議專為大型貨車和重工機械車輛設計的 J1939 協議。近年來, 它具有的高可靠性和良好的錯誤檢測能力受到重視,被廣泛應用於汽車計算機控制系統和環境溫度惡劣、電磁輻射強及振動大的工業環境。
CAN物理層
與 I2C、 SPI 等具有時鍾信號的同步通訊方式不同, CAN 通訊並不是以時鍾信號來進行同步的,它是一種異步通訊,只具有 CAN_High 和 CAN_Low 兩條信號線,共同構成一組差分信號線,以差分信號的形式進行通訊。
- 閉環總線網絡
CAN 物理層的形式主要有兩種, 圖 43-1 中的 CAN 通訊網絡是一種遵循 ISO11898 標准的高速、短距離“閉環網絡”,它的總線最大長度為 40m,通信速度最高為 1Mbps,總線的兩端各要求有一個“120 歐”的電阻。
- 開環總線網絡
圖 43-2 中的是遵循 ISO11519-2 標准的低速、遠距離“開環網絡”,它的最大傳輸距離為 1km,最高通訊速率為 125kbps,兩根總線是獨立的、不形成閉環,要求每根總線上各串聯有一個“2.2 千歐”的電阻。
- 通訊節點
從 CAN 通訊網絡圖可了解到, CAN 總線上可以掛載多個通訊節點,節點之間的信號經過總線傳輸,實現節點間通訊。由於 CAN 通訊協議不對節點進行地址編碼,而是對數據內容進行編碼的,所以網絡中的節點個數理論上不受限制,只要總線的負載足夠即可,可以通過中繼器增強負載。
CAN 通訊節點由一個 CAN 控制器及 CAN 收發器組成,控制器與收發器之間通過CAN_Tx 及 CAN_Rx 信號線相連,收發器與 CAN 總線之間使用 CAN_High 及 CAN_Low信號線相連。其中 CAN_Tx 及 CAN_Rx 使用普通的類似 TTL 邏輯信號,而 CAN_High 及CAN_Low 是一對差分信號線,使用比較特別的差分信號,下一小節再詳細說明。
當 CAN 節點需要發送數據時, 控制器把要發送的二進制編碼通過 CAN_Tx 線發送到收發器,然后由收發器把這個普通的邏輯電平信號轉化成差分信號,通過差分線CAN_High 和 CAN_Low 線輸出到 CAN 總線網絡。而通過收發器接收總線上的數據到控制器時,則是相反的過程,收發器把總線上收到的 CAN_High 及 CAN_Low 信號轉化成普通的邏輯電平信號,通過 CAN_Rx 輸出到控制器中。
例如, STM32 的 CAN 片上外設就是通訊節點中的控制器,為了構成完整的節點,還要給它外接一個收發器,在我們實驗板中使用型號為 TJA1050 的芯片作為 CAN 收發器。CAN 控制器與 CAN 收發器的關系如同 TTL 串口與 MAX3232 電平轉換芯片的關系,MAX3232 芯片把 TTL 電平的串口信號轉換成 RS-232 電平的串口信號, CAN 收發器的作用則是把 CAN 控制器的 TTL 電平信號轉換成差分信號(或者相反)。
- 差分信號
差分信號又稱差模信號,與傳統使用單根信號線電壓表示邏輯的方式有區別,使用差分信號傳輸時,需要兩根信號線,這兩個信號線的振幅相等,相位相反,通過兩根信號線的電壓差值來表示邏輯 0 和邏輯 1。見圖 43-3,它使用了 V+與 V-信號的差值表達出了圖下方的信號。
相對於單信號線傳輸的方式,使用差分信號傳輸具有如下優點:
抗干擾能力強,當外界存在噪聲干擾時,幾乎會同時耦合到兩條信號線上,而接收端只關心兩個信號的差值,所以外界的共模噪聲可以被完全抵消。
能有效抑制它對外部的電磁干擾,同樣的道理,由於兩根信號的極性相反,他們對外輻射的電磁場可以相互抵消,耦合的越緊密,泄放到外界的電磁能量越少。
時序定位精確, 由於差分信號的開關變化是位於兩個信號的交點,而不像普通單端信號依靠高低兩個閾值電壓判斷,因而受工藝,溫度的影響小,能降低時序上的誤差,同時也更適合於低幅度信號的電路。
由於差分信號線具有這些優點,所以在 USB 協議、 485 協議、以太網協議及 CAN 協議的物理層中,都使用了差分信號傳輸。
- CAN 協議中的差分信號
CAN 協議中對它使用的 CAN_High 及 CAN_Low 表示的差分信號做了規定,見表 43-1及圖 43-4。以高速 CAN 協議為例,當表示邏輯 1 時(隱性電平), CAN_High 和 CAN_Low線上的電壓均為 2.5v,即它們的電壓差 VH-VL=0V;而表示邏輯 0 時(顯性電平),CAN_High 的電平為 3.5V, CAN_Low 線的電平為 1.5V,即它們的電壓差為 VH-VL=2V。例如,當 CAN 收發器從 CAN_Tx 線接收到來自 CAN 控制器的低電平信號時(邏輯 0),它會使 CAN_High 輸出 3.5V,同時 CAN_Low 輸出 1.5V,從而輸出顯性電平表示邏輯 0。
在 CAN 總線中,必須使它處於隱性電平(邏輯 1)或顯性電平(邏輯 0)中的其中一個狀態。假如有兩個 CAN 通訊節點,在同一時間,一個輸出隱性電平,另一個輸出顯性電平,類似 I2C 總線的“線與”特性將使它處於顯性電平狀態,顯性電平的名字就是這樣來的, 即可以認為顯性具有優先的意味。
由於 CAN 總線協議的物理層只有 1 對差分線,在一個時刻只能表示一個信號,所以對通訊節點來說, CAN 通訊是半雙工的,收發數據需要分時進行。在 CAN 的通訊網絡中,因為共用總線,在整個網絡中同一時刻只能有一個通訊節點發送信號,其余的節點在該時刻都只能接收。
協議層
以上是 CAN 的物理層標准,約定了電氣特性,以下介紹的協議層則規定了通訊邏輯。
- CAN 的波特率及位同步
由於 CAN 屬於異步通訊,沒有時鍾信號線,連接在同一個總線網絡中的各個節點會像串口異步通訊那樣,節點間使用約定好的波特率進行通訊,特別地, CAN 還會使用“位同步” 的方式來抗干擾、吸收誤差,實現對總線電平信號進行正確的采樣,確保通訊正常。
位時序分解
為了實現位同步, CAN 協議把每一個數據位的時序分解成如圖 43-5 所示的 SS 段、PTS 段、 PBS1 段、 PBS2 段,這四段的長度加起來即為一個 CAN 數據位的長度。分解后最小的時間單位是 Tq,而一個完整的位由 8~25 個 Tq 組成。為方便表示, 圖 43-5 中的高低電平直接代表信號邏輯 0 或邏輯 1(不是差分信號)。
該圖中表示的 CAN 通訊信號每一個數據位的長度為 19Tq,其中 SS 段占 1Tq, PTS 段占 6Tq, PBS1 段占 5Tq, PBS2 段占 7Tq。信號的采樣點位於 PBS1 段與 PBS2 段之間,通過控制各段的長度,可以對采樣點的位置進行偏移,以便准確地采樣。
各段的作用如介紹下:
SS 段(SYNC SEG)
SS 譯為同步段, 若通訊節點檢測到總線上信號的跳變沿被包含在 SS 段的范圍之內,則表示節點與總線的時序是同步的,當節點與總線同步時,采樣點采集到的總線電平即可被確定為該位的電平。 SS 段的大小固定為 1Tq。
PTS 段(PROP SEG)
PTS 譯為傳播時間段,這個時間段是用於補償網絡的物理延時時間。 是總線上輸入比較器延時和輸出驅動器延時總和的兩倍。 PTS 段的大小可以為 1~8Tq。
PBS1 段(PHASE SEG1),PBS1 譯為相位緩沖段,主要用來補償邊沿階段的誤差,它的時間長度在重新同步的時候可以加長。 PBS1 段的初始大小可以為 1~8Tq。
PBS2 段(PHASE SEG2)
PBS2 這是另一個相位緩沖段,也是用來補償邊沿階段誤差的,它的時間長度在重新同步時可以縮短。 PBS2 段的初始大小可以為 2~8Tq。
通訊的波特率
總線上的各個通訊節點只要約定好 1 個 Tq 的時間長度以及每一個數據位占據多少個Tq,就可以確定 CAN 通訊的波特率。
例如,假設上圖中的 1Tq=1us,而每個數據位由 19 個 Tq 組成,則傳輸一位數據需要時間 T1bit =19us,從而每秒可以傳輸的數據位個數為:
1x106/19 = 52631.6 (bps)
這個每秒可傳輸的數據位的個數即為通訊中的波特率。
同步過程分析
波特率只是約定了每個數據位的長度,數據同步還涉及到相位的細節,這個時候就需要用到數據位內的 SS、 PTS、 PBS1 及 PBS2 段了。
根據對段的應用方式差異, CAN 的數據同步分為硬同步和重新同步。其中硬同步只是當存在“幀起始信號”時起作用,無法確保后續一連串的位時序都是同步的,而重新同步方式可解決該問題,這兩種方式具體介紹如下:
(1) 硬同步
若某個 CAN 節點通過總線發送數據時,它會發送一個表示通訊起始的信號(即下一小節介紹的幀起始信號),該信號是一個由高變低的下降沿。而掛載到 CAN 總線上的通訊節點在不發送數據時,會時刻檢測總線上的信號。
見圖 43-6,可以看到當總線出現幀起始信號時,某節點檢測到總線的幀起始信號不在節點內部時序的 SS 段范圍,所以判斷它自己的內部時序與總線不同步,因而這個狀態的采樣點采集得的數據是不正確的。所以節點以硬同步的方式調整,把自己的位時序中的 SS段平移至總線出現下降沿的部分,獲得同步,同步后采樣點就可以采集得正確數據了。
(2) 重新同步
前面的硬同步只是當存在幀起始信號時才起作用,如果在一幀很長的數據內,節點信號與總線信號相位有偏移時,這種同步方式就無能為力了。因而需要引入重新同步方式,它利用普通數據位的高至低電平的跳變沿來同步(幀起始信號是特殊的跳變沿)。重新同步與硬同步方式相似的地方是它們都使用 SS 段來進行檢測,同步的目的都是使節點內的 SS段把跳變沿包含起來。
重新同步的方式分為超前和滯后兩種情況,以總線跳變沿與 SS 段的相對位置進行區分。第一種相位超前的情況如圖 43-7,節點從總線的邊沿跳變中,檢測到它內部的時序比總線的時序相對超前 2Tq,這時控制器在下一個位時序中的 PBS1 段增加 2Tq 的時間長度,使得節點與總線時序重新同步。
第二種相位滯后的情況如圖 43-8,節點從總線的邊沿跳變中,檢測到它的時序比總線的時序相對滯后 2Tq,這時控制器在前一個位時序中的 PBS2 段減少 2Tq 的時間長度,獲得同步。
在重新同步的時候, PBS1 和 PBS2 中增加或減少的這段時間長度被定義為“重新同步補償寬度 SJW (reSynchronization Jump Width)”。一般來說 CAN 控制器會限定 SJW 的最大值,如限定了最大 SJW=3Tq 時,單次同步調整的時候不能增加或減少超過 3Tq 的時間長度,若有需要,控制器會通過多次小幅度調整來實現同步。當控制器設置的 SJW 極限值較大時,可以吸收的誤差加大,但通訊的速度會下降。
- CAN 的報文種類及結構
在 SPI 通訊中, 片選、時鍾信號、數據輸入及數據輸出這 4 個信號都有單獨的信號線,I2C 協議包含有時鍾信號及數據信號 2 條信號線,異步串口包含接收與發送 2 條信號線,這些協議包含的信號都比 CAN 協議要豐富,它們能輕易進行數據同步或區分數據傳輸方向。而 CAN 使用的是兩條差分信號線,只能表達一個信號,簡潔的物理層決定了 CAN 必然要配上一套更復雜的協議,如何用一個信號通道實現同樣、甚至更強大的功能呢? CAN協議給出的解決方案是對數據、操作命令(如讀/寫)以及同步信號進行打包,打包后的這些內容稱為報文。
報文的種類
在原始數據段的前面加上傳輸起始標簽、片選(識別)標簽和控制標簽,在數據的尾段加上 CRC 校驗標簽、應答標簽和傳輸結束標簽,把這些內容按特定的格式打包好,就可以用一個通道表達各種信號了, 各種各樣的標簽就如同 SPI 中各種通道上的信號,起到了協同傳輸的作用。當整個數據包被傳輸到其它設備時,只要這些設備按格式去解讀,就能還原出原始數據,這樣的報文就被稱為 CAN 的“數據幀” 。
為了更有效地控制通訊, CAN 一共規定了 5 種類型的幀,它們的類型及用途說明如表43-2。
幀
|
幀用途
|
---|---|
數據幀
|
用於節點向外傳送數據
|
遙控幀
|
用於向遠端節點請求數據
|
錯誤幀
|
用於向遠端節點通知校驗錯誤,請求重新發送上一個數據
|
過載幀
|
用於通知遠端節點:本節點尚未做好接收准備
|
幀間隔
|
用於將數據幀及遙控幀與前面的幀分離開來
|
數據幀的結構
數據幀是在 CAN 通訊中最主要、最復雜的報文,我們來了解它的結構,見圖 43-9。
數據幀以一個顯性位(邏輯 0)開始,以 7 個連續的隱性位(邏輯 1)結束,在它們之間,分別有仲裁段、控制段、數據段、 CRC 段和 ACK 段
幀起始
SOF 段(Start Of Frame),譯為幀起始,幀起始信號只有一個數據位,是一個顯性電平,它用於通知各個節點將有數據傳輸,其它節點通過幀起始信號的電平跳變沿來進行硬同步。
仲裁段
當同時有兩個報文被發送時,總線會根據仲裁段的內容決定哪個數據包能被傳輸,這也是它名稱的由來。
仲裁段的內容主要為本數據幀的 ID 信息(標識符), 數據幀具有標准格式和擴展格式兩種,區別就在於 ID 信息的長度,標准格式的 ID 為 11 位,擴展格式的 ID 為 29 位,它在標准 ID 的基礎上多出 18 位。在 CAN 協議中, ID 起着重要的作用,它決定着數據幀發送的優先級,也決定着其它節點是否會接收這個數據幀。 CAN 協議不對掛載在它之上的節點分配優先級和地址,對總線的占有權是由信息的重要性決定的,即對於重要的信息,我們會給它打包上一個優先級高的 ID,使它能夠及時地發送出去。也正因為它這樣的優先級分配原則,使得 CAN 的擴展性大大加強,在總線上增加或減少節點並不影響其它設備。報文的優先級,是通過對 ID 的仲裁來確定的。根據前面對物理層的分析我們知道如果總線上同時出現顯性電平和隱性電平,總線的狀態會被置為顯性電平, CAN 正是利用這個特性進行仲裁。
若兩個節點同時競爭 CAN 總線的占有權,當它們發送報文時, 若首先出現隱性電平,則會失去對總線的占有權,進入接收狀態。見圖 43-10,在開始階段,兩個設備發送的電平一樣,所以它們一直繼續發送數據。到了圖中箭頭所指的時序處,節點單元 1 發送的為隱性電平,而此時節點單元 2 發送的為顯性電平,由於總線的“線與”特性使它表達出顯示電平,因此單元 2 競爭總線成功,這個報文得以被繼續發送出去。
仲裁段 ID 的優先級也影響着接收設備對報文的反應。因為在 CAN 總線上數據是以廣播的形式發送的,所有連接在 CAN 總線的節點都會收到所有其它節點發出的有效數據,因而我們的 CAN 控制器大多具有根據 ID 過濾報文的功能,它可以控制自己只接收某些 ID的報文。
回看圖 43-9 中的數據幀格式,可看到仲裁段除了報文 ID 外,還有 RTR、 IDE 和 SRR位。
(1) RTR 位(Remote Transmission Request Bit),譯作遠程傳輸請求位,它是用於區分數據幀和遙控幀的,當它為顯性電平時表示數據幀,隱性電平時表示遙控幀。
(2) IDE 位(Identifier Extension Bit),譯作標識符擴展位,它是用於區分標准格式與擴展格式,當它為顯性電平時表示標准格式,隱性電平時表示擴展格式。
(3) SRR 位(Substitute Remote Request Bit),只存在於擴展格式,它用於替代標准格式中的RTR 位。由於擴展幀中的 SRR 位為隱性位, RTR 在數據幀為顯性位,所以在兩個 ID相同的標准格式報文與擴展格式報文中,標准格式的優先級較高。
控制段
在控制段中的 r1 和 r0 為保留位,默認設置為顯性位。它最主要的是 DLC 段(Data Length Code),譯為數據長度碼,它由 4 個數據位組成,用於表示本報文中的數據段含有多少個字節, DLC 段表示的數字為 0~8。
數據段
數據段為數據幀的核心內容,它是節點要發送的原始信息,由 0~8 個字節組成, MSB先行。
CRC 段
為了保證報文的正確傳輸, CAN 的報文包含了一段 15 位的 CRC 校驗碼,一旦接收節點算出的 CRC 碼跟接收到的 CRC 碼不同, 則它會向發送節點反饋出錯信息,利用錯誤幀請求它重新發送。 CRC 部分的計算一般由 CAN 控制器硬件完成,出錯時的處理則由軟件控制最大重發數。
在 CRC 校驗碼之后,有一個 CRC 界定符,它為隱性位,主要作用是把 CRC 校驗碼與后面的 ACK 段間隔起來。
ACK 段
ACK 段包括一個 ACK 槽位,和 ACK 界定符位。類似 I2C 總線,在 ACK 槽位中,發送節點發送的是隱性位,而接收節點則在這一位中發送顯性位以示應答。在 ACK 槽和幀結束之間由 ACK 界定符間隔開。
幀結束
EOF 段(End Of Frame),譯為幀結束,幀結束段由發送節點發送的 7 個隱性位表示結束。
其它報文的結構
關於其它的 CAN 報文結構,不再展開講解,其主要內容見圖 43-11。
STM32的CAN外設簡介
STM32 的芯片中具有 bxCAN 控制器 (Basic Extended CAN), 它支持 CAN 協議 2.0A 和2.0B 標准。
該 CAN 控制器支持最高的通訊速率為 1Mb/s;可以自動地接收和發送 CAN 報文,支持使用標准 ID 和擴展 ID 的報文;外設中具有 3 個發送郵箱,發送報文的優先級可以使用軟件控制,還可以記錄發送的時間;具有 2 個 3 級深度的接收 FIFO,可使用過濾功能只接收或不接收某些 ID 號的報文;可配置成自動重發;不支持使用 DMA 進行數據收發。
STM32的CAN架構剖析
STM32 的有兩組 CAN 控制器,其中 CAN1 是主設備,框圖中的“存儲訪問控制器”是由 CAN1 控制的, CAN2 無法直接訪問存儲區域,所以使用 CAN2 的時候必須使能CAN1 外設的時鍾。框圖中主要包含 CAN 控制內核、發送郵箱、接收 FIFO 以及驗收篩選器,下面對框圖中的各個部分進行介。
- CAN 控制內核
框圖中標號1處的 CAN 控制內核包含了各種控制寄存器及狀態寄存器,我們主要講解其中的主控制寄存器 CAN_MCR 及位時序寄存器 CAN_BTR。
主控制寄存器 CAN_MCR
主控制寄存器 CAN_MCR 負責管理 CAN 的工作模式,它使用以下寄存器位實現控制。
(1) DBF 調試凍結功能
DBF(Debug freeze)調試凍結,使用它可設置 CAN 處於工作狀態或禁止收發的狀態,禁止收發時仍可訪問接收 FIFO 中的數據。這兩種狀態是當 STM32 芯片處於程序調試模式時才使用的,平時使用並不影響。
(2) TTCM 時間觸發模式
TTCM(Time triggered communication mode)時間觸發模式,它用於配置 CAN 的時間觸發通信模式,在此模式下, CAN 使用它內部定時器產生時間戳, 並把它保存在CAN_RDTxR、CAN_TDTxR 寄存器中。內部定時器在每個 CAN 位時間累加,在接收和發送的幀起始位被采樣,並生成時間戳。 利用它可以實現 ISO 11898-4 CAN 標准的分時同步通信功能。
(3) ABOM 自動離線管理
ABOM(Automatic bus-off management) 自動離線管理,它用於設置是否使用自動離線管理功能。 當節點檢測到它發送錯誤或接收錯誤超過一定值時,會自動進入離線狀態,在離線狀態中, CAN 不能接收或發送報文。 處於離線狀態的時候,可以軟件控制恢復或者直接使用這個自動離線管理功能,它會在適當的時候自動恢復。
(4) AWUM 自動喚醒
AWUM(Automatic bus-off management), 自動喚醒功能, CAN 外設可以使用軟件進入低功耗的睡眠模式,如果使能了這個自動喚醒功能,當 CAN 檢測到總線活動的時候,會自動喚醒。
(5) NART 自動重傳
NART(No automatic retransmission)報文自動重傳功能,設置這個功能后, 當報文發送失敗時會自動重傳至成功為止。若不使用這個功能,無論發送結果如何,消息只發送一次。
(6) RFLM 鎖定模式
RFLM(Receive FIFO locked mode)FIFO 鎖定模式,該功能用於鎖定接收 FIFO。鎖定后,當接收 FIFO 溢出時,會丟棄下一個接收的報文。若不鎖定,則下一個接收到的報文會覆蓋原報文。
(7) TXFP 報文發送優先級的判定方法
TXFP(Transmit FIFO priority)報文發送優先級的判定方法,當 CAN 外設的發送郵箱中有多個待發送報文時,本功能可以控制它是根據報文的 ID 優先級還是報文存進郵箱的順序來發送。
位時序寄存器(CAN_BTR)及波特率
CAN 外設中的位時序寄存器 CAN_BTR 用於配置測試模式、波特率以及各種位內的段參數。
(1) 測試模式
為方便調試, STM32 的 CAN 提供了測試模式,配置位時序寄存器 CAN_BTR 的 SILM及 LBKM 寄存器位可以控制使用正常模式、靜默模式、回環模式及靜默回環模式,見圖43-13。
各個工作模式介紹如下:
正常模式
正常模式下就是一個正常的 CAN 節點,可以向總線發送數據和接收數據。
靜默模式
靜默模式下,它自己的輸出端的邏輯 0 數據會直接傳輸到它自己的輸入端,邏輯1 可以被發送到總線,所以它不能向總線發送顯性位(邏輯 0),只能發送隱性位(邏輯 1)。輸入端可以從總線接收內容。由於它只可發送的隱性位不會強制影響總線的狀態,所以把它稱為靜默模式。這種模式一般用於監測,它可以用於分析總線上的流量,但又不會因為發送顯性位而影響總線。
回環模式
回環模式下,它自己的輸出端的所有內容都直接傳輸到自己的輸入端,輸出端的內容同時也會被傳輸到總線上,即也可使用總線監測它的發送內容。輸入端只接收自己發送端的內容,不接收來自總線上的內容。使用回環模式可以進行自檢。
回環靜默模式
回環靜默模式是以上兩種模式的結合,自己的輸出端的所有內容都直接傳輸到自己的輸入端,並且不會向總線發送顯性位影響總線,不能通過總線監測它的發送內容。輸入端只接收自己發送端的內容,不接收來自總線上的內容。這種方式可以在“熱自檢”時使用,即自我檢查的時候,不會干擾總線。
以上說的各個模式,是不需要修改硬件接線的,如當輸出直連輸入時,它是在 STM32芯片內部連接的,傳輸路徑不經過 STM32 的 CAN_Tx/Rx 引腳,更不經過外部連接的 CAN收發器,只有輸出數據到總線或從總線接收的情況下才會經過 CAN_Tx/Rx 引腳和收發器。
(2) 位時序及波特率
STM32 外設定義的位時序與我們前面解釋的 CAN 標准時序有一點區別,見圖 43-14。
STM32 的 CAN 外設位時序中只包含 3 段,分別是同步段 SYNC_SEG、位段 BS1 及位段 BS2,采樣點位於 BS1 及 BS2 段的交界處。其中 SYNC_SEG 段固定長度為 1Tq,而BS1 及 BS2 段可以在位時序寄存器 CAN_BTR 設置它們的時間長度,它們可以在重新同步期間增長或縮短,該長度 SJW 也可在位時序寄存器中配置。
理解 STM32 的 CAN 外設的位時序時,可以把它的 BS1 段理解為是由前面介紹的CAN 標准協議中 PTS 段與 PBS1 段合在一起的,而 BS2 段就相當於 PBS2 段。
了解位時序后,我們就可以配置波特率了。 通過配置位時序寄存器 CAN_BTR 的TS1[3:0]及 TS2[2:0]寄存器位設定 BS1 及 BS2 段的長度后,我們就可以確定每個 CAN 數據位的時間:
BS1 段時間:
TS1=Tq x (TS1[3:0] + 1),
BS2 段時間:
TS2= Tq x (TS2[2:0] + 1),
一個數據位的時間:
T1bit =1Tq+TS1+TS2 =1+ (TS1[3:0] + 1)+ (TS2[2:0] + 1)= N Tq
其中單個時間片的長度 Tq 與 CAN 外設的所掛載的時鍾總線及分頻器配置有關,CAN1 和 CAN2 外設都是掛載在 APB1 總線上的,而位時序寄存器 CAN_BTR 中的 BRP[9:0]寄存器位可以設置 CAN 外設時鍾的分頻值 ,所以:
Tq = (BRP[9:0]+1) x TPCLK
其中的 PCLK 指 APB1 時鍾,默認值為 45MHz。
最終可以計算出 CAN 通訊的波特率:
BaudRate = 1/N Tq
例如表 43-3 說明了一種把波特率配置為 1Mbps 的方式。
- CAN 發送郵箱
回到圖 24-5 中的 CAN 外設框圖,在標號2處的是 CAN 外設的發送郵箱,它一共有 3個發送郵箱,即最多可以緩存 3 個待發送的報文。每個發送郵箱中包含有標識符寄存器 CAN_TIxR、數據長度控制寄存器 CAN_TDTxR及 2 個數據寄存器 CAN_TDLxR、 CAN_TDHxR,它們的功能見表 43-5。
當我們要使用 CAN 外設發送報文時,把報文的各個段分解,按位置寫入到這些寄存器中,並對標識符寄存器 CAN_TIxR 中的發送請求寄存器位 TMIDxR_TXRQ 置 1,即可把數據發送出去。
其中標識符寄存器 CAN_TIxR 中的 STDID 寄存器位比較特別。我們知道 CAN 的標准標識符的總位數為 11 位,而擴展標識符的總位數為 29 位的。當報文使用擴展標識符的時候,標識符寄存器 CAN_TIxR 中的 STDID[10:0]等效於 EXTID[18:28]位,它與 EXTID[17:0]共同組成完整的 29 位擴展標識符。
- CAN 接收 FIFO
圖 24-5 中的 CAN 外設框圖,在標號3處的是 CAN 外設的接收 FIFO,它一共有 2 個接收 FIFO,每個 FIFO 中有 3 個郵箱,即最多可以緩存 6 個接收到的報文。當接收到報文時, FIFO 的報文計數器會自增,而 STM32 內部讀取 FIFO 數據之后,報文計數器會自減,我們通過狀態寄存器可獲知報文計數器的值,而通過前面主控制寄存器的 RFLM 位,可設置鎖定模式,鎖定模式下 FIFO 溢出時會丟棄新報文,非鎖定模式下 FIFO 溢出時新報文會覆蓋舊報文。
跟發送郵箱類似,每個接收 FIFO 中包含有標識符寄存器 CAN_RIxR、數據長度控制寄存器CAN_RDTxR 及 2 個數據寄存器 CAN_RDLxR、 CAN_RDHxR,它們的功能見表43-5。
通過中斷或狀態寄存器知道接收 FIFO 有數據后,我們再讀取這些寄存器的值即可把接收到的報文加載到 STM32 的內存中。
- 驗收篩選器
圖 24-5 中的 CAN 外設框圖,在標號4處的是 CAN 外設的驗收篩選器,一共有 28 個篩選器組,每個篩選器組有 2 個寄存器, CAN1 和 CAN2 共用的篩選器的。
在 CAN 協議中,消息的標識符與節點地址無關,但與消息內容有關。因此,發送節點將報文廣播給所有接收器時,接收節點會根據報文標識符的值來確定軟件是否需要該消息,為了簡化軟件的工作, STM32 的 CAN 外設接收報文前會先使用驗收篩選器檢查,只接收需要的報文到 FIFO 中。
篩選器工作的時候,可以調整篩選 ID 的長度及過濾模式。根據篩選 ID 長度來分類有
有以下兩種:
(1) 檢查 STDID[10:0]、 EXTID[17:0]、 IDE 和 RTR 位,一共 31 位。
(2) 檢查 STDID[10:0]、 RTR、 IDE 和 EXTID[17:15],一共 16 位。
通過配置篩選尺度寄存器 CAN_FS1R 的 FSCx 位可以設置篩選器工作在哪個尺度。
而根據過濾的方法分為以下兩種模式:
(1) 標識符列表模式,它把要接收報文的 ID 列成一個表,要求報文 ID 與列表中的某一個標識符完全相同才可以接收,可以理解為白名單管理。
(2) 掩碼模式,它把可接收報文 ID 的某幾位作為列表,這幾位被稱為掩碼,可以把它理解成關鍵字搜索,只要掩碼(關鍵字)相同,就符合要求,報文就會被保存到接收 FIFO。
通過配置篩選模式寄存器 CAN_FM1R 的 FBMx 位可以設置篩選器工作在哪個模式。
不同的尺度和不同的過濾方法可使篩選器工作在圖 43-15 的 4 種狀態。
每組篩選器包含 2 個 32 位的寄存器,分別為 CAN_FxR1 和 CAN_FxR2,它們用來存儲要篩選的 ID 或掩碼,各個寄存器位代表的意義與圖中兩個寄存器下面“映射”的一欄一致,各個模式的說明見表 43-6。
例如下面的表格所示,在掩碼模式時,第一個寄存器存儲要篩選的 ID,第二個寄存器存儲掩碼,掩碼為 1 的部分表示該位必須與 ID 中的內容一致,篩選的結果為表中第三行的ID 值,它是一組包含多個的 ID 值,其中 x 表示該位可以為 1 可以為 0。
而工作在標識符模式時, 2 個寄存器存儲的都是要篩選的 ID,它只包含 2 個要篩選的ID 值(32 位模式時)。
如果使能了篩選器,且報文的 ID 與所有篩選器的配置都不匹配, CAN 外設會丟棄該報文,不存入接收 FIFO。
- 整體控制邏輯
回到圖 24-5 結構框圖,圖中的標號5處表示的是 CAN2 外設的結構,它與 CAN1 外設是一樣的,他們共用篩選器且由於存儲訪問控制器由 CAN1 控制,所以要使用 CAN2 的時候必須要使能 CAN1 的時鍾。
CAN初始化結構體
從 STM32 的 CAN 外設我們了解到它的功能非常多,控制涉及的寄存器也非常豐富,而使用STM32 標准庫提供的各種結構體及庫函數可以簡化這些控制過程。跟其它外設一樣,STM32 標准庫提供了 CAN 初始化結構體及初始化函數來控制 CAN 的工作方式,提供了收發報文使用的結構體及收發函數,還有配置控制篩選器模式及 ID 的結構體。這些內容都定義在庫文件“stm32f4xx_can.h”及“stm32f4xx_can.c”中,編程時我們可以結合這兩個文件內的注釋使用或參考庫幫助文檔。
首先我們來學習初始化結構體的內容,見代碼清單 24-1。
代碼清單 43-1 CAN 初始化結構體
/**
* @brief CAN 初始化結構體
*/
typedef struct {
uint16_t CAN_Prescaler; /*配置 CAN 外設的時鍾分頻,可設置為 1-1024*/
uint8_t CAN_Mode; /*配置 CAN 的工作模式,回環或正常模式*/
uint8_t CAN_SJW; /*配置 SJW 極限值 */
uint8_t CAN_BS1; /*配置 BS1 段長度*/
uint8_t CAN_BS2; /*配置 BS2 段長度 */
FunctionalState CAN_TTCM; /*是否使能 TTCM 時間觸發功能*/
FunctionalState CAN_ABOM; /*是否使能 ABOM 自動離線管理功能*/
FunctionalState CAN_AWUM; /*是否使能 AWUM 自動喚醒功能 */
FunctionalState CAN_NART; /*是否使能 NART 自動重傳功能*/
FunctionalState CAN_RFLM; /*是否使能 RFLM 鎖定 FIFO 功能*/
FunctionalState CAN_TXFP; /*配置 TXFP 報文優先級的判定方法*/
} CAN_InitTypeDef;
這些結構體成員說明如下,其中括號內的文字是對應參數在 STM32 標准庫中定義的宏,這些結構體成員都是“43.2.1 1CAN 控制內核”小節介紹的內容,可對比閱讀:
(1) CAN_Prescaler
本成員設置 CAN 外設的時鍾分頻,它可控制時間片 Tq 的時間長度,這里設置的值最終會減 1 后再寫入 BRP 寄存器位,即前面介紹的 Tq 計算公式:
Tq = (BRP[9:0]+1) x TPCLK
等效於: Tq = CAN_Prescaler x TPCLK
(2) CAN_Mode
本成員設置 CAN 的工作模式,可設置為正常模式(CAN_Mode_Normal)、回環模式(CAN_Mode_LoopBack)、靜默模式(CAN_Mode_Silent)以及回環靜默模式(CAN_Mode_Silent_LoopBack)。
(3) CAN_SJW
本成員可以配置 SJW 的極限長度,即 CAN 重新同步時單次可增加或縮短的最大長度,它可以被配置為 1-4Tq(CAN_SJW_1/2/3/4tq)。
(4) CAN_BS1
本成員用於設置 CAN 位時序中的 BS1 段的長度,它可以被配置為 1-16 個 Tq 長度(CAN_BS1_1/2/3…16tq)。
(5) CAN_BS2
本成員用於設置 CAN 位時序中的 BS2 段的長度,它可以被配置為 1-8 個 Tq 長度(CAN_BS2_1/2/3…8tq)。SYNC_SEG、 BS1 段及 BS2 段的長度加起來即一個數據位的長度,即前面介紹的原來
計算公式:
T1bit =1Tq+TS1+TS2 =1+ (TS1[3:0] + 1)+ (TS2[2:0] + 1)
等效於: T1bit = 1Tq+CAN_BS1+CAN_BS2
(6) CAN_TTCM
本成員用於設置是否使用時間觸發功能(ENABLE/DISABLE),時間觸發功能在某些CAN 標准中會使用到。
(7) CAN_ABOM
本成員用於設置是否使用自動離線管理(ENABLE/DISABLE),使用自動離線管理可以在節點出錯離線后適時自動恢復,不需要軟件干預。
(8) CAN_ AWUM
本成員用於設置是否使用自動喚醒功能(ENABLE/DISABLE),使能自動喚醒功能后它會在監測到總線活動后自動喚醒。
(9) CAN_ABOM
本成員用於設置是否使用自動離線管理功能(ENABLE/DISABLE),使用自動離線管理可以在出錯時離線后適時自動恢復,不需要軟件干預。
(10) CAN_NART
本成員用於設置是否使用自動重傳功能(ENABLE/DISABLE),使用自動重傳功能時,會一直發送報文直到成功為止。
(11) CAN_RFLM
本成員用於設置是否使用鎖定接收 FIFO(ENABLE/DISABLE),鎖定接收 FIFO 后,若FIFO 溢出時會丟棄新數據,否則在 FIFO 溢出時以新數據覆蓋舊數據。
(12) CAN_TXFP
本成員用於設置發送報文的優先級判定方法(ENABLE/DISABLE),使能時,以報文存入發送郵箱的先后順序來發送,否則按照報文 ID 的優先級來發送。
配置完這些結構體成員后,我們調用庫函數 CAN_Init 即可把這些參數寫入到 CAN 控制寄存器中,實現 CAN 的初始化。
CAN發送及接收結構體
在發送或接收報文時,需要往發送郵箱中寫入報文信息或從接收 FIFO 中讀取報文信息,利用 STM32 標准庫的發送及接收結構體可以方便地完成這樣的工作,它們的定義見代碼清單 43-2。
代碼清單 43-2 CAN 發送及接收結構體
/**
* @brief CAN Tx message structure definition
* 發送結構體
*/
typedef struct {
uint32_t StdId; /*存儲報文的標准標識符 11 位, 0-0x7FF. */
uint32_t ExtId; /*存儲報文的擴展標識符 29 位, 0-0x1FFFFFFF. */
uint8_t IDE; /*存儲 IDE 擴展標志 */
uint8_t RTR; /*存儲 RTR 遠程幀標志*/
uint8_t DLC; /*存儲報文數據段的長度, 0-8 */
uint8_t Data[8]; /*存儲報文數據段的內容 */
} CanTxMsg;
/**
* @brief CAN Rx message structure definition
* 接收結構體
*/
typedef struct {
uint32_t StdId; /*存儲了報文的標准標識符 11 位, 0-0x7FF. */
uint32_t ExtId; /*存儲了報文的擴展標識符 29 位, 0-0x1FFFFFFF. */
uint8_t IDE; /*存儲了 IDE 擴展標志 */
uint8_t RTR; /*存儲了 RTR 遠程幀標志*/
uint8_t DLC; /*存儲了報文數據段的長度, 0-8 */
uint8_t Data[8]; /*存儲了報文數據段的內容 */
uint8_t FMI; /*存儲了 本報文是由經過篩選器存儲進 FIFO 的, 0-0xFF */
} CanRxMsg;
這些結構體成員都是“43.2.1 2CAN 發送郵箱及 CAN 接收 FIFO”小節介紹的內容,可對比閱讀,發送結構體與接收結構體是類似的,只是接收結構體多了一個 FMI 成員,說明如下:
(1) StdId
本成員存儲的是報文的 11 位標准標識符,范圍是 0-0x7FF。
(2) ExtId
本成員存儲的是報文的 29 位擴展標識符,范圍是 0-0x1FFFFFFF。 ExtId 與 StdId 這兩個成員根據下面的 IDE 位配置,只有一個是有效的。
(3) IDE
本成員存儲的是擴展標志 IDE 位,當它的值為宏 CAN_ID_STD 時表示本報文是標准幀,使用 StdId 成員存儲報文 ID;當它的值為宏 CAN_ID_EXT 時表示本報文是擴展幀,使用 ExtId 成員存儲報文 ID。
(4) RTR
本成員存儲的是報文類型標志 RTR 位,當它的值為宏 CAN_RTR_Data 時表示本報文是數據幀;當它的值為宏 CAN_RTR_Remote 時表示本報文是遙控幀,由於遙控幀沒有數據段,所以當報文是遙控幀時,下面的 Data[8]成員的內容是無效的。
(5) DLC
本成員存儲的是數據幀數據段的長度,它的值的范圍是 0-8,當報文是遙控幀時 DLC值為 0。
(6) Data[8]
本成員存儲的就是數據幀中數據段的數據。
(7) FMI
本成員只存在於接收結構體,它存儲了篩選器的編號,表示本報文是經過哪個篩選器存儲進接收 FIFO 的,可以用它簡化軟件處理。
CAN篩選器結構體
CAN 的篩選器有多種工作模式,利用篩選器結構體可方便配置,它的定義見代碼清單43-3。
代碼清單 43-3 CAN 篩選器結構體
/**
* @brief CAN filter init structure definition
* CAN 篩選器結構體
*/
typedef struct {
uint16_t CAN_FilterIdHigh; /*CAN_FxR1 寄存器的高 16 位 */
uint16_t CAN_FilterIdLow; /*CAN_FxR1 寄存器的低 16 位*/
uint16_t CAN_FilterMaskIdHigh; /*CAN_FxR2 寄存器的高 16 位*/
uint16_t CAN_FilterMaskIdLow; /*CAN_FxR2 寄存器的低 16 位 */
uint16_t CAN_FilterFIFOAssignment; /*設置經過篩選后數據存儲到哪個接收 FIFO
*/
uint8_t CAN_FilterNumber; /*篩選器編號,范圍 0-27*/
uint8_t CAN_FilterMode; /*篩選器模式 */
uint8_t CAN_FilterScale; /*設置篩選器的尺度 */
FunctionalState CAN_FilterActivation; /*是否使能本篩選器*/
} CAN_FilterInitTypeDef;
這些結構體成員都是“43.2.1 4 驗收篩選器”小節介紹的內容,可對比閱讀,各個結構體成員的介紹如下:
(1) CAN_FilterIdHigh
CAN_FilterIdHigh 成員用於存儲要篩選的 ID,若篩選器工作在 32 位模式,它存儲的是所篩選 ID 的高 16 位;若篩選器工作在 16 位模式,它存儲的就是一個完整的要篩選的 ID。
(2) CAN_FilterIdLow
類似地, CAN_FilterIdLow 成員也是用於存儲要篩選的 ID,若篩選器工作在 32 位模式,它存儲的是所篩選 ID 的低 16 位;若篩選器工作在 16 位模式,它存儲的就是一個完整的要篩選的 ID。
(3) CAN_FilterMaskIdHigh
CAN_FilterMaskIdHigh 存儲的內容分兩種情況,當篩選器工作在標識符列表模式時,它的功能與 CAN_FilterIdHigh 相同,都是存儲要篩選的 ID; 而當篩選器工作在掩碼模式時,它存儲的是 CAN_FilterIdHigh 成員對應的掩碼,與 CAN_FilterIdLow 組成一組篩選器。
(4) CAN_FilterMaskIdLow
類似地, CAN_FilterMaskIdLow 存儲的內容也分兩種情況,當篩選器工作在標識符列表模式時,它的功能與 CAN_FilterIdLow 相同,都是存儲要篩選的 ID; 而當篩選器工作在掩碼模式時,它存儲的是 CAN_FilterIdLow 成員對應的掩碼,與CAN_FilterIdLow 組成一組篩選器。
上面四個結構體的存儲的內容很容易讓人糊塗,請結合前面的圖 43-14 和下面的表43-7 理解,如果還搞不清楚,再結合庫函數 CAN_FilterInit 的源碼來分析。
對這些結構體成員賦值的時候,還要注意寄存器位的映射,即注意哪部分代表 STID,哪部分代表 EXID 以及 IDE、 RTR 位。
(5) CAN_FilterFIFOAssignment
本成員用於設置當報文通過篩選器的匹配后,該報文會被存儲到哪一個接收 FIFO,它的可選值為 FIFO0 或 FIFO1(宏 CAN_Filter_FIFO0/1)。
(6) CAN_FilterNumber
本成員用於設置篩選器的編號,即本過濾器結構體配置的是哪一組篩選器, CAN 一共有 28 個篩選器,所以它的可輸入參數范圍為 0-27。
(7) CAN_FilterMode
本成員用於設置篩選器的工作模式,可以設置為列表模式(宏 CAN_FilterMode_IdList)及掩碼模式(宏 CAN_FilterMode_IdMask)。
(8) CAN_FilterScale
本成員用於設置篩選器的尺度,可以設置為 32 位長(宏 CAN_FilterScale_32bit)及 16 位長(宏 CAN_FilterScale_16bit)。
(9) CAN_FilterActivation
本成員用於設置是否激活這個篩選器(宏 ENABLE/DISABLE)。
配置完這些結構體成員后,我們調用庫函數 CAN_FilterInit 即可把這些參數寫入到篩選控制寄存器中, 從而使用篩選器。我們前面說如果不理解那幾個 ID 結構體成員存儲的內容時,可以直接閱讀庫函數 CAN_FilterInit 的源代碼理解,就是因為它直接對寄存器寫入內容,代碼的邏輯是非常清晰的。
參考引用:
- 野火---《零死角玩轉STM32-F429挑戰者》
- 《STM32F4xx中文參考手冊》
- 《Cortex-M4內核編程手冊》