DMA_STM32

一、DMA简介

  • DMA(Direct Memory Access)直接存储器存取
  • DMA的主要作用是:提供外设(各类外设的寄存器)和存储器(运行内存SRAM和程序存储器Flash)或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源
  • STM32中最多有12个独立可配置的通道: DMA1(7个通道), DMA2(5个通道);每个通道都支持软件触发和特定的硬件触发
    - 存储器到存储器之间的数据转运,一般用软件触发
    - 外设到存储器之间的数据转运,一般用特定的硬件触发,如ADC

STM32存储器映像
在这里插入图片描述

  • 外设寄存器本质也是存储器
  • ROM存储器:只读存储器,非易失性的、掉电不丢失的存储器
  • RAM存储器 :随机存储器,易失性的、掉电丢失的存储器

二、DMA基本结构

2.1 DMA总线框图

在这里插入图片描述

  • 总线矩阵左边为主动单元,右边为被动单元,主动单元可以主动访问读写被动单元。主动动单元分为内核部分(DCode和系统总线)以及DMA部分(DMA1、2),被动单元为各类存储器。

  • Flash是只读寄存器,因此CPU和DMA无法直接对其进行写入,需要通过FLASH接口控制器进行整页操作,因此DMA不能直接填入Flash的地址进行数据写入。

  • DMA中,仲裁器用于根据不同通道的优先级,选择通道接入总线的顺序。

  • 若DMA总线和CPU访问冲突,DMA会暂停CPU的访问,但会保留CPU一半的总线带宽(?不太懂一半的带宽是什么意思)

  • CPU通过DMA内的AHB从设备部分,配置DMA内部的寄存器。

  • DMA请求即DMA的触发源,可以通过硬件触发或软件触发。

2.2 DMA内部框图

在这里插入图片描述

  • 外设站点与存储器站点仅为命名,实际上外设寄存器也可以放在存储器站点,存储器也可以放在外设站点。

  • 传输计数器为自减计数器,决定了DMA将转运几次数据,每转运一次计数器-1,计数器为0时停止转运,自动重装器决定了传输计数器是否会自动重装。

  • 需要修改传输计数器时,需在开关控制Cmd失能的情况下进行。

  • M2M用于控制DMA的触发方式为硬件触发/软件触发,每一个通道都可以选择软件触发,但每个通道只能由指定的硬件触发。
    - 比如:DMA1_Channel1只能由ADC1、TIM2_CH3、TIM4_CH1触发。

  • 软件触发时,触发源将一直开启,因此不能与自动重装同时使用,否则DMA会一直转运。

  • 数据宽度问题:当转运源端宽度小于转运目的地宽度时,高位补0转运;源端宽度大于目的地宽度时,高位舍弃转运。

  • DMA开启转运的三个条件: 1.传输计数器不为零;2.触发源触发;3.开关控制Cmd使能。

  • 配置DMA步骤:开启DMA的RCC时钟 → 初始化DMA(配置结构体,调用初始化函数) → 如果是硬件触发,需要调用对应外设的xxx_DMACmd → 如果需要DMA的中断,则开启中断输出,并配置NVIC → 开关控制使能


三、配置DMA

  • DMA数据转运任务中,DMA初始化需设置为:
    外设站点、存储器站点自增:ENABLE;
    自动重装:否(即Mode_Normal)
    触发源:软件触发

  • ADC扫描模式+DMA”连续转运ADC数据任务中,DMA初始化需设置为:
    外设站点起始地址:ADC1数据寄存器的地址,可以写成:(uint32_t)&ADC1_DR;
    外设站点自增:DISABLE;存储器站点自增:ENABLE;
    自动重装:ADC单次扫描,否; ADC连续扫描,是;
    触发源:ADC硬件触发
    注意使用时,ADC需配置为扫描模式,且需开启ADC_DMACmd(ADC1, ENABLE);

'1. 开启DMA的RCC时钟'
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
'2. 初始化DMA'
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = 0x20000000;	
		// 外设站点的基地址,为8位16进制数(32位2进制),一般用形参代替
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
		// 外设站点的数据宽度,Byte/HalfWord/Word分别对应8位/16位/32位
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_ENABLE;	
		// 外设站点是否自增,ENABLE或DISABLE
DMA_InitStructure.DMA_MemoryBaseAddr = 0x40000000;
		// 存储器站点的基地址
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
		// 存储器站点的数据宽度
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_ENABLE;
		// 存储器站点是否自增
DMA_InitStructure.DMA_DIR = DMA_PeripheralSRC;
		// 指定数据转运方向,DST/SRC表示:外设站点作为目的地(DST:destination)/源端(SRC:source)
DMA_InitStructure.DMA_BufferSize = 10; 
		// 传输计数器的值,0-65535
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
		// 指定操作模式,即传输计数器是否自动重装,Normal/Circular对应不重装/重装
DMA_InitStructure.DMA_M2M = DMA_M2M_ENABLE;
		// 是否设置为软件触发(即存储器到存储器模式),DISABLE即设置为硬件触发
		// !!!注意软件触发不能与循环模式(自动重装模式)同时使用,会导致DMA一直执行
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
		// 指定通道的优先级,有VearHigh/High/Medium/Low,同优先级时通道序号小的优先
DMA_Init(DMA1_Channel1, &DMA_InitStructure);			// 初始化DMA
'3. 如果是硬件触发,需要调用对应外设的xxx_DMACmd'
'4. 如果需要DMA的中断,则开启中断输出,并配置NVIC'
'5. 开关控制使能'
DMA_Cmd(DMA1_Channel1, ENABLE);
'6. 如果需要多次转运的话,可以利用获取/清除标志位函数循环等待'

四、DMA常用库函数

void DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx);
		// 重置函数
void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);
		// DMA初始化函数,选择DMAx_通道x
void DMA_StructInit(DMA_InitTypeDef* DMA_InitStruct);
		// 结构体初始化函数
void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);
		// 开关控制函数,使能/失能DMA
void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState);
		// 中断输出控制使能/失能
void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber); 
		// 设置当前传输计数器,用于设置传输计数器的值
		// !!!注意,设置传输计数器时,DMA_Cmd必须处于失能状态
uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);
		// 获取当前传输计数器
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);
		// 清除中断标志位

五、补充


Reference
STM32入门教程-2023版(江科大)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值