DMA工作原理-STM32 DMA和ARM9 DMA,彻底理解DMA

前序

网上文章一大堆都有介绍DMA的作用,是直接内存获取控制器,但由于用途的局限或者用在了复杂的外设上面,导致没有很好的把DMA的作用说的很系统,本人也是根据网上的资料,进行一些DMA的总结,个人觉得比较系统,也权当是笔记,哈哈。如有错误,请各位大神指正。

DMA的作用是什么?

在没有CPU的参与下,把数据从一个地方搬运到另外一个地方。从这句话,我们可以总结出他的作用:
(1)搬运数据。
(2)“一个地方”指的是外设或者内存,外设当然包括片内外设和片外外设,比如ADC、UART片内外设,外挂的flash属于片外外设(最终控制的仍然是内部flash控制器);内存当然包括片内内存和片外内存(仍然是内部的内存控制器),其实,不论外设还是内存,最终都是控制处理器内部的地址
(3)搬运数据的过程中不需要CPU参与,就是不需要有CPU运行汇编指令,也就是说DMA有自己“CPU”,自己干自己需要干的活。
总结:DMA就是自己把一个地址的数据搬到另外一个地址。

为什么能够DMA?他在处理器中的内部原理图是什么?

从DMA的作用中知道,DMA是把一个地址的数据搬运到另外一个地址,所以它需要控制地址,这些地址在处理器内部是AHB和APB总线矩阵管理的,所以DMA必须要挂到AHB和APB上面,下图是ATMEL ARM9的DMA的框图:
在这里插入图片描述
下图是STM32F4XX的DMA内部的框图:
在这里插入图片描述
注意,AHB是可以通往操作APB总线的,所以挂到AHB总线上就可以操作外设的。

通过上述的两个图,总结一下:
(1)DMA需要把数据从“一个地址”搬运到“另外一个地址”,所以它有“两个出入口”。
(2)挂到AHB总线的“出入口”可以操作APB上的外设,所以ARM9的DMA控制器,可以实现外设到内存、内存到外设、内存到内存搬运3种功能;然而,STM32F4XX的DMA控制器,的DMA2可以实现3种功能,但是DAM1的一个端口只挂到APB总线上,所以他不能实现内存到内存的功能。
(3)一个DMA控制器的构造:
(i)数据出入口。
(ii)DMA被编程配置的端口,让CPU可以配置DMA的寄存器。
(iii)硬件握手的接口,需要接收外设的DMA请求和相应请求。
(iv)中断发出接口,当DMA到达某种条件后,需要发出中断通知CPU,比如传输完成、传输出错。

DMA的功能细节描述

首先数据传输三要素:源、目的、大小。在理想情况下,一个寄存器放源地址,一个寄存器存放目的地址,一个寄存器存放数据大小,最后在DMA通道寄存器使能,让DMA愉快的搬运数据即可。理想是美好的,但现实是多变的,其实,在平时使用中,还要满足各种情况,还要考虑很多细节。

(1)源地址的细节。
首先,必须有个寄存器存放源地址,一个地址只能存放一个字节的数据,那么考虑问题:
(i)如果源的结构是由2个或者4个字节构成的,怎么办?比如说32位的寄存器其实就是4个字节的构造。
答:此时需要一个寄存器来设置,源地址的构造是字节、半字还是字。

(ii)如果需要传输很多连续单位(字节、半字、字),怎么办?
答:此时需要一个寄存器来设置,源地址传输一个单位后,再传输下一个单位的地址是连续递增或者递减。

(iii)如果传输多个连续单位(字节、半字、字),怎么办?
答:此时需要有多个寄存器设置多个源地址的起始地址。当然别不是所有的DMAC都支持任意多个连续单位,STM32有双buffer功能,就是说可以设置2个起始地址,这两个地址是硬件自动切换的;ARM9通过LLI技术,就是把每个起始地址都提前存放到内存中,形成一个链表,当第一个传输完成后,根据链表查到下一个起始地址的地址,直到最后一个,这种技术可以支持非常多的起始地址,当然链表中的每个节点不只是一个寄存器的内容,下图就是LLI的构造。
在这里插入图片描述
(iv)由于DMAC都是挂在AHB总线上,如果需要使用AHB总线,必须要AHB总线仲裁给与权限, 每个获取一次权限发送一个单位的数据,所以说这个单位最多就是一个字,从宏观上看,其实速度已经非常的快了,如果还想更快更多怎么办?
答:此时就产生了“突发”传输的技术,突发传输的核心是以“量和速度”为核心的传输,啥意思、啥东西,这么复杂?通俗的说的说,就是每当DMAC获得AHB使用权的时候,传输多个单位,在STM32中,是通过FIFO来实现的,因为FIFO最多存16字节的数据(4深度32位),DMAC先把数据存入FIFO,存多少,是根据用户的配置,最少要4个节拍,也就是4个单位,等FIFO的数据阈值达到了用户的设定,STM32是有MBURST域决定的,ARM9如下图,由下面的域决定的:
在这里插入图片描述此时DMAC如果获取到了总线的使用权的时候,他会抓住机会不释放总线,直接把用户需求的数据,一次性(分多次)全部传输,下图是“野火”根据英文手册,总结的中文表格(大家都喜欢中文,所以在此引用):
在这里插入图片描述
这个图的意思是必须达到这么多节拍才进行突发传输,FIFO阈值,是FIFO要达到总的(16字节)比例,例如用户配置MSIZE=半字,MBURST=4,FIFO级别=1/2,意思就是一次突发由4个节拍(单位)构成,此时达到FIFO的1/2(也就是8个字节),此时MSIZE=半字,所以4半字=8个字节,需要1次突发就可以完成;如果此时FIFO级别=满,此时FIFO里面有16个字节,此时MSIZE=半字,所以(4半字)*2=16字节,因此,需要连续2次突发完成。
在ARM9中,是否使用突发传输不需要额外的配置,只是根据请求传输的类型(single或者chunk)DMAC自己决定是否使用突发传输。

关于请求开始传输数据

(1)不论是DMA还是外设流控,不论是传输方向是内存到外设还是外设到内存,每次传输都是外设发起请求,也就是握手信号由外设产生,但是握手的方式有两种:软件握手和硬件握手。如果是内存到内存模式,就不需要外设参与,也就不需要外设进行请求。
(i)软件握手。
当外设准备好之后,会通过中断的方式通知CPU自己“已准备就绪”,此时CPU写相应的DMAC寄存器开始DMA传输。
(ii)硬件握手。
当外设准备好之后,直接通知DMAC自己“已准备就绪”,此时DMAC直接开始传输。

STM32所有外设请求硬件握手,而ARM9则可以选择硬件还是软件握手,如果设置成硬件握手还需要设置SRC_PER 或者 DST_PER 的域,把域设置成对应的硬件ID号。

关于流控

(1)DMA流控的时候,需要传输数据的多少是在传输之前已知的;外设流控的时候,在传输数据之前,需要传输数据的多少是未知的,此时,如果数据传输完成,需要外设发出信号,通知DMA“数据已经发送完成”,STM32中只有SDIO才有这种功能,其他外设不存在这种功能,所以其他外设都要设置成DMA流控,传输次数寄存器DMA_SxNDTR会被硬件自动设置成0xffff,当传输0xffff次之后,如果硬件不通知DMA停止传输,此时仍然会强制让DMA产生完成中断,同时通道也会被强制关闭。在ARM9中,我们发现并不能使用外设流程,如下图:
在这里插入图片描述
(2)内存到内存的传输,流控只能是DMAC。

关于FIFO

(1)在单次传输的时候可以开启FIFO使用功能,在突发传输的时候,必须使用FIFO功能,因为突发传输,就是以“数据量和传输速度”为目的的。

关于一次传输

(1)什么是一次传输?
一次传输有三要素:
(a)原地址以及位宽。
(b)目的地址以及位宽。
(c)传输的次数,STM32由DMA_SxNDTR寄存器决定。ARM9是由DMAC_CTRLAx寄存器的BTSIZE域决定的。

关于开始和结束传输

(1)DMA怎么知道要开始传输了?
当源或者目的(非内存外设)准备好之后,就发出请求,此时DMAC就知道可以进行数据传输了。
当源和目的都是内存外设的时候,就由DMAC控制器,直接进行数据传输,并不需要请求信号。
(a)STM32中,请求信号直接直接与DMAC连接,只有相应的通道使能后,外设准备好之后,就立刻发出请求,并不需要软件参与。
(b)在ARM9中,请求是通过设置寄存器发出的,如下图单次传输请求是在DMAC_SREQ寄出器域中:
在这里插入图片描述
下图是在DMAC_CREQ寄存器的chunk请求:
在这里插入图片描述
ARM9为什么会有两种不同的请求呢?因为ARM9重DMAC并不能通过配置相关的寄存器进行burst突发传输,而是直接根据请求类型来决定是否进行burst突发传输。

(2)CPU怎么知道一次传输完成了?
(a)在stm32中,每次传输都会有几种不同的中断产生,当然也可以轮训,下图是可以进行产生的中断种类:
在这里插入图片描述
大致有三类:传输一半、传输完成、传输出错。
(b)在ARM9中,也能产生中断,如下图:
在这里插入图片描述
大致也是有三类:一个buffer传输完成、buffer链传输完成、传输错误。
通过(a)(b)可知,可以通过相应的标志位或者中断,进行判定传输完成。

(3)循环传输怎么判断传输完成?
在每次的“一次传输”完成都会产生中断标志进的,所以,CPU就能够判断传输完成的。

关于传输模式

(1)直接模式。不使用FIFO,如果有请求直接进行一次传输。
(2)burst突发模式。使用FIFO,根据burst的配置进行突发传输。内存到内存必须使用突发传输。、
直接传输和burst传输的区别就是是否使用FIFO,传输模式软件编程需要注意哪些事项?
(1)STM32来说是需要配置是否使用直接模式,默认是直接模式,所以不进行突发传输。
(2)ARM9并不需要配置是否是直接模式,只是根据请求类型来决定使用哪种方式进行传输。

STM32和ARM9的DMA的差异在哪里?

(1)握手方面,STM32外设的握手线直接与DMAC连通,并不需要软件配置;ARM9需要进行软件或者硬件握手配置。
(2)传输模式方面,STM32需要配置是否使用FIFO的突发传输;ARM9直接根据请求类型,自己决定是否进行突发传输。
(3)功能方面,STM32可以进行单次传输和双buffer传输;ARM9由于LLI技术,所以可以进行单buffer和多buffer传输。
(4)源和目的地址方面,STM32只能是递增、递减或者固定三种方式;AM9则可以递增、递减、固定或者从LLI中获取。

总结

DMAC就是进行数据搬运的,搬运中由于需求不同,可以进一步细节的优化,burst突发传输、多buffer技术,最后再奉上一个问答题目:
DMA请求总线后,CPU把总线控制权交给了DMA,那么CPU不是就没法从内存读取指令和数据了吗?那么,CPU不就处于干瞪眼的状态吗?这样的话,也没法提高CPU的效率啊,还不然直接让CPU去干DMA的活呢?
答:资源是有限的,肯定有争抢和效率的问题(不仅仅是memory,在memory之前还存在对总线的争抢)。但也不用过于悲观,因为(我们从CPU的视角往下说):
(1)CPU不是一直在取指和取数。指令执行的过程包取指、译码和执行,译码肯定不需要访问memory,执行访问memory的概率也不会超过50%。
(2)复杂SoC通常有很多级的指令cache和数据cache,在顺序执行的情况下,又可以大大减少CPU访问memory的可能性,降低和DMA冲突、争抢的概率。
(3)复杂SoC的总线通常具有仲裁能力,可以配置CPU、DMA等访问总线的优先级,这很大程度上会影响CPU和DMA对memory的访问,如果不想CPU被影响,可以调高它的优先级,反正DMA传输可以慢慢来(见缝插针,这也是DMA设计的初衷)。
(4)关于CPU和DMA对memory资源的争抢,也可以通过DMA burst size进行调整。
(5)很多时候,系统中的memory(例如DDR),是有并发访问的能力的,可以想象成有多个可并行工作的memory,因此竞争的概率又可以降低了。
(6)最后再强调:DMA的性能和CPU的性能是不可调和的,需要根据实际的应用场景小心的平衡。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值