【DMA】直接存储器存取

文章详细介绍了STM32中的DMA(DirectMemoryAccess)机制,包括DMA的功能、通道配置、存储器映像、硬件和软件触发方式,以及DMA的基本结构和工作原理。文中通过举例说明了如何使用DMA进行存储器到存储器的数据转运,以及在ADC扫描模式下如何配合DMA进行数据传输。此外,提到了DMA的传输计数器、自动重装器和触发选择等关键参数的设置。
摘要由CSDN通过智能技术生成
一、DMA简介
  • DMA Direct Memory Access )直接存储器存取
  • DMA 可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须 CPU 干预,节省了 CPU 的资源
//外设:指外设的寄存器,一般是外设的数据寄存器DR(Data Register),比如ADC的数据寄存器,串口的数据寄存器
//存储器:运行内存SRAM和程序存储器Flash,是存储变量数组和程序代码的地方
  • 12 个独立可配置的通道: DMA1 7 个通道), DMA2 5 个通道)
  • 每个通道都支持软件触发和特定的硬件触发
//软件触发: 存储器和存储器之间的高速数据传输(比如:Flash——>SRAM)
DMA会一股脑地把这些数据以最快的速度全部转运完成
//硬件触发: 外设和存储器 之间的高速数据传输( 比如转运ADC的数据)
DMA不会一股脑地传送数据,而是触发一次DMA再转运一次
//DMA每个通道的硬件触发源是不一样的,使用某个外设的硬件触发源,就得使用它连接的那个通道
  • STM32F103C8T6的 DMA 资源: DMA1 7 个通道)

二、存储器映像(STM32都有哪些存储器,这些存储器又被安排到了哪些地址上)
  • ROM:只读存储器,是一种非易失性、掉电不丢失的存储器
  • RAM:随机存储器,是一种易失性、掉电丢失的存储器

三、DMA框图
  • 为了高校有条理地访问存储器,图中设计了【总线矩阵】(梯形)
【总线矩阵】的左端是【主动单元】,拥有存储器的访问权
【总线矩阵】的右端是【被动单元】,它们的存储器只能被左边的主动单元读写
  • 主动单元:【DCode】、【系统总线】、【DMA】(DMA1、DMA2、//以太网外设DMA暂时不管)
  • 内核有【DCode】和【系统总线】可以访问右边的存储器
//【DCode】总线是专门访问Flash的,【系统总线】是访问其他东西的
  • 由于DMA要转运数据,所以DMA也必须要有访问的主动权
  • DMA1和DMA2各有一条DMA总线
  • DMA1有7个通道,DMA2有5个通道,各个通道可以分别设置它们转运数据的源地址和目的地址,可以各自独立工作
  • DMA内部【仲裁器】:虽然多个通道可以独立转运数据,但最终DMA总线只有一条,所有通道只能分时复用这条DMA总线
//如果产生了冲突,由【仲裁器】根据通道的优先级来决定谁先用,谁后用
//另外:在【总线矩阵】(梯形)里也设计了【仲裁器】,如果DMA和CPU都要访问同一目标,DMA会暂停CPU的访问以防止冲突,但【总线仲裁器】仍会保证CPU得到一半的总线带宽,使CPU也能正常工作
  • DMA内还有【AHB从设备】,也就是DMA自身的寄存器(配置DMA参数),通过【桥】连接到了右边的【AHB】总线
因此DMA既是总线矩阵的主动单元——可以读写各种存储器;也是AHB总线上的被动单元——内部AHB从设备可以被CPU配置
  • 从右向左是【DMA请求】(DMA的硬件触发源),右边的触发源是各个外设
//比如ADC转换完成、串口接收到数据,需要触发DMA转运数据时,通过这条线路向DMA发出硬件触发信号,DMA执行数据转运
//CPU或DMA直接访问Flash的话,只可读而不可写
//SRAM是运行内存,可以任意读写

三、DMA基本结构
  • DMA的数据转运,可以是从外设到存储器,也可以是从存储器到外设,具体的方向通过【方向】参数进行控制
//还有一种转运方式就是存储器到存储器(Flash到SRAM、SRAM到SRAM)
//由于Flash是只读的,所以DMA不可以进行SRAM到Flash、Flash到Flash的转运操作
  • 【外设参数】、【存储器参数】
1)外设端的起始地址:决定数据从哪里来,到哪里去
2)数据宽度:指定一次转运要按多大的数据宽度进行,可以选择字节Byte(8位)、半字HalfWord(16位)、字Word(32位)
3)地址是否自增:指定一次转运完成后,下一次的转运是否要将地址移动到下一个位置(相当于指针,p++)
//如果要进行【存储器到存储器】的数据转运,需要把其中一个存储器的地址放在【外设站点】,在外设起始地址里写Flash或者SRAM的地址,那么存储器就会去Flash或SRAM找数据
  • 传输计数器:用来指定总共需要转运几次,传输计数器是一个自减计数器
//比如给传输计数器写5,那么DAM就只能进行5次数据转运,每转运一次计数器的数就会减1,当减到0时DMA不再进行数据转运
//另外:减到0之后,之前自增的地址也会恢复到起始地址的位置,以方便DMA之后开始新一轮的转运
  • 【自动重装器】:传输计数器减到0之后,是否要自动恢复到初始值 (不重装:单次模式;重装:循环模式)
//比如最初传输计数器写5,如果不使用自动重装器,那么转运5次后DMA就结束了;
//如果使用自动重装器,那么转运5次,传输计数器减到0后,就会立即重装到初始值5
  • DMA触发控制:触发,就是决定DMA需要在什么时机进行转运的
  • 触发源:硬件触发、软件触发,具体选择由【M2M(Memory to Memory)存储器到存储器】参数决定
//【M2M】置1——软件触发;【M2M】置0——硬件触发
  • 软件触发:以最快的速度连续不断地触发DMA,争取早日把传输计数器清零,完成这一轮转换(可理解为连续触发)
//适用于存储器到存储器的转运
//【软件触发】和【循环模式】不能同时用,【软件触发】——努力把传输计数器清零,【循环模式】——清零后自动重装
//如果同时用,DMA就一直重装一直清零,根本停不下来
  • 硬件触发:硬件触发源可以选择【ADC】、【串口】、【定时器】等等
  • 当硬件达到转运时机,传一个信号过来触发DMA进行转运
//使用硬件触发的转运一般都是与外设有关的转运
//转运时刻有时机要求,如【ADC转换完成】、【串口收到数据】、【定时时间到】
  • 开关控制
//当给DMA使能后,DMA准备就绪就可以进行转运了
  • DMA工作条件
1)开关控制,DMA_Cmd必须使能
2)传输计数器必须大于0
3)触发源,必须有触发信号,触发一次转运一次,传输计数器自减一次;当传输计数器等于0,且没有自动重装时,无论是否触发,DMA都不会再进行转运
//解决方法:先给DMA_Cmd(DISABLE)关闭DMA,再为传输计数器写入一个大于0的数,再DMA_Cmd(ENABLE)开启DMA
//注意:写传输计数器时必须先关闭DMA再进行写入,不能在DMA开启时写传输计数器

四、DMA请求
|
|
|
V
对应
  • 【EN】决定数据选择器(梯形)是否工作——【EN】=0,数据选择器不工作;【EN】=1,数据选择器1工作
  • 【MEM2MEM】——【MEM2MEM】=1,选择软件触发;【MEM2MEM】=0,选择硬件触发
  • 【外设请求信号】(硬件触发源):每个通道的硬件触发源不同,需要使用某个硬件触发源时,就必须使用其所在通道
//如果需要用ADC1触发的话,则需要选择通道1
//如果使用软件触发的话,通道则可以任意选择
  • 【外设请求信号】(硬件触发源)的选择取决于把哪个外设对应的DMA输出函数开启了
  • 之后这7个触发源进入仲裁器,进行优先级判断,最终产生内部的DMA1请求

五、数据宽度与对齐
  • 数据转移的两个站点各自都有一个数据宽度的参数,如果数据宽度一样就是正常的一个个转运
  • 如果数据宽度不一样,参考表中数据执行
  • 第一列【源端宽度】,第二列【目标宽度】,第三列【传输数目】(注意地址)
//当源端和目标都是【8位】时:
//转运第一步,在源端的0位置读数据B0,在目标的0位置写数据B0
// 转运第二步,在源端的1位置读数据B1,在目标的1位置写数据B1
//转运第三步…………
总结:目标数据宽度=源端数据宽度,正常一位位转运
//当源端是【8位】,目标是【16位】时:
//转运第一步,在源端的0位置读数据B0,在目标的0位置写数据00B0
//转运第二步,在源端的1位置读数据B1,在目标的2位置写数据00B1
// 转运第三步…………
总结:源端数据宽度<目标数据宽度,目标数据在前面多出来的空位补0
//当源端是【16位】,目标是【8位】时:
//转运第一步,在源端的0位置读数据B1B0,在目标的0位置写数据B0
//转运第二步,在源端的1位置读数据B3B2,在目标的1位置写数据B2
// 转运第三步…………
总结:源端数据宽度>目标数据宽度,目标数据舍弃源端数据多出来的高位

六、数据转运+DMA
任务:将SRAM里的数组DataA,转运到另一个数组DataB中
EX:如何根据【DMA基本结构】图中参数进行配置
  • 起始地址
//【外设地址】——DataA数据的首地址;【寄存器地址】——DataB数据的首地址
  • 数据宽度
//两个数组的类型都是uint8_t,因此数据宽度都按【8位的字节传输】
  • 地址是否自增
//两个数据转运的位置一一对应,转运完DataA[0]和DataB[0]后,两个站点的地址都应该【自增】,移动到下一个数据的位置
  • 方向参数
//【外设站点】——>【存储器站点】
  • 传输计数器
//数据需要转运7次,所以传输寄存器给7
  • 自动重装器
//暂时不需要,单次模式一次性转运就行
  • 触发选择部分
//使用【软件触发】(存储器[SRAM]到存储器[SRAM]的数据转运),不需要等待硬件时机,尽快转运完成就行
  • 调用DMA_Cmd函数给DMA使能
//数据就从DataA转运到DataB了,转运7次后,传输计数器自减到0,DMA停止,转运完成
//这里的数据转运是一种复制转运,转运完成后DataA的数据并不会消失

七、ADC扫描模式+DMA
  • 左边是ADC扫描模式的执行流程
  • 有7个通道,触发一次后,7个通道依次进行AD转换,转换结果放在ADC_DR数据寄存器里面
//配合DMA完成:在每次单独的通道转换完成后,进行一个DMA数据转运,并且目的地址进行自增,这样数据就不会被覆盖了
DMA配置为
  • 【外设地址】——ADC_DR数据寄存器的地址
  • 【存储器地址】——在SRAM中定义一个数组ADValue,把ADValue的地址当作存储器的地址
  • 【数据宽度】——因此ADC_DR和SRAM数组ADValue都是uint16_t,所以数据宽度都是【16位的半字传输】
  • 【地址是否自增】——【外设地址】不自增;【存储器地址】自增
  • 【传输方向】——【外设站点】到【存储器站点】
  • 【传输计数器】——通道有7个,所以计数7次
  • 【自动重装器】——ADC如果是【单次扫描】——不自动重装(转换一轮停止);ADC如果是【连续扫描】——自动重装
  • 【触发选择】——ADC_DR值在ADC单个通道转换完成后才会有效,所以DMA转运时机需要和ADC单个通道转换完成同步
//因此DMA的触发源选择【ADC的硬件触发】

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值