英飛凌Aurix2G TC3XX GETH模塊詳解

本文主要介紹Infineon Aurix2G TC3XX系列芯片GETH模塊硬件原理,MCAL相關配置和代碼示例。
1 模塊介紹
隨著汽車科技的不斷發展,車載以太網已經成為許多車型的標配技術。相比傳統的汽車通信網絡技術,車載以太網具有更高的帶寬和數據傳輸速度,這使得車輛內部的各個系統可以更快地響應和交換信息。此外,車載以太網還能夠支持更多的設備連接,從而滿足現代汽車日益增長的智能化和互聯需求。
英飛凌Aurix2G TC3XX系列芯片的GETH模塊采用的是新思科技(Synopsys)的內核,全稱DesignWare Cores Ethernet Quality-of-Service(DWC_ether_qos)。DWC_ether_qos通常用于嵌入式系統或網絡設備中,可以幫助實現更可靠的數據傳輸、更低的延遲和更好的網絡性能。
TC3XX系列中除了旗艦的TC39X系列具有兩個GETH模塊,即支持兩路MAC,其他大部分型號都只支持一路MAC。支持10Mbps\100Mbps的RMII協議以及1000Mbps的RGMII協議(部分中低型號不支持RGMII),提供符合IEEE 802.3-2008的MAC、MII協議。
2 功能介紹
2.1 車載以太網硬件框架
為了使讀者能夠更好地理解GETH模塊的相關功能,我們需要先介紹下車載以太網的硬件基本框架。

以太網的MAC(Media Access Control)是數據鏈路層中的一個子層,負責控制數據在物理介質上的傳輸。MAC層負責實現數據幀的封裝和解封裝,處理數據幀的發送和接收順序,并通過MAC地址來識別數據包的接收方。MAC一般在我們的MCU中,類似Can Controller。
MAC之外還需要一個以太網收發器,也就是我們常說的PHY,負責物理層的功能,例如將數據轉換為適合在傳輸介質上傳輸的信號、管理數據的編碼和解碼,以及處理與傳輸介質相關的電氣特性。MAC和PHY之間有兩條交互,一條是IEEE指定的MII(Medium Independent Interface),主要進行數據幀的交互;另外一個就是SMI接口,用于通過MAC進行PHY的配置、讀取PHY寄存器等功能。二者一個是數據接口,一個是控制接口。
IEEE 802.3標準中對以太網通信系統明確了有電氣隔離的要求,因此,在以太網物理層PHY芯片之間,一般需要會通過網絡變壓器進行隔離。因此PHY需要接信號變壓器、保護電路等。
然后末端就是一個RJ45接口,也就是我們電腦常見的網線插孔,用于進行物理層信號的傳輸。但是車載設備中一般沒有網口,控制器之間的連接都是直接集成在線束中。
關于以太網的其他相關內容,大家可以自行查閱資料,工業上這塊內容已經相當成熟了。
2.2 GETH總覽
Aurix中的GETH模塊除了包含MAC內核,還具有專屬的DMA模塊,負責進行數據的收發處理。英飛凌集成后的GETH架構如圖所示:

從圖中我們可以看出,和其他片內外設一樣,MCU內部通過SRI數據總線,與GETH模塊進行以太網數據,通過SPB總線進行GETH模塊寄存器設置。GETH同樣和IR模塊進行交互,以進行中斷路由處理。
GETH獨有的DMA模塊用于數據的仲裁和搬運處理,從驅動層解放了MCU的負載。
Aurix TC3XX系列支持MII、RMII、RGMII等媒體獨立接口,從圖中我們可以看出,它們作為可選接口出現,通過Port與外部相連。另外部分中低型號是不支持RGMII的,選型時需要注意。
下方SMI接口用來進行PHY的配置,以及寄存器讀寫等操作。
然后我們看GETH模塊內部框圖(下圖為Synopsys提供的手冊,因此命名為EQOS,指DWC_ether_qos,即GETH模塊):

該圖和前面的類似,只是進行了內部拆解,最外層AHB Master接口接到英飛凌的SRI總線上,供DMA進行數據讀取和寫入;AHB Slave總線接入到英飛凌的SPB總線上用于MCU對GETH模塊的控制。第二層EQOS-DMA主要包含DMA硬件,包括仲裁單元。第三層EQOS-MTL是傳輸層,用于組包拆包(不是TCP)。最后一層是EOQS-Core,就是模塊的內核,負責數據的最下層收發處理。本節我們分別介紹這些模塊的結構和功能。
2.2.1 GETH時鐘
GETH模塊時鐘為fGETH,其來源為fSOURCE0,即系統時鐘,分頻系數為CCUCON5.GETHDIV,計算公式為:

GETH模塊的寄存器控制總線時鐘和其他外設一樣,使用SPB時鐘。
對于MII、RMII和RGMII的數據總線時鐘,大部分來自外部,僅有RGMII的TxClk來自GETH模塊,下文連接關系中我們會展開介紹。
2.2.2 CSR Slave Interface
CSR全稱為Control and Status Register,在GETH內部DMA、MTL、MAC都有各自的寄存器。前文也提到,MCU通過SPB總線訪問該接口,接口內部轉AHB協議進行數據處理。這些對于程序員來說是透明的,我們只需要根據寄存器說明訪問寄存器即可。
2.2.3 Application Master Interface
AHB Master接口用來進行AHB總線數據訪問,該接口由DMA進行控制,在系統內存和GETH模塊之間進行數據傳輸。在GETH模塊工作過程中,不管是發送端還是接收端,總是由GETH的DMA主動訪問SRI接口。
2.2.4 DMA控制器
DMA負責把從外界接收到的數據包,傳輸到系統內存中的RX Buffer里,同時把系統內存中Tx Buffer里需要發送的數據傳輸出去。DMA具有各自獨立的Tx Engine和Rx Engine,Tx和Rx各4個DMA通道,Tx Engine的方向是從系統內存到MTL,Rx Engine則是從MTL到系統內存中。
GETH模塊的DMA利用一種寄存器和Descriptors Lists(描述符鏈表)結合的機制,在高效搬運數據的同時,最大程度減小CPU的負荷。
描述符是保存在系統內存中的具有特定格式的鏈表結構數據,GETH中相關的寄存器會指向對應的描述符,而描述符指向內存中的用戶Buffer,這個結構有點類似CSA的機制。每個DMA有一個Tx描述符鏈表和一個Rx描述符鏈表。
由于Tx和Rx都會通過AHB總線訪問系統內存,即用戶Buffer,所以在全雙工的情況下,存在總線訪問沖突的場景,這時候就需要進行DMA仲裁。仲裁支持兩種模式:
Round-Robin Arbitration:當寄存器DMA_MODE.DA被設置為0時,使用該模式,該模式通過DMA_MODE.PR來按照比例為Tx和Rx分配總線帶寬;
Fixed-Priority Arbitration:當寄存器DMA_MODE.DA被設置為1,DMA_MODE.TXPR為0時,則接收的優先級永遠高于發送;如果DMA_MODE.TXPR為1時,則仲裁規則按照下表實施;

DMA的控制并不需要用戶直接干預,用戶只需要通過描述符來控制數據的收發,DMA的搬運完全在后臺由硬件完成,該內容在下文中會詳細介紹。
2.2.5 MAC Transaction Layer
MAC傳輸層(MTL)提供FIFO內存接口,用于緩沖和調節應用系統內存與MAC之間的數據包傳輸,它位于GETH模塊的DMA和MAC內核之間。傳輸層對于數據處理有兩條路徑:Trasmit Path和Receive Path,分別使用Application Transmit Interface (ATI)和Application Receive Interface (ARI)接口進行數據訪問。
在發送端DMA將數據搬運到MTL的Buffer中,當MTL中隊列滿了(threshold mode)或者隊列中已經有了完整的packet(store-and-forward mode),MTL就會將該packet取出隊列并發往MAC Core。同樣在接收端,MTL從MAC Core接收數據并存入Buffer中,當數據達到閾值或者組成一個完整的packet,則MTL會通知DMA以進行向系統內存的數據搬運。
MAC Transaction Layer的邏輯主要由硬件后臺處理,在完成初始化之后幾乎不用用戶進行處理,所以此處加以贅述,感興趣的讀者可以閱讀DWC_ether_qos手冊。
2.2.6 MAC
MAC主要負責與PHY芯片進行數據交互,MAC支持與PHY交互的多種接口,可以選擇一種PHY接口進行通訊。MAC的通訊接口除了與PHY進行通訊的MAC Transmit Interface(MTI)和MAC Receive Interface (MRI)以外,還有MCU進行MAC寄存器配置的MAC Control Interface (MCI)。
到這里就是數據鏈路層和物理層的邊界了,這里簡單介紹下以太網幀結構:

一個普通的以太網數據鏈路層幀包括目的地址、源地址、類型、數據以及校驗和,本文提到的packet是指除了校驗和以外的內容,因為以太網幀校驗和在GETH模塊中是由MAC Core處理的。
Preamble前同步碼為7個字節的1和0交替數據,用于MAC進行數據速率調整。SFD幀起始為1字節前6位1和0交替,最后的兩個連續的1表示告訴接收端適配器幀信息要來了。幀間隔是最小96bit的時間寬度,此間不進行數據傳輸。
MTL層處理的數據為數據鏈路層數據(除校驗和以外的內容),MAC層在收發端負責物理層數據的拆包和組包工作。
MAC Transmission
當MTL將數據發送到MAC,并同時拉高SOP信號線,則視為啟動一次發送,此時MAC開始將數據發往MII或者GMII。然后中間有一系列延時、ACK等邏輯完成MTL向MAC的數據發送,最后MTL拉高EOP信號線,視為MTL傳輸完成。如果是全雙工模式,意味著這一包發送完成了;但是如果是半雙工模式,MAC層還需要進行載波偵聽和碰撞檢測,以防止總線Busy的時候發包失敗,并進行重發流程。MAC層的發送流程如下圖所示:

同時MAC將MTL發來的鏈路層數據進行組包,在包頭加上前導碼、幀起始,然后計算CRC填充到尾部,并在尾部留上幀間隔。
MAC Reception
當MAC從連接PHY端的MII或者GMII接口檢測到SFD幀起始以后,首先會拆包取出Preamble前導碼和SFD幀起始,隨后開始進行數據接收。數據接收到Buffer中以后需要進行MAC地址過濾和CRC校驗,如果不通過則該包會被丟棄。接收端時序圖如圖所示:

2.3 Descriptors描述符機制
GETH模塊的收發機制采用了寄存器與描述符結合的方式,來進行數據處理,下面我們來詳細介紹這套機制以及描述符的結構。
類似CSA的機制,Aurix中使用系統內存存放描述符,使用盡可能簡潔的寄存器來表征描述符的狀態。描述符(Descriptors)是存放在系統內存,也就是RAM中的鏈接信息,它的主要功能是用作Buffer的指針,另外包括一些狀態信息和控制信息。每條描述符大小為4個word,一共16字節。描述符之間雖然可以配置為帶間隙,但是一般都是連續存放。
從數據傳遞方向的角度來說,描述符有發送描述符(Transmit Descriptor)和接收描述符(Receive Descriptor);從功能的角度來說,描述符有兩種:
Normal Descriptor:常規描述符,用來描述packet的數據,并提供適用于將要傳輸的packet的控制信息;
Context Descriptor:增強描述符,用于提供適用于將要傳輸的數據包的控制信息。
增強描述符一般很少會用到,所以本文著重介紹常規描述符,圍繞其在發送端和收發端的功能進行展開。
雖然雖然手冊上說一個描述符可以指向至多兩個Buffer,且可以把MAC幀的Header和Payload分開存放,但是實際使用過程中,包括MCAL相關的代碼及配置,都是一個描述符指向一個Buffer,多個描述符組成一個RingBuffer結構,如下圖所示。

比如當我們執行發送操作時(通過寫描述符尾寄存器),DMA就會從當前發送描述符(Current Descriptor Pointer)指向的位置開始往下輪詢,直到描述符尾指針,對所有屬于DMA控制的描述符指向的Buffer執行數據搬運。
2.3.1 描述符相關寄存器
這里我們先介紹下和描述符相關的寄存器。這里注意一下,由于搬運是由DMA通道執行的,所以每個DMA通道有自己的一套描述符寄存器。
DMA_CHi_CURRENT_APP_TXDESC:當前發送描述符,用于指向DMA下一條會讀取的描述符,也就是當前用戶可用的描述符;
DMA_CHi_CURRENT_APP_TXBUFFER:當前發送描述符指向的Buffer地址,雖然描述符里有Buffer的信息,但是Aurix還是提供了當前發送Buffer的寄存器,表示當前發送描述符指向的Buffer地址;
DMA_CHi_CURRENT_APP_RXBUFFER:當前接收描述符,表示當前用戶可用的接收描述符。
DMA_CHi_CURRENT_APP_RXBUFFER:當前接收描述符指向的Buffer地址。
DMA_CHi_TXDESC_LIST_ADDRESS:發送描述符基址,指向第一個發送描述符;
DMA_CHi_RXDESC_LIST_ADDRESS:接收描述符基址,指向第一個接收描述符;
DMA_CHi_TXDESC_RING_LENGTH:發送描述符長度,注意0表示1個描述符,以此類推;
DMA_CHi_RXDESC_RING_LENGTH:接收描述符長度,注意0表示1個描述符,以此類推;
DMA_CHi_TXDESC_TAIL_POINTER:發送描述符尾指針,指向最后一個描述符之后的地址;
DMA_CHi_RXDESC_TAIL_POINTER:接收描述符尾指針,指向最后一個描述符之后的地址。
我們通過一個實際場景來介紹下這些描述符寄存器的作用,描述符的內容可以先不用關注,后面會介紹。這是我在使用過程中的一段實際內存,它里面放了4個發送描述符,因為我這里配置了4個Buffer。

然后我們看各個寄存器的值:


我們可以看到當前CURRENT_TXDESC指向的是第二個描述符,也就是說我們要發送數據的話就使用這個描述符。然后TXDESC_LIST_ADDRESS指向第一個描述符,TXDESC_RING_LENGTH為3表示配置了4個描述符。當我們向TXDESC_TAIL_POINTER寫入尾部地址時,DMA會輪詢從CURRENT_TXDESC到TXDESC_TAIL_POINTER(左閉右開)的所有描述符,執行發送操作。當然只有第二個描述符的DMA歸屬位置位了,到第三個時DMA會自動Suspend,詳細流程我們后面再討論。
2.3.2 Transmit Descriptors發送描述符
這里我們只介紹常規描述符。
常規描述符有兩種狀態,Read-format和Write-back Format。當我們需要向外部發送數據,要按照Read-format向其中寫入Buffer地址及控制信息,然后將其控制權釋放給DMA;DMA在執行完搬運和數據發送之后,會對該描述符進行回寫,提供時間戳及狀態信息,相當于回調,告知發送狀態。
Read-Format

Read Format下的描述符如上圖所示,主要包括兩個Buffer指針、Buffer長度信息和一些其他的控制信息。從上到下4個Word依次是TDES0到TDES3,我們一一展開介紹。
TDES0:
BUF1AP:Buffer1的地址;
TDES1:
BUF2AP:Buffer2的地址,但是我們一般不使用,包括Infineon官方的MCAL代碼都是不用的;
TDES2:
IOC(31):Interrupt on Completion,完成中斷標志位,packet發送完之后會置位;
TTSE(30):Transmit Timestamp Enable,發送時間戳使能位;
B2L(29:16):Buffer2的長度;
VTIR(15:14):VLAN標簽插入、替換標志位,VLAN一般由上層處理,AUTOSAR中也一般交給EthIf來管理,所以該位一般是0;
B1L(13:0):Buffer1的長度;
TDES3:
OWN(31):DMA控制權標志位,該位置位表示DMA擁有該描述符的控制權,它會去讀取相應的Buffer,并回寫該描述符,并將該位清除;
CTXT(30):常規描述符和增強描述符位,0表示常規描述符;
FD(29):First Descriptor,表征第一個描述符,一般數據存在于多個Buffer時,有頭部、連續描述符之分,我們一般使用連續Buffer,只需要一個描述符,因此FD包括下面的LD一直都置位;
LD(28):Last Descriptor,表征是最后一個描述符;
CPC(27:26):CRC Pad控制位,
SAIC(25:23):SA Insertion Control,源地址插入控制,可以配置讓MAC層根據MAC地址寄存器自動修改源MAC地址,而不用上層指定;
SLOTNUMorTHL(22:19):Slot Number Control Bits in AV Mode,AV模式下的槽數量控制位,用于上層Header信息的輔助處理,一般不使用;
RES_18(18):預留;
CIC/TPL(17:16):Aurix提供了TCP/IP的CheckSum輔助計算功能,能夠通過硬件計算為上層降低負載;
TPL(15):Reserved or TCP Payload Length;
FL/TPL(14:0):Packet Length or TCP Payload Length,一般用作Packet長度;
Write-Back Format

我們可以看到Write-Back格式的描述符包含了時間戳和狀態位,狀態位這里就不展開介紹了,感興趣的讀者可以翻閱手冊進行查詢。
2.3.3 發送流程介紹
然后我們就著描述符來介紹GETH的發送流程:
1)用戶根據發送數據向描述符中寫入信息,包括Buffer地址、長度等,然后將描述符中的DMA控制權標志位置位;
2)用戶寫入描述符尾指針寄存器,啟動DMA;(該操作是一個啟動DMA的動作,即使描述符尾指針沒有變動,也需要寫一下)
3)DMA對所有的請求進行仲裁;
4)DMA根據當前描述符寄存器,從內存中讀取描述符;
5)DMA通道從當前發送描述符指針指向的描述符開始遍歷,直到以下條件滿足,然后DMA進入Suspend狀態,執行步驟11:
a.遍歷到的描述符屬于APP(TDES3 [31] = 0) ;
b.當前發送描述符指針等于描述符尾指針寄存器;
c.發生錯誤;
6)如果遍歷到的描述符屬于DMA,則DMA從描述符中解析Buffer地址;
7)DMA根據解析到的Buffer地址,從系統內存中讀取用戶的發送數據,送到MTL進行發送;
8)如果packet被存放在多個Buffer里,并且使用了多個描述符,DMA會立即讀取下一個描述符,步驟3到7會重復直到packet中的所有數據都被傳輸到MTL;
9)packet傳輸完成之后,如果IEEE標準規定的時間戳使能了,從MTL獲取的發送時間戳將被回寫到發送描述符(TDES0和TDES1),如果是多個描述符的packet,則寫到最后一個描述符中;相關的狀態位會被寫回到TDES3,并且DMA控制位會被清空,APP拿回描述符控制權;如果沒有使能時間戳,則DMA不修改TDES0和TDES1;
10)如果描述符中的發送完成中斷標志位使能了,DMA狀態寄存器中的發送中斷位會置位,DMA回到步驟3;
11)當用戶向描述符尾指針寄存器寫入任何值時,會啟動DMA的Polling,并回到步驟3,并且下溢中斷狀態位被清零。如果用戶通過清除DMA控制寄存器中的相應標志位來停止DMA,則DMA進入Stop模式;
下面是對應的流程圖:

也就是說,DMA初始化之后,停留在左下角的Suspend Tx DMA Queue狀態中進行等待,用戶寫入描述符尾寄存器之后DMA開始進行Transmit輪詢,完成發送之后繼續停留在Suspend狀態中。當前發送描述符寄存器是描述符鏈表的關鍵句柄,DMA每次完成一次發送后其會指向下一個描述符,末尾的描述符使用完之后會回到第一個描述符。
DMA將數據傳輸到MTL之后,就會由硬件進行后續數據的打包和發送,參考前面MAC章節。
2.3.4 Receive Descriptor接收描述符及接收流程介紹
接收描述符包括兩種類型:常規描述符和增強描述符。常規描述符同樣有Read-format和Write-back format。用戶按照Read-format格式,根據Buffer的實際容量配置完描述符之后,將描述符控制權釋放給DMA,DMA在收到完整且通過校驗的packet之后,會將數據搬運到描述符指定的接收Buffer,隨后將狀態信息以Write-back格式寫回到描述符。相比于發送描述符,接收描述符的回寫內容比較多,因此它的狀態回寫會額外占用一個增強描述符,用于補充描述狀態信息。
Read-format

Read-format的接收描述符格式如上圖,RDES0包含的是接收Buffer的地址,RDES2包含的是Buffer2或者頭的地址,但是我們一般packet存放到一個Buffer里,RDES3包含兩個重要的位,一個是DMA控制權位OWN,另一個是常規/增強描述符標志位INTE。
Write-Back Format

Write-back格式的描述符見上圖,可以看到其信息還是比較多的,但是前面也提到,VLAN一般我們會交給上層處理,所以RDES0一般在Write-back中DMA不去修改它的值。
RDES0:
IVT(31:16):如果RDES3中的RS0V置位,則該內容為接收packet的Inner VLAN標簽,否則為無效值;
OVT(31:16):如果RDES3中的RS0V置位,則該內容為接收packet的Outer VLAN標簽,否則為無效值;
RDES1:
OPC(31:16):OAM Sub-Type碼,或MAC包控制操作碼,取決于RDES3的OAM Sub-Type CodeIf Bits位域;
TD(15):Timestamp Dropped,標志著時間戳被捕獲到但是由于溢出導致丟失;
TSA(14):Timestamp Available,時間戳有效標志,該位如果置位則下一個增強描述符的RDES0和RDES1的時間戳有效;
PV(13):PTP Version,PTP版本;
PFT(12):PTP Packet type;
PMT(11:8):PTP Message Type;
IPCE(7):IP Payload Error;
IPCB(6):IP Checksum Bypass,僅當使用了IP Checksum功能時有效;
IPV6(5):IPv6 Header Present;
IPV4(4):IPv4 Header Present;
IPHE(3):IP Header Error;
PT(2:0):Payload Type,指示上層包類型,如UDP、TCP、ICMP;
RDES2:
Rsvd(31:27):Reserved;
MADRM(26:19):MAC地址或者Hash值;
HF(18):Hash Filter Status;
DAF(17):Destination Address Filter Fail,指示目標MAC地址過濾失敗;
SAF(16):SA Address Filter Fail,指示源MAC地址過濾失敗
OTS(15):VLAN filter status;
ITS(14):Inner VLAN Tag filter status;
Rsvd(13:11):Reserved;
ARPNR(10):ARP Reply Not Generated,指示MAC是否進行ARP回復;僅當使用了IPv4 ARP Offload功能時有效;
HL(9:0):L3/L4 Header Length,有些情況下packet會將上層的頭和數據分開存放到不同的Buffer中,該位域表征分割之后Header的長度;
RDES3:
OWN(31):DMA控制權標志位,1表示DMA擁有該標識符的控制權;
CTXT(30):常規/增強描述符標志位,1表示增強描述符;
FD(29):First Descriptor,首描述符;
LD(28):Last Descriptor,末尾描述符;注意,額外的增強描述符不算在內;
RS2V(27):RDES2有效位,0表示該描述符的RDES2未使用;
RS2V(26):RDES1有效位,0表示該描述符的RDES1未使用;
RS2V(25):RDES0有效位,0表示該描述符的RDES0未使用;
CE(24):CRC錯誤標志位;
GP(23):Giant Packet;
RWT(22):Receive Watchdog Timeout,表示接收超時;
OE(21):Overflow Error,表示Rx FIFO溢出;
RE(20):Receive Error,gmii_rxer_i signal信號位置位時該寄存器置位,同時該位也可表征半雙工模式下的載波偵聽錯誤;
DE(19):Dribble Bit Error;
LT(18:16):Length/Type Field;
ES(15):Error Summary;
PL(14:0):Packet Length,表征收到的packet的數據長度,包含CRC;
Receive Context Descriptor

如前所述,接收的回寫需要在常規描述符之后跟隨一個額外的增強描述符,所以這里介紹下接收增強描述符。它的RDES0是時間戳的低位,RDES1是時間戳的高位,RDES3中包含一個DMA控制權標志位OWN和一個常規/增強類型標志位CTXT。
2.3.5 接收流程介紹
接收流程和發送流程類似,都是APP操作描述符,然后等DMA操作數據,區別在于APP需要通過輪詢或中斷來判斷是否有數據接收,并進行處理,然后重置描述符,將Buffer還給DMA用于后續數據接收。
1)用戶根據接收Buffer地址填充接收描述符,然后將描述符中的DMA控制權標志位置位;
2)如果DMA已經完成初始化,則會在當前接收描述符指針和接收描述符尾指針之間進行遍歷,查找可用的描述符,如果沒有找到,則進入Suspend狀態,并執行步驟11;
3)DMA讀取可用的接收描述符然后解析接收Buffer地址;
4)如果當前描述符的時間戳使能了且上一個描述符的時間戳可用,DMA將時間戳寫入當前描述符的RDES0和RDES1,并將常規/增強描述符標志位置位,就是前文所說的跟隨的額外增強描述符;
5)DMA處理接收到的數據并將其放置到描述符指定的Buffer中;
6)如果當前packet沒有接收完全,DMA將當前描述符暫時關閉,然后到步驟10;
7)DMA將MTL傳遞過來的相關狀態位寫入到當前描述符中,清除DMA控制權標志位,并將Last Descriptor位置位;
8)DMA將幀長度寫入到RDES3中,將VLAN TAG寫入到RDES0中,并寫入MAC control frame opcode、OAM control frame code、extended status information到RDES1中;
9)如果時間戳使能了,DMA將接收時間戳值暫存。后續將其寫入到下一個增強描述符中(如步驟4描述);
10)如果描述符鏈表中仍有描述符需要處理,執行步驟3,否則進入Suspend狀態,執行步驟11;
11)DMA進入Suspend狀態,等待用戶通過寫接收描述符尾寄存器進行輪詢請求。
下面是對應的流程圖:

總結下來,就是用戶給了指定的Buffer,然后將對應描述符的控制權交給DMA,然后輪詢或者中斷查看描述符狀態,如果有收到packet,將數據傳給上層進行處理,然后重置下描述符繼續交給DMA去接收數據。
2.4 PHY控制接口
對于MCU來說,PHY是MCU的外設,除了使用RMII、RGMII等接口進行數據傳輸以外,還需要對其進行控制。PHY作為信號收發器,其內部邏輯比其他收發器如CAN收發器要復雜得多。其控制邏輯一般是使用SMI協議,包含一個MDC主機時鐘線,和一根MDIO半雙工數據線。

SMI協議的傳輸相對還是比較簡單的,它有讀和寫兩種訪問形式:

結構包括一個類似前導碼的idle位,一個起始位,讀寫標志位,操作碼,PHY地址,目的寄存器,半雙工控制轉換位,數據和結尾的idle位。
因為一個SMI接口可以控制多個PHY,所以硬件連接上PHY是需要地址的,具體參考硬件設計說明。
PHY的讀寫控制是有指定序列的,雖然大同小異,但是還是要根據其手冊編寫對應代碼。下面是英飛凌iLLD中使用的讀PHY寄存器的Demo代碼,具體的邏輯可以參考DP83825i手冊。其中的Eth_WriteMii和Eth_ReadMii就是MAC的接口。
Std_ReturnType IfxGeth_Eth_Phy_Dp83825i_read_mdio_reg(uint8 EthCtrl, uint16 regAddr, uint16 *pdata)
{
Std_ReturnType ret = E_OK;
uint16 regDomain;
if(regAddr<=0x1F){
ret |= Eth_ReadMii(EthCtrl, DP83_TRCVID, (uint8)regAddr, pdata);
}else{
regDomain = DP83_GetRegDomain(regAddr);
ret |= Eth_WriteMii(EthCtrl, DP83_TRCVID, DP83_REGCR, regDomain);
ret |= Eth_WriteMii(EthCtrl, DP83_TRCVID, DP83_ADDAR, regAddr);
ret |= Eth_WriteMii(EthCtrl, DP83_TRCVID, DP83_REGCR, regDomain|DP83_NOINC);
ret |= Eth_ReadMii(EthCtrl, DP83_TRCVID, DP83_ADDAR, pdata);
}
return ret;
}
2.5 調試相關寄存器
這里介紹幾個比較重要的寄存器,調試過程中使用還是非常有必要的。下面寄存器的屬性比較固定,就不一一解釋了,TX表示發送,RX表示接收,GOOD_BAD表示所有包,GOOD表示成功的包,OCTET表示字節數,Packet表示包數:
TX_OCTET_COUNT_GOOD_BAD
TX_OCTET_COUNT_GOOD
TX_PACKET_COUNT_GOOD_BAD
TX_PACKET_COUNT_GOOD
RX_OCTET_COUNT_GOOD_BAD
RX_OCTET_COUNT_GOOD
RX_PACKETS_COUNT_GOOD_BAD
RX_RECEIVE_ERROR_PACKETS
RX_CRC_ERROR_PACKETS
這里需要注意的是,接收端的計數是位于VLAN過濾器和MAC地址過濾器之后的,對于MAC地址不符的幀上述Counter都不會累加。
2.6 引腳與中斷連接
對于不同的介質獨立接口,如RMII、MII、RGMII,有不同的連接定義,也需要不同的數據時鐘。另外除了RGMII需要輸出發送時鐘以外,MCU的時鐘都需要外部進行輸入。SMI協議的引腳是固定的,一根時鐘線MDC,和一根半雙工數據線MDIO,我們只需要根據硬件設計進行配置接口。
下面我們以RMII接口為例,來介紹如何查詢接口引腳,以進行相關配置。我們先來看RMII的引腳定義,下圖是DP83825i的RMII Master信號定義,本文只關注MAC這一側:

TX_EN:TX使能,發送數據時拉高;
TX_D[1:0]:發送數據線,RMII有兩根發送數據線;
RX_CLK:接收時鐘,不使用
RX_DV:接收數據有效位,不使用;
RX_ER:接收錯誤位,不使用;
RX_D:接收數據線,RMII有兩根接收數據線;
CRS_DV:載波偵聽位和接收數據有效位的結合線,使用該線不需要RX_D線;
50-MHz Reference Clock:50MHz參考時鐘,需要PHY或者外部晶振提供;
對于這些引腳,我們在MCAL中是可以直接下拉選擇的,但是對于某些工具如Vector DaVinci配置工具,是沒法直接選擇的,所以我們還是需要掌握芯片內部的配置原理。
GETH模塊的引腳配置,在GPCTL(General Purpose Control Register)寄存器中,其中位域ALTIx(x=0~10)用來配置對應的引腳,這些配置我們不一定需要全部去配,因為它包含了RMII、RGMII等所有支持的配置,因此我們只需要根據我們的接口類型,配置我們需要的引腳即可。它的定義如下:

然后我們來到芯片手冊(注意是特定型號的手冊,類似TC37x UserManual,不是TC3XX Family UserManual)中,來到42.4 Connectivity章節(本文使用的是TC37X手冊),Table 348 Connections of GETH。
比如我要配置RXD0,查詢到該數據線支持連接的引腳RXD0A(TC37X系列只有一個,如果其他型號會有RXD0B、RXD0C等供選擇):

因此GPCTL中ALTI6位域設置為0(A對應0,以此類推),在Port模塊中配置P11.10即可,可參考之前發布的Port相關的文章。對于發送數據,GETH模塊會在所有可選的輸出腳中輸出該信號,因此不需要在GETH中配置,只取決于Port中是否將該引腳分配給GETH使用。
這里需要額外注意的是,對于數據發送信號,Pin的配置最下面有一個PortPinControllerSelect選項需要使能。

另外MDIO作為半雙工數據引腳,引腳方向需要配置為OUT。
中斷連接同樣也是查詢芯片用戶手冊:

3 MCAL配置及代碼示例
本文使用TC375芯片,以RMII 100M接口為例,對MCAL配置和代碼進行說明。
3.1 General

General頁面中大多是一些接口使能配置和權限,這里只對一些特殊項進行說明:
EthTimeoutCount:該參數定義了WriteMii、復位DMA等訪問的超時時間;
EthDmaSwResetWaitCycle:該參數定義了DMA復位之后的等待時鐘周期;

GETH模塊具有填充上層如網絡層Checksum的功能,可以在這里進行使能。
3.2 EthCtrlConfig
我這里使用的AUTOSAR版本是AR4.2.2,如果是AR4.4.0,controller這里參數會稍微多一點,但是整體邏輯沒有大改。


EthSpeed:這里配置了信號收發頻率,100M或10M,硬件內部會自動計算分頻,無需修改外部輸入時鐘;
EthPhyInterface:MII接口模式,這里配置RMII;
EthOpMode:信號模式,全雙工;
EthCtrlPhyAddress:源MAC地址;
EthCtrlRxBufLenByte:接收數據Buffer尺寸,這里配最大值1522;
EthCtrlTxBufLenByte:發送數據Buffer尺寸,這里配最大值1522;
EthRxBufTotal:接收Buffer數量,一般4個就夠了;
EthTxBufTotal:發送Buffer數量,一般4個就夠了;
EthMdioAlternateInput:MDIO接口輸入選擇,下面幾個接口相同,可參考上文連接章節,不再一一贅述;
EthCtrlEnableMii:Mii接口使能,控制PHY用的,勾選;
EthCtrlEnableRxInterrupt:接收中斷使能,一般建議接收使用輪詢,中斷模式下外部數據發送較快的時候系統不可控;
EthCtrlEnableTxInterrupt:發送完成中斷,MCAL給的中斷里主要是更新Buffer的使用狀態,如果不用中斷需要調用TxConfirmation來輪詢Buffer狀態,建議使用中斷;
EthSkewTxClockDelay:Tx發送延時,單位222ps,RGMII下才需要使用;
EthSkewRxClockDelay:Rx發送延時,單位222ps,RGMII下才需要使用;
EthCtrlEnableCrcStripping:CRC字段剝離配置,如果勾選MAC幀的CRC將不再傳遞到上層;
EthMDCClockFrequency:SMI接口MDC時鐘線的頻率,一般配置2.5M,太高PHY會不支持;
到這里配置就結束了,是不是很簡單,但這只是以太網調試的開始。
3.3 代碼示例
本文示例內容包括初始化、數據發送、數據接收,均使用Infineon MCAL標準接口。
3.3.1 初始化
首先是初始化:
Eth_Init(&Eth_Config); /* 模塊初始化 */
IfxGeth_Eth_Phy_Dp83825i_init(); /* PHY初始化,這里不展開介紹了 */
/* 設置Controller Mode為Active */
Eth_SetControllerMode(Eth_17_GEthMacConf_EthCtrlConfig_EthCtrlConfig_0, ETH_MODE_ACTIVE);
3.3.2 數據發送
信號發送方面只需要先申請Buffer,然后填充對應的數據,進行發送即可,如果沒有使能發送中斷,需要周期調用Eth_TxConfirmation。發送的時候Buffer從網絡層數據開始填充,目的MAC地址和報文類型以入參形式傳遞。這里注意bufferPtr是用來獲取Buffer的地址,因此入參要取指針的地址。
uint8 *bufferPtr;
Eth_BufIdxType bufferIdx;
bufRet = Eth_ProvideTxBuffer(Eth_17_GEthMacConf_EthCtrlConfig_EthCtrlConfig_0, &bufferIdx, &bufferPtr, &length);
if(bufRet == BUFREQ_OK){
/* Buffer填充,這里填充的數據不包括目的MAC地址、源MAC地址和報文類型,僅包含網絡層數據報內容 */
}
txRet = Eth_Transmit(Eth_17_GEthMacConf_EthCtrlConfig_EthCtrlConfig_0, bufferIdx, frameType, TRUE, numOfBufToLow, &desPhyAddr[0]);
我這里使用的是發送UDP報文,發送Buffer地址為0x70002906,Buffer數據長度為38個字節,僅包含網絡層內容,內存如下:

然后我們觀察數據包,內容同上(以太網最小64字節,多出的8字節0為填充):

3.3.3 數據接收
對于接收來說,首先需要進行輪詢,以更新描述符,以及進行數據處理,放到周期任務中即可。
Eth_RxStatusType rxStatus; Eth_Receive(Eth_17_GEthMacConf_EthCtrlConfig_EthCtrlConfig_0, &rxStatus);
然后接收下層會進行回調,GETH調用EthIf_RxIndication通知上層,本文這里集成了Lwip,所以接入了對應的接口。另外注意這里如果接收用的是中斷,是在中斷中進行回調,處理邏輯需要注意。
void EthIf_RxIndication( uint8 CtrlIdx, Eth_FrameType FrameType, boolean IsBroadcast, const uint8* PhysAddrPtr, Eth_DataType* DataPtr, uint16 LenByte )
{
netif_Indication(CtrlIdx,FrameType,IsBroadcast,PhysAddrPtr,DataPtr,LenByte);
}
然后我們發送一個PING包給控制器,電腦端觀察包內容(已進行過ARP的MAC地址查找):

然后我們觀察EthIf_RxIndication輸入的內容,首先我們看傳參:

傳參這里幀類型為IPv4的0x0800,源MAC地址存在0x70000516,數據地址為0x7000051E,數據長度為64字節,這里起始GETH硬件是將MAC幀整包傳上來的,從0x70000510開始,只是函數接口形式將包進行了拆分:

相對于PING包的原始內容,末尾多了4字節的CRC字段,這是因為電腦端WireShark沒有打開CRC觀測。
4 小結
本文詳細介紹了英飛凌Aurix TC3XX中的GETH模塊,對其內部硬件結構和原理進行了分層闡述,并結合描述符機制對發送和接收流程進行了說明。最后對MCAL中GETH模塊的配置進行了介紹,并通過MCAL示例代碼對數據收發做了演示。

