STM32教程:简单易懂的DMA使用指南

一、介绍

        MDA是英文Direct Memory Access的缩写,中文意思是直接存储器存取。它是单片机的一个外设,作用主要是用来数据传输。数据传输支持从外设到存储器或者存储器到存储器,这里的存储器可以是 SRAM 或者是 FLASH。 DMA 控制器包含了 DMA1 和 DMA2,其中 DMA1 有 7 个通道,DMA2 有 5 个通道,这里的通道 可以理解为传输数据的一种管道。

       STM32F103

DMA
有以下一些特性:

●每个通道都直接连接专用的硬件
DMA
请求,每个通道都同样支持软件触发。这些功能

通过软件来配置。

●在七个请求间的优先权可以通过软件编程设置
(
共有四级:很高、高、中等和低
)
,假如

在相等优先权时由硬件决定
(
请求
0
优先于请求
1
,依此类推
)

●独立的源和目标数据区的传输宽度
(
字节、半字、全字
)
,模拟打包和拆包的过程。源和

目标地址必须按数据传输宽度对齐。

●支持循环的缓冲器管理。

●每个通道都有
3
个事件标志
(DMA
半传输,
DMA
传输完成和
DMA
传输出错
)
,这
3

事件标志逻辑或成为一个单独的中断请求。

●存储器和存储器间的传输。

●外设和存储器,存储器和外设的传输。

●闪存、
SRAM
、外设的
SRAM

APB1

APB2

AHB
外设均可作为访问的源和目标。

●可编程的数据传输数目:最大为
65536

二、功能框图

三、功能描述、

       DMA
控制器和
Cortex™-M3
核心共享系统数据总线,执行直接存储器数据传输。当
CPU

DMA 同时访问相同的目标(RAM
或外设
)
时,
DMA
请求会暂停
CPU
访问系统总线达若干个周期,总线

仲裁器执行循环调度,以保证
CPU
至少可以得到一半的系统总线
(
存储器或外设
)
带宽。

四、DMA请求

       如果外设要想通过
DMA
来传输数据,必须先给
DMA
控制器发送
DMA
请求,
DMA
收到请求信 号之后,控制器会给外设一个应答信号,当外设应答后且 DMA
控制器收到应答信号之后,就会

启动
DMA
的传输,直到传输完毕。

五、通道配置的过程

        

1.

DMA_CPARx
寄存器中设置外设寄存器的地址。当外设数据传输请求时,这个地址将

是数据传输的源或目标。

2.

DMA_CMARx
寄存器中设置数据存储器的地址。发生外设数据传输请求时,传输的数

据将从这个地址读出或写入这个地址。

3.

DMA_CNDTRx
寄存器中设置要传输的数据量。在每个数据传输后,这个数值递减。

4.

DMA_CCRx
寄存器的
PL[1:0]
位中设置通道的优先级。

5.

DMA_CCRx
寄存器中设置数据传输的方向、循环模式、外设和存储器的增量模式、外

设和存储器的数据宽度、传输一半产生中断或传输完成产生中断。

6.
设置
DMA_CCRx
寄存器的
ENABLE
位,启动该通道。

六、实验

        M–>M(存储器传输到存储器)

        函数的解释:(实验并没有全部的函数都用到)

//初始化DMA默认重置值

void DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx);

//DMA的通道的初始化
void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);

//用默认值填充每个DMA_InitStruct成员。


void DMA_StructInit(DMA_InitTypeDef* DMA_InitStruct);

//DMA使能
void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);

//启用或禁用指定的DMAy通道的中断。


void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState);

//设置当前DMAy通道传输中的数据单元数。


void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber); 

//返回当前中剩余数据单元的数量


uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);

//控制DMA的标志位

FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG);
void DMA_ClearFlag(uint32_t DMAy_FLAG);
ITStatus DMA_GetITStatus(uint32_t DMAy_IT);
void DMA_ClearITPendingBit(uint32_t DMAy_IT);

        DMA初始化函数的配置:

 

void DMA_Config(void)
{
	  DMA_InitTypeDef DMA_InitStructure;
	
		// 开启DMA时钟
		RCC_AHBPeriphClockCmd(DMA_CLOCK, ENABLE);
		// 源数据地址
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)aSRC_Const_Buffer;
		// 目标地址
		DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)aDST_Buffer;
		// 方向:外设到存储器(这里的外设是内部的FLASH)	
		DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
		// 传输大小	
		DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE;
		// 外设(内部的FLASH)地址递增	    
		DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
		// 内存地址递增
		DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
		// 外设数据单位	
		DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
		// 内存数据单位
		DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;	 
		// DMA模式,一次或者循环模式
		DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
		//DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  
		// 优先级:高	
		DMA_InitStructure.DMA_Priority = DMA_Priority_High;
		// 使能内存到内存的传输
		DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
		// 配置DMA通道		   
		DMA_Init(DMA_CHANNEL, &DMA_InitStructure);
        //清除DMA数据流传输完成标志位
        DMA_ClearFlag(DMA_FLAG_TC);
		// 使能DMA
		DMA_Cmd(DMA_CHANNEL,ENABLE);
}

        数据源设置

const uint32_t aSRC_Const_Buffer[BUFFER_SIZE]= {
                                    0x01020304,0x05060708,0x090A0B0C,0x0D0E0F10,
                                    0x11121314,0x15161718,0x191A1B1C,0x1D1E1F20,
                                    0x21222324,0x25262728,0x292A2B2C,0x2D2E2F30,
                                    0x31323334,0x35363738,0x393A3B3C,0x3D3E3F40,
                                    0x41424344,0x45464748,0x494A4B4C,0x4D4E4F50,
                                    0x51525354,0x55565758,0x595A5B5C,0x5D5E5F60,
                                    0x61626364,0x65666768,0x696A6B6C,0x6D6E6F70,
                                    0x71727374,0x75767778,0x797A7B7C,0x7D7E7F80};

        接收设置

int32_t aDST_Buffer[BUFFER_SIZE];

#define SOFT_DELAY Delay(0x0FFFFF);
void Delay(__IO u32 nCount); 
uint8_t Buffercmp(const uint32_t* pBuffer, uint32_t* pBuffer1, uint16_t BufferLength);
void DMA_Config(void);																	
						

        通过LED的颜色来判断数据是否正确发送,红色为错误,蓝色为正确

int main(void)
{
  /* 定义存放比较结果变量 */
  uint8_t TransferStatus;
  
	/* LED 端口初始化 */
	LED_GPIO_Config();
    
  /* 设置RGB彩色灯为紫色 */
  LED_PURPLE;  
  
  /* 简单延时函数 */
  Delay(0xFFFFFF);  
  
  /* DMA传输配置 */
  DMA_Config(); 
  
  /* 等待DMA传输完成 */
  while(DMA_GetFlagStatus(DMA_FLAG_TC)==RESET)
  {
    
  }   
  
  /* 比较源数据与传输后数据 */
  TransferStatus=Buffercmp(aSRC_Const_Buffer, aDST_Buffer, BUFFER_SIZE);
  
  /* 判断源数据与传输后数据比较结果*/
  if(TransferStatus==0)  
  {
    /* 源数据与传输后数据不相等时RGB彩色灯显示红色 */
    LED_RED;
  }
  else
  { 
    /* 源数据与传输后数据相等时RGB彩色灯显示蓝色 */
    LED_BLUE;
  }

	while (1)
	{		
	}
}

        

作者:番茄炒西红柿996

物联沃分享整理
物联沃-IOTWORD物联网 » STM32教程:简单易懂的DMA使用指南

发表评论