相對于其他總線,以太網(wǎng)的知識龐雜,當(dāng)然,可獲取的資料也豐富。以太網(wǎng)的知識從驅(qū)動層到上層協(xié)議棧,很難一下消化,所以,不妨從點(diǎn)開始,不斷地拓展和鏈接,從而形成完整地以太網(wǎng)知識框架,進(jìn)而更好地解決工程問題。本文,從通信出發(fā),聊一聊以太網(wǎng)發(fā)送描述符(Transmit Descriptor)。我們知道:相比與CAN、Lin等總線,以太網(wǎng)的數(shù)據(jù)吞吐量比較大,eg:1500bytes。如果讓CPU干數(shù)據(jù)搬運(yùn)工作,尤其大量數(shù)據(jù)搬運(yùn)工作,這有點(diǎn)"屈才"。所以,系統(tǒng)設(shè)計中,為了最大程度的釋放CPU,在以太網(wǎng)的數(shù)據(jù)搬運(yùn)中,會使用專門的DMA(Direct Memory Access)搬運(yùn)。如果想讓DMA知道如何搬運(yùn)數(shù)據(jù),就需要提前告知其搬運(yùn)規(guī)則,因此,描述符(Descriptor)應(yīng)用而生。對于以太網(wǎng)數(shù)據(jù)發(fā)送,則使用Transmit Descriptor描述以太網(wǎng)數(shù)據(jù)的發(fā)送規(guī)則。 Transmit Descriptor有兩種格式:Read格式和Write-Back格式。Transmit Descriptor Read Format如下所示: 如上圖,在進(jìn)行數(shù)據(jù)發(fā)送時,需要注意字節(jié)序(單片機(jī)一般是小端模式),而如上的描述符可能需要大端處理。 Transmit Normal Descriptor (Write-Back Format),示意如下: 當(dāng)DMA完成數(shù)據(jù)搬運(yùn)以后,會對描述符進(jìn)行寫回操作,主要操作TDES3的OWN和DESC STATUS位域,將發(fā)送狀態(tài)反饋給Application。 描述符是Application與DMA之間的紐帶,Application通過描述符將待發(fā)送的信息填充到Transmit Descriptor中,DMA通過判斷DES3.OWN獲取發(fā)送請求。即:Application需要發(fā)送數(shù)據(jù)時,將數(shù)據(jù)地址放入Buffer1(對應(yīng)DES0),同時,將一些控制信息寫入可用的Transmit Descriptor中,最后,設(shè)置DES3.OWN = 1,請求DMA發(fā)送數(shù)據(jù),這一步可以看作:Application將操作后的發(fā)送描述符控制權(quán)交給DMA;當(dāng)DMA發(fā)送完數(shù)據(jù)以后,將對應(yīng)發(fā)送描述符的DES3.OWN復(fù)位(=0),這一步可以看作:DMA將目標(biāo)描述符的控制權(quán)返還給Application。通過DES3.OWN,Application與DMA進(jìn)行交流,也就是"握手"動作,進(jìn)而保證數(shù)據(jù)有序交互,示意如下: DMA發(fā)送完成或者接收完成,一般會有中斷觸發(fā),如果有特殊操作,也可以在中斷回調(diào)函數(shù)中處理。 實(shí)際使用中,常常使用環(huán)形DMA描述符結(jié)構(gòu)(DMA Descriptor Ring),示意如下: 如上結(jié)構(gòu),大家并不陌生。這里,我們需要注意一些細(xì)節(jié)。 當(dāng)使用多個描述符時,描述符之間可以設(shè)置間隔(eg:DMA_Ch(#i)_Control寄存器的DSL位域,Descriptor Skip Length)。間隔設(shè)置多少需要根據(jù)手冊要求,本文可以設(shè)置的數(shù)據(jù)間隔:DWord(8 byte)的整數(shù)倍,如果DSL = 0,則意味著描述符間沒有間隔。理解以太網(wǎng)發(fā)送,還需要理解與描述符操作相關(guān)的寄存器。本文聚焦發(fā)送相關(guān)的幾個DMA寄存器:
DMA_CHi_TXDESC_LIST_ADDRESS:發(fā)送描述符的基地址,指向發(fā)送描述符鏈表的第一個描述符,初始化時賦值; DMA_CHi_CURRENT_APP_TXDESC:當(dāng)前發(fā)送描述符,指向DMA當(dāng)前可用的描述符; DMA_CHi_TXDESC_RING_LENGTH:存放發(fā)送描述符長度,可使用長度 = n + 1(n是寄存器中存儲的實(shí)際值); DMA_CHi_TXDESC_TAIL_POINTER:發(fā)送描述符尾指針,每次請求發(fā)送以太網(wǎng)Frame后,需要Application更新Transmit Descriptor地址,即:指向下一個可用的空閑描述符地址。
如果Current Descriptor Pointer == Descriptor Tail Pointer,則DMA會自動掛起(Suspend),停止數(shù)據(jù)搬運(yùn)。當(dāng)Application再次請求數(shù)據(jù)發(fā)送時,需要向Descriptor Tail Pointer中寫入發(fā)送信息,偏移Descriptor Tail Pointer,使其滿足:Current Descriptor Pointer < Descriptor Tail Pointer。如果Descriptor Tail Pointer偏移到尾部,則重新回到Descriptor Base Address。 以太網(wǎng)Frame的發(fā)送流程,示意如下:
1、Application通過DMA_CHi_CURRENT_APP_TXDESC寄存器獲取當(dāng)前可用的發(fā)送描述符地址,將發(fā)送信息填充到可用的發(fā)送描述符中,即:告知DMA搬運(yùn)規(guī)則。之后,Application將TDES3.OWN置位(=1),請求發(fā)送數(shù)據(jù);2、DMA能否搬運(yùn)數(shù)據(jù),需要判斷DMA的工作模式,如果DMA處于Stop模式,需要重新啟動DMA。通過判斷DMA_CHj_Status (j=0-7)的TPS(Transmit Process Stopped)位域確認(rèn)其是否處于Stop模式。具體描述:如果TPS == 1,表示DMA處于Stop模式,需要向TPS位域?qū)?清除,同時,進(jìn)行DMA使能操作。當(dāng)然,還可以進(jìn)一步的檢查其他信息,eg:TBU(Transmit Buffer Unavailable);3、當(dāng)Application將描述符的控制權(quán)交給DMA以后,還需要Transmit Poll Demand,即:向DMA_CHi_TXDESC_TAIL_POINTER寄存器寫入信息,一般寫入下一個可用發(fā)送描述符地址,讓DMA脫離掛起狀態(tài),去查詢待處理的發(fā)送描述符信息;4、當(dāng)DMA發(fā)送完數(shù)據(jù)以后,DMA_CHi_CURRENT_APP_TXDESC寄存器的發(fā)送描述符地址自動偏移一個,如果Current Descriptor Pointer < Descriptor Tail Pointer,DMA繼續(xù)發(fā)送數(shù)據(jù);如果Current Descriptor Pointer == Descriptor Tail Pointer,DMA隨即掛起(Suspend),停止數(shù)據(jù)搬運(yùn),同時,數(shù)據(jù)的發(fā)送狀態(tài)回寫(write-back)到TDES3中。
數(shù)據(jù)的發(fā)送流程關(guān)鍵步驟如上,理解了數(shù)據(jù)發(fā)送,也就不難理解數(shù)據(jù)的接收過程。 (一)DMA狀態(tài)變化流程 1、以太網(wǎng)專用DMA初始化以后,如果沒有數(shù)據(jù)發(fā)送,進(jìn)入Suspend狀態(tài)。此時,DMA_CHi_TXDESC_TAIL_POINTER指向空,示意如下:
2、Application請求發(fā)送數(shù)據(jù)時,從DMA_CHi_CURRENT_APP_TXDESC寄存器獲取可用的發(fā)送描述符地址,填充發(fā)送規(guī)則。向DMA_CHi_TXDESC_TAIL_POINTER寄存器寫入下一個可用描述符地址,使其滿足Current Descriptor Pointer < Descriptor Tail Pointer,即:觸發(fā)DMA發(fā)送,示意如下:3、Frame發(fā)送完成以后,DMA_CHi_CURRENT_APP_TXDESC寄存器中的可用描述符地址,自動向后偏移一個,使得Current Descriptor Pointer == Descriptor Tail Pointer,DMA隨即掛起(Suspend),示意如下:
|