首页 > 其他分享 >基于STM32F407MAC与DP83848实现以太网通讯四(STM32F407MAC数据收发与DMA描述符)

基于STM32F407MAC与DP83848实现以太网通讯四(STM32F407MAC数据收发与DMA描述符)

时间:2024-02-27 20:44:43浏览次数:26  
标签:DMA Tx Rx STM32F407MAC uint32 描述符 ETH 以太网 SIZE

上一章实现的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;

在发送描述符配置完成后,就将配置完成的描述符链表设置到发送描述符地址寄存器中,完成发送描述符初始化。

标签:DMA,Tx,Rx,STM32F407MAC,uint32,描述符,ETH,以太网,SIZE
From: https://www.cnblogs.com/fuyunxiansen/p/18034641

相关文章

  • 2024年Apache DolphinScheduler RoadMap:引领开源调度系统的未来
    非常欢迎大家来到ApacheDolphinScheduler社区!随着开源技术在全球范围内的快速发展,社区的贡献者“同仁”一直致力于构建一个强大而活跃的开源调度系统社区,为用户提供高效、可靠的任务调度和工作流管理解决方案。在过去的一段时间里,我们取得了一些重要的成就,但我们的愿景远未实......
  • nvmet_rdma_offload_mem_start 预留内存
    要在modprobenvmet_rdma时找到合法的nvmet_rdma_offload_mem_start和nvmet_rdma_offload_mem_size_mb参数,你需要进行一系列步骤以确保选定的内存区域既未被系统其他部分使用,又适合于你的NVMeoverFabrics(NVMe-oF)RDMA目标配置。以下是一个示例流程,展示如何进行这一过......
  • NavigableMap.headMap()的用法
    Java中NavigableMap接口的headMap()方法用于返回此Map的一部分,其键小于(或等于,如果包含,则为true)toKey的map NavigableMap<K,V>headMap(KtoKey,booleaninclusive)参数:此函数接受两个参数:toKey:此参数指的是key。inclusive:此参数决定是否......
  • RDMA网络
    在Kubernetes的标准框架里,容器是只有1个网络平面的。即容器里面,只有1个eth0网卡。所以无论是利用overlay实现容器隧道网络,还是underlay实现容器网络直通,其目的都是解决容器网络“通与不通”的问题。而大规模AI集群中,百亿、千亿级别参数量的大模型通常需要做分布式训练,这时参数梯......
  • 基于STM32F407MAC与DP83848实现以太网通讯三(STM32F407MAC配置以及数据收发)
    本章实现了基于STM32F407MAC的数据收发功能,通过开发板的RJ45接口连接网线到电脑,电脑使用Wiershark工具抓包验证。参考文档:DP83848IV英文DP83848EP中文STM32F4xx参考手册一、工程模板以及参考源码的获取工程源码我使用的正点原子的探索者开发板STM32F407(V2)参考源码:正点原子......
  • 基于STM32F407MAC与DP83848实现以太网通讯二(DP83848硬件配置以及寄存器)
    参考内容:DP83848数据表一、PHYDP83848功能模块图                     DP83848的硬件模块主要为:MII/RMII/SNI INTERFACES:用于与MAC数据传输的MII/RMII/SNI接口Transmit BLOCK:数据发送模块,将从外部MAC(例如STM32ETH外设的MAC)接收......
  • 基于STM32F407MAC与DP83848实现以太网通讯一(STM32以太网(ETH)外设)
    STM32F4xx可以通过以太网按照IEEE802.3-2002标准发送和接收数据。支持与外部物理层(PHY)相连的两个工业标准接口:默认情况下使用的介质独立接口(MII)(在IEEE802.3规范中定义)和简化介质独立接口(RMII)。具体的以太网(ETM)特性参考:STM32F4xx中文参考手册这里将重要的地方进......
  • 基于stm32的spi接口dma 数据收发实例解析
    一前记  SPI接口平时用的比较少,再加上对CUBEMX不是很熟悉,这里踩了不少坑才把问题解决。针对遇到了不少问题,是要值得梳理一下了。二源码解析1SPI的DMA发送端配置: 2主函数源码:uint32_tg_spi_cnt=0;voidHAL_SPI_TxCpltCallback(SPI_HandleTypeDef*hspi){......
  • STM32 SPI接口 DMA normal 和circual区别
     DMA有normal和circular两种模式。circular模式:就调用这个函数一次就可以了,DMA一直开启,一帧数据发送完毕之后里面发送下一帧,中间没有停顿。这样确实是快了,也释放了CPU,各路的数据采集因为缺少了等待串口发送的时间,所以就间接提高的了数据更新速率。但有个致命缺陷:数据采集和数......
  • ADI CCES ADSPI2156X UART DMA模式中,获取当前存到第几个数CurrXCount, 重新从头开始接
    关键的一些寄存器关键的寄存器pUARTDstDMARegstypedefstruct{uint32_tnTmrDevNum;/*TimerassosiatedtotheselectedUARTforAutobaud*/ADI_UART_TypeDef*constpUARTRegs;/*Pointertobaseadd......