STM32之DMA学习

概述:

传统的DMA的概念是用于大批量数据的传输,但是我理解,在STM32中,它的概念被扩展了,也许更多的时候快速是其应用的重点。数据可以从1~65535个。

DMA的基本定义

DMA,全称Direct Memory Access,即直接存储器访问。
DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM和IO设备开辟一条直接传输数据的通道,使得CPU的效率大大提高。[摘自STM32官方数据手册]
DMA 控制器和Cortex-M3核共享系统数据总线执行直接存储器数据传输。当CPU和DMA同时访问相同的目标(RAM或外设)时,DMA请求可能会停止 CPU访问系统总线达若干个周期,总线仲裁器执行循环调度,以保证CPU至少可以得到一半的系统总线(存储器或外设)带宽。
在发生一个事件后,外设发送一个请求信号到DMA控制器。DMA控制器根据通道的优先权处理请求。当DMA控制器开始访问外设的时候,DMA控制器立即发送给外设一个应答信号。当从DMA控制器得到应答信号时,外设立即释放它的请求。一旦外设释放了这个请求,DMA控制器同时撤销应答信号。如果发生更多的请求时,外设可以启动下次处理。

DMA传送由3个操作组成:

  1. 从外设数据寄存器或者从DMA_CMARx寄存器指定地址的存储器单元执行加载操作。
  2. 存数据到外设数据寄存器或者存数据到DMA_CMARx寄存器指定地址的存储器单元。
  3. 执行一次DMA_CNDTRx寄存器的递减操作。该寄存器包含未完成的操作数目。
    STM32之DMA学习_第1张图片
    仲裁器根据通道请求的优先级来启动外设/存储器的访问。优先级分为两个等级:软件(4个等级:最高、高、中等、低)、硬件(有较低编号的通道比拥有较高编号的通道有较高的优先权)。
    可以在DMA传输过半、传输完成和传输错误时产生中断。
    STM32中DMA的不同中断(传输完成、半传输、传输完成)通过“线或”方式连接至NVIC,需要在中断例程中进行判断
    进行DMA配置前,不要忘了在RCC设置中使能DMA时钟。STM32的DMA控制器挂在AHB总线上。
    DMA总共有7个通道,各个通道的DMA映射关系如下
    STM32之DMA学习_第2张图片

外设的事件连接至相应DMA通道,每个通道均可以通过软件触发实现存储器内部的DMA数据传输(M2M模式)
Tips:库2.0中函数RCC_AHBPeriphClockCmd的参数由“RCC_AHBPeriph_DMA”改成“RCC_AHBPeriph_DMA1”(如果是DMA1控制器的话)。
DMA的传输标志位(CHTIFx、CTCIFx、CGIFx)由硬件设置为“1”,但需要软件清零,在中断服务程序中清除。当CGIFx(全局中断标志位)清零后,CHTIFx 和 CTCIFx均清零。
过程:怎样启用DMA?首先,众所周知的是初始化,任何设备启用前都要对其进行初始化,要对模块初始化,还要先了解该模块相应的结构及其函数,以便正确的设置;由于DMA较为复杂,我就只谈谈DMA的基本结构和和常用函数,这些都是ST公司提供在库函数中的。
1、 下面代码是一个标准DMA设置,当然实际应用中可根据实际情况进行裁减:
DMA_DeInit(DMA_Channel1);
上面这句是给DMA配置通道,根据ST提供的资料,STM3210Fx中DMA包含7个通道(CH1~CH7),也就是说可以为外设或memory提供7座“桥梁”
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
上面语句中的DMA_InitStructure是一个DMA结构体,在库中有声明了,当然使用时就要先定义 了;DMA_PeripheralBaseAddr是该结构体中一个数据成员,给DMA一个起始地址,好比是一个buffer起始地址,数据流程是:外设 寄存器à DMA_PeripheralBaseAddàmemory中变量空间(或flash中数据空间等),ADC1_DR_Address是我定义的一个地址变量;

STM32外设DMA使用总结:

1、根据需要选择DAM模式:
(1)循环模式—DMA_Mode = DMA_Mode_Circular
(2)正常模式—DMA_Mode = DMA_Mode_Normal

2、对于DMA1的Chanel3,对应外设为USART3的RX
试想:如果串口接收中断和DAM中断同时打开,CPU如何相应?
(1)中断优先级不同:这好说,支持嵌套中断(NVIC)的Cortex-M3自然优先服务中断优先级高的
(2)中断优先级相同:处理原则,先来先处理;若同时到来,中断号低的优先处理
查询手册可知,DMA(IRQn number 13)会先于USART3(39)被CPU处理

3、设置DMA模式为循环模式,则:
(1)只开DMA中断,关闭外设中断,将只进一次DMA服务函数
(2)开启DMA中断,开启外设中断,才会循环进DMA服务函数
4、在开启多个DMA中断时,注意每个中断的优先级设置
5、在中断函数中,禁止DMA使能后要重新设置DMA传输数据量大小并开启DMA

void DMA1_Channel3_IRQHandler(void)
{
	if(DMA_GetITStatus(DMA1_FLAG_TC3))
	{
		DMA_ClearITPendingBit(DMA1_IT_GL3);
		/* 处理数据期间关闭DMA,防止数据篡改 */
		DMA_Cmd(DMA1_Channel3, DISABLE);	
		
		/* 处理数据 */
		
		/* 重新设置DMA传输数据量大小并开启DMA */
		DMA1_Channel3->CNDTR = DMA_CH3_RECV_BYTES;
		DMA1_Channel3->CCR |= DMA_CCR3_EN;
	}
}

6、DMA配置选项:

typedef struct
{
	/* 设置DMA传输的外设基地址,比如USART的DMA传输,基地址为(uint32_t)USART3-DR */
	uint32_t DMA_PeripheralBaseAddr; 
	/* 设置DMA内存基地址,存放DMA传输数据的内存地址 */
	uint32_t DMA_MemoryBaseAddr;
	/* 操作的外设是源地(从外设取数据)、目的地(发送数据到外设) */
	uint32_t DMA_DIR;                
	/* 一次DMA传输数据量的大小 */
	uint32_t DMA_BufferSize; 
	/* 外设地址是否自动递增,比如对于USART的DMA传输,外设地址是固定的 */
	uint32_t DMA_PeripheralInc; 
	/* 同上,只不过针对的是内存地址 */
	uint32_t DMA_MemoryInc;
	/* 设置外设数据宽度,8bits/16bits/31bits */
	uint32_t DMA_PeripheralDataSize; 
	/* 同上 */
	uint32_t DMA_MemoryDataSize; 
	/* 选择DAM模式,循环模式还是正常模式 */
	uint32_t DMA_Mode;
	/* DMA通道的优先级,DMA_Priority_VeryHigh,DMA_Priority_High,DMA_Priority_Medium,DMA_Priority_Low  */
	/* 如果开启多个DMA通道的话,记得设置合适的值 */
	uint32_t DMA_Priority;
	/* 设置DMA是否为Mem到Mem模式 */
	uint32_t DMA_M2M; 
}DMA_InitTypeDef;

你可能感兴趣的:(STM32之DMA学习)