DMA介绍

之前有讲到,我们在使用规则组的时候规则组有16个通道,但是相应的数据寄存器只有1个,那么多的数据就会被覆盖。简单来说我们只有一个水杯,我们连续往里面倾倒16杯水,一开始的水就会不断被后面的水移出去,最终只剩第16杯水也就是数据不断被覆盖,只剩最后一个数据。而DMA   相对于很多杯子, 就可以帮助我们把第一杯水移出去给第二杯水留空间,循环往复,到最后一杯,而DMA已经转运完前面的15杯水完美的保留了数据。

那么现在就会对DMA有了一个初步理解。下面我们来具体介绍一下DMA

DMA(Direct Memory Access)直接存储器存取;

DMA可以提供外设(数据寄存器)和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源,留下了更多的时间给CPU去做其他的事情,而DMA负责转运数据。

STM32F系列最多有12个独立可配置的通道: DMA1(7个通道), DMA2(5个通道) 每个通道都支持软件触发和特定的硬件触发

软件触发:负责寄存器到寄存器的数据转运

硬件触发:负责外设和存储器的数据转运,触发一次转换一次。

STM32F103C8T6 DMA资源:DMA1(7个通道)

首先我们了解了,DMA主要负责存储器内容的转运,那么就要了解一下,我们有哪些存储器。

简单介绍一下计算机的组成,

计算机的CPU由运算器和控制器构成,当然具体介绍有,累加器A(数据加操作),寄存器B(乘除操作),布尔运算器(特殊操作),状态寄存器,程序计数器,指令寄存器,译码器等等。

而存储器,需要了解的主要是两部分,一个存储器里面放的是什么?存储器的地址是什么?

简单介绍一下存储器,根据用途可以分为程序存储器(ROM)和数据寄存器(RAM)两种,单片机系统和一般需要容量较大的程序存储器和容量较小的数据存储器(价格比较贵)。

像STC89C52单片机,ROM有8KB,而RAM只有256B。

而STM32F103C8T6是一款基于ARM Cortex-M3内核的微控制器,其ROM和RAM大小如下:

ROM大小为64KB,即64 * 1024字节。RAM大小为20KB,即20 * 1024字节。

ROM(read only memory)发展介绍:

1.(固化)ROM:这种ROM一般用于产品程序固定的生产,一旦下载程序无法修改,一般用于批量生产。

2.EPROM:EPROM分为有窗口和无窗口的两种,窗口用于擦除程序,但是需要紫外线照射3小时以上才能擦除。

3.E2PROM:可以电子擦除(上电擦除),可以使用编程工具擦除,但是是一个字节一个字节擦除。

4.Flash Memory:可以擦除非常快,是代码段的擦除,和E2PROM相比速度快太多。

RAM(Random Access Memory)介绍:

静态随机存储器SRAM和动态随机存储器(DRAM);具体涉及到存储器组成(晶体管,锁存器)不做过多介绍。

介绍这么多主要让心目中又一个1概念能分清楚,ROM和RAM是什么。

好了介绍一下DMA:

这是我在数据手册中找到的存储器地址分布,右边包含一些具体的特殊寄存器地址,

寄存器其实属于一种特殊存储器,CPU可以对其读写,而寄存器连接着线路,可以根据内部所存储的数据,控制一些引脚电平也可以当作数据寄存器。所以说寄存器是软件到硬件的桥梁。

具体结构参考手册:

其实你看地址从0X0000 0000 到0XFFFF FFFF能代表的内存非常大,在32位系统下为4GB

但是实际上32内存只有RAM:64KB,ROM:128KB.实际利用率很小,大部分都被Reserved保留了

我大概整理了一些常用的在下面表格:
 

类型起始地址存储器用途
ROM:0X8000 0000系统存储器存储程序,程序一般也从这里执行
0x1FFF F000系统存储器存储BootLoader,用于串口下载
0X1FFF F800选项字节存储一些独立系统的一些配置参数
RAM:0X2000 0000运行内存RAM存储代码运行的一些零时变量
0X4000 0000 外设寄存器存储各个外设的配置参数
0XE000 0000内核外设寄存器存储内核各个外设的配置参数

以上是大体的分类,具体参考数据手册。

我们了解了地址,那么就要了解一下具体结构框图到底是什么样子的?

手册中DMA框图如下:

看着很复杂,其实除了内核Cortex-M3也就是CPU,其他剩下的都可以说是存储器,至于其他一些输入输出设备也不在这里。

直接可以划分成两部分:

而存储器里面又有许多寄存器,

接下来就要思考,CPU如何管理存储器这个问题了。在32这种资源很多的设备当中,对于寄存器的管理就很厉害!

规定一个总线矩阵,在矩阵左边是主动单元(DCode主要负责Flash,和系统总线和DMA给数据转运主动权):拥有对存储器的访问权;在总线矩阵的右边是被动单元:只能被左边的主动单元访问读写。

介绍了大概的部分下面介绍DMA的部分详细:

我们知道DMA总线只有一条,但是又有2个DMA,包括:DMA1,DMA2(DMA1有七个通道,DMA2有5个通道),所以只能分时复用DMA总线,那么对于两个DMA之间数据转运就存在一个先后的关系,这时候仲裁器就可以根据通道优先级去分配先后。

就像CPU和DMA之间也存在一个管理的仲裁器,CPU需要访问存储器,而DMA也需要访问存储器的时候也有仲裁器管理,就当它是“和事佬”。

了解了,那我们就要思考对于DMA参数配置是在哪里配置,就在AHB从设备当中管理配置,不难看出DMA其实挂在在AHB总线上。

而内部的通道可以进行独立的数据转运。

至于DMA请求:硬件触发DMA,硬件设备向DMA发出请求,申请DMA数据转运,所以在硬件触发的时候需要加一个DMA请求的一个函数*。

需要注意的是上面的Flash属于ROM只能读取不能写入,记得转运地址不要写错乱。

了解了这些相信对于DMA的配置就有了一定了解那么来看一下实际配置的流程图:

具体步骤就是:

1.打开DMA开关,DMA_Cmd使能;

 2.传输计数器要大于0;(因为它是自减计数器,设定值以后自己向下减至0。)

 3.必须有触发信号,硬件触发的时候没有自动重装器的时候,计数器自减一次。

当传输计数器减到0的时候需要关闭,DMA给计数器重更新数值(手册规定)。除非自动重装

4.设置传输地址和接收地址,以及数据宽度。

数据宽度主要包含:8位字节byte,半字16位Halfword,16位字word。

当数据转运长度不够时,一般会对左位补0,高位补0:

当数据长度超过我们设置数据宽度的时候我们就会舍弃高位;

所以对于数据宽度的选择要一般选择合适的,没有就选择相对大一级的宽度;

5.地址是否自增,设置方向等等。

接下来实际操作一遍

这是没有使用自动重装,手动转运,多适用于存储器之间的转运。

#include "stm32f10x.h"  // Device header
uint16_t DMA_SIZE=0;
/**
  * @brief  函数名:DMA配置函数
  * @param  有无形参:uint32_t addrA 需要转运的外设地址,
	                    uint32_t addrB  需要转运的寄存器地址,
											uint16_t SIZE  传输计数器的值
  * @retval 有无返回值:无
  */
void MYDMA_Init(uint32_t addrA,uint32_t addrB,uint16_t SIZE)
{
	DMA_SIZE=SIZE;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//开启AHB总线时钟;
	DMA_InitTypeDef DMA_InitStructure;
	/*配置外设站点:起始地址,数据宽度,是自增,*/
	DMA_InitStructure.DMA_PeripheralBaseAddr=addrA;//32位地址
	DMA_InitStructure.DMA_PeripheralDataSize= DMA_PeripheralDataSize_Byte;// 8位字节|16位半字|32位字
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Enable;//是否地址自增;
	DMA_InitStructure.DMA_MemoryBaseAddr=addrB;//32位地址
	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte ;// 8位字节|16位半字|32位字
	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//是否地址自增;
	DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC ;//传输方向:外设站点为起点|源点
	DMA_InitStructure.DMA_BufferSize=SIZE;//传输计数器的值
	DMA_InitStructure.DMA_Mode= DMA_Mode_Normal;//传输模式是否使用自动重装
	DMA_InitStructure.DMA_M2M=DMA_M2M_Enable;//是使用软件触发还是硬件触发
	DMA_InitStructure.DMA_Priority=DMA_Priority_Medium;//优先级
	DMA_Init(DMA1_Channel1,&DMA_InitStructure);
	
	DMA_Cmd(DMA1_Channel1,DISABLE);//关闭DMA开关,否则DMA立即工作
}	

/**
  * @brief  函数名:DMA转运函数
  * @param  有无形参:无
  * @retval 有无返回值:无
  */
void MYDMA_Transfer(void)
{
	DMA_Cmd(DMA1_Channel1,DISABLE);//先关闭DMA开关
	DMA_SetCurrDataCounter(DMA1_Channel1,DMA_SIZE); //重新配置DMA传输计数器的值
	DMA_Cmd(DMA1_Channel1,ENABLE);//打开DMA开关
	while(DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);//检测DMA转运完成标志位
	DMA_ClearFlag(DMA1_FLAG_TC1);//清楚标志位
}


       

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值