首页 > 代码库 > STM32学习笔记8(DMA控制器)

STM32学习笔记8(DMA控制器)

DMA简介(1)

DMA,全称为:Direct Memory Access,即直接存储器访问,DMA 用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。当 CPU 初始化这个传输动作,传输动作本身是由DMA 控制器 来实行和完成。DMA 传输对于高效能嵌入式系统算法和网络是很重要的。DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。STM32 最多有 2 个 DMA 控制器(DMA2 仅存在大容量产品中),DMA1 有 7 个通道,DMA2 有 5个通道。每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个 DMA 请求的优先权。

从外设(TIMx、ADC、SPIx、I2Cx 和 USARTx)产生的 DMA 请求,通过逻辑或输入到DMA 控制器,这就意味着同时只能有一个请求有效。外设的 DMA 请求,可以通过设置相应的外设寄存器中的控制位,被独立地开启或关闭。 
表1是 DMA1 各通道一览表:

表1 DMA各通道一览表

逻辑或,通道 1 的几个 DMA1 请求(ADC1、 TIM2_CH3、 TIM4_CH1),这几个是通过逻辑或到通道 1 的,这样我们在同一时间,就只能使用其中的一个。其他通道也是类似的。

DMA寄存器

注意: 在以下列举的所有寄存器中,所有与通道6和通道7相关的位,对DMA2都不适用,因为DMA2只有5个通道。

DMA 中断状态寄存器(DMA_ISR)

如果开启了 DMA_ISR 中这些中断,在达到条件后就会跳到中断服务函数里面去,如果没开启,我们也可以通过查询这些位来获得当前 DMA 传输的状态。这里常用的是TCIFx,即通道 DMA 传输完成与否的标志。 注意此寄存器为只读寄存器,所以在这些位被置位之后,只能通过其他的操作来清除。

 DMA 中断标志清除寄存器(DMA_IFCR)。

DMA简介(2):
stm32F10x中配置了两个独立的DMA控制器,他们分别连接到了不同的外设。DMA1有7个通道,DMA2有5个通道,尽管通道之间独立,但同时DMA只能处理一个通道的请求。
DMA的特点是在脱离CPU的情况下直接利用数据总线,在外设和存储器自检进行数据传输。解放了CPU在数据传输过程中的消耗。
DMA的工作机制类似于中断响应,当外设的DMA时间产生后就产生DMA请求,DMA控制器根据优先级选择相应DMA通道的请求,执行数据传输。
1.优先级配置
分为软件和硬件两件配置两种:软件配置有4中方式,在DMA_CCRx中设置,00:低 01:中 10:高 11:最高,
可见软件设置的优先级数目比实际的DMA通道数目少,所以硬件优先级的判定就是在两个通道的软件优先级一样的情况下,比较通道号,序号低的具有更高的优先级。
2.数据传输设置
一旦DMA响应了某个外设的请求,就要开始在外设之间传输数据,这是要提供源地址和目标地址
在DMA_CPARx寄存器中设置外设寄存器的地址,在DMA_CMARx寄存器中设置数据存储器的地址。
然后在DMA_CMARx寄存器的DIR中设置传输的方向。
在DMA_CCRx寄存器中的PSIZE 和MSIZE位没别设置外设和存储器的位宽,一般要保持两个位宽一致。如果不一致在手册中也有提到,半字写入不会出错。
3.传输模式
一般一次请求会连续的传输一串数据,这是通过设置DMA_CNDTRx设置传输数据量,没传输一个数据将会递减1,。
设置设置DMA_CCRx寄存器中的PINC和MINC标志位设定是否开启增量模式,开启了增量的条件下降会根据位宽对地址进行增减。
循环:DMA_CCRx寄存器中的CIRC设置是否开启循环模式,如果开启将会在一次请求传输完毕之后,自动复位计数值和地址,重新开始传输。
4.存储器之间的互传
通过设置了DMA_CCRx寄存器中的MEM2MEM位来使能,同时软件设置了DMA_CCRx寄存器中的EN位启动DMA通道时,DMA传输将马上开始。DMA通道硬件请求外分配给了外外设,存储器之间互传用软件启动。
5.DMA的CPU中断请求
具有三个中断类型,都连接在一个中断通道上。
可以配置这个中断在数据传输完成后进入中断服务函数,进行数据处理,如AD采样传输到存储器之后,进行软件滤波,均值等,当然也可以用查询的方式。
 
根据以上介绍,在使用DMA读取规则组连续转换时的AD值,基本步骤如下:
a.使能AD1的DMA请求允许,
b.设置DMA位连续循环(根据需要),并且使能AD1所在的DMA1通道1.
c.外设地址设置成AD1地址,存储地址根据程序设置为AD采样值得数组。
d.设置位宽为半字,设置优先级,设置CNDTR为1,一次传输一个数据,数据长度是半字。
e.使能DMA1
这样当ADC1每次转换完成一一个数据,就会产生DMA通道,数据会传输到指定的内存,注意的是,要合理安排采样和存储的方式,符合数组的序列要求。
具体的流程要按实际需要来配合使用。
 
[cpp] view plaincopyprint?
 
  1. void Init_DMA()  
  2. {  
  3.   DMA_InitTypeDef DMA_InitStructure;  
  4.   DMA_DeInit(DMA1_Channel1);  
  5.   DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;  
  6.   DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue;  
  7.   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                    //  
  8.   DMA_InitStructure.DMA_BufferSize = 1;                                 //  
  9.   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;            //  
  10.   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;               //  
  11.   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  //  
  12.   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;    //  
  13.   DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                         
  14.   DMA_InitStructure.DMA_Priority = DMA_Priority_High;                         
  15.   DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                         
  16.   DMA_Init(DMA1_Channel1, &DMA_InitStructure);          
  17.     /* Enable DMA1 channel1 */  
  18.   DMA_Cmd(DMA1_Channel1, ENABLE);  
  19. }  
 
实际DMA的思想很简单,外设DMA事件请求使能,DMA使能对应通道,设置源地址目标地址,即可进行传输。

STM32学习笔记8(DMA控制器)