詳解STM32網(wǎng)絡(luò)之DMA控制器
STM32網(wǎng)絡(luò)控制器框圖如下:

前面的文章我們已經(jīng)講解了:
①External PHY Intereface:《STM32網(wǎng)絡(luò)電路設(shè)計(jì)》
②MAC控制器:《STM32MAC控制器》
下面我們講解第③部分,STM32網(wǎng)絡(luò)的DMA控制器。
01DMA控制器操作
DMA具有自主的發(fā)送和接收引擎,還有一個(gè)CSR(控制和狀態(tài)寄存器)空間。發(fā)送引擎將數(shù)據(jù)從系統(tǒng)存儲(chǔ)器傳送到 TxFIFO,而接收引擎將數(shù)據(jù)從Rx FIFO傳送到系統(tǒng)存儲(chǔ)器。
控制器(也就是DMA)利用描述符有效的將數(shù)據(jù)從源地址移動(dòng)到目的地,很小的CPU干預(yù)。DMA專為面向包的數(shù)據(jù)傳送(如以太網(wǎng)中的幀)而設(shè)計(jì)。
控制器可以編程去打斷CPU,例如完成幀發(fā)送和接收傳送操作時(shí)以及其它正常/錯(cuò)誤條件下。
DMA和STM32F20x 和STM32F21x通過以下兩種數(shù)據(jù)結(jié)構(gòu)進(jìn)行通信:
- 控制和狀態(tài)寄存器 (CSR)
- 描述符列表和數(shù)據(jù)緩沖區(qū)。
DMA控制器發(fā)送接收到的數(shù)據(jù)幀到STM32F20x的接收緩存中和STM32F21x存儲(chǔ)器中,也可以發(fā)送數(shù)據(jù)幀從STM32F20x的存儲(chǔ)器的發(fā)送緩存,位于STM32F20x存儲(chǔ)器的描述符指向這些緩存。
這里有兩個(gè)描述符列表:一個(gè)用于接收,一個(gè)用于發(fā)送。
DMA描述符如下圖,左邊是環(huán)形結(jié)構(gòu),右邊是鏈?zhǔn)浇Y(jié)構(gòu)。

02DMA描述符
在ST提供的以太網(wǎng)驅(qū)動(dòng)庫stm32f2x7_eth.c中使用是鏈接結(jié)構(gòu),鏈接結(jié)構(gòu)如下:
描述符注意事項(xiàng):
1、一個(gè)以太網(wǎng)數(shù)據(jù)包可以跨越一個(gè)或多個(gè)DMA描述符
2、一個(gè)DMA描述符只能用于一個(gè)以太網(wǎng)數(shù)據(jù)包
3、DMA描述符列表中的最后一個(gè)描述符指向第一個(gè),形成鏈?zhǔn)浇Y(jié)構(gòu)!
描述符有分為增強(qiáng)描述符和常規(guī)描述符,我們只講常規(guī)描述符!因?yàn)槲覀兊木W(wǎng)絡(luò)例程只使用到了常規(guī)描述符。常規(guī)描述符和增強(qiáng)描述符的結(jié)構(gòu)體成員變量不同。常規(guī)描述符只使用了描述符的前4個(gè)成員變量。
注意:這里說的描述符,沒有硬件結(jié)構(gòu),不是寄存器,它完全是純軟件的概念。
那么描述符怎么和硬件關(guān)聯(lián)的呢?
描述符的本質(zhì)就是我們自己用結(jié)構(gòu)體來實(shí)現(xiàn)這個(gè)描述符,然后將描述符的首地址寫入到【ETH_DMATDLAR】寄存器中,STM32就知道這片內(nèi)存是用來作為發(fā)送描述符了。
常規(guī)描述符和增強(qiáng)描述符又有發(fā)送描述符和接收描述符兩種。
下圖是常規(guī)TxDMA描述符:
TDES0主要用來表示描述符的狀態(tài)和控制信息。
TDES1表示該描述符緩沖區(qū)數(shù)據(jù)的有效長度。
TDES2表示描述符緩沖區(qū)的地址,我們要發(fā)送的數(shù)據(jù),就是放在這個(gè)地址所指向的內(nèi)存中。
TDES3表示下一個(gè)描述符的地址。
發(fā)送過程:
1、當(dāng)OWN位為0的時(shí)候,表示CPU可以將要發(fā)送的數(shù)據(jù)拷貝到描述符中,拷貝完成以后,我們手動(dòng)將描述符的OWN位設(shè)置為1,以此來告訴DMA控制器,我已經(jīng)拷貝完數(shù)據(jù)了,你可以從描述符中取出數(shù)據(jù)進(jìn)行發(fā)送了。
2、這時(shí)候DMA就會(huì)取出描述符中的數(shù)據(jù),將數(shù)據(jù)發(fā)送出去,DMA在操作完描述符以后,自動(dòng)將OWN位設(shè)置為0,告訴CPU,我DMA已經(jīng)發(fā)送完數(shù)據(jù)啦,你可以拷貝下一幀數(shù)據(jù)到描述符上了。
3、這個(gè)時(shí)候OWN為0了,重復(fù)步驟1
整個(gè)發(fā)送的過程就是這樣配合的。這樣DMA和CPU之間就不會(huì)搶占數(shù)據(jù)了。
DES 0中的位20 TCH:鏈接的第二個(gè)地址(Second address chained)
用來表示描述符中的第二個(gè)地址是用來保存下一個(gè)描述符地址還是第二個(gè)緩沖區(qū)的地址。
該位置1時(shí),表示描述符中的第二個(gè)地址是下一個(gè)描述符地址,而非第二個(gè)緩沖區(qū)地址。也就是上ST使用的鏈?zhǔn)浇Y(jié)構(gòu)。
常規(guī)RxDMA描述符如下
常規(guī)RxDMA描述符中RDES1的bit14用來表示描述符中的第二個(gè)地址是用來保存一個(gè)描述符地址還是第二個(gè)緩沖區(qū)的地址。
描述符在代碼中的表現(xiàn),在stm32f2x7_eth.h文件中。
- /**--------------------------------------------------------------------------**/
- /**
- * @brief DMA descriptors types
- */
- /**--------------------------------------------------------------------------**/
- /**
- * @brief ETH DMA Descriptors data structure definition
- */
- typedef struct {
- __IO uint32_t Status; /*!< Status */
- uint32_t ControlBufferSize; /*!< Control and Buffer1, Buffer2 lengths */
- uint32_t Buffer1Addr; /*!< Buffer1 address pointer */
- uint32_t Buffer2NextDescAddr; /*!< Buffer2 or next descriptor address pointer */
- /* Enhanced ETHERNET DMA PTP Descriptors */
- #ifdef USE_ENHANCED_DMA_DESCRIPTORS
- uint32_t ExtendedStatus; /* Extended status for PTP receive descriptor */
- uint32_t Reserved1; /* Reserved */
- uint32_t TimeStampLow; /* Time Stamp Low value for transmit and receive */
- uint32_t TimeStampHigh; /* Time Stamp High value for transmit and receive */
- #endif /* USE_ENHANCED_DMA_DESCRIPTORS */
- } ETH_DMADESCTypeDef;
03ST提供的庫中描述符
ST官方以太網(wǎng)庫stm32f2x7中使用鏈接結(jié)構(gòu)的DMA描述符,那么在以太網(wǎng)描述符結(jié)構(gòu)體ETH_DMADESCTypeDef中Buffer1Addr就是緩沖區(qū)的地址,Buffer2NextDescAddr就是下一個(gè)描述符的地址,
如下圖。
在stm32f2x7_eth.c中定義了兩個(gè)DMA描述符數(shù)組,一個(gè)用于DMA接收,一個(gè)用于DMA發(fā)送,如下:

接收和發(fā)送描述的大小通過宏ETH_RXBUFNB和ETH_TXBUFNB來定義,默認(rèn)都為5。
我們知道以鏈接結(jié)構(gòu)太網(wǎng)描述符的Buffer1Addr成員用來存放緩沖區(qū)地址,那么數(shù)據(jù)緩沖區(qū)在哪里?這個(gè)數(shù)據(jù)緩沖區(qū)也是定義為數(shù)組的,如下:

把他們聯(lián)系在一起的代碼,把描述符和緩沖區(qū)聯(lián)系起來,也就是下面的函數(shù)把描述符標(biāo)構(gòu)成鏈?zhǔn)浇Y(jié)構(gòu)。
在ethernetif.c的low_level_init函數(shù)中

解析如下
全局描述符指針,用來記錄當(dāng)前使用的描述符

描述數(shù)據(jù)包的描述符(英文:用于保存最后一個(gè)接收的包描述符信息的結(jié)構(gòu)。)

結(jié)構(gòu)體

第一個(gè)表示數(shù)據(jù)包的第一個(gè)描述符,第二個(gè)表示數(shù)據(jù)包的最后一個(gè)描述符,第三個(gè)表示數(shù)據(jù)包描述符的個(gè)數(shù)。
最終的效果如下:

04FIFO
從STM32網(wǎng)絡(luò)控制器框圖中可以看到兩個(gè)2KB的FIFO,一個(gè)發(fā)送FIFO,一個(gè)接收FIFO。
發(fā)送FIFO
提供兩種FIFO數(shù)據(jù)模式用于幀傳輸
- 閾值模式:當(dāng)達(dá)到閾值后,盡快傳輸數(shù)據(jù)。
- Store-and-Forward mode:FIFO中會(huì)存儲(chǔ)一個(gè)完整的幀結(jié)構(gòu)。
STM32的發(fā)送FIFO采用Store-and-Forwardmode模式。

接收FIFO
接收FIFO采用Store-and-Forwardmode模式。
