https://mp.weixin.qq.com/s/CQQSV26Xvmt2xuAPFnh-YQ

鱼鹰  鱼鹰谈单片机 3月3日

预计阅读时间: 9 分钟

数据传输耗时又耗力?交给 DMA 去干吧!

参考:

stm32f2 技术培训_直接存储器访问_dma http://www.doc88.com/p-7952436689372.html

AN4031 应用笔记:使用 STM32F2 和 STM32F4 DMA 控制器

AN2548 应用笔记:使用 STM32F101xx 和 STM32F103xx DMA 控制器

STM32中文参考手册

看完这些就差不多了。

首先大概介绍一下功能吧,看笔记对于初学者可能有些吃力,在这里我将按我的理解进行说明。

DMA 的作用是在没有 Cortex-M3 核心的干预下,在后台完成数据传输。在传输数据的过程中,主处理器可以执行其它任务,只有在整个数据块传输结束后,需要处理这些数据时才会中断主处理器的操作。它可以在对系统性能产生较小影响的情况下,实现大量数据的传输。

以上是官方话。怎么理解呢?

假如现在你是 CPU,然后你的一个伙伴是 DMA,你的伙伴和你还有些不同,你可以做很多事情,比如判断、计算、存储、I/O 操作等等,但你的伙伴就比较笨了,他只能干一件事情,就是存储功能,但正因为他的专一性,所以干活的速度特别快,同样是干存储的活,他干的就比你快。所以你就会想,既然他能干存储的活,我干嘛还干,交给他就行了啊!所以当有人(用户)让你去干存储的活时,你就让你的伙伴 DMA 干了,你首先告诉你的伙伴从哪往哪搬数据、数据大小是多少、数据宽度是多少,把这些基本的信息告诉他之后,你就可以忙你自己的事情了,对了,记得提醒他一声,让他干完活就过来通知你(中断),好让你知道他已经干完了活,是继续干其他活还是去休息了。如果继续干活,就要继续把新的基本信息告诉他;如果是休息,就让他休息就好了。这样你就能节省不少时间忙你的其他工作,数据传输量少的时候可能区别不是很大,毕竟在小数据量的时候也要每次通知 DMA 告诉他基本情况,然后他干完活后又得通知你,有这时间,你自己就把活干了。但是在数据量大的时候就不一样了,你会发现 DMA 还是很有用的,你会发现你俩干活的差距是很大的。还有在你分身乏术的时候,也可以叫他。比如有些外设数据(SPI、UART、I2C 等)可能来的比较突然,就需要 DMA 始终监控这些数据,一旦有新数据来了,就开始搬运数据,这样就不怕新数据覆盖旧数据了。

这些就是大方向上的理解了,但是只是懂这些东西还是没用的,如果你不能从细节上把握,你还是不能很好的使用 DMA,细节上的东西就交给上面的文档了,下面是读文档之后的一些总结性内容,你可以在看完这些文档之后再回过头来看这些。

看完之后你会发现 STM32F4 的 DMA 和 STM32F1 的 DMA 有很大差别。

第一个区别就是,STM32F1 的通道和 STM32F4 的通道意义不同,F1 的通道指的是传输通道,如下所示:

而 F4 的通道是这样的:

你会发现 F1 通道意义类似与 F4 的数据流,而 F1 请求信号和 F4 的通道号类似的,只是以前直接使用或门,现在换成了通道选择开关,避免了一些干扰。他们的关系如下:

然后通过表格来了解一下他们之间的关系:

这是 F1 的

这是 F4 的

是不是发现他们很接近啊。但是如果你看了之前的文档,你就会发现她们的差异是很大的。

最大的区别就是 FIFO 了,这也是很多人(包括我)用过 F1 的 DMA,但是发现 F4 的 DMA 不好用,原因就在这个 FIFO 里面。关于 FIFO 原理可以参考另一篇文章,不过那个是讲软件实现,这个是硬件 FIFO。

FIFO 的存在是为了优化带宽,但是也增加了操作的复杂性,但是也可以禁用 FIFO,这样就类似 F1 的 DMA 了。但是明明有这么好的东西却不用,就有些可惜了。

FIFO 很大的一个特点,就是可以暂存数据,这样如果一次性有很多数据进来了,但你的出口端没有获得传输的条件,那么就可以暂存在 FIFO 里面了,一旦获得了总线仲裁,那么就可以开始传输了,这样数据就不容易丢失。

如果启用 FIFO,这里面就有一个阈值需要考虑。我们知道外设数据的传输条件是通过请求的,比如说串口接收数据过程。当串口接收到一个字节数据之后,串口就向 DMA 控制器发出请求,就会将数据传输至 FIFO 中暂存,如果关闭 FIFO 的情况下,这个数据是会马上传输到目的地的,但是现在你启用了 FIFO,那么这个数据就要在这里停留一段时间,那么这段时间是多少呢?不确定。不确定怎么玩?别急,慢慢听我说。

有三种条件会将 FIFO 数据传输到目的地中:

  1. 关闭 DMA。

在你启用了数据流的情况下,又关闭了数据流,如果 FIFO 里面有数据,那么就会将 FIFO 里面的数据传输到目的地中去,这个称之为刷新,但是 FIFO 的数据量你是不确定的,你怎么知道有多少个数据传输到了目的地呢?这个就要通过计数器反推了。比如说你设置数据流接收 10 个字节数据,现在计数器等于 3,那就说明你已经接收了 7 个字节,因为没接收一次数据,计数器都会减一,这样你就知道目的地到底存了多少个有效数据。再说一点,通过这种方式,再打开串口空闲中断,就可以接收不定长的串口数据了,不必像一些协议一样,通过一些特殊数据来判断帧头帧尾的方式来接收不定长数据,这样简单而高效。

注意:关闭 DMA 的时候一定要确定一已经关闭了,因为如果 DMA 当前还有工作在做,比如正在传输一个数据,这个时候 DMA 其实还没有关闭,只有在传输完成之后才会关闭。所以一定要在进行下一次 DMA 操作之前确保已经关闭了 DMA,在此之前必须等待,等待的条件可以是传输完成标志,也可以是 DMA 关闭位 EN。

  1. 接收完成。

还是串口接收过程,还是接收 10 个字节,当接收完 10 个字节之后,因为计数器已经是 0 了,所以硬件自动进行刷新工作,并且关闭数据流,如果下次要接收的话,就要重新打开了。不过这里有一个双缓冲模式,启用他的话,它就不会关闭数据流,而是继续工作,不过这次工作的目的地换了一个地方了。

  1. 阈值

通过设置阈值,也可以触发 FIFO 的传输工作。FIFO 的大小为 4 个字,一个字为 4 个字节,所以就有 16 个字节的空间大小。如果你设置的阈值为 1/2,那么当数据传输了 8 个字节的时候,就会触发条件,将 FIFO 中的数据传输到目的地当中去,当然了如果在传输的过程中串口又来了数据,那也是没问题的,毕竟 FIFO 就是用来缓存的啊,后来的数据在后面排队就行。但是如果你设置的阈值是满,那么可能就会丢失数据了,毕竟现在 FIFO 里已经没有空间了,不过不太可能的,因为串口传输数据实在是太慢了,当你触发满的条件开始传输时,在下一个字节数据来之前肯定最少能转移出一个字节数据,给新数据留个位置的。所以不用担心。

这里还有一点就是,假如你设置接收 10 个字节数据,设置的阈值是 1/4,也就是 4 字节,你现在接收了 5 个字节,前面四个字节因为触发了阈值条件已经将数据传输到目的地了,但是还有 1 个字节数据还滞留在 FIFO 里面没动,怎么办?就是通过关闭 DMA 的方式来将 FIFO 的数据转移至目的地。

使用 DMA 的时候要特别注意操作顺序。比如我做的一个项目,需要定时器触发 DMA,然后将内存中的数据转移至 PSC(实现实时改变频率的功能),一开始不懂,首先开启了定时器的请求,然后才配置 DMA,开启 DMA。这样导致的后果是,打开 DMA 失败,最后查找原因发现是出现了错误(通过错误状态寄存器观察),虽然通过清除错误的方式成功启动了 DMA,但还是不知道为什么会发生这种错,后面才知道原因:如果一开始就开始定时器请求的话,因为 DMA 中还没有数据,无法进行传输工作,所以就导致了错误。后面换了操作顺序就没有这种错误出现了。

最后在总结几点:

  1. F4 的 DMA 只有 DMA2 可以进行内存到内存的传输模式,并且必须开启 FIFO。

  2. 突发配置的限制

  1. 不同于 F1,F4 的不同数据长度进行 DMA 传输时必须开启 FIFO

  2. 停止外设的流程,不能只关闭 DMA,而不断开外设连接请求。

------------------------------------------------------------------------------------2018/12/05  Osprey

数据传输还用 CPU?不如交给 DMA 吧!的更多相关文章

  1. (三)stm32之串口通信DMA传输完成中断

    一.DMA功能简介 首先唠叨一下DMA的基本概念,DMA的出现大大减轻了CPU的工作量.在硬件系统中,主要由CPU(内核).外设.内存(SRAM).总线等结构组成,数据经常要在内存和外设之间,外设和外 ...

  2. 驱动之DMA的介绍与应用20170210

    本文主要介绍的是DMA相关的知识,首先: 1)在实现DMA传输时,是由DMA控制器直接掌管总线,因此,存在着一个总线控制权转移问题.即DMA传输前,CPU要把 总线控制权交给DMA控制器,而在结束DM ...

  3. 关于DMA和它的仇家

    [基础知识]什么叫做DMA?DMA=Direct Memory Access.这是一种通过硬件实现的数据传输机制.简单的说,就是不在CPU的参与下完成数据的传输.[/基础知识]不太明白?我举个简单的例 ...

  4. STM32 DMA模块的配置与使用

    DMA有什么用? 直接存储器存取用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输.无须CPU的干预,通过DMA数据可以快速地移动.这就节省了CPU的资源来做其他操作. 有多少个DMA资源 ...

  5. STM32 DMA使用详解

    DMA部分我用到的相对简单,当然,可能这是新东西,我暂时还用不到它的复杂功能吧.下面用问答的形式表达我的思路. DMA有什么用? 直接存储器存取用来提供在外设和存储器之间或者存储器和存储器之间的高速数 ...

  6. STM32之DMA

    一.DMA简介 1.DMA简介 DMA(Direct Memory Access:直接内存存取)是一种可以大大减轻CPU工作量的数据转移方式. CPU有转移数据.计算.控制程序转移等很多功能,但其实转 ...

  7. STM32学习笔记——DMA控制器(向原子哥学习)

    一.DMA简介 DMA,全称为:Direct Memory Access,即直接存储器访问,DMA 用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输.当 CPU 初始化这个传输动作,传输 ...

  8. stm32 DMA数据搬运 [操作寄存器+库函数](转)

    源:stm32 DMA数据搬运 [操作寄存器+库函数]        DMA(Direct Memory Access)常译为“存储器直接存取”.早在Intel的8086平台上就有了DMA应用了.   ...

  9. 【转】scatterlist && DMA

    原文:scatterlist && DMA DMA是一种无须CPU的参与就可以让外设与系统内存之间进行双向数据传输的硬件机制.使用DMA可以是系统CPU从实际的IO数据传输过程中摆脱出 ...

随机推荐

  1. idea配置git的步骤

    第一次git到GitHub过程 打开到项目 这样就不用再用git Bash敲命令了

  2. navicat破解版的下载与激活

    原文链接:http://www.cnblogs.com/djwhome/p/9289295.html 以前一直使用的老版的破解版的navicat,但是最近老是报错 而且连接还特别慢,今天终于不忙了额, ...

  3. Hash冲突的四种解决办法

    一.哈希表简介 非哈希表的特点:关键字在表中的位置和它自检不存在一个确定的关系,查找的过程为给定值一次和各个关系自进行比较,查找的效率取决于给定值进行比较的次数. 哈希表的特点:关键字在表中位置和它自 ...

  4. JS利用async、await处理少见的登录业务逻辑

    在用uniapp开发一个项目时,有这样一个需求:用户首次登录后,uniapp自动保存用户名密码,之后不管是再次打开项目(打开项目时登录状态已失效)还是 请求接口(接口返回登录失效)时,都会先自动默认的 ...

  5. IDEA配置之tomcat相关配置

    1. tomcat起服务时, 日志乱码 -server -XX:PermSize=512M -XX:MaxPermSize=1024m -Dfile.encoding=UTF-8 设置tomcat参数

  6. 将neo4j的一个节点上的关系移动到另一个节点上

    将neo4j中一个节点的全部关系移动到另一个节点上面,采用先建立新关系,之后删除原先的关系的方式 def move_relations(source_node_id,target_node_id,gr ...

  7. thinkphp5分页查询paginate()传递参数

    使用paginate()分页,我这里实现的是搜索后分页显示,翻页后传递搜索关键字 www.demo.com/home/search/?k=搜索关键字&page=2 搜索分页源码在: think ...

  8. System.Data.EntityException: The underlying provider failed on Open.

    场景:IIS默认站点建立程序,使用Windows集成身份验证方式,连接SQLServer数据库也是采用集成身份验证.我报“System.Data.EntityException: The underl ...

  9. vue 安装插件

    import VueClipboard from 'vue-clipboard2' import MessagePlugin from '../message' import * as filters ...

  10. JS闭包的简单理解。优缺点以及垃圾回收机制

    闭包是什么? ·了解闭包首先了解js的‘链式作用域’结构,对象可以一级一级的向上查找父对象的变量,所以父对象的变量对子对象可见,反之不成立:所以都可以访问全局变量 ·为了解决函数外部无法访问函数内局部 ...