DMA(STM32系列)

DMA概述

DMA简介

  直接存储器访问 (DMA) 用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输。可以在无需任何 CPU 操作的情况下通过 DMA 快速移动数据。这样节省的 CPU 资源可供其它操作使用。
  DMA 控制器基于复杂的总线矩阵架构,将功能强大的==双 AHB 主总线架构与独立的 FIFO ==结合在一起,优化了系统带宽。
  两个 DMA 控制器总共有 16 个数据流(每个控制器 8 个),每一个 DMA 控制器都用于管理一个或多个外设的存储器访问请求。每个数据流总共可以有多达 8 个通道(或称请求)。每个通道都有一个仲裁器,用于处理 DMA 请求间的优先级。

为什么需要DMA

  在我们使用协议通信时,时常会采用查询相关状态寄存器对应标志位是否变化,从而使用循环等待标志位,然而在等待标志位的时候经常会使MCU卡死在循环当中,占死CPU,而除了查询方式之外,我们会想到使用中断防止卡死,但当我们数据传输较多时,导致CPU在主函数和中断服务函数中反复切换或在中断当中停留过长时间,导致效率大大降低,那么这里DMA的作用就来了,DMA使用时可以直接访问存储器进行相应的数据传输,无需CPU的情况下可以进行数据的搬运。
有DMA参与的uart的收发过程
在这里插入图片描述

STM32中DMA控制器概述

DMA控制数据传输的方向只有三种:
1、外设到存储器
2、存储器到外色
3、存储器到存储器
外设指的是片上外设,存储器为FLASH、SRAM、FSMC等存储设备,也可以是变量、数组这种存储空间。
示例:串口发送数据到PC端 数据方向存储器到外设
   串口接收PC端的数据 数据方向外设到存储器

STM32的DMA特征

● 双 AHB 主总线架构,一个用于存储器访问,另一个用于外设访问
● 仅支持 32 位访问的 AHB 从编程接口
● 每个 DMA 控制器有 8 个数据流,每个数据流有多达 8 个通道(或称请求)
● 每个数据流有单独的四字深 32 位先进先出存储器缓冲区 (FIFO),可用于 FIFO 模式或直接模式:
— FIFO 模式:可通过软件将阈值级别选取为 FIFO 大小的 1/4、1/2 或 3/4
— 直接模式
每个 DMA 请求会立即启动对存储器的传输。当在直接模式(禁止 FIFO)下将 DMA 请求配置为以存储器到外设模式传输数据时,DMA 仅会将一个数据从存储器预加载到内部 FIFO,从而确保一旦外设触发 DMA 请求时则立即传输数据。
● 通过硬件可以将每个数据流配置为:
— 支持外设到存储器、存储器到外设和存储器到存储器传输的常规通道
— 也支持在存储器方双缓冲的双缓冲区通道
● 8 个数据流中的每一个都连接到专用硬件 DMA 通道(请求)
● DMA 数据流请求之间的优先级可用软件编程(4 个级别:非常高、高、中、低),在软件优先级相同的情况下可以通过硬件决定优先级(例如,请求 0 的优先级高于请求 1)
● 每个数据流也支持通过软件触发存储器到存储器的传输(仅限 DMA2 控制器)
● 可供每个数据流选择的通道请求多达 8 个。此选择可由软件配置,允许几个外设启动 DMA请求
● 要传输的数据项的数目可以由 DMA 控制器或外设管理:
— DMA 流控制器:要传输的数据项的数目是 1 到 65535,可用软件编程
— 外设流控制器:要传输的数据项的数目未知并由源或目标外设控制,这些外设通过硬件发出传输结束的信号
● 独立的源和目标传输宽度(字节、半字、字):源和目标的数据宽度不相等时,DMA 自动封装/解封必要的传输数据来优化带宽。这个特性仅在 FIFO 模式下可用
● 对源和目标的增量或非增量寻址
● 支持 4 个、8 个和 16 个节拍的增量突发传输。突发增量的大小可由软件配置,通常等于外设 FIFO 大小的一半
● 每个数据流都支持循环缓冲区管理
● 5 个事件标志(DMA 半传输、DMA 传输完成、DMA 传输错误、DMA FIFO 错误、直接模式错误),进行逻辑或运算,从而产生每个数据流的单个中断请求

STM32DMA框架

在这里插入图片描述

分析上图可知:
DMA控制器1存储器接口只连接了FLASH和SRAM存储器,外设接口只连接了APB1外设,DMA控制器1只能对存储器和外设之间相互传输,无法实现存储器与存储器之间传输。
DMA控制器2存储器接口连接了存储器和AHB,AHB外设,外设接口连接了存储器以及外设,可以实现存储器和存储器之间的传输和存储器和外设之间的传输。

在这里插入图片描述
每个DMA有八个数据流的、每个数据流有八个通道
八个数据流是可以同时搬运数据的(每个数据流有单独的FIFO结构)
每个数据流中的八个通道是不能同时搬运数据的(需要使用仲裁器分配优先级)

通道选择

不同的外设/存储器需要连接不同的通道进行数据搬运、通道的映射图查表
DMA1:
在这里插入图片描述
DMA2:
在这里插入图片描述

FIFO模式与直接模式

FIFO模式
FIFO 用于在源数据传输到目标之前临时存储这些数据。
每个数据流都有一个独立的 4 字 FIFO,阈值级别可由软件配置为 1/4、1/2、3/4 或满,阈值决定的传输数据的大小。
在这里插入图片描述
DMA 控制器可以产生单次传输或 4 个、8 个和 16 个节拍的增量突发传输。
当 AHB 外设端口被配置为突发传输时,根据 DMA_SxCR 寄存器 PBURST[1:0] 和PSIZE[1:0] 位的值,每个 DMA 请求相应地生成 4 个、8 个或 16 个节拍的字节、半字或字的传输。
提高数据的速度和保证数据的完整性,一次突发传输的字节数等于 节拍数*MSIZE(CR寄存器设置)

如果需要使用FIFO模式、必须禁止直接模式的
数据宽度问题:
外设的数据宽度(数据存储器的大小)我们决定不了的(USART ADC)
存储器的数据宽度可以自己定义的(数组 变量…)
一般外设与存储器的数据宽度是一致的
直接模式
默认情况下, FIFO 以直接模式操作(将 DMA_SxFCR 中的 DMDIS 位置 1),不使用 FIFO
阈值级别。如果在每次 DMA 请求之后,系统需要至/自存储器的立即和单独传输,这种模式
非常有用。
循环模式
循环模式可用于处理循环缓冲区和连续数据流(例如 ADC 扫描模式)

传输方向

在这里插入图片描述

地址递增

源与目标的地址
示例:
1)搬运USART_TX引脚数据(8位数据寄存器)
数据方向:存储器到外设
源:存储器
目标:外设(USART_DR)
源的数据宽度:字节
目标的数据宽度:字节
源地址是否递增:是
目标地址是否递增:否

2)搬运ADC数据(16位数据寄存器)
数据方向:外设到存储器
源:外设(ADC_DR)
目标:存储器
源的数据宽度:半字
目标的数据宽度:半字
源地址是否递增:否
目标地址是否递增:是

USART发送实验
  1. 打开时钟(DMA2)
  2. 使能USART的DMA发送使能
  3. EN=0(禁止使能)
  4. 数据项数目
  5. 外设地址
  6. 存储器地址
  7. 直接模式
  8. DMA是流控制器
  9. 数据方向
  10. 外设地址是否递增
  11. 存储器地址是否递增
  12. 外设数据大小
  13. 存储器数据大小
  14. 优先级
  15. 通道
  16. 使能(EN=1)
/*
函 数 名:DMA_USART_Config
函数功能:USART使用DMA数据搬运发送数据
返 回 值:
形    参:u32 addr--存储器基地址
				 u32 num -- 存储器数据项数目,数组大小
备    注:
*/
void DMA_USART_Config(u32 addr,u32 num)
{

//	RCC->AHB1ENR 		  |= (1<<22);					//打开DMA2时钟
//	USART1->CR3  		  |= (1<<7);					//打开串口DMA发送器
//	
//	DMA2_Stream7->CR 	  &= ~(1<<0);					//数据流关闭
//	DMA2_Stream7->NDTR 	   = num; 						//数据项数目
//	DMA2_Stream7->PAR      = (uint32_t)(&USART1->DR);
//	DMA2_Stream7->M0AR     = addr;
//	DMA2_Stream7->FCR     &= ~(1<<2);					//使能直接模式
//	
//	DMA2_Stream7->CR      &= ~(1<<5);					//DMA是流控制器
//	DMA2_Stream7->CR      |= (1<<6);					//存储器到外设
//	DMA2_Stream7->CR      &= ~(1<<9);					//外设地址固定
//	DMA2_Stream7->CR      |= (1<<10);					//存储器地址递增
//	DMA2_Stream7->CR      &= ~(3<<11);					//外设数据大小 1字节
//	DMA2_Stream7->CR      &= ~(3<<13);					//存储器数据大小 1字节
//	DMA2_Stream7->CR      |= (3<<16);					//优先级非常高
//	DMA2_Stream7->CR      |= (4<<25);					//通道4
//	
//	
//	DMA2_Stream7->CR 	  |=  (1<<0);					//使能数据流
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);						//打开DMA2时钟
	USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);							//打开串口DMA发送器
	
	DMA_Cmd(DMA2_Stream7,DISABLE);											//数据流关闭
	DMA_InitTypeDef dma_InitTypeDef={0};									//注意初始化清零结构体
	dma_InitTypeDef.DMA_FIFOMode								=	DMA_FIFOMode_Disable;				//直接模式
	dma_InitTypeDef.DMA_BufferSize 								= 	num;								//数据项数目
	dma_InitTypeDef.DMA_Channel  								=   DMA_Channel_4;						//通道4
	dma_InitTypeDef.DMA_DIR  									=   DMA_DIR_MemoryToPeripheral;			//存储器到外设
	dma_InitTypeDef.DMA_Memory0BaseAddr           				= addr;									//存储器地址
	dma_InitTypeDef.DMA_MemoryDataSize            				= DMA_MemoryDataSize_Byte;				//存储器数据大小 1字节
	dma_InitTypeDef.DMA_MemoryInc                 				= DMA_MemoryInc_Enable;					//存储器地址递增
	dma_InitTypeDef.DMA_PeripheralBaseAddr        				= (uint32_t)(&USART1->DR);				//外设地址
	dma_InitTypeDef.DMA_PeripheralDataSize        				= DMA_PeripheralDataSize_Byte;			//外设数据大小 1字节
	dma_InitTypeDef.DMA_PeripheralInc             				= DMA_PeripheralInc_Disable;			//外设地址固定
	dma_InitTypeDef.DMA_Priority 								= DMA_Priority_High;					//高优先级
	DMA_Init(DMA2_Stream7,&dma_InitTypeDef);
	
	
	DMA_Cmd(DMA2_Stream7,ENABLE);
	

}
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值