STM32网络控制器框图如下:
前面的文章我们已经讲解了:
①External PHY Intereface:《STM32网络电路设计》
②MAC控制器:《STM32MAC控制器》
下面我们讲解第③部分,STM32网络的DMA控制器。
01、DMA控制器操作
DMA具有自主的发送和接收引擎,还有一个CSR(控制和状态寄存器)空间。发送引擎将数据从系统存储器传送到 TxFIFO,而接收引擎将数据从Rx FIFO传送到系统存储器。
控制器(也就是DMA)利用描述符有效的将数据从源地址移动到目的地,很小的CPU干预。DMA专为面向包的数据传送(如以太网中的帧)而设计。
控制器可以编程去打断CPU,例如完成帧发送和接收传送操作时以及其它正常/错误条件下。
DMA和STM32F20x 和STM32F21x通过以下两种数据结构进行通信:
-
控制和状态寄存器 (CSR)
-
描述符列表和数据缓冲区。
DMA控制器发送接收到的数据帧到STM32F20x的接收缓存中和STM32F21x存储器中,也可以发送数据帧从STM32F20x的存储器的发送缓存,位于STM32F20x存储器的描述符指向这些缓存。
这里有两个描述符列表:一个用于接收,一个用于发送。
DMA描述符如下图,左边是环形结构,右边是链式结构。
02、DMA描述符
在ST提供的以太网驱动库stm32f2x7_eth.c中使用是链接结构,链接结构如下:
描述符注意事项:
1、一个以太网数据包可以跨越一个或多个DMA描述符
2、一个DMA描述符只能用于一个以太网数据包
3、DMA描述符列表中的最后一个描述符指向第一个,形成链式结构!
描述符有分为增强描述符和常规描述符,我们只讲常规描述符!因为我们的网络例程只使用到了常规描述符。常规描述符和增强描述符的结构体成员变量不同。常规描述符只使用了描述符的前4个成员变量。
注意:这里说的描述符,没有硬件结构,不是寄存器,它完全是纯软件的概念。
那么描述符怎么和硬件关联的呢?
描述符的本质就是我们自己用结构体来实现这个描述符,然后将描述符的首地址写入到【ETH_DMATDLAR】寄存器中,STM32就知道这片内存是用来作为发送描述符了。
常规描述符和增强描述符又有发送描述符和接收描述符两种。
下图是常规TxDMA描述符:
TDES0主要用来表示描述符的状态和控制信息。
TDES1表示该描述符缓冲区数据的有效长度。
TDES2表示描述符缓冲区的地址,我们要发送的数据,就是放在这个地址所指向的内存中。
TDES3表示下一个描述符的地址。
重要的信息有:
TDES 0中的OWN位:
0:表示CPU占有描述符,CPU可以从DMA中提取数据,但是DMA不能从FIFO从接收数据。
1:表示DMA占有描述符,CPU不可以从DMA中提取数据,DMA可以从FIFO从接收数据。
DMA在传输完整个帧或者这个缓存里的数据全部读出以后把该位清0'。每个帧的第一个缓存描述符的占有位,必须在后面缓存描述符的占有位全部置'1'以后,才能置"1'。
发送过程:
1、当OWN位为0的时候,表示CPU可以将要发送的数据拷贝到描述符中,拷贝完成以后,我们手动将描述符的OWN位设置为1,以此来告诉DMA控制器,我已经拷贝完数据了,你可以从描述符中取出数据进行发送了。
2、这时候DMA就会取出描述符中的数据,将数据发送出去,DMA在操作完描述符以后,自动将OWN位设置为0,告诉CPU,我DMA已经发送完数据啦,你可以拷贝下一帧数据到描述符上了。
3、这个时候OWN为0了,重复步骤1
整个发送的过程就是这样配合的。这样DMA和CPU之间就不会抢占数据了。
DES 0中的位20 TCH:链接的第二个地址(Second address chained)
用来表示描述符中的第二个地址是用来保存下一个描述符地址还是第二个缓冲区的地址。
该位置1时,表示描述符中的第二个地址是下一个描述符地址,而非第二个缓冲区地址。也就是上ST使用的链式结构。
常规RxDMA描述符如下
常规RxDMA描述符中RDES1的bit14用来表示描述符中的第二个地址是用来保存一个描述符地址还是第二个缓冲区的地址。
描述符在代码中的表现,在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;
03、ST提供的库中描述符
ST官方以太网库stm32f2x7中使用链接结构的DMA描述符,那么在以太网描述符结构体ETH_DMADESCTypeDef中Buffer1Addr就是缓冲区的地址,Buffer2NextDescAddr就是下一个描述符的地址,
如下图。
在stm32f2x7_eth.c中定义了两个DMA描述符数组,一个用于DMA接收,一个用于DMA发送,如下:
接收和发送描述的大小通过宏ETH_RXBUFNB和ETH_TXBUFNB来定义,默认都为5。
我们知道以链接结构太网描述符的Buffer1Addr成员用来存放缓冲区地址,那么数据缓冲区在哪里?这个数据缓冲区也是定义为数组的,如下:
把他们联系在一起的代码,把描述符和缓冲区联系起来,也就是下面的函数把描述符标构成链式结构。
在ethernetif.c的low_level_init函数中
解析如下
全局描述符指针,用来记录当前使用的描述符
描述数据包的描述符(英文:用于保存最后一个接收的包描述符信息的结构。)
结构体
第一个表示数据包的第一个描述符,第二个表示数据包的最后一个描述符,第三个表示数据包描述符的个数。
最终的效果如下:
04、FIFO
从STM32网络控制器框图中可以看到两个2KB的FIFO,一个发送FIFO,一个接收FIFO。
发送FIFO
提供两种FIFO数据模式用于帧传输
-
阈值模式:当达到阈值后,尽快传输数据。
-
Store-and-Forward mode:FIFO中会存储一个完整的帧结构。
STM32的发送FIFO采用Store-and-Forwardmode模式。
接收FIFO
接收FIFO采用Store-and-Forwardmode模式。
点击查看本文所在的专辑,STM32F207网络开发