学过STM32的同学都应该知道DMA就是不需要CPU的参与就能够实现内存和外设之间的数据交换,同样的,对于STM32互联型单片机的以太网DMA的作用也是如此,它的作用就是在不需要CPU的参与下,实现内存和以太网外设的数据交换。
用通俗一点的话来表述,就是我们将要发送的数据放到一片内存去,告诉以太网DMA,我已经将数据放过去了,你去取出来发送到网络中去吧。当网络数据来了的时候,以太网DMA自动将数据拷贝到一片内存中,产生中断告诉CPU,数据来了,你去取出来吧。
在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,有数据来了,我们就可以取出描述符的数据,从而知道接收到了什么。
上面我们说了,描述符是的本质就是4个32位的内存,描述符的Status表示该描述符的状态和控制信息。因为描述符是DMA和CPU二者之间的共享内存,既然是共享资源,就需要进行保护,当DMA在使用的时候,CPU就不能使用,当CPU在使用的时候,DMA就不能使用。这个使用权的控制,就通过TDES0寄存器中的OWN位体现出来,对应到发送描述符结构体就是Status变量的最高位。
我们看上图可知,当OWN位为0的时候,表示CPU可以将要发送的数据拷贝到描述符中,拷贝完成以后,我们手动将描述符的OWN位设置为1,以此来告诉DMA控制器,我已经拷贝完数据了,你可以从描述符中取出数据进行发送了。这时候DMA就会取出描述符中的数据,将数据发送出去,DMA在操作完描述符以后,自动将OWN位设置为0,告诉CPU,我DMA已经发送完数据啦,你可以拷贝下一帧数据到描述符上了。整个发送的过程就是这样配合的。
发送DMA描述符只有4个32Bit的内存空间,这点内存肯定放不下我们要发送的以太网数据帧,那么我们要发送的数据实际上是存在描述符的哪里呢?
TDES2就是用来设置存放要发送数据缓冲区的首地址的,TDES1是用来告诉DMA这个缓冲区有效数据长度的。我们可以开辟一个数组,将数组的首地址写入Buffer1Addr中,这样就设置好了发送描述符实际存放数据的内存地址,我们往这个数组中写入要发送的数据,再把数据长度写入ControlBufferSize中,DMA就可以从这片内存中取ControlBufferSize长度的数据出来进行发送了。
例如,我们要发送一帧512字节的数据,那么我们就需要先建立一个至少大于512字节的数组,将要发送的数据拷贝到这个数组里面,然后设置这个描述符的数据长度是512即可,如下图所示。
如果我们发送的一帧数据很大,一个描述符没有办法放下那么多数据,应该怎么办呢?这时候就需要用到链表,将这帧以太网数据分割位若干部分,分别存放在多个描述符里面,描述符之间用链表的形式建立连接。说起来有点抽象,我们举个例子。
例如,有4K字节的一帧数据要发送出去,但是每一个描述符的缓冲区大小只有1K,这时候就需要用4个描述符来存储要发送的这一帧数据,请看下图。我们把第一个1K的数据放入描述符中,并且设置它的TEDS0寄存器的FS位为1,表示这个描述符存储了数据帧的第一个分块,把最后1K的数据放入描述符中,设置它的TDES0寄存器的LS位为1,表示这是该帧数据的最后一个分块。这样DMA就能够根据这些信息组合出一条完整的数据帧,进行发送。
本文写于2020年2月12日。
逻辑结构上相邻的数据元素。存储在指定的一块内存空间中,数据元素只允许在该块内存空间中随机存放。该存储结构生成的链表称为静态链表。静态链表与动态链表的区别:静态链表限制了数据元素存放的位置范围;动态链表存储元素范围是分配整个内存空间;接下来看静态链表的数据结构:typedef struct aa{ int data;//数据域 int cur;//游标 }component;...
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/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目标检测框架。本文不会描述网络的优点/缺点或每个设计选择的原因,而是关注于它是如何工作的。在阅读本文之前,假设读者对神经网络,特别是CNN有一个基本的了解。文中所有的描述都与YOLO的原论文有关: You Only Look Once: Unified, Real-Time Object Detection by Joseph Redmon, Sa...
在学校学习软件设计专业的时候,老师就曾说过,IT专业找工作很容易的,别看工作时用的编程语言比较单一,但是学校的知识能让你找到IT行业各种种类的工作,比如程序员,测试,实施,技术支持,产品研发,数据库专员等等.........,以前一直做编程也就是JAVA程序员,接触到的都是测试,产品研发的人,一直认为实施就是给别人安装软件的,直到身体原因康复后不得不转行发现实施需要的综合能力挺强的。实施到底是做什...
办法方案1 : https://blog.csdn.net/sinat_32972877/article/details/78275772更新 pods 之后,发觉一直提示要把#import <AFN> 改成#import“AFN” ,然后折腾了一会,看到可能是路径问题。然后把#import<AFN/AFN.h>,加上/ 。然后再Build Settin...
概述:浮点数据类型包括real型、float型、decimal型和numeric型。浮点数据类型用于存储十进制小数。在SQL Server 中浮点数值的数据采用上舍入(Round up)的方式进行存储,所谓上舍入也就是,要舍入的小数部分不论其大小,只要是一个非零的数,就要在该数字的最低有效位上加1,并进行必要的进位。由于浮点数据为近似值,所以并非数据类型范围内的所有数据都能精确地表示。1、区别说明decimal(numeric):同义,用于精确存储数值float 和 real...
https://www.cnblogs.com/dolphin0520/p/3920373.html
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自定权限的时候,发现一个错误:11-25 16:16:24.819 1747-1747/com.example.android.renderscriptintrinsic E/AndroidRuntime﹕ FATAL EXCEPTION: mainProcess: com.example.android.renderscriptintrinsic, PID: 174...
迭代器(Iterator)是一种设计模式、提供了一种方法,来对集合、容器进行遍历的方式,不需要关注底层数据结构和数据类型,来达到底层和上层遍历解耦的目的。简单来说呢,迭代器就是遍历集合的一种方式,并且必须依赖于集合而存在!但是他的底层实现还是不容易想通的,所以下面通过源码和我个人的理解来看一下啦~Iterator里面有三个方法:boolean hasNext() :判断集合是否还有元素;...
报错如下: 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