基于STM32F407MAC与DP83848实现以太网通讯四(STM32F407MAC数据收发与DMA描述符)
上一章实现的MAC数据包的基础收发功能,但是只是简单的操作了ETH外设的收发包函数并没有深入了解其中的原理逻辑,本章结合STM32F40x文档与STM32F4x7_ETH_Driver驱动库了解MAC的收发包流程。
一、描述符列表

在创建描述符列表之前先了解描述符列表的定义,描述符就软件来说就是一个结构体,而描述符列表分为两种结构。
①环形结构(环形队列)
②链接结构(环形链表)
这两种数据结构可以参考网上其他的说明,了解数据结构的话对这两种结构应该很熟悉了。
驱动库中定义的描述符结构体如下:
/**
* @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;
 
结合代码与手册图,TDES0 为DMA描述符状态位,TDES1为控制位和对RDES2、RDES3的字节计数。使用环形结构时TDES3 作为缓冲区2的地址,使用链接结构时TDES3作为下一个描述符的地址。
Tx描述符与Rx描述符在TDES0 不同,RDES1、RDES2、RDES3都是相同的。
MAC的发送与接收主要就是对DMA描述符的读写操作。
USE_ENHANCED_DMA_DESCRIPTORS 为定义使用增强描述符,具体参考STM32F4xx手册。
接下来就是具体的MAC发送、接收以及描述符相关操作的代码分析了。
二、链接结构描述符创建
ETH驱动库创建的描述符列表是环形链接结构的。
/* Initialize Tx Descriptors list: Chain Mode */
ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
/* Initialize Rx Descriptors list: Chain Mode */
ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
ethernetif.c中,low_level_init()函数在配置完MAC地址之后,创建了Tx和Rx的描述符链表。使用到的参数如下:
/* Ethernet Rx & Tx DMA Descriptors */
extern ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB], DMATxDscrTab[ETH_TXBUFNB];
/* Ethernet Driver Receive buffers */
extern uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE];
/* Ethernet Driver Transmit buffers */
extern uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE];
//stm32f4x7_eth.c
#define ETH_RXBUFNB 4 /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
#define ETH_TXBUFNB 4 /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
首先是创建Tx和Rx描述符的第一参数:DMARxDscrTab[ETH_RXBUFNB]和DMATxDscrTab[ETH_TXBUFNB]为两个结构体数组,数组的成员为描述符列表的成员,也就是说创建了有4个节点Rx描述符链表和4个节点Dx描述符链表。
//stm32f4x7_eth.c
#ifdef CUSTOM_DRIVER_BUFFERS_CONFIG
/* Redefinition of the Ethernet driver buffers size and count */
#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */
#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */
#define ETH_RXBUFNB 4 /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
#define ETH_TXBUFNB 4 /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
#endif
/** @defgroup ENET_Buffers_setting
* @{
*/
#define ETH_MAX_PACKET_SIZE 1524 /*!< ETH_HEADER + ETH_EXTRA + VLAN_TAG + MAX_ETH_PAYLOAD + ETH_CRC */
#define ETH_HEADER 14 /*!< 6 byte Dest addr, 6 byte Src addr, 2 byte length/type */
#define ETH_CRC 4 /*!< Ethernet CRC */
#define ETH_EXTRA 2 /*!< Extra bytes in some cases */
#define VLAN_TAG 4 /*!< optional 802.1q VLAN Tag */
#define MIN_ETH_PAYLOAD 46 /*!< Minimum Ethernet payload size */
#define MAX_ETH_PAYLOAD 1500 /*!< Maximum Ethernet payload size */
#define JUMBO_FRAME_PAYLOAD 9000 /*!< Jumbo frame payload size */
以上是定义的Rx缓冲区1以及Tx缓冲区1的大小(1524byte),4 Tx buffers 也就是对应了Rx和Tx描述符的环形链表结构中的4个节点。
第二个参数是链表第一个节点的数据(缓存)地址。
//stm32f4x7_eth.c
__align(4)
uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE]; /* Ethernet Receive Buffer */
__align(4)
uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE]; /* Ethernet Transmit Buffer */
为Rx和Tx缓冲区分别开辟了一段内存,创建了Rx_Buff和Tx_Buff两个4行1524列的二维数组,也就是第[0:3]行对应描述符[0:3]缓冲区1的地址。1524为MAC数据包的最大帧大小。
第三个参数是链表的节点计数,与Rx_Buff和Tx_Buff的行参数一致。
创建描述符链表的函数如下:
//stm32f4x7_eth.c
/**
* @brief Initializes the DMA Tx descriptors in chain mode.
* @param DMATxDescTab: Pointer on the first Tx desc list
* @param TxBuff: Pointer on the first TxBuffer list
* @param TxBuffCount: Number of the used Tx desc in the list
* @retval None
*/
void ETH_DMATxDescChainInit(ETH_DMADESCTypeDef *DMATxDescTab, uint8_t* TxBuff, uint32_t TxBuffCount)
{
uint32_t i = 0;
ETH_DMADESCTypeDef *DMATxDesc; /* Set the DMATxDescToSet pointer with the first one of the DMATxDescTab list */
DMATxDescToSet = DMATxDescTab;
/* Fill each DMATxDesc descriptor with the right values */
for(i=0; i < TxBuffCount; i++)
{
/* Get the pointer on the ith member of the Tx Desc list */
DMATxDesc = DMATxDescTab + i;
/* Set Second Address Chained bit */
DMATxDesc->Status = ETH_DMATxDesc_TCH; /* Set Buffer1 address pointer */
DMATxDesc->Buffer1Addr = (uint32_t)(&TxBuff[i*ETH_TX_BUF_SIZE]); /* Initialize the next descriptor with the Next Descriptor Polling Enable */
if(i < (TxBuffCount-1))
{
/* Set next descriptor address register with next descriptor base address */
DMATxDesc->Buffer2NextDescAddr = (uint32_t)(DMATxDescTab+i+1);
}
else
{
/* For last descriptor, set next descriptor address register equal to the first descriptor base address */
DMATxDesc->Buffer2NextDescAddr = (uint32_t) DMATxDescTab;
}
} /* Set Transmit Desciptor List Address Register */
ETH->DMATDLAR = (uint32_t) DMATxDescTab;
}
简单分析下代码
/* Set the DMATxDescToSet pointer with the first one of the DMATxDescTab list */
DMATxDescToSet = DMATxDescTab;
首先将DMATxDescToSet(DMA当前发送描述符)设置为DMATxDescTab的以一个元素,也就是等于描述符0(创建的描述符结构体数组的第一个元素)。
接下来的for循环就是创建环形链接描述符的具体实现了
/* Set Second Address Chained bit */
DMATxDesc->Status = ETH_DMATxDesc_TCH;
这一行初始化描述符的状态(TDES0),将TCH(位20)置1,其他值0,表示TDES3的数据为下一个描述符的地址。
/* Set Buffer1 address pointer */
DMATxDesc->Buffer1Addr = (uint32_t)(&TxBuff[i*ETH_TX_BUF_SIZE]);
这一行为每一个链表中的描述符的缓冲区1设置了内存地址。
接下来的if语句用于判断当前节点是否为最后一个节点,中间节点时将当前描述符的TDES3(数据缓冲区2)指向下一个描述符的地址,也就是DMATxDescTab数组元素的下一个,当前节点为最后一个描述符时,将描述符的TDES2指向第一个节点(DMATxDescTab的地址)。
/* Set Transmit Desciptor List Address Register */
ETH->DMATDLAR = (uint32_t) DMATxDescTab;
在发送描述符配置完成后,就将配置完成的描述符链表设置到发送描述符地址寄存器中,完成发送描述符初始化。
基于STM32F407MAC与DP83848实现以太网通讯四(STM32F407MAC数据收发与DMA描述符)的更多相关文章
- 基于CC2530的ZigBee转以太网网关的设计与实现
		
*已刊登至:<无线电>8月刊 物联网技术的实现中,无线技术是必不可少的部分. 近年无线技术的发展,将ZigBee推入人们的视线中.那么ZigBee是如何的一种技术呢?带着疑问.我查询了它的 ...
 - 西门子S7系列以太网通讯处理器功能介绍
		
北京华科远创科技有限研发的远创智控型号ETH-YC模块适用于西门子S7-200/S7-300/S7-400.SMART S7-200.西门子数控840D.840DSL.合信.亿维PLC的PPI/MPI ...
 - 西门子S7200/300/400以太网通讯处理器选型分类
		
北京华科远创科技有限研发的远创智控转以太网模块适用于西门子S7-200/S7-300/S7-400.SMART S7-200.西门子数控840D.840DSL.合信.亿维PLC的PPI/MPI/PRO ...
 - 构建一个基本的前端自动化开发环境 —— 基于 Gulp 的前端集成解决方案(四)
		
通过前面几节的准备工作,对于 npm / node / gulp 应该已经有了基本的认识,本节主要介绍如何构建一个基本的前端自动化开发环境. 下面将逐步构建一个可以自动编译 sass 文件.压缩 ja ...
 - STM32F412应用开发笔记之五:结合W5500实现以太网通讯
		
因实际使用需求我们测试一下网络通讯,在NUCLEO-F412ZG测试板上没有以太网部分,我们选择外接一个W5500的实验板.W5500支持SPI接口通讯,DC3.3V供源.而NUCLEO-F412ZG ...
 - 基于.net开发chrome核心浏览器【四】
		
原文:基于.net开发chrome核心浏览器[四] 一: 上周去北京出差,给国家电网的项目做架构方案,每天都很晚睡,客户那边的副总也这样拼命工作. 累的不行了,直接导致第四篇文章没有按时发出来. 希望 ...
 - Creating Dialogbased Windows Application (4) / 创建基于对话框的Windows应用程序(四)Edit Control、Combo Box的应用、Unicode转ANSI、Open File Dialog、文件读取、可变参数、文本框自动滚动 / VC++, Windows
		
创建基于对话框的Windows应用程序(四)—— Edit Control.Combo Box的应用.Unicode转ANSI.Open File Dialog.文件读取.可变参数.自动滚动 之前的介 ...
 - 基于flask的网页聊天室(四)
		
基于flask的网页聊天室(四) 前言 接前天的内容,今天完成了消息的处理 具体内容 上次使用了flask_login做用户登录,但是直接访问login_requare装饰的函数会报401错误,这里可 ...
 - ACE框架 基于共享内存的进程间通讯
		
ACE框架将基于共享内存的进程间通讯功能,如其它IO组件或IPC组件一样,设计成三个组件.流操作组件ACE_MEM_Stream,连接器组件ACE_MEM_Connector,以及接收连接组件ACE_ ...
 - 【转】基于TMS320C6455的千兆以太网设计
		
基于TI公司最新DSP芯片TMS320C6455.设计并实现了以太网通信软硬件接口.采用TMS320C6455片内以太网接口模块EMAC/MDIO,结合片外AR8031 PHY芯片,在嵌入式操作系统D ...
 
随机推荐
- 全套解决方案:中文NLP训练框架,支持大模型训练和文本生成,快速上手,海量训练数据!
			
全套解决方案:基于pytorch.transformers的中文NLP训练框架,支持大模型训练和文本生成,快速上手,海量训练数据! 1.简介 目标:基于pytorch.transformers做中文领 ...
 - 文档级关系抽取:基于结构先验产生注意力偏差SSAN模型
			
文档级关系抽取:基于结构先验产生注意力偏差SSAN模型 Entity Structure Within and Throughout: Modeling Mention Dependencies fo ...
 - 2.3 CE修改器:浮点数扫描
			
本关需要使用 Cheat Engine 工具对浮点数进行扫描,完成修改任务.浮点数是一种带有小数点的数值,通过"浮点数"扫描方式进行修改.本关中,健康值为单精度浮点数,弹药值为双精 ...
 - Bootstrap Table 动态修改行的颜色
			
Bootstrap Table 官网地址 https://bootstrap-table.com/百度搜了大量资料 还是找不 动态改变行的颜色,一般搜索到的都是 初始化的时候 使用 rowStyle ...
 - 设计模式-2 简单工厂模式Factory Method
			
设计模式-2 简单工厂模式 1 意图: 定义一个用户创建对象的接口,让子类决定实例化那个类.Factory Method使一个类的实例化延迟到其子类 使用场景:将一个类的实例化延迟到其子类结构: 优缺 ...
 - Delphi 字符串截取函数【LeftStr,RightStr,MidStr】
			
如果要使用LeftStr,RightStr,MidStr必需引用系统单元StrUtils; 声明变量Str:string; Str:=HelloWorld; 1,LeftStr(Str,2)=He;/ ...
 - 《ASP.ENT Core 与 RESTful API 开发实战》-- (第6章)-- 读书笔记(上)
			
第 6 章 高级查询和日志 6.1 分页 在 EF Core 中,数据的查询通过集成语言查询(LINQ)实现,它支持强类型,支持对 DbContext 派生类的 DbSet 类型成员进行访问,DbSe ...
 - JS 判断两个数组是否相等,元素以及顺序相等,顺序不同但元素相等
			
壹 ❀ 引 在日常开发中,判断两个数组是否相等应该是较为常见的场景,因为常用,所以想着简单记录下.关于判断数组相等,这里我分为两种场景,第一种是数组完全相等,即数组元素相同且元素顺序一致:第二则为元素 ...
 - Jsp+Servlet实现文件上传下载(二)--文件列表展示
			
接着上一篇讲: Jsp+Servlet实现文件上传下载(一)--文件上传 点击打开链接 本章来实现一下上传文件列表展示,同时优化了一下第一章中的代码. 废话少说,上代码 --------------- ...
 - Innodb存储引擎之锁
			
目录 一.概述 二.lock 与 latch 三.Innodb存储引擎中的锁 锁 一致性非锁定读 一致性锁定读 自增长与锁 外键与锁 四.锁的算法 锁的算法 Phantom Problem 幻读问题 ...