STM32—DMA直接存储器

DMA存储器的介绍

DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源。

一、DMA总体架构图&配置图

 

 二、DMA模块的相关函数配置(MyDMA_Init)

2.1、DMA常见的初始化函数

2.1.1、DMA_DeInit()

//将DMAy Channelx寄存器初始化为其默认重置值。

DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx)

2.1.2、DMA_StructInit()

//用默认值填充每个DMA_InitStruct成员。(即结构体初始化)

DMA_StructInit(DMA_InitTypeDef* DMA_InitStruct)

2.1.3、DMA_Init()

//根据DMA_InitStruct中指定的参数初始化DMAy通道。

DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct)

2.1.4、DMA_Cmd()

//启用或禁用指定的DMAy通道。(即使能)

DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState)

2.1.5、DMA_ITConfig()

//中断输出使能

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

2.1.6、DMA_GetFlagStatus()

//获取标志为状态

DMA_GetFlagStatus(uint32_t DMAy_FLAG)

2.1.7、DMA_ClearFlag()

//清除标志位

DMA_ClearFlag(uint32_t DMAy_FLAG)

2.1.8、DMA_GetITStatus()

//获取中断状态

DMA_GetITStatus(uint32_t DMAy_IT)

2.1.9、DMA_ClearITPendingBit()

//清除中断挂起位

DMA_ClearITPendingBit(uint32_t DMAy_IT)

2.2、DMA寄存器函数

2.2.1、DMA_SetCurrDataCounter()

//设置当前DMAy通道传输中的数据单元数(即给传输计数器写数据)

DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber)

2.2.2、DMA_GetFlagStatus()

//获取当前数据寄存器,返回传输计数器的值

DMA_GetFlagStatus(uint32_t DMAy_FLAG)

三、配置MyDMA_Init()

根据上图配置,其中使用DMA_Init()便可以配置以上相关参数。

3.1、开启时钟

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE)

3.2、DMA_Init参数配置

  1. DMA_PeripheralBaseAddr 
    指定DMAy通道的外设基址,即外设的起始地址,需要填写一个32位的地址,而对于SRAM的数组,他的地址是编译器分配的,并非固定地址,因此我们可以通过数组名来获取地址。我们可以吧这个地址提取成一个初始化函数的参数,以便我们可以更改外设起始地址。
  2. DMA_PeripheralDataSize
    外设数据宽度。可以是下图中指定的值

    其中(148)Byte,字节,对应着shi uint8_t,(149)HalfWord,半字节,对应着uint16_t,(150)Word,字,对应着uint32_t 
  3. DMA_PeripheralInc
    外设地址是否自增。有以下两个参数选项,自增or不自增
  4. DMA_MemoryBaseAddr&DMA_MemoryDataSize&DMA_MemoryInc
    这三个参数分别对应着寄存器地址&寄存器数据宽度&寄存器是否自增,与1~3点类似。
  5. DMA_BufferSize
    传输计数器。(该例程中把这个参数提取到初始化函数——uint32_t,以便更好修改)
  6. DMA_DIR
    指定外设是源端还是目标端。 
    参数可以从下图选择。DST—目的地,SRC—源头(外设站点到存储器 站点的传输方向)。
  7. DMA_M2M
    是否应用于存储器到存储器的转运,即软件触发模式。
    参数从下图选择。ENABLE—软件触发,DISABLE—硬件触发
  8. DMA_Mode
    传输模式,即是否使用自动重装。(注意自动重装和软件触发不可同时使用
    参数从下图选择。Circular—自动重装,Normal—正常模式(非自动重装)
  9. DMA_Priority
    指定通道的软件优先级。

3.3、DMA使能

DMA_Cmd(DMA1_Channel1,DISABLE);

 以下是DMA_Init函数完整代码

void MyDMA_Init(uint32_t AddrA,uint32_t AddrB,uint16_t Size)
{
	MyDMA_Size=Size;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	
	DMA_InitTypeDef DMA_InitStructure;
	DMA_InitStructure.DMA_PeripheralBaseAddr=AddrA;		//外设的起始地址
	DMA_InitStructure.DMA_PeripheralDataSize=	DMA_PeripheralDataSize_Byte;	//外设的数据宽度
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Enable;		//外设是否自增
	DMA_InitStructure.DMA_MemoryBaseAddr=	AddrB;	//存储器的起始地址
	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;		//存储器的数据宽度
	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;		//存储器是否自增
	DMA_InitStructure.DMA_BufferSize=Size;		//传输计数器
	DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;			//传输方向
	DMA_InitStructure.DMA_M2M=	DMA_M2M_Enable;	//选择硬件触发or软件触发
	DMA_InitStructure.DMA_Mode=	DMA_Mode_Normal;		//传输模式,即是否使用自动重装
	DMA_InitStructure.DMA_Priority=	DMA_Priority_Medium;		//优先级
	DMA_Init(DMA1_Channel1,&DMA_InitStructure);
	
	DMA_Cmd(DMA1_Channel1,DISABLE);

}

四、数据多次转运

 (3.3)的完整代码仅能完成一次的数据转运。若想完成多次数据的转运,需要给计数器重新赋值,而给计数器重新赋值,需要令DMA_Cmd()处于使能状态,完成计数器赋值后再令其使能。为便于实现以上功能。我么使用MyDMA_Transfer()函数将以上功能封装起来

void MyDMA_Transfer(void)
{
	DMA_Cmd(DMA1_Channel1,DISABLE);
	DMA_SetCurrDataCounter(DMA1_Channel1,MyDMA_Size);
	DMA_Cmd(DMA1_Channel1,ENABLE);
	while(DMA_GetFlagStatus(DMA1_FLAG_GL1)==RESET);
	DMA_ClearFlag(DMA1_FLAG_GL1);
	
}
  1.  首先令DMA_Cmd()失能。
  2. DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber)
    设置当前DMAy通道传输中的数据单元数。即赋值计数器。
    为保证前后转运时计数器的值一致,我们需要获取DMA_Init函数中的参数Size,但是又因为Size仅在DMA_Init()中起作用,因此我们定义一个全局变量uint16_t MyDMA_Size,吸收Size的值,并传入DMA_SetCurrDataCounter()。
  3. DMA_Cmd(DMA1_Channel1,ENABLE);
    赋值完成后重新令Cmd使能。
  4. DMA_GetFlagStatus(uint32_t DMAy_FLAG)
    检查是否设置了指定的DMAy通道标志。GL1—全局标志位,TC1—转运完成标志位,HT1—转运过半标志位,TE1—转运错误标志位

    while(DMA_GetFlagStatus(DMA1_FLAG_GL1)==RESET)//等待转运的完成
  5. DMA_ClearFlag(DMA1_FLAG_GL1);
    清除标志位,转运完成标志位需要手动清除,
     

五、现象代码&现象

#include "stm32f10x.h"                  // Device header
#include "Delay.h"                  // Device header
#include "OLED.h" 
#include "MyDMA.h" 

uint8_t DaTaA[]={0x01,0x02,0x03,0x04};
uint8_t DaTaB[]={0,0,0,0};

int main(void)
{
	
	OLED_Init();												//OLED初始化
	OLED_Clear();	
	MyDMA_Init((uint32_t)DaTaA,(uint32_t)DaTaB,4);
	OLED_ShowString(1,1,"DaTaA:");
	OLED_ShowString(3,1,"DaTaB:");
	OLED_ShowHexNum(1,8,(uint32_t)DaTaA,8);
	OLED_ShowHexNum(3,8,(uint32_t)DaTaB,8);
	
	OLED_ShowHexNum(2,1,DaTaA[0],2);
	OLED_ShowHexNum(2,4,DaTaA[1],2);
	OLED_ShowHexNum(2,7,DaTaA[2],2);
	OLED_ShowHexNum(2,10,DaTaA[3],2);
	
	OLED_ShowHexNum(4,1,DaTaB[0],2);
	OLED_ShowHexNum(4,4,DaTaB[1],2);
	OLED_ShowHexNum(4,7,DaTaB[2],2);
	OLED_ShowHexNum(4,10,DaTaB[3],2);

	while(1)
	{	
		DaTaA[0]++;
		DaTaA[1]++;
		DaTaA[2]++;
		DaTaA[3]++;
		
	OLED_ShowHexNum(2,1,DaTaA[0],2);
	OLED_ShowHexNum(2,4,DaTaA[1],2);
	OLED_ShowHexNum(2,7,DaTaA[2],2);
	OLED_ShowHexNum(2,10,DaTaA[3],2);
	
	OLED_ShowHexNum(4,1,DaTaB[0],2);
	OLED_ShowHexNum(4,4,DaTaB[1],2);
	OLED_ShowHexNum(4,7,DaTaB[2],2);
	OLED_ShowHexNum(4,10,DaTaB[3],2);
	
	Delay_ms(1000);
		
	MyDMA_Transfer();
	
	OLED_ShowHexNum(2,1,DaTaA[0],2);
	OLED_ShowHexNum(2,4,DaTaA[1],2);
	OLED_ShowHexNum(2,7,DaTaA[2],2);
	OLED_ShowHexNum(2,10,DaTaA[3],2);
	
	OLED_ShowHexNum(4,1,DaTaB[0],2);
	OLED_ShowHexNum(4,4,DaTaB[1],2);
	OLED_ShowHexNum(4,7,DaTaB[2],2);
	OLED_ShowHexNum(4,10,DaTaB[3],2);
		
		Delay_ms(1000);
	}
}

 

 注意:该现象代码中的MyDMA_Init()中的MDA_Cmd被设置成了DMA_Cmd(DMA1_Channel1,DISABLE)。以令其无法立即转运。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橘洲青年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值