DMA直接存储器访问

DMA简介

STM32最多有2个DMA控制器(DMA2仅存在大容量产品中)
DMA1有7个通道。DMA2有5个通道。
还有一个仲裁起来协调各个DMA请求的优先权。

原理图:

在这里插入图片描述

一、DMA配置过程

在这里插入图片描述

二、.DMA配置参数

在这里插入图片描述

1.DMA外设与通道对应图

每个通道都直接连接专用的硬件DMA请求,都支持软件触发。
参考寄存器手册
在这里插入图片描述
参考寄存器手册
在这里插入图片描述

2.优先级

在这里插入图片描述

仲裁器根据优先管理着通道的请求和启动外设/存储访问
优先级管理分两个方面:

  • 软件:可通过DMA_CCRx寄存器配置每个通道的优先级,优先级分4个等级如下:

      最高优先级
      高优先级 
      中等优先级
      低优先级
    
  • 硬件:如果2个请求有相同的软件优先级,则较低编号的通道比较高编号的通道有较高的优先权。举个例子,通道2优先于通道4

即:DMA 数据流请求之间的优先级可用软件编程(4 个级别:非常高、高、中、低),在软件优先级相同的情况下可以通过硬件决定优先级(例如,请求 0 的优先级高于请求 1)

3.DMA传输方向

(闪存)、(SRAM)、(外设的SRAM)、(APB1 APB2和AHB外设)均可作为访问的源和目标
DMA_CCRx寄存器:配置数据的传输方向
如果是存储器到存储器模式,需要配置DMA_CCRx的MEM2MEM位

DMA1传输模式:

● 外设到存储器的传输
● 存储器到外设的传输

DMA2传输模式:

● 外设到存储器的传输
● 存储器到外设的传输
● 存储器到存储器的传

4.外设、存储器数据宽度与对齐

DMA_CCRx寄存器中的PSIZE和MSIZE位:

设置源和目的的数据宽度,两边的位宽尽量保持一致。要不然就会出问题,
例如:ADC采用的12位,2个字节,因此此处数据设置应该也是2个字节

5.双方地址是否增量

DMA_CPARx寄存器:设置外设寄存器地址

DMA_CMARx寄存器:设置存储器地址

通过设置DMA_CCRx寄存器中的PINC和MINC标志位,外设和存储器的指针在每次传输后可以有选择的完成自动增量,当设置为增量模式时,下一个要传输的地址将是前一个地址加上增量值,增量值取决于所选的数据宽度1个数据宽度、2个数据宽度或4个数据宽度 (字节、半字、全字)。
例:ADC占12位,ADC->DR寄存器地址不变,所以存储器(存储数组)的增量应该设置为2。(32位的地址,需要16位来存储)

6.DMA工作模式

DMA-CCRx寄存器–CIRC位设置是否循环

  • 正常缓存模式(DMA_Mode_Normal),在该模式下,每次使能仅进行一轮传输,一旦计数器的值减至0时,DMA传输会停止。想要再次传输,必须重新设置计数器CNDTR的数值;

  • 循环工作模式(DMA_Mode_Circular),主要处理连续的数据传输,每进行一轮传输,计数器会被自动恢复为初始值,同时DMA传输进入下一轮,非常适合同ADC多通道(扫描)模式一起工作。

7.数据传输量

DMA_CNDTRx寄存器:写入需要传输的数据量,(0到65535)

例:.DMA_BufferSize=200;	

8.结构体配置

typedef struct
{
uint32_t DMA_Channel;  //DMA数据流对应的通道
uint32_t DMA_PeripheralBaseAddr;//外设基地址
uint32_t DMA_Memory0BaseAddr;//存储器基地址
uint32_t DMA_DIR;//传输方向,是存储器到外设还是存储器到存储器
uint32_t DMA_BufferSize;//一次传输的数据量大小

uint32_t DMA_PeripheralInc;//外设地址是否增量
uint32_t DMA_MemoryInc;//存储器地址是否增量
uint32_t DMA_PeripheralDataSize;//外设传输单位,字节还是字还是半字等等
uint32_t DMA_MemoryDataSize;//存储器传输单位,节拍定义

uint32_t DMA_Mode;//是否循环采集
uint32_t DMA_Priority;//DMA优先级别,是较高,高,中还是低
uint32_t DMA_FIFOMode;//FIFO模式是否开启
uint32_t DMA_FIFOThreshold; //FIFO模式阈值
uint32_t DMA_MemoryBurst;//用来配置存储器是几个单位数据的突发传输
uint32_t DMA_PeripheralBurst;//用来配置外设是几个单位数据的突发传输
}DMA_InitTypeDef;

实例:

void dma_init()
{
 
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

/*DMA配置*/

DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;//串口数据寄存器地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SendBuff; //内存地址(要传输的变量的指针)
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //方向(从内存到外设)
DMA_InitStructure.DMA_BufferSize = 500; //传输内容的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址不增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址自增
DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_Byte ; //外设数据单位
DMA_InitStructure.DMA_MemoryDataSize =
DMA_MemoryDataSize_Byte ; //内存数据单位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ; //DMA模式:一次传输,循环
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium ; //优先级:高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //禁止内存到内存的传输
 
DMA_Init(DMA1_Channel4, &DMA_InitStructure); //配置DMA1的4通道
DMA_Cmd(DMA1_Channel4,ENABLE);
DMA_SetCurrDataCounter(DMA_CH4,DMA1_MEM_LEN);//DMA通道的DMA缓存的大小
DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);//配置DMA发送完成后产生中断
 
}

三、DMA中断

在这里插入图片描述
每个通道都有3个事件标志(DMA 半传输,DMA传输完成和DMA传输出错),
这3个事件标志逻辑或成为一个单独的中断请求。

在大容量产品中,DMA2通道4和通道5的中断被映射在一个中断向量上,
在互联网产品中,DMA2通道4和通道5的中断分别有独立的中断向量,
所有其他的DMA通道都有自己的中断向量。

中断服务函数:清除中断标志位

	void DMA1_Channel4_IRQHandler(void)
	{
		if(DMA_GetFlagStatus(DMA1_FLAG_TC4)==SET)
		{
			DMA_ClearFlag(DMA1_FLAG_TC4);
		}
	}

DMA配置流程

使能DMA时钟
	RCC_AHBPeriphClockCmd();
初始化DMA通道
	 DMA_Init();
ADC模块使能DMA传输:
 	ADC_DMACmd();
使能DMA1通道,启动传输。
	  DMA_Cmd();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

好好睡觉好好吃饭

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

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

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

打赏作者

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

抵扣说明:

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

余额充值