詳解STM32網絡之DMA控制器
STM32網絡控制器框圖如下:

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

02DMA描述符
在ST提供的以太網驅動庫stm32f2x7_eth.c中使用是鏈接結構,鏈接結構如下:
描述符注意事項:
1、一個以太網數據包可以跨越一個或多個DMA描述符
2、一個DMA描述符只能用于一個以太網數據包
3、DMA描述符列表中的最后一個描述符指向第一個,形成鏈式結構!
描述符有分為增強描述符和常規(guī)描述符,我們只講常規(guī)描述符!因為我們的網絡例程只使用到了常規(guī)描述符。常規(guī)描述符和增強描述符的結構體成員變量不同。常規(guī)描述符只使用了描述符的前4個成員變量。
注意:這里說的描述符,沒有硬件結構,不是寄存器,它完全是純軟件的概念。
那么描述符怎么和硬件關聯(lián)的呢?
描述符的本質就是我們自己用結構體來實現(xiàn)這個描述符,然后將描述符的首地址寫入到【ETH_DMATDLAR】寄存器中,STM32就知道這片內存是用來作為發(fā)送描述符了。
常規(guī)描述符和增強描述符又有發(fā)送描述符和接收描述符兩種。
下圖是常規(guī)TxDMA描述符:
TDES0主要用來表示描述符的狀態(tài)和控制信息。
TDES1表示該描述符緩沖區(qū)數據的有效長度。
TDES2表示描述符緩沖區(qū)的地址,我們要發(fā)送的數據,就是放在這個地址所指向的內存中。
TDES3表示下一個描述符的地址。
發(fā)送過程:
1、當OWN位為0的時候,表示CPU可以將要發(fā)送的數據拷貝到描述符中,拷貝完成以后,我們手動將描述符的OWN位設置為1,以此來告訴DMA控制器,我已經拷貝完數據了,你可以從描述符中取出數據進行發(fā)送了。
2、這時候DMA就會取出描述符中的數據,將數據發(fā)送出去,DMA在操作完描述符以后,自動將OWN位設置為0,告訴CPU,我DMA已經發(fā)送完數據啦,你可以拷貝下一幀數據到描述符上了。
3、這個時候OWN為0了,重復步驟1
整個發(fā)送的過程就是這樣配合的。這樣DMA和CPU之間就不會搶占數據了。
DES 0中的位20 TCH:鏈接的第二個地址(Second address chained)
用來表示描述符中的第二個地址是用來保存下一個描述符地址還是第二個緩沖區(qū)的地址。
該位置1時,表示描述符中的第二個地址是下一個描述符地址,而非第二個緩沖區(qū)地址。也就是上ST使用的鏈式結構。
常規(guī)RxDMA描述符如下
常規(guī)RxDMA描述符中RDES1的bit14用來表示描述符中的第二個地址是用來保存一個描述符地址還是第二個緩沖區(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官方以太網庫stm32f2x7中使用鏈接結構的DMA描述符,那么在以太網描述符結構體ETH_DMADESCTypeDef中Buffer1Addr就是緩沖區(qū)的地址,Buffer2NextDescAddr就是下一個描述符的地址,
如下圖。
在stm32f2x7_eth.c中定義了兩個DMA描述符數組,一個用于DMA接收,一個用于DMA發(fā)送,如下:

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

把他們聯(lián)系在一起的代碼,把描述符和緩沖區(qū)聯(lián)系起來,也就是下面的函數把描述符標構成鏈式結構。
在ethernetif.c的low_level_init函數中

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

描述數據包的描述符(英文:用于保存最后一個接收的包描述符信息的結構。)

結構體

第一個表示數據包的第一個描述符,第二個表示數據包的最后一個描述符,第三個表示數據包描述符的個數。
最終的效果如下:

04FIFO
從STM32網絡控制器框圖中可以看到兩個2KB的FIFO,一個發(fā)送FIFO,一個接收FIFO。
發(fā)送FIFO
提供兩種FIFO數據模式用于幀傳輸
- 閾值模式:當達到閾值后,盡快傳輸數據。
- Store-and-Forward mode:FIFO中會存儲一個完整的幀結構。
STM32的發(fā)送FIFO采用Store-and-Forwardmode模式。

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