文章目录
- DMA直接存储器存取
- DMA简介
- 存储器映像
- DMA框图
- DMA基本结构
- 存储器到存储器的数据转运
- ADC扫描模式和DMA配合使用流程
DMA直接存储器存取
DMA简介
DMA进行存储器到存储器的数据转运,比如Flash里的一批数据转运到SRAM里,需要软件触发,使用软件触发后DMA就会一股脑地把这批数据以最快的速度全部转运完成,如果DMA进行的是外设到存储器的数据转运,就不能一股脑地转运,因为外设的数据是有一定时机的,这时需要用硬件触发,比如转运ADC的数据,ADC每个通道AD转换完成后,硬件触发一次DMA,之后DMA再转运,触发一次,转运一次。
存储器到存储器的数据转运一般用软件触发,外设到存储器的数据转运一般用硬件触发。
存储器映像
ROM只读存储器,非易失性、掉电不丢失。RAM随机存储器,易失性、掉电丢失的存储器。
DMA框图
寄存器是一种特殊的存储器,一方面CPU可以对寄存器进行读写,就像读写运行内存一样,另一方面寄存器的每一位都连一根导线,这些导线可以用于控制外设电路的状态,比如置引脚的高低电平、导通和断开开关、切换数据选择器、多位结合起来当做计数器或数据寄存器等等。寄存器是连接软件和硬件的桥梁。软件读写寄存器,相当于控制硬件的执行。外设就是寄存器,寄存器就是存储器,那使用DMA进行数据转运,就可以归为一类问题了,就是从某个地址取内容,再放到另一个地址去。
总线矩阵的左端,是主动单元,也就是拥有存储器的访问权,右边是被动单元,它们的存储器只能被左边的主动单元读写,主动单元,内核有DCode和系统总线,可以访问右边的存储器,其中DCode总线是专门访问Flash的,系统总线是访问其他东西的,另外,由于DMA要转运数据,所以DMA也必须要有访问的主动权,也是主动单元。
仲裁器的作用是防止冲突,根据优先级决定通道的使用权。
AHB从设备就是DMA自身的寄存器,DMA作为一个外设,自己也会有相应的配置寄存器,这里连在了总线右边的AHB总线上,所以DMA既是总线矩阵的主动单元,可以读写各种寄存器,也是AHB总线的被动单元,CPU通过系统总线到总线矩阵再到AHB从设备就可以对DMA进行配置。
DMA请求就是触发的意思,右边的触发源是各个外设,所以DMA请求就是DMA的硬件触发源,比如ADC转换完成、串口接收到数据需要触发DMA转运数据的时候,就会通过DMA请求线路向DMA发出硬件触发信号,之后DMA就可以执行数据转运的工作了。
另注意CPU或DMA直接访问Flash的时候,是只可以读不可以写的,想要写入需要配置Flash接口控制器。SRAM可以任意读写。外设寄存器有的只读有的只写,数据寄存器都是可以正常读写的。
DMA基本结构
寄存器的地址不用自增,存储器地址需要自增。如果进行存储器到存储器的数据转移,就是Flash到SRAM,需要把其中一个存储器的地址放在外设的站点,只要在外设起始地址里写Flash或SRAM的地址,那它就会去Flash或SRAM找地址,也就是虽然叫外设寄存器但也可以写别的地址。
传输计数器用来指定总共需要几次的,是一个自减计数器,比如写5,DMA就只能进行5次数据转运,转运过程中每转运一次,计数器的数就会减1,当传输计数器减到0之后,DMA就不会再进行数据转运了,另外减到0之后,之前自增的地址也会恢复到起始地址的位置,方便之后DMA开始新一轮的转运。
传输计数器的右边是自动重装器,作用是传输计数器减到0后是否要自动恢复到最初的值,比如最初传输计数器给5,如果不使用自动重装器,转运5次后DMA就结束了,如果使用,计数器减到0后会立即重装到初始值5,所以自动重装器决定了转运的模式,如果不重装就是正常的单次模式,如果重装就是循环模式。比如如果想转运一个数字,一般是单次模式,转运一轮就结束了,如果ADC扫描模式+连续转换,为了配合ADC,DMA也需要使用循环模式。
最下面是触发,触发就是决定DMA需要在什么时机进行转运,触发源有硬件触发和软件触发,由M2M参数决定选择哪个,M2M就是Memory to Memory存储器到存储器的意思。
给M2M位1时,DMA选择软件触发,执行逻辑是以最快的速度连续不断地触发DMA,争取早日把传输计数器清零,完成这一轮的转换,和之前外部中断、ADC的软件触发不一样,不是调用某个函数一次,触发一次,可以把这里理解为连续触发。软件触发和循环模式不能同时使用,软件触发就是想把传输计数器清零,循环模式是清零后自动重装,如果同时用就死循环。软件触发一般适用于存储器到存储器的转运,软件启动,不需要时机,并且想尽快完成任务。
给M2M位0,就是使用硬件触发,硬件触发源选ADC、串口、定时器等等,使用 硬件触发的转运,一般是与外设有关的转运,需要一定的时机,比如ADC转换完成、串口收到数据、定时时间到等等,在硬件达到这些时机时,传一个信号过来触发DMA进行转运。
开关控制,是DMA_Cmd函数,当给DMA使能后DMA准备就绪,可以进行转运,DMA进行转运有几个条件,第一,开关控制,DMA_Cmd必须使能,第二,传输计数器必须大于0,第三,触发源必须有触发信号,触发一次转运一次,传输计数器自减一次,当传输计数器等于0且没有自动重装时,无论是否触发,DMA都不会再进行转运了,此时需要DMA_Cmd给DISABLE关闭DMA,再为传输计数器写一个大于0的数,再DMA_Cmd,给ENABLE,开启DMA,DMA才能继续工作。注意,写传输计数器时,必须要先关DMA再进行,不能在DMA开启时,写传输计数器。
如果目标的数据宽度比源端的数据宽度大,在目标数据前面多出来的空位补0,当目标数据宽度比源端数16据宽度小时,比如由16位转到8位,读B1B0,只写入B0,读B3B2,只写入B2。总之,小转大,高位补0,大转小,高位舍去。
存储器到存储器的数据转运
外设地址填DataA数组的首地址,存储器地址给DataB数组的首地址,数据宽度按8位的字节传输,两边地址都需要自增,方向参数决定外设站点和存储器站点间的转运方向,传输寄存器给7,自动重装器暂时不需要,触发选择部分使用软件触发,最后调用DMA_Cmd,给DMA使能。这样数据从DataA转运到DataB,转运7次后,传输计数器自减到0,DMA停止,转运完成,转运完成后DataA的数据并不会消失,相当于复制。
ADC扫描模式和DMA配合使用流程
左边是ADC扫描模式的执行流程,7个通道,触发一次后,7个通道依次进行AD转换,转换结果都放到ADC_DR数据寄存器里,要在每个单独的通道转换完成后,进行一次DMA转运,并且目的地址进行自增,这样数据不会被覆盖。配置DMA,外设地址写入ADC_DR这个寄存器的地址,存储器的地址,可以在SRAM中定义一个数组ADValue,然后把ADValue的地址当做存储器的地址,之后数据宽度,因为ADC_DR和SRAM数组要的都是uint16_t的数据,所以是16位的半字传输,继续看地址是否自增,图里外设地址不自增,存储器地址自增,传输方向,外设站点到存储器站点,传输计数器,通道7个所以计数7次,计数器是否自动重装看ADC的配置,ADC如果单次扫描,DMA的传输计数器可以不自动重装,转换一轮就停止,如果ADC连续扫描,DMA使用自动重装,在ADC启动下一轮转换的时候,DMA也启动下一轮转运,ADC和DMA同步工作,最后触发选择,ADC_DR的值是在ADC单个通道转换完成后才会有效,所以DMA转运的时机,需要和ADC单个通道转换完成同步,DMA的触发要选择ADC的硬件触发。ADC扫描模式在每个单独的通道转换完成后,没有任何标志位,也不会触发中断,所以程序不太好判断某一个通道转换完成的时机是什么时候,但是会产生DMA请求触发DMA转运。