DMA

使用范围

DMA(直接存储器存取)提供在外设与存储器之间或者存储器和存储器之间的高速数据传输使用。

这里的外设指的是32的外设,比如spi、usart、iic、adc等基于APB1 、APB2或AHB时钟的外设,而这里的存储器包括32自身的闪存(flash)或者内存(SRAM)以及外设的存储设备都可以作为访问的源或者目的。

外部存储设备其自身在这就是外设了,配置时属于外设,不要与配置寄存器的存储设备混淆。
  
DMA和CPU分时使用内存
  
三种方法:

• 停止CPU访问内存;
• 周期挪用;
• DMA与CPU交替访问内存。

停止CPU访问内存
  
当外围设备要求传送一批数据时,由DMA控制器发一个停止信号给CPU,要求CPU放弃对地址总线、数据总线和有关控制总线的使用权。DMA控制器获得总线控制权以后,开始进行数据传送。

在一批数据传送完毕后,DMA控制器通知CPU可以使用内存,并把总线控制权交还给CPU,图(a)是这种传送方式的时间图。很显然,在这种DMA传送过程中,CPU基本处于不工作状态或者说保持状态。

这些关于STM32 DMA的使用,你都知道吗?

优点:控制简单,它适用于数据传输率很高的设备进行成组传送。
  
缺点:在DMA控制器访内阶段,内存的效能没有充分发挥,相当一部分内存工作周期是空闲的。这是因为,外围设备传送两个数据之间的间隔一般总是大于内存存储周期,即使高速I/O设备也是如此。例如,软盘读出一个8位二进制数大约需要32us,而半导体内存的存储周期小于0.5us,因此许多空闲的存储周期不能被CPU利用。
  
周期挪用
  
当I/O设备没有DMA请求时,CPU按程序要求访问内存;一旦I/O设备有DMA请求,则由I/O设备挪用一个或几个内存周期。
  
这种传送方式的时间图如下图(b):

这些关于STM32 DMA的使用,你都知道吗?

I/O设备要求DMA传送时可能遇到两种情况:

• 此时CPU不需要访内,如CPU正在执行乘法指令。由于乘法指令执行时间较长,此时I/O访内与CPU访内没有冲突,即I/O设备挪用一二个内存周期对CPU执行程序没有任何影响。

  
• I/O设备要求访内时CPU也要求访内,这就产生了访内冲突,在这种情况下I/O设备访内优先,因为I/O访内有时间要求,前一个I/O数据必须在下一个访问请求到来之前存取完毕。

显然,在这种情况下I/O 设备挪用一二个内存周期,意味着CPU延缓了对指令的执行,或者更明确地说,在CPU执行访内指令的过程中插入DMA请求,挪用了一二个内存周期。

与停止CPU访内的DMA方法比较,周期挪用的方法既实现了I/O传送,又较好地发挥了内存和CPU的效率,是一种广泛采用的方法。

但是I/O设备每一次周期挪用都有申请总线控制权、建立线控制权和归还总线控制权的过程,所以传送一个字对内存来说要占用一个周期,但对DMA控制器来说一般要2—5个内存周期(视逻辑线路的延迟而定)。

因此,周期挪用的方法适用于I/O设备读写周期大于内存存储周期的情况。
  
DMA与CPU交替访问内存
  
如果CPU的工作周期比内存存取周期长很多,此时采用交替访内的方法可以使DMA传送和CPU同时发挥最高的效率。
  
这种传送方式的时间图如下:

这些关于STM32 DMA的使用,你都知道吗?

假设CPU工作周期为1.2us,内存存取周期小于0.6us,那么一个CPU周期可分为C1和C2两个分周期,其中C1专供DMA控制器访内,C2专供CPU访内。
  
这种方式不需要总线使用权的申请、建立和归还过程,总线使用权是通过C1和C2分时制的。CPU和DMA控制器各自有自己的访内地址寄存器、数据寄存器和读/写信号等控制寄存器。

在C1周期中,如果DMA控制器有访内请求,可将地址、数据等信号送到总线上。在C2周期中,如CPU有访内请求,同样传送地址、数据等信号。

事实上,对于总线,这是用C1,C2控制的一个多路转换器,这种总线控制权的转移几乎不需要什么时间,所以对DMA传送来讲效率是很高的。

这种传送方式又称为“透明的DMA”方式,其来由是这种DMA传送对CPU来说,如同透明的玻璃一般,没有任何感觉或影响。在透明的DMA方式下工作,CPU既不停止主程序的运行,也不进入等待状态,是一种高效率的工作方式。当然,相应的硬件逻辑也就更加复杂。

非循环方式传输

STM32使用DMA非循环方式传输完成后重新开启传输:通道配置为非循环模式时,传输结束后(即传输计数变为0)将不再产生DMA操作。要开始新的DMA传输,需要在关闭DMA通道的情况下,在DMA_CNDTRx寄存器中重新写入传输数目。
  
即关DMA->写传输数目->开DMA。
 
存储器到存储器模式
  
DMA通道的操作可以在没有外设请求的情况下进行,这种操作就是存储器到存储器模式。

以串口为例,这种外设查看串口使能DMA时序可知其会自动向CPU提DMA请求,而对于比如外设也是存储设备那么他自身不具有自动提DMA申请功能,这种就属于存储器到存储器模式,这是m2m位需置1。

这些关于STM32 DMA的使用,你都知道吗?

以上图DMA1请求映像为例,可知外设(这里指的是比如串口spi TIM等32自带的外设)都是以硬件自动触发的DMA请求,而非自身外设比如加的外部存储设备无硬件自动触发机制就需要通过设置M2M位实现软件触发DMA请求给CPU了当设置了DMA_CCRx寄存器中的MEM2MEM位之后,在软件设置了DMA_CCRx寄存器中的EN位启动DMA通道时, DMA传输将马上开始。

当DMA_CNDTRx寄存器变为0时, DMA传输结束。存储器到存储器模式不能与循环模式同时使用。

来源: 电子产品世界

围观 531

DMA(Direct Memory Access)常译为“存储器直接存取”。早在Intel的8086平台上就有了DMA应用了。

一个完整的微控制器通常由CPU、存储器和外设等组件构成。这些组件一般在结构和功能上都是独立的,而各个组件的协调和交互就由CPU完成。如此一来,CPU作为整个芯片的核心,其处理的工作量是很大的。如果CPU先从A外设拿到一个数据送给B外设使用,同时C外设又需要D外设提供一个数据。。。这样的数据搬运工作将使CPU的负荷显得相当繁重。

严格的说,搬运数据只是CPU的比较不重要的一种工作。CPU最重要的工作室进行数据运算,从加减乘除到一些高级的运算,包括浮点、积分、微分、FFT等。CPU还需要负责复杂的中断申请和响应,以保证芯片的实时性能。

理论上常见的控制外设,比如Usart、I2C、SPI甚至是USB等通信接口,单纯的利用CPU进行协议模拟也是可以实现的,比如51单片机经常使用I/O口模拟I2C协议通信。但这样既浪费了CPU的资源,同时实现后的性能表现往往和使用专门的硬件模块实现的效果相差甚远。从这个角度来看,各个外设控制器的存在,无疑降低了CPU的负担,解放了CPU的资源。

数据搬运这一工作占用了大部分的CPU资源,成为了降低CPU的工作效率的主要原因之一。于是需要一种硬件结构分担CPU这一职能—— DMA。

从数据搬运的角度看,如果要把存储地址A的数值赋给另外一个地址上B的变量,CPU实现过程为首先读出A地址上的数据存储在一个中间变量,然后再转送到B地址的变量上。使用DMA则不需要中间变量,直接将A地址的数值传送到B地址的变量里。无疑减轻了CPU的负担,也提高了数据搬运的效率。

stm32中 DMA1有7个通道,DMA2有5个通道。DMA挂载的时钟为AHB总线,其时钟为72Mhz,所以可以实现高速数据搬运。

聊聊STM32中DMA模块的使用

stm32使用DMA的相关操作:

1、DMA的配置

void DMA_Configuration(void){ DMA_InitTypeDefDMA_InitStructure; //DMA设置: //设置DMA源:内存地址&串口数据寄存器地址 //方向:内存-->外设 //每次传输位:8bit //传输大小DMA_BufferSize=SENDBUFF_SIZE //地址自增模式:外设地址不增,内存地址自增1 //DMA模式:一次传输,非循环 //优先级:中 DMA_DeInit(DMA1_Channel4);//串口1的DMA传输通道是通道4 DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base; DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外设作为DMA的目的端 DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;//传输大小 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不增加 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址自增1 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

//DMA_Mode_Normal(只传送一次), DMA_Mode_Circular(不停地传送) DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//(DMA传送优先级为中等) DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel4, &DMA_InitStructure);}

注:

1、传输通道:
通过查表,串口1的发送对应的是DMA的通道4,所以此处选择通道4.

2、DMA传输方式:
(1)DMA_Mode_Normal,正常模式,当一次DMA数据传输完后,停止DMA传送,对于上例而言,就是DMA_PeripheralDataSize_Byte个字节的传送完成后,就停止传送。

(2) DMA_Mode_Circular

循环模式,当传输完一次后,重新接着传送,永不停息。

2、外设的DMA方式设置
将串口1设置成DMA模式:

USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

3、待传输数据的定义和初始化
#define SENDBUFF_SIZE 10240vu8 SendBuff[SENDBUFF_SIZE];

for(i=0;i

4、开始DMA传输(使能对应的DMA通道) DMA_Cmd(DMA1_Channel4, ENABLE);

5、DMA传输的完成
while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET) { LED_1_REV; //LED翻转 Delay(); //浪费时间 }

当传输完成后,就会跳出上面的死循环。

来源: 21ic电子网

围观 908

页面

订阅 RSS - DMA