英飛凌Aurix2G TC3XX CAN模塊詳解

本文主要介紹Infineon Aurix2G TC3XX系列芯片CAN模塊硬件原理,MCAL相關配置,和代碼示例實現。
1 模塊介紹
CAN總線是一種廣泛應用于汽車、工業控制和其他領域的串行通信協議。CAN總線是Controller Area Network的縮寫,最初由德國的Bosch公司開發,用于汽車電子系統之間的通信。CAN總線具有高可靠性、抗干擾能力強和實時性好等特點,因此被廣泛應用于需要可靠數據傳輸的領域。
CAN 2.0B協議中的CAN最多支持29位ID,但是網絡架構中使用的一般是11位的標準幀ID。下面是標準CAN FD幀數據結構:

關于CAN協議相關的內容,本文不作闡述,建議讀者自行查閱資料,以便更好地理解本文中的CAN硬件原理。
Aurix2G TC3XX系列的CAN模塊稱為MCMCAN,集成的是Bosch的M_CAN內核,最多集成了3個CAN Module,每個CAN Module包含4個CAN節點(M_CAN)。支持ISO 11898-1&-4協議,支持SAE1939協議,支持最高單幀64字節的CANFD傳輸,支持5Mbit/s的波特率,且在時鐘高達80MHz的情況下可擴展至8Mbit/s。
2 功能介紹
2.1 CAN硬件框架
這里我們首先介紹下車載CAN網絡在控制器級別的硬件框架,下圖是控制器端的結構示意圖。

在CAN控制器節點中,一般MCU中集成了CAN控制器,同時節點配備板載CAN信號收發器,也就是Can Transceiver,CAN控制器和CAN Transceiver之間通過TX和RX進行數據交互。MCU通過IO控制Transeiver的狀態,以及狀態回讀。
Transceiver則通過CAN_H和CAN_L連接到整車的CAN網絡上,通過差分信號進行數據交互。
另外對于具備休眠喚醒的Transceiver,存在一些電源控制連接,此處就不展開說明了。
2.2 CAN時鐘
作為通信模塊,我們先來看CAN模塊時鐘相關連接。
TC3XX CAN模塊有兩路主時鐘源,來自系統的CCU模塊。其中fMCANH是CAN模塊主時鐘,決定CAN模塊工作及CAN RAM訪問速度,通過CCUCON5.MCANHDIV來進行配置;fMCAN是CAN模塊時鐘,用來配置CAN的波特率,必須小于fMCANH,通過CCUCON1.MCANDIV來進行配置。
在每個CAN Module內部,fMCANH連接fSYN,fMCAN連接fASYN,和其他外設模塊一樣,CAN模塊時鐘可通過時鐘控制寄存器(CLC)關閉。

然后CAN模塊內部每個Node的時鐘都可以通過MCR.CLKSELi進行獨立控制,此處不分頻。

fASYN作為CAN總線波特率的基準時鐘,推薦配置位80, 40, 20 MHz,以與節點波特率取整倍數。
2.3 波特率及采樣點
波特率及采樣點的設置涉及到同步段Sync_Seg、傳播段Prop_Seg、相位緩沖段Phase_Seg等。
fASYN時鐘到達CAN模塊之后,通過設置DBTP.DBRP進行分頻,得到CAN時鐘。

波特率的計算公式為:

采樣點的計算公式為:

M_CAN中,DBTP.DTSEG1等于傳播段、相位緩沖段1長度的和減1(無需分開配置),DBTP.DTSEG2等于相位緩沖段2的長度減1。DBTP.DSJW等于同步跳轉寬度減1。同步段為固定值1。
2.4 MCMCAN總覽
TC3XX中一個CAN Module包含4個M_CAN Node,其芯片框圖如下圖所示:

從圖中我們可以看到每個CAN Module有一塊公有的RAM,稱為Message RAM。因為CAN模塊需要一塊額外的RAM用于數據的收發和控制等,這個是由芯片廠商來實現的,比如在TC3XX系列中,Message RAM就集成在CAN模塊外設地址起始位置。每個CAN Node有Host IF和Memory IF與主機(CPU)相連,同時通過TX/RX與外部進行信號交互。
然后我們把CAN Node展開,該部分為Bosch IP內核,每個M_CAN Node的框架如下圖所示:

從圖中可以看到,CAN模塊作為從機通過Host IF接口接入到芯片內部的Host(TC3XX中即CPU),Host通過控制CAN模塊的寄存器來進行控制交互。CAN模塊還作為主機通過Memory IF接口接入到Message RAM,用于存取傳輸數據。
CAN Core
CAN協議內核控制器,接收、發送移位寄存器,支持ISO 11898-1:2015協議功能,支持11位和29位CAN ID。
Sync
用于在CAN Core和Host之間進行時鐘同步。
Clk
時鐘管理模塊。
Cfg&Ctrl
CAN Core及相關模塊的控制和配置位。
Interrupt & Timestamp
中斷控制和16位CAN位時間計數器用于接收和發送時間戳的生成。
Tx Handler
控制從Message RAM到CAN Core的消息傳輸。最多可配置32個Tx Buffers用于傳輸。Tx緩沖區可以用作專用Tx Buffer、Tx FIFO, Tx Queue的一部分,或作為它們的組合。一個Tx事件FIFO存儲Tx時間戳和相應的消息ID。M_CAN還支持發送取消。
Rx Handler
控制從CAN Core到Message RAM的接收消息的傳輸。Rx處理程序支持兩個Rx FIFO,每個都是可配置的大小,以及多達64個專用的Rx Buffer,用于存儲已通過接受過濾的所有消息。一個專用的Rx Buffer,用于僅存儲具有特定標識符的消息。Rx時間戳與每條消息一起存儲。最多可為11位ID定義128個過濾器,最多可為29位ID定義64個過濾器 。
Generic Slave Interface
將M_CAN連接到客戶指定的主機CPU。通用從屬接口能夠連接到8/16/32位總線,以支持廣泛的互連結構。
Generic Master Interface
將M_CAN訪問連接到外部32位Message RAM。最大Message RAM 大小為16K*32bit。單個M_CAN最多可以使用4.25K*32bit。
Extension Interface
中斷寄存器IR的所有標志以及選定的內部狀態和控制信號都路由到這個接口。該接口用于M_CAN與模塊外部中斷單元或其他模塊外部組件的連接。這些信號的連接是可選的。
2.5 Message RAM
Message RAM,也就是CAN RAM,這里我們先介紹CAN RAM在內存中的結構,以方便讀者理解CAN模塊的收發邏輯。(TC3XX系列中一個CAN Module的4個Node共享一塊RAM)
CAN RAM是32位寬格式,用于存儲CAN的接收過濾配置、收發數據。其在內存中的結構如下:

圖中可以看出,CAN RAM被劃分為多個塊,每個塊都有特定的寄存器指示其相對于CAN RAM的地址偏移。比如Tx Buffers塊的絕對地址等于CAN RAM StartAddr+TXBC.TBSA。
CAN RAM中每個塊都有自己的數據格式定義,CAN手冊中有詳細說明,下面我們會以11-bit Filter和Tx Buffers舉例說明。
另外需要注意的是,TC3XX中每個CAN Module中的4個CAN Node是共用一塊CAN RAM的,因此在資源數量分配時,如果控制器需要的CAN節點數量沒有超過CAN Module數量時,盡量使用不同CAN Module中的Node。
2.5.1 Standard Message ID Filter Element
我們知道,CAN ID有11bit的標準ID,還有29bit的擴展型ID,因此CAN模塊的ID過濾器有兩種。Standard Message ID Filter Element,即上圖中的11-bit Filter。
一個標準過濾器(Filter Element)占一個Word(4字節),我們可以通過寄存器SIDFC.FLSSA獲取過濾器區域在CAN RAM中的相對地址偏移,通過SIDFC.LSS獲取過濾器的數量。(SIDFC.FLSSA在2~15位,低位需要擴展兩個bit的0)
標準過濾器的結構如下:

SFT:Standard Message ID Filter Element,標準過濾器過濾類型
00= 范圍過濾,SFID1到SFID2之間 (SFID2 ≥ SFID1)
01= 雙ID過濾,SFID1或SFID2
10= 經典過濾,SFID1 = filter, SFID2 = mask
11= 過濾器關閉
SFEC:Standard Filter Element Configuration,標準過濾器配置,所有過濾器都會被用于接收幀的處理,直到第一個過濾器與之匹配,或者達到過濾器末端。如果SFE=111b,則SFT無視,該幀直接存儲到Rx Buffer中;
SFID:Standard Filter ID 1,標準過濾器ID1,在Rx Buffer、同步報文、Debug報文下,ID與之相等的幀就會過濾成功,被存儲到Rx Buffer中;
SSYNC:Standard Sync Message,標準同步幀,用于標記是否使能時間戳;
SFID2:Standard Filter ID 2,標準過濾器ID2,該ID在SFEC定義的特殊匹配模式下配合SFID1使用;另外其中SFID[5:0]指示該過濾器引用的Rx Buffer(SFEC為111b時有效);
當我們使用FULL CAN類型的接收幀時,配置SFEC為111b,配置SFID1為目標幀的ID,即可進行接收。
比如這里我使用的CAN RAM地址為0xF0200000,過濾器地址偏移為0,過濾器數量為3,則前3個Word就是我對應使用的3個過濾器,通過上述位域轉換可知,分別對應ID為0x111、0x222和0xC,對應的Rx Buffer索引分別為0、1、3。

2.5.2 Tx Buffer Element
Tx Buffer用于處理CAN數據的發送,CPU通過將用戶的待發送數據復制到Tx Buffer中,操作CAN發送寄存器,隨后CAN模塊就從CAN RAM的Tx Buffer中讀取數據進行發送。Tx Buffer可用于特定幀Buffer、Tx FIFO以及Tx Queue。
Tx Buffer的數據位寬不是固定的,取決于數據寬度。通過TXBC.TBSA獲取Tx Buffer在CAN RAM中的相對地址偏移,通過TXBC.NDTB獲取Buffer的數量。
每個Tx Buffer包括兩個Word的頭和若干數據組成,每個CAN Node的數據長度由TXESC.TBDS獲取指定,比如CAN FD一般數據為64字節。其結構如下:

篇幅原因就不展開介紹每個位域了,讀者可自行查閱手冊。通過Tx buffer,完成了CPU與M_CAN之間的數據交互協議,CPU填寫Tx Buffer的頭部信息,包括CAN ID、DLC等,以及數據內容,然后操作寄存器進行,CAN模塊按照Tx Buffer中的信息和數據進行發送。
假設我們配置數據寬度為64字節,則第n個TxBuffer的內存中的絕對地址為 CanRamStartAddr+TXBC.TBSA+n*(8+64)。
同上我這里的CAN RAM基址為0xF0200000,TXBC.TBSA=0x57,左移兩位補齊得到0x15C。

所以0xF020015C就是我使用的第一個Tx Buffer,通過解析得知其發送ID為0x123(T0[28:18]),DLC為8,數據內容為{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }。

2.6 Operation Modes操作模式
2.6.1 初始化
軟件需要設置CCCR.INIT,并設置CCCR.CCE(M_CAN配置寄存器僅當該位置位時才可訪問),然后開始初始化,此時CAN模塊停止收發,錯誤計數保持不變。然后通過軟件配置各項寄存器,以及CAN RAM初始化。
完成寄存器配置后將CCCR.INIT位清除,CCCR.CCE會自動隨之清除,以完成硬件配置。
2.6.2 普通模式
當完成寄存器和CAN RAM的配置后,CAN模塊會自動與外部收發器進行同步,進入普通工作模式。
對于接收幀的過濾器和Rx Buffer、FIFO等,是在初始化階段設置的。CAN模塊在工作模式下如果收到與之匹配的CAN報文,就會保存到Rx Buffer或者FIFO中。
而發送幀報文的Tx Buffer則是在發送時更新的。
2.6.3 CANFD模式
CANFD(Controller Area Network Flexible Data Rate)模式中有兩種變種,一種是常規的CANFD發送模式(BRS==1),即報文中的控制段、數據段、CRC段以較高的波特率進行傳輸,而幀開頭和結尾以普通速度進行傳輸。另外一種則是所有段都按照普通波特率進行傳輸。
2.6.4 第二采樣點 Transmitter Delay Compensation Measurement
我們知道CAN總線節點在發送過程中,是要對輸入信號進行回采的,以進行總線仲裁以及錯誤判斷。如果在一定時間內沒有回采到預期值,則會出現位錯誤。該時間閾值取決于CAN時鐘頻率。
當使用CANFD時,且配置了較高頻率的時鐘,就會導致該延時閾值較短,也就是需要硬件在更短的時間進行回讀,但硬件的延時相對較為固定,這個時候就容易誤報位錯誤。也就是實際該幀發送正常,但是硬件回讀時間大于閾值。
M_CAN針對該特性提供了發送采樣延時補償,也就是我們常說的第二采樣點。通過硬件來放寬回讀的間隔,且該特性使能后由硬件自動標定,能夠對不同時鐘頻率進行自適應。

2.6.5 受限操作模式Restricted Operation Mode
當總線出現錯誤或負載過高時,比如發送錯誤計數ECR.TEC達到一定次數,表示無法往總線發送報文,CAN控制器會進入受限模式。在受限模式下CAN模塊停止發送報文,進入監聽模式,直到總線空閑,之后CAN模塊會重新與總線同步。
Host可以通過設置CCCR.ASM寄存器主動進入受限操作模式。當CAN模塊主動或被動進入受限模式,需要清除CCCR.ASM以進行恢復。
2.6.6 總線偵聽模式Bus Monitoring Mode
M_CAN模塊可以通過設置CCCR.MON進入偵聽模式,在偵聽模式下,CAN模塊的發送被切斷,只偵聽總線上的報文。

2.6.7 休眠模式Power Down (Sleep Mode)
M_CAN支持硬件休眠模式,通過設置CCCR.CSR寄存器,使CAN模塊進入休眠模式。當所有等待發送的報文完成發送,M_CAN會自行設置CCCR.INIT來阻止后續報文的發送,此時M_CAN通過設置CCCR.CSA表征其已經準備好進入休眠模式了,然后Host可以關閉CAN模塊時鐘。
要退出休眠模式,首先也要啟動M_CAN時鐘,然后清除CCCR.CSR寄存器。同樣M_CAN通過清除CCCR.CSA來表征自己退出休眠模式,然后Host可以通過設置CCCR.INIT,并設置寄存器以重啟CAN模塊。
2.6.8 Test Mode測試模式
M_CAN模塊支持測試模式,通過先將CCCR.TEST寄存器置位來開啟。
測試模式有兩種,一種是External Loop Back Mode,即外回環模式,通過設置TEST.LBCK為1來實現。在該模式下,CAN模塊切斷了外界的接收連接,將自己發送的報文視為接收報文,以進行CAN回環測試。在該模式下,CAN忽略總線應答錯誤。
另外一種是Internal Loop Back Mode,即內回環模式,除了TEST.LBCK,還需要設置CCCR.MON,區別在于該模式下CAN模塊的發送連接也被切斷,也就是測試模式和偵聽模式的組合。

2.7 時間戳功能
M_CAN模塊提供了一個內部16位的循環計時器,并且具備一個4位的分頻寄存器TSCC.TCP。可通過TSCV.TSC寄存器讀取計時器的值。當計時器回滾時,中斷標志位IR.TSW置位。
在接收、發送報文的開始時刻,計時器的值會被保存到Rx Buffer、Rx FIFO、Tx Event FIFO的時間戳段中,以實現計時功能。
2.8 接收流程Rx Handling
Rx Handler控制接收過濾,Rx Buffers和兩個Rx FIFO接收消息的傳輸,以及Rx FIFO的Put和Get索引。
2.8.1 接收過濾 Acceptance Filtering
前文提到,M_CAN提供兩套過濾器,分別用于對標準CAN ID和擴展CAN ID進行ID過濾。這些過濾器可以被分配到Rx Buffer、Rx FIFO1、Rx FIFO2(通過過濾器中字段進行配置)。當收到一幀報文時,會從對應過濾器列表從頭到尾進行匹配。當出現匹配過濾器時,后續的過濾器就不會再執行匹配。
值得一提的是,不同于發送報文,接收過濾器是在初始化階段由Host配置好的,當初始化完成之后M_CAN按照指定的配置進行接收過濾。
過濾器主要包括以下特性:
1)支持以下三種過濾模式:
2)范圍過濾(from - to -)
3)一個或者兩個特定ID過濾
4)經典的按位掩碼過濾
5)過濾器可以配置為接收過濾或者拒絕過濾;
6)每個過濾器可以獨立使能;
7)過濾器按照順序依次匹配,出現第一個匹配的過濾器即停止后續過濾。
相關的寄存器包括全局過濾配置寄存器(Global Filter Configuration,GFC),標準ID過濾器配置寄存器(Standard ID Filter Configuration,SIDFC),擴展ID過濾器配置寄存器(Extended ID Filter Configuration,XIDFC),擴展ID&掩碼寄存器(Extended ID AND Mask,XIDAM)。
當過濾器與接收報文匹配上時,根據CAN RAM中過濾器的配置(SFEC/EFEC),執行相應的操作:
1)將接收幀存儲到FIFO0或者FIFO1;
2)將接收幀存儲到Rx Buffer;
3)將接收幀存儲到Rx Buffer并在過濾器事件pin上產生信號;
4)拒絕該幀;
5)設置高優先級中斷標志位IR.HPM;
6)設置高優先級中斷標志位IR.HPM,并將接收幀存儲到FIFO0或者FIFO1
當一幀報文到達CAN模塊的時候,過濾器的工作流如下圖所示(以標準ID幀為例):

從圖中可以看出,當一幀11bit ID標準幀到達時,如果不是遠程幀且接收過濾器使能了,就會進入過濾器匹配環節。如果沒有與之匹配的ID,且配置模式不接收非匹配幀(一般不對非預期幀進行處理),該幀就會被丟棄。如果過濾器中有與之匹配的ID,且所引用的存儲空間可用(Rx Buffer或者FIFO),則進行幀存儲。
2.8.2 Rx FIFO
我們知道,在AUTOSAR協議中, CAN報文類型在接口層分為FULL CAN和BASIC CAN,FULL CAN表示該報文的處理獨占一個硬件資源,也就是Rx Buffer;而BASIC CAN則表示多個接收幀需要共用一個硬件FIFO,并且相同ID的報文可以在FIFO中存儲多次,這個FIFO在硬件上就是我們要介紹的M_CAN的Rx FIFO。
每個M_CAN節點有兩個Rx FIFO,每個FIFO最多可處理64幀報文。分別通過RXF0C和RXF1C寄存器來進行Rx FIFO的配置。初始化階段我們通過RXFnC.FnSA配置該FIFO在CAN RAM中的相對地址偏移,通過RXFnC.FnS配置該FIFO的尺寸,也就是最多容納的報文數量。通過RXFnC.FnWM配置該FIFO的水位線。
當過濾器中的SFEC/EFEC字段指定過濾器的動作為存儲到RX FIFO中,在接收幀與過濾器匹配時,就會被存儲到指定的RX FIFO中。
RX FIFO的設計采用的是典型的帶水位線的Ring Buffer模型。

該模型的狀態由M_CAN模塊維護,Host可以通過RXFnS寄存器訪問。RX FIFO有兩個索引,一個是Put索引RXFnS.FnPI,接收到報文后從該位置進行存儲,然后將Put索引累加。另一個是Get索引RXFnS.FnGI,Host從該位置開始進行報文讀取。還有一個填充指示位RXFnS.FnFL,用來表征當前FIFO里已經有多少報文了。當FIFO滿了時(Get索引等于Put索引),FIFO溢出標志位RXFnS.FnF會置位,同時發送IR.RFnF中斷信號。
前面提到通過RXFnC.FnWM配置該FIFO的水位線,它的作用是當FIFO中存儲的報文數量達到水位線時,產生FIFO中斷,即IR.RFnW信號,以促使Host進行接收報文處理。
RX FIFO在CAN RAM中的相對地址偏移分別為RXF0C.F0SA和RXF1C.F1SA。與Tx Buffer形式相同,每個Rx FIFO包含3個Word的頭和特定長度的數據,數據尺寸由RXFnC.FnDS決定。
Rx FIFO有兩種工作模式,通過操作RXFnC.FnOM來控制。當RXFnC.FnOM=0時,Rx FIFO配置為默認的Block模式,該模式下,如果FIFO滿了,將不再接收任何報文。當RXFnC.FnOM=1時,Rx FIFO配置為覆寫模式,在該模式下如果FIFO滿了,新到的報文將覆蓋最舊的一幀報文,并且將兩個索引都累加。

2.8.3 Rx Buffer
當我們配置接收幀為FULL CAN時,也就給該幀配置了一個專屬的Rx Buffer,用于該幀的報文接收。每個M_CAN最多可配置64個Rx Buffer,其在CAN RAM中的相對地址偏移由RXBC.RBSA指定,Rx Buffer的格式與Rx FIFO完全相同,每個Rx Buffer包含3個Word的頭和特定長度的數據,數據尺寸由RXBC.RBDS決定。
在過濾器ID匹配成功時,且過濾器中的SFEC/EFEC為111b(表示幀存儲到Rx Buffer中),且SFID2/EFID2[10:9]為0(非Debug幀),則CAN模塊將該報文存儲到指定的Rx Buffer中,其中Rx Buffer的索引由過濾器中SFID2/EFID2[5:0]位域指定。同時中斷標志位IR.DRX (Message stored in Dedicated Rx Buffer)置位,這也就是我們常說的CAN接收中斷。
除此之外,接收完成之后,對應的New Data Flag寄存器NDAT1或NDAT2中的位會置位(每個Buffer一個位),在該位被清除前,該Rx Buffer將拒絕數據接收,同時對應的過濾器也停止進行過濾,但是位于該過濾器后面的其他過濾器可以繼續對該幀,也就是說該幀可以被存儲到其他Rx Buffer或者FIFO中。用戶可以通過對該位寫1進行清除。
接收的處理流程如下:
1)清除中斷標志位IR.DRX;
2)讀取New Data Flag寄存器確定需要處理的Buffer;
3)從CAN RAM中讀取數據;
4)清除處理好的Buffer的New Data Flag。
2.9 發送流程 Tx Handling
Tx Handler處理專用Tx Buffers、Tx FIFO和Tx Queue的傳輸請求。它負責傳輸報文到到CAN Core,管理Put和Get索引, 以及Tx Event FIFO的傳輸。不同于Rx Buffer和Rx FIFO有各自的獨立資源,在發送端專用Tx Buffer和Tx FIFO、Tx Queue共用32個Tx Buffer。
CAN模塊在發送端可以發出三類報文:普通報文、非變速CANFD報文、變速CANFD報文,受節點的CCCR寄存器和每個Tx Buffer內部的配置影響,參照下表。

Tx Handler在每次發送Buffer請求等待寄存器(Tx Buffer Request Pending register,TXBRP)更新時執行依次掃描,然后在CAN RAM中尋找優先級最高(CANID最小的Tx Buffer)的等待中的Tx Buffer開始發送。而TXBRP是在每次有一幀發送完成,或者有用戶通過寫發送發送Buffer添加請求寄存器(Tx Buffer Add Request register, TXBAR)時更新。也就是說,當發送完一幀,或者用戶添加發送請求,Tx Handler就會開始執行發送掃描,尋找優先級高的Tx Buffer然后發送。
2.9.1 發送暫停
CAN總線是無主式通訊,仲裁的依據是CANID。但如果具有高優先級ID的控制器以較高的頻率持續發送報文,持有低優先級ID的控制器便無法將報文發出。因此CAN控制器存在一個發送暫停的功能,通過將CCCR.TXP置位來使能。使能之后,該控制器在完成每幀發送之后,會進行兩個bit的暫停,以保證低優先級ID的報文能夠發送到總線上。
2.9.2 Tx Buffer
每個M_CAN最多可配置32個Tx Buffer,其在CAN RAM中的相對地址偏移由TXBC.TBSA指定,每個Tx Buffer包括兩個Word的頭和若干數據組成,每個CAN Node的數據長度由TXESC.TBDS獲取指定,比如CAN FD一般數據為64字節。Tx Buffer可以用作給特定幀的專有Buffer,也可以組成Tx FIFO、Tx Queue,更可以組成Tx Buffer與FIFO/Queue的混合模式,這種使用較少本文就不加以贅述。但是FIFO和Tx Queue是二選一存在的。
專有Tx Buffer是完全由Host來控制的,每個Tx Buffer指定專有的CAN ID。和接收一樣,專有Tx Buffer對應配置中的FULL CAN。以防多個Tx Buffer具有相同的CAN ID,因此Tx Buffer的發送順序是按照Buffer的序號進行的,低序號的Tx Buffer具有優先發送權,一般也將較小ID的報文分配給靠前的Tx Buffer。每個Tx Buffer都可以通過寫TXBAR寄存器中的關聯位單獨進行發送請求添加。
2.9.3 Tx FIFO
當我們把TXBC.TFQM配置為0,并通過TXBC.TFQS配置一定數量的Tx Buffer用作FIFO,就可以使用Tx FIFO模式進行報文發送,并允許同一個ID的報文多次添加到FIFO中。FIFO的結構同樣類似Rx FIFO,有一個Get索引TXFQS.TFGI,和一個Put索引TXFQS.TFQPI,用來指示頭和尾。用TXFQS.TFFL來指示當前Buffer空閑數量。
當Host執行發送請求時,Put索引進行累加,當Tx Handler執行發送時,Get索引進行累加。當FIFO滿了以后,TXFQS.TFQF置位。
2.9.4 Tx Queue
當我們把TXBC.TFQM配置為1,并通過TXBC.TFQS配置一定數量的Tx Buffer用作Queue,就使用了Tx Queue模式。Queue中的報文從ID小的開始執行發送。當Queue中出現相同ID的Buffer,則先從Buffer序號小的發送。Tx Queue只有一個Put索引TXFQS.TFQPI ,用于指示Queue中序號最小的可用Buffer。
當新的發送請求發送到Tx Queue中,Put索引會自動指向下一個Queue中序號最小的可用Buffer。當Queue滿了時(TXFQS.TFQF),Put索引成為無效值,并且后續報文無法添加到Queue中,直到一個報文發出去或者有報文被取消。
2.9.5 發送取消 Transmit Cancellation
M_CAN支持發送取消功能,該特性是專門為AUTOSAR中網關應用程序設計的。為了取消Tx Buffer或者Tx Queue中的pending報文的發送,Host需要向發送Buffer取消請求寄存器(Tx Buffer Cancellation Request register,TXBCR)中的相關位CRn寫1。Tx FIFO中的報文無法取消。
取消成功后,TXBCF中的相應位CFn會置位。
如果一幀已經在發送流程中了,如果最終沒有取消成功,那么TXBCF和TXBTO中的相應位都會置位,如果取消成功,那么只有TXBCF中相應位置位。
2.9.6 發送事件FIFO Tx Event FIFO
為了支持發送事件處理,M_CAN維護了一套Tx Event FIFO機制。在CAN RAM設置了一塊內容,專門保存CAN發送事件的信息。當CAN模塊往總線上發送一幀報文之后,報文ID、Message Marker、時間戳等信息就會被保存到Tx Event FIFO中。
這么做的目的是把CAN發送處理和發送事件信息處理分開,好處是當一幀報文發送完成之后,Tx Buffer能夠立刻給下一幀使用,尤其是在Tx Queue模式下。
當出現新的Tx Event之后,觸發中斷標志位IR.TEFN,表示專有Tx Buffer、Tx FIFO有發送完成,一般將該信號用作CAN發送中斷。
Tx Event FIFO滿了之后會觸發中斷標志位IR.TEFF。后續的事件便無法繼續保存,直到下一次讀取發生。
為了避免FIFO溢出,可以使用Tx Event FIFO水位線,通過設置TXEFC.EFWM,當Tx Event FIFO中的事件數量達到了水位線,將中斷標志位IR.TEFW置位。
2.10 FIFO Ack機制
前面提到的Rx FIFO0、FIFO1和Tx Event FIFO,它們的Get索引都是通過Ack機制來實現控制的。通過寫入指定的Ack寄存器,來將FIFO的Get索引進行累加。比如在從Rx FIFO0中接收報文完成之后,需要在接收FIFO0應答寄存器(Rx FIFO 0 Acknowledge,RXF0A)來修改與該Buffer關聯的索引號。
2.11 中斷連接
一個M_CAN節點提供了十幾種中斷,包括前文提到的接收中斷、發送完成事件中斷等。

首先在M_CAN模塊內部,對于每種類型的中斷,在中斷使能寄存器CAN_N_IE中都有一個專屬的使能位。該使能位需要在啟動階段由Host設置(一般在Start Controller時)。
然后在TC3XX的中斷路由模塊IR中,每個CAN Module分配了16個中斷源,也就是說一個Module中的4個Node要共用這16個中斷源,每個Node的中斷信號與這16個中斷源是可以任意連接的,來自這些Node的多個信號也可以連接到同一個中斷源中。通過設置Node中的GRINT1和GRINT2來為Node中的中斷信號指定中斷源。

一般情況下,我們會將16個中斷源平均分給4個Node,每個Node使用4個關鍵中斷信號,分別分配給Rx Buffer中斷、Tx Buffer中斷、BusOff中斷和Rx FIFO中斷。
2.12 引腳連接
TC3XX中CAN模塊與Port的連接也是比較豐富的,對于每個節點都有多組引腳可選為CanRx和CanTx信號。
連接需要指定型號的用戶手冊(非Family手冊),這里我們以TC38X User Manual為例,我們打開手冊38.4 MCMCAN Connectivity章節,找到Table 388 Connections of CAN00。

這里CAN00表示是CAN Module0,Node0的連接關系,如果是Module1,Node2就是CAN12,以此類推。
CAN00提供了8對引腳可供選擇,我們從硬件設計獲悉引腳關系后,查詢對應的Rx Signals,比如Rx硬件連接為P12.0,則在MCAL中配置Rx為RXDC。發送端不需要配置,因為對于CAN模塊來說,對每個內部連接都進行發送,由Port來配置使用哪個。
選擇了對應的Rx Tx引腳之后,在Port端進行引腳功能配置即可。
3 MCAL配置及代碼示例
3.1 內部總線連接
Infineon在M_CAN模塊集成中,設計了Module internal Loop-back模式,能夠將同一Module中的多個節點進行總線連接。我們在CAN調試過程中,如果手上沒有CANOE,或者沒有其他控制器進行聯合調試。通過將對應NPCRx.LBM寄存器位置位即可(MCAL中可配置)。這樣我們內部配置兩個CAN Controller進行數據對發就能調試。

這里我們直接使用Infineon官方原版的MCAL配置和代碼,稍加調整,實現兩個CAN Node的報文對發。
另外這里對Port、Irq、時鐘配置就不再贅述了,讀者可以參考之前發布的相關文章。每個Can Module的16個中斷源依次分配給4個Node,我們這里使用Module0的Node0和Node1,Irq中給Module0前8個中斷進行配置即可。
3.2 General

照例General中還是一些常規接口使能配置。
1)CanMainFunctionModePeriod:CAN的發送接收等可以選擇是中斷還是輪詢,這里我們選擇中斷,所以忽視該配置;
2)CanMultiplexedTransmission:該配置表示是否使用Tx FIFO/Tx Queue和專有Tx Buffer混用,這里我們只使用專有Buffer,不勾選;
3.3 Can Controller
然后我們來到Can Controller中,這里對應的就是我們的Can Node配置,每路CAN有各自的一個Controller。

1)CanBusoffProcessing、CanRxProcessing、CanTxProcessing、CanWakeupProcessing:中斷、輪詢選擇,這些都是代碼邏輯,如前所述,如果選擇Polling就是在MainFunction中輪詢,MCAL中斷代碼中便不會進行處理,配了也沒用;這里我們配置為中斷;
2)CanControllerActivation:Controller激活,勾選視為激活;
3)CanControllerLoopbackEnable:內部總線測試連接,這里我們需要利用兩路內部Controller進行內部總線連接,因此需要勾選,注意非測試軟件不要勾選,且勾選后RxInputSelection默認只能使用RXDA;
4)CanRxInputSelection:Rx引腳選擇,如前所述;
5)CanControllerBaseAddress:CAN Controller基址,MCAL配置中對于該Controller使用哪個Module的哪個Node,由本參數決定,對應ACCENNODE0寄存器的地址,可在對應型號手冊中查詢,或者IfxCan_reg.h文件中搜索CAN0_N0_ACCENNODE0,比如Module0 Node0的ACCENNODE0地址為0xF0208100(十進制4028662016);
6)CanControllerId:Controller的軟件ID標識;
7)CanWakeupFunctionalityAPI:Can_CheckWakeup() 使能;
8)CanControllerDefaultBaudrate:默認波特率配置引用,我們可以配置多種波特率,并在運行時切換,這里配置啟動后的默認波特率;
然后來到波特率配置頁面:

這里對應前面章節提到的波特率計算,用戶根據實際需求填寫傳播段、相位緩沖段等參數即可。另外注意的是,時鐘分頻是不能填寫的,而是工具根據這些參數自動計算的,參考前文公式。
后面頁面的CANFD波特率設置同理,這里如果設置了CANFD波特率,自動打開CANFD使能。另外如果配置了第二采樣點,則打開了發送采樣延時補償,這里由硬件自動標定,配置了任意數字都只是使能。

3.4 CanHardwareObject
然后我們來到CanHardwareObject,這里是對發送、接收幀硬件資源定義的地方,也就是配置前文提到的Rx Buffer、Tx Buffer等。
值得一提的是,這里只是硬件資源,并沒有分配CAN ID,因為CANID是CanIf層的概念,CanIf來決定為某個CANID引用哪個硬件資源。當然有些工具如Vector DaVinci也會在CAN模塊中設置CANID配置,操作更直觀。

1)CanHandleType:硬件資源類型,FULL CAN還是BASIC CAN;
2)CanHwObjectCount:Tx FIFO數量,這里我們FULL CAN,使用專有Buffer,配置為1即可;
3)CanHwFIFOThreshold:Tx FIFO水位線,也就是中斷觸發閾值;
4)CanIdType:ID類型,標準11位還是擴展29位;
5)CanObjectId:軟件中HardwareObject ID;
6)CanObjectType:Obj類型,發送或接收;
7)CanControllerRef:分配給哪個Controller;
這里順便介紹下CanHwFilter,當我們配置為Basic CAN時生效,可以通過掩碼過濾方式配置過濾器。

這里有兩個配置,一個FilterCode,一個FilterMask,假設我們接收到的ID為RxID,其過濾成功條件為:RxID & Mask == Code & Mask,也就是Mask決定哪些位需要考察,Code決定該位的目標值。比如我要過濾0x4XX的幀,設置掩碼為0xF00,設置Code為0x400即可。
3.5 代碼及示例
這里我們使用Infineon官方MCAL接口,及MCAL Demo示例。
首先對外設進行初始化,并初始化中斷配置,然后使能相應中斷。
IrqCan_Init();
Can_17_McmCan_Init(&Can_17_McmCan_Config);
SRC_CAN_CAN0_INT0.U |= CAN_SRC_SET_SRE ;
SRC_CAN_CAN0_INT1.U |= CAN_SRC_SET_SRE ;
SRC_CAN_CAN0_INT2.U |= CAN_SRC_SET_SRE ;
SRC_CAN_CAN0_INT3.U |= CAN_SRC_SET_SRE ;
SRC_CAN_CAN0_INT4.U |= CAN_SRC_SET_SRE ;
SRC_CAN_CAN0_INT5.U |= CAN_SRC_SET_SRE ;
SRC_CAN_CAN0_INT6.U |= CAN_SRC_SET_SRE ;
SRC_CAN_CAN0_INT7.U |= CAN_SRC_SET_SRE ;
然后設置CanController模式,這一步在Autosar中是由CanSM向下通過CanIf來進行控制的,這里我們手動啟動。
Can_17_McmCan_SetControllerMode (Can_17_McmCanConf_CanController_CanController_0, CAN_T_START);
然后我們定義數據及類型,調用AUTOSAR標準接口進行發送。這里說明下Can_PduType中,第一個元素為Pdu回調標識符,用于在CanIf_TxConfirmation函數中進行識別;第二個元素為DLC,第三個元素為CANID,第四個元素為數據指針。
Can_17_McmCan_Write中第一個入參為硬件資源ID,即前文CanHardwareObject配置中的ID,這里使用序號為8的硬件資源。
uint8 tx_data_1[][10] = {
{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 },
...
}
Can_PduType PduInfo_1[] =
{
{8, 8, 0x123, tx_data_1[0] },
...
};
Can_17_McmCan_Write(8, &PduInfo_1[0]) ;
然后發送之后首先Controller1會通過內部總線連接收到該幀,進入CAN中斷,并調用標準接口函數CanIf_RxIndication。
void CanIf_RxIndication(const Can_HwType *Mailbox, const PduInfoType *PduInfoPtr)
{
...
該回調將CAN層的信息傳遞到CanIf層,供上層進行數據解析。我們在這里打斷點,可以看到其中的信息。這里接收使用的HardwareObjectId為4,接收ID對應,數據符合發送端源數據。

然后在發送端Controller0會產生發送中斷,并調用標準回調函數CanIf_TxConfirmation。
void CanIf_TxConfirmation (PduIdType CanTxPduId)
{ ...
我們在這里打斷點可以看到入參CanTxPduId為前面發送時提到的Can_PduType的第一個元素,用于標識是哪個PDU的回調,以便我們在這里處理對應PDU的完成事件。

到這里我們就完成了示例,通過內部連接總線測試,實現一路Controller向另一路Controller的數據發送,并進行接收。
大家在調試過程中,如果遇到問題可以查看PSR寄存器和ECR寄存器。
PSR.LEC表征最新的錯誤狀態,比如我這里如果沒有接內部回環,就會報Ack錯誤;PSR.ACT表征當前CAN模塊的動作,如果使用具備實時觀測的調試器,在發送時能看到這個值會變成11b(比較短,非實時觀測調試器捕捉不到)。還有BusOff狀態位PSR.BO等。
ECR寄存器則用來查詢硬件錯誤計數使用的。
4 小結
本文詳細介紹了英飛凌Aurix TC3XX中的M_CAN模塊,對其內部硬件結構和原理進行了詳細介紹,對其發送、接收流程進行了詳細描述,并介紹了其在TC3XX中的集成連接。最后對MCAL中CAN模塊的配置進行了介紹,并借助MCAL Demo實現了收發示例。

