【STM32CubeMX】DMA

下述以STM32F407VGT6为例,记录下学习DAM的相关理解以及记录。

理论

DMA介绍摘要自官方手册介绍

该设备具有两个通用双端口dma (DMA1和DMA2),每个DMA1和DMA2有8个流。它们能够管理内存到内存、外设到内存和内存到外设的传输。它们具有用于APB/AHB外设的专用fifo,支持突发传输,旨在提供最大的外设带宽(AHB/APB)。这两个DMA控制器支持循环缓冲区管理,因此当控制器到达缓冲区的末端时不需要特定的代码。两个DMA控制器还具有双重缓冲功能,可以自动使用和切换两个内存缓冲区,而不需要任何特殊代码。每个流连接到专用硬件DMA请求,支持每个流上的软件触发。配置由软件完成,源和目标之间的传输大小是独立的。

此外我发现ST官网也有对DMA的相关介绍STM32F2 STM32F4 DMA,肯定是讲的嘎嘎好的。

模式

  正常模式:是最基本的DMA传输模式,它执行一次性的数据传输。工作方式,在正常模式下,DMA控制器会在完成指定数量的数据传输后停止传输。应用场景,适合一次性传输固定数量的数据,例如,从一个缓冲区复制数据到另一个缓冲区,或者从外设读取一定数量的数据。

  循环模式:是一种特殊的DMA传输模式,它允许DMA传输在一个指定的缓冲区内循环进行。工作方式,在循环模式下,当DMA控制器完成指定数量的数据传输后,它会重新回到缓冲区的起始位置,并继续传输。适合需要持续传输数据的应用场景,例如实时数据流处理、音频数据传输等。例如,从ADC读取连续的数据流,或者向DAC写入连续的数据流。

Fifo

相当于使用先进先出的队列结构和其下的结构,来控制DMA的每次传输的数据量,传输触发条件等


Mx配置

STM32CubeMX的配置框图中参数介绍:

在这里插入图片描述

MenToMen处添加的,只能是内存到内存的控制流,假如是内存到外设或者外设到内存,如串口,ADC等,就要对外设配置好后,在看那个DMA总线的连接到该外设上,就可以去对应的DMA1DMA2的选项卡上添加,都是有专属的DMA请求名称的。

通常DMA请求确定后,方向也随之确定了,也就是无法修改了。至于的选择,可以点看查看还有那个空闲的流可以选的,通常部分外设与内存之间的流有唯一的映射流(可以在数据手册中查看到),是不可选的。优先级:共四级可选,Low(低),Medium(中),High(高),Very High(非常高),用于管理多个DMA请求之间的优先顺序。

下框图,模式:有正常模式和循环模式,内存到内存模式无法启用循环模式。地址是否自增:源内存和目的内存都可以勾选,例如:想要把一个数组的数据复制到另一个空数组中,那源内存和目的内存都必须勾选了,这样才能达到一一对应数据长读:三种可选,Byte(8位),Half Word(16位),Word(32位)。

当勾选上Use Fifo后,下述参数可配置:阀值:One Quarter Full(四分之一),Half Full(一半),Three Quarters Full(三分之一), Full(全满),当到达预设阀值后便会开始释放。释放值:Single(单次传输),4 Increment(4个节拍的突发增量传输),8 Increment(8个节拍的突发增量传输),16 Increment(16个节拍的突发增量传输)。

  参考网上资料,对上述使用Fifo的突发增量传输,写下个人理解:DMA要进行传输,就要获得总线仲裁管理总线事务裁决后分配的控制权,像是单次触发,就是接收到数据后就向裁决器申请控制权,至于突发增量传输的释放量,则是一次什么控制权后要传输的数据量,相对应的也是占用总线的时间数。阀值:则是内部数据量达到配置量时,会触发一次DMA传输。以目前开放板STM32F4为例,Fifo区的大小为4字(16字节)。例如:数据长度配置为word,释放量为4 Increment,阀值就只能选Full。因为目标传输数量就是数据长度*释放量=4*word=Fifo缓冲区大小

  狭义总结:数据长度*释放量=传输大小(以及占用总线的节拍时间),阀值为Fifo缓冲区的数据达到多少了,就触发一次DMA传输,因为启用Fifo,数据的走向是,函数提交数据–>Fifo缓冲区–>达到阀值,开始申请DMA传输。


相关代码

STM32CubeMX中DMA的相关函数声明:

/*** 操作 ***/
HAL_StatusTypeDef HAL_DMA_Start (DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);	// 开始DMA传输
HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);	  // 启用中断启动DMA传输
HAL_StatusTypeDef HAL_DMA_Abort(DMA_HandleTypeDef *hdma);		// 终止DMA传输
HAL_StatusTypeDef HAL_DMA_Abort_IT(DMA_HandleTypeDef *hdma);	// 终止在中断模式下的DMA传输
HAL_StatusTypeDef HAL_DMA_PollForTransfer(DMA_HandleTypeDef *hdma, HAL_DMA_LevelCompleteTypeDef CompleteLevel, uint32_t Timeout);	// 完成传输轮询
void              HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma);	// 处理DMA中断请求
HAL_StatusTypeDef HAL_DMA_CleanCallbacks(DMA_HandleTypeDef *hdma);	// (没有定义)
HAL_StatusTypeDef HAL_DMA_RegisterCallback(DMA_HandleTypeDef *hdma, HAL_DMA_CallbackIDTypeDef CallbackID, void (* pCallback)(DMA_HandleTypeDef *_hdma));	// 注册回调函数
HAL_StatusTypeDef HAL_DMA_UnRegisterCallback(DMA_HandleTypeDef *hdma, HAL_DMA_CallbackIDTypeDef CallbackID);	// 注销回调

/*** 状态 ***/
HAL_DMA_StateTypeDef HAL_DMA_GetState(DMA_HandleTypeDef *hdma);
uint32_t             HAL_DMA_GetError(DMA_HandleTypeDef *hdma);

轮询模式

轮询模式,又称堵塞模式。基本的使用流程,这里验证用的是DMA2流4,要预先在STM32CubeMX上定义,验证的是内存到内存(变量到变量)。

// 定义两个变量
uint32_t i = 0;uint32_t num = 0; 
// DMA_MemToMen验证(堵塞模式)
HAL_DMA_Start(&hdma_memtomem_dma2_stream4,(uint32_t)&i,(uint32_t)&num,1);
HAL_DMA_PollForTransfer(&hdma_memtomem_dma2_stream4, HAL_DMA_FULL_TRANSFER, HAL_MAX_DELAY);

中断模式

中断模式,又称非堵塞模式。基本的使用流程,除了上述讲到的按定义好DMA2流2外,还要在NVIC中使能该控制流的全局中断,才能使用下述函数。

// 定义两个变量
uint32_t i = 0;uint32_t num = 0; 
// DMA_MemToMen验证(非堵塞模式)
HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream4,(uint32_t)&i,(uint32_t)&num,1);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值