【STM32】以太网DMA描述符_RiverFormSky的博客-程序员秘密

技术标签: STM32  以太网  


武汉加油!中国加油!


1、什么是以太网DMA?

学过STM32的同学都应该知道DMA就是不需要CPU的参与就能够实现内存和外设之间的数据交换,同样的,对于STM32互联型单片机的以太网DMA的作用也是如此,它的作用就是在不需要CPU的参与下,实现内存和以太网外设的数据交换。

用通俗一点的话来表述,就是我们将要发送的数据放到一片内存去,告诉以太网DMA,我已经将数据放过去了,你去取出来发送到网络中去吧。当网络数据来了的时候,以太网DMA自动将数据拷贝到一片内存中,产生中断告诉CPU,数据来了,你去取出来吧。

2、DMA描述符的本质是什么?

在STM32的参考手册中,我们可以找到发送描述符的定义,如下:
在这里插入图片描述
一眼看上去好像很复杂,这些是寄存器吗?但是找了一大堆文档,也没有找到它的寄存器地址,因为它根本就不是什么寄存器,而是4个32Bit的内存。对的,你去找发送描述符的硬件结构,是肯定找不到的,因为它完全是纯软件的概念,它的本质就是我们自己用结构体来实现这个描述符,然后将描述符的首地址写入到【ETH_DMATDLAR】寄存器中,STM32就知道这片内存是用来作为发送描述符了。

发送描述符的主要作用就是用来记录发送缓冲区的大小,缓冲区的地址,还有这个缓冲区的状态等等,里面有很多信息,这些信息是用来协同CPU和DMA二者之间工作的,我把他们的功能简要的写了出来,如下所示:

TDES0主要用来表示描述符的状态和控制信息
TDES1表示该描述符缓冲区数据的有效长度
TDES2表示描述符缓冲区的地址,我们要发送的数据,就是放在这个地址所指向的内存中
TDES3表示下一个描述符的地址

我们通过定义一个结构体来实现这个发送描述符,如下所示

typedef struct  {
  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 */
} ETH_DMADESCTypeDef;

这个结构体的本质就是4个32Bit的变量,和STM32参考手册中定义的一样。
Status用来表示该描述符的状态
ControlBufferSize表示该描述符缓冲区数据的长度
Buffer1Addr用来存放该描述符缓冲区的地址,我们要发送的数据,就是放在这个地址开始的内存中
Buffer2NextDescAddr表示下一个描述符的地址

当我们需要发送数据的时候,我们把数据拷贝到发送描述符的缓冲区中(Buffer1Addr),告诉DMA我们拷贝完成了,DMA就会从发送描述符的缓冲区中取数据,将数据通过以太网外设发送到网络中去。

同样地,以太网外设接收到了网络中的数据时,DMA自动拷贝数据到接收描述符的缓冲区中(Buffer1Addr),产生中断告诉CPU,有数据来了,我们就可以取出描述符的数据,从而知道接收到了什么。

3、DMA和CPU如何有序地访问描述符?

上面我们说了,描述符是的本质就是4个32位的内存,描述符的Status表示该描述符的状态和控制信息。因为描述符是DMA和CPU二者之间的共享内存,既然是共享资源,就需要进行保护,当DMA在使用的时候,CPU就不能使用,当CPU在使用的时候,DMA就不能使用。这个使用权的控制,就通过TDES0寄存器中的OWN位体现出来,对应到发送描述符结构体就是Status变量的最高位。
在这里插入图片描述
我们看上图可知,当OWN位为0的时候,表示CPU可以将要发送的数据拷贝到描述符中,拷贝完成以后,我们手动将描述符的OWN位设置为1,以此来告诉DMA控制器,我已经拷贝完数据了,你可以从描述符中取出数据进行发送了。这时候DMA就会取出描述符中的数据,将数据发送出去,DMA在操作完描述符以后,自动将OWN位设置为0,告诉CPU,我DMA已经发送完数据啦,你可以拷贝下一帧数据到描述符上了。整个发送的过程就是这样配合的。

4、发送的数据实际上放在哪里?

发送DMA描述符只有4个32Bit的内存空间,这点内存肯定放不下我们要发送的以太网数据帧,那么我们要发送的数据实际上是存在描述符的哪里呢?
在这里插入图片描述
TDES2就是用来设置存放要发送数据缓冲区的首地址的,TDES1是用来告诉DMA这个缓冲区有效数据长度的。我们可以开辟一个数组,将数组的首地址写入Buffer1Addr中,这样就设置好了发送描述符实际存放数据的内存地址,我们往这个数组中写入要发送的数据,再把数据长度写入ControlBufferSize中,DMA就可以从这片内存中取ControlBufferSize长度的数据出来进行发送了。

例如,我们要发送一帧512字节的数据,那么我们就需要先建立一个至少大于512字节的数组,将要发送的数据拷贝到这个数组里面,然后设置这个描述符的数据长度是512即可,如下图所示。
建立发送数据和描述符的关系

5、要发送的数据长度超出一个描述符能够存放的最大长度怎么办?

如果我们发送的一帧数据很大,一个描述符没有办法放下那么多数据,应该怎么办呢?这时候就需要用到链表,将这帧以太网数据分割位若干部分,分别存放在多个描述符里面,描述符之间用链表的形式建立连接。说起来有点抽象,我们举个例子。

例如,有4K字节的一帧数据要发送出去,但是每一个描述符的缓冲区大小只有1K,这时候就需要用4个描述符来存储要发送的这一帧数据,请看下图。我们把第一个1K的数据放入描述符中,并且设置它的TEDS0寄存器的FS位为1,表示这个描述符存储了数据帧的第一个分块,把最后1K的数据放入描述符中,设置它的TDES0寄存器的LS位为1,表示这是该帧数据的最后一个分块。这样DMA就能够根据这些信息组合出一条完整的数据帧,进行发送。
在这里插入图片描述


本文写于2020年2月12日。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_22902757/article/details/104275441

智能推荐

线性表-静态链表_Shelton-N的博客-程序员秘密

逻辑结构上相邻的数据元素。存储在指定的一块内存空间中,数据元素只允许在该块内存空间中随机存放。该存储结构生成的链表称为静态链表。静态链表与动态链表的区别:静态链表限制了数据元素存放的位置范围;动态链表存储元素范围是分配整个内存空间;接下来看静态链表的数据结构:typedef struct aa{ int data;//数据域 int cur;//游标 }component;...

DP 60题 -3 HDU1058 Humble Numbers DP求状态数的老祖宗题目_风骨散人Chiam的博客-程序员秘密

Humble NumbersTime Limit: 2000/1000 MS (Java/Others)Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 32718Accepted Submission(s): 14308Problem DescriptionA number whose o...

torch.stack, torch.cat, torch.stack.max/mean/sum维度变换详解_jsk_learner的博客-程序员秘密

torch.stack,torch.cat, torch.stack.max/mean/sumtorch.stack创建两个[x,x,x,x]tensor变量torch.stack([x,x], dim=0)torch.stack([x,x], dim=1)torch.stack([x,x], dim=2)torch.stack([x,x], dim=3)torch.stack([x,x], di...

YOLO算法解读_yolo是什么_Grant_Ward的博客-程序员秘密

本文以从头实现YOLO的角度出发,解释了YOLO目标检测框架。本文不会描述网络的优点/缺点或每个设计选择的原因,而是关注于它是如何工作的。在阅读本文之前,假设读者对神经网络,特别是CNN有一个基本的了解。文中所有的描述都与YOLO的原论文有关: You Only Look Once: Unified, Real-Time Object Detection by Joseph Redmon, Sa...

程序员转实施工程师_实施工程师到底做什么的?我认为比程序员接触面更广_Dandakaranya的博客-程序员秘密

在学校学习软件设计专业的时候,老师就曾说过,IT专业找工作很容易的,别看工作时用的编程语言比较单一,但是学校的知识能让你找到IT行业各种种类的工作,比如程序员,测试,实施,技术支持,产品研发,数据库专员等等.........,以前一直做编程也就是JAVA程序员,接触到的都是测试,产品研发的人,一直认为实施就是给别人安装软件的,直到身体原因康复后不得不转行发现实施需要的综合能力挺强的。实施到底是做什...

iOS Pod 'xxx.h' file not found with <angled> include; use "quotes" instead_use quotes instead_豪冷啊的博客-程序员秘密

办法方案1 : https://blog.csdn.net/sinat_32972877/article/details/78275772更新 pods 之后,发觉一直提示要把#import &lt;AFN&gt; 改成#import“AFN” ,然后折腾了一会,看到可能是路径问题。然后把#import&lt;AFN/AFN.h&gt;,加上/ 。然后再Build Settin...

随便推点

SQL中的real、float、decimal、numeric数据类型区别_numeric sql_cnmeimei的博客-程序员秘密

概述:浮点数据类型包括real型、float型、decimal型和numeric型。浮点数据类型用于存储十进制小数。在SQL Server 中浮点数值的数据采用上舍入(Round up)的方式进行存储,所谓上舍入也就是,要舍入的小数部分不论其大小,只要是一个非零的数,就要在该数字的最低有效位上加1,并进行必要的进位。由于浮点数据为近似值,所以并非数据类型范围内的所有数据都能精确地表示。1、区别说明decimal(numeric):同义,用于精确存储数值float 和 real...

PYTORCH安装(conda)_conda安装pytorch_笛儿,,的博客-程序员秘密

PYTORCH安装(conda)1.搜索框收入cmd2.添加清华镜像源(加快速度)conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/conda config --set show_channel_urls yes.

自定义权限 android,android自定义权限_爱reo樱桃的纱雾酱的博客-程序员秘密

今天在研究android自定权限的时候,发现一个错误:11-25 16:16:24.819 1747-1747/com.example.android.renderscriptintrinsic E/AndroidRuntime﹕ FATAL EXCEPTION: mainProcess: com.example.android.renderscriptintrinsic, PID: 174...

java集合之迭代器_sspudding的博客-程序员秘密

迭代器(Iterator)是一种设计模式、提供了一种方法,来对集合、容器进行遍历的方式,不需要关注底层数据结构和数据类型,来达到底层和上层遍历解耦的目的。简单来说呢,迭代器就是遍历集合的一种方式,并且必须依赖于集合而存在!但是他的底层实现还是不容易想通的,所以下面通过源码和我个人的理解来看一下啦~Iterator里面有三个方法:boolean hasNext() :判断集合是否还有元素;...

python里面读取h5文件报错OSError: Can‘t read data (address of object past end of allocation)_"file \"h5py/_selector.pyx\", line 361, in h5py._s_木里先森的博客-程序员秘密

报错如下: File "h5py/_objects.pyx", line 54, in h5py._objects.with_phil.wrapper File "h5py/_objects.pyx", line 55, in h5py._objects.with_phil.wrapper File "h5py/h5d.pyx", line 182, in h5py.h5d.DatasetID.read File "h5py/_proxy.pyx", line 158, in h5py._p

推荐文章

热门文章

相关标签