DMA学习

文章详细介绍了DMA在STM32F4中的应用,包括DMA的功能、结构组成,如通道、数据流、仲裁器等。STM32F4拥有2个DMA控制器,共16个数据流,每个数据流有8个通道。配置DMA时涉及源地址、目标地址、传输模式、通道选择、仲裁优先级等参数。文中还展示了如何配置DMA驱动程序以及在主程序中触发DMA传输的例子。
摘要由CSDN通过智能技术生成

DMA功能概述:

DMA用于数据传输,绕过CPU进行数据大量传输,保证系统运行速度。

DMA框图:

在这里插入图片描述

DMA包含有: REQ_STR0_CH0为通道, REQ_STREAM0为数据流, 外设端口,储存器端口,仲裁器、通道选择器、数据流选择器。

MDA数据流表功能

在这里插入图片描述
在这里插入图片描述

STM32F4最多有2个DMA控制器,2个DMA控制器总共有16个数据流(一个DMA8个数据流)。每个数据流8个通道,每个通道只特定传输固定的外设端口。

DMA原理配置原理概述

源、目标传输地址和传输模式确定和配置
——》数据流和通道的确定和配置
----》仲裁器的优先级
-----》传输时指针递增确定,包含源和目标的指针。
------》循环模式,双缓冲区模式的确定和配置
----》数据宽度确定
–》单次传输或者突发增量传输
----》FIFO启用确定

值得注意的是在配置DMA之前要禁止掉数据流,并等待数据流被禁止成功。
每次去触发DMA之前,根据通道的特定功能,去功能文件库找使能DMA使能功能。
比如DMA2数据流7的通道四,是串口一的发送功能。(可以看DMA数据流的表)。DMA触发前应该在串口库函数找到函数
DMACmd(USART1,USART_DMAReq_Tx, ENABLE);
然后使能相应功能,再使能DMA,函数如:
MYDMA_Enable(DMA2_Stream7,SEND_BUF_SIZE);//此时可以执行其他任务

DMA驱动程序:

#include"dma.h"

// DMA_Streamx is sach as     DMA1_Stream0
/* DMA配置
   DMA_Streamx DMAx的数据流
	 chx   储存器地址
	 par   外储存器地址
	 mar   储存器地址
	 ndtr  数据量
*/
void MYDMA_Config(DMA_Stream_TypeDef *DMA_Streamx,u32 chx,u32 par,u32 mar,u16 ndtr)
{
		 DMA_InitTypeDef DMA_InitStruct;
	  
	   if((u32)DMA_Streamx>(u32)DMA2)  //按地址判断DMA几,后使能DMA几时钟
		 {
				RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); 
		 }
		 else
		 {
				RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
		 }
		 DMA_DeInit( DMA_Streamx);     //数据流禁止
		 while(DMA_GetCmdStatus(DMA_Streamx)==1);//等待数据流被禁止成功
		 DMA_InitStruct.DMA_Channel=chx;//通道配置
	   DMA_InitStruct.DMA_PeripheralBaseAddr=par;//外设地址
		 DMA_InitStruct.DMA_Memory0BaseAddr=mar;//存储器地址
     DMA_InitStruct.DMA_DIR=DMA_DIR_MemoryToPeripheral; //传输方向
	   DMA_InitStruct.DMA_BufferSize=ndtr;  //数据量,依赖于配置的外设存储器的宽度
	   DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址不增加
	   DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;//存储器地址增加
	   DMA_InitStruct.DMA_PeripheralDataSize= DMA_PeripheralDataSize_Byte;//外设数据宽度,字节
	   DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;//内存数据宽度。字节
	   DMA_InitStruct.DMA_Mode=DMA_Mode_Normal; //正常模式
	   DMA_InitStruct.DMA_Priority=DMA_Priority_Medium;//优先级为中
	   DMA_InitStruct.DMA_FIFOMode=DMA_FIFOMode_Disable;//不用FIFO
	   DMA_InitStruct.DMA_FIFOThreshold=DMA_FIFOThreshold_Full; //FIFo配置阈值为满,FIFO被禁止,满不满都不起作用
	   DMA_InitStruct.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;//突增模式
	   DMA_InitStruct.DMA_MemoryBurst=DMA_MemoryBurst_Single;//突增模式
	   

			
		 DMA_Init(DMA_Streamx,&DMA_InitStruct);


}

void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr)//DMA使能
{

   DMA_Cmd( DMA_Streamx,DISABLE); //禁止数据流
   while(DMA_GetCmdStatus(DMA_Streamx)==1); //等待禁止成功
	 DMA_SetCurrDataCounter(DMA_Streamx, ndtr);//设置数据量
   DMA_Cmd( DMA_Streamx,ENABLE); //使能数据流

}

主程序:触发DMA


#include "main.h"

#define SEND_BUF_SIZE  8200
unsigned char SendBuff[SEND_BUF_SIZE];
unsigned char buff1[]={"哥们你看到了吗,这是DMA传输1234 \r\n "};

int main(void)
{ 
 
  u8 key;           //保存键值
	u32 i;
	delay_init(168);  //初始化延时函数
	uart_init(115200);
	LED_Init();				//初始化LED端口 
	BEEP_Init();      //初始化蜂鸣器端口
	KEY_Init();       //初始化与按键连接的硬件接口
	MYDMA_Config(DMA2_Stream7,DMA_Channel_4,(u32)&USART1->DR,(u32)SendBuff,SEND_BUF_SIZE);//初始化DMA
  for( i=0;i<8200;i=i+sizeof(buff1)-1 ) //填充数据到数组,填满
	{
	  memcpy( SendBuff+i,buff1 ,sizeof(buff1) );
	
	}
	
	while(1)
	{
		key=KEY_Scan(0);		//得到键值
	   	if(key)
		{						   
			switch(key)
			{				 
				case WKUP_PRES:	//控制蜂鸣器
					          USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
										MYDMA_Enable(DMA2_Stream7,SEND_BUF_SIZE);//此时可以执行其他任务
                     										
										while(1)//以下为测试用到的,等待DMA传输完成,正常这里用不到,仅仅测试用
										{
										  if(DMA_GetFlagStatus(DMA2_Stream7, DMA_FLAG_TCIF7)==SET)
											{
											    
													DMA_ClearFlag(DMA2_Stream7, DMA_FLAG_TCIF7);
											    break;
											}
										
										}					
				
				
				   
					break;
				case KEY0_PRES:	//控制LED0翻转
					LED0=!LED0;
				printf("%s ",SendBuff);
					break;
				case KEY1_PRES:	//控制LED1翻转	 
					LED1=!LED1;
					break;
				case KEY2_PRES:	//同时控制LED0,LED1翻转 
					LED0=!LED0;
					LED1=!LED1;
					break;
			}
		}else delay_ms(10); 
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值