DMA的三种传输方式,你GET到了吗?

以下文章来源于:公_众_号开源电子网
读取更多技术文章,请扫码关注
在这里插入图片描述

关注公众号,后台回复:DMA

(免费领取项目文件)

DMA的三种传输方式,你GET到了吗?

前言

DMA,详称“Direct Memory access”,直接寄存器访问,被亲切的称为“数据搬运工”。DMA的传输是不需要CPU去控制的,CPU只需要对DMA进行配置即可。所以,在进行大量数据传输的时候,我们首先想到的是能不能用DMA帮我们完成数据传输工作,CPU就可以去干别的事情。

DMA传输简单来说,就是要确定三要素:源地址(从哪里提取数据),目标地址(数据传输到哪里去)还有传输的数据量(传多少数据)。

而这里的源地址和目标地址就可以是“外设”或者“内存”。“外设”可以理解成外设的数据寄存器(XX_DR),而“内存”就可以理解成大数组。

DMA的传输方式就分为三种“内存到外设”、“外设到内存”以及“内存到内存”,本文着重说明使用,细节的东西,可以查看正点原子教程《DMA实验》。

DMA配置步骤简单来说:
1、初始化DMA时钟(具体用到DMA1还是DMA2,查一下参考手册就知道了)。
2、配置好DMA相关工作参数,通过HAL_DMA_Init函数进行初始化。
3、通过外设提供的DMA函数接口进行数据的发送,例如串口1的DMA发送即使用HAL_UART_Transmit_DMA函数即可。
4、开始DMA传输后,肯定需要查询当前当前的DMA传输状态了,这时候就可以使用__HAL_DMA_GET_FLAG函数。
5、使用HAL提供的函数接口,大多数在函数内部已经使能了某些中断位,所以想要配置中断,需要设置NVIC相关和编写中断服务函数xxx_IRQHandler。

接下来就介绍这三种传输方式,都有相对应的例子提供。

内存到外设

这里我们以串口1发送使用DMA为例子。具体情景:DMA控制器把数组里的数据传输到串口1的数据寄存器中。DMA初始化相关代码如下:

在这里插入图片描述

当然事先,串口1肯定是需要配置好的。在初始化函数这里并没有明确源地址和目标地址相关信息,其实HAL库提供的USART-DMA发送函数中形参就需要三要素。
在这里插入图片描述

而我们也是使用这个接口启动DMA传输。启动DMA传输的另一种方式可以直接通过操作寄存器去实现,这种方式将在“内存到内存”部分介绍。

启动DMA传输后,通过__HAL_DMA_GET_FLAG去查询当前DMA传输情况,假如传输完成,那么就需要清除传输完成标记并且停止串口的DMA功能。当然对于DMA传输来说,很多时候想获取当前数据量,就可以通过查询DMA_CNDTR寄存器查询或者用HAL库提供的接口__HAL_DMA_GET_COUNTER。

具体实现如下图:
在这里插入图片描述

在HAL_UART_Tramsit_DMA函数中已经默认USART_DR寄存器作为目标寄存器,那么传参中的SendBuff就是要传输的大数组,而SEND_BUF_SIZE就是传输的数据量了。

外设到内存

这里我们以ADC1使用DMA为例子。具体情景:DMA控制器将ADC转换后的数据传输到我们定义好的大数组。DMA初始化相关代码如下:
在这里插入图片描述

这部分DMA代码与前面的串口相关的DMA代码有点差别,这里使能了DMA1通道1的中断,也就是当满足了条件,例如DMA传输完成,程序就会跳进中断服务函数,通过HAL库提供的一个公共处理中断接口函数HAL_DMA_IRQHandler,最终会进入ADC转换完成的回调函数接口里,这里我们通过一个全局变量去标记是否已经完成ADC的转换,进而在main函数中做完成的数据处理。

而ADC初始化函数存在一点小变动,即使能连续转换,对ADC初始化结构体变量成员ContinuousConvMode赋值ENABLE。具体代码如下:
在这里插入图片描述

回调函数这里也列出来,主要就是进行GPIO初始化还有ADC时钟配置。
在这里插入图片描述

进行ADC的DMA传输使用的是HAL_ADC_Start_DMA函数接口,具体函数说明可以看下面。
在这里插入图片描述

在while循环中的操作,就如下图。
在这里插入图片描述

上图中g_adc_dma_buf即ADC完成转换后,DMA会把数据传输到该数组中。
通过对全局变量g_adc_dma_sta得值进行判断(该值会在ADC转换完成中断回调函数中进行置1),转换完成即可对数据进行计算。

内存到内存
DMA的所有通道都支持内存到内存的传输方式,这里指的是F1,其他系列就不一样了,可以查看对应手册说明。具体情景:DMA控制器将源地址中存放的数据传输到我们定义好的大数组。DMA初始化相关代码如下:
在这里插入图片描述

这里我们是在初始化函数中直接用了HAL_DMA_Start函数接口去确定DMA传输的三要素,只不过传输数据量为0。这时候,我们就可以通过上面提到的另一种方式去传输数据,即通过DMA_CNDTR寄存器,对该寄存器赋值后,开始DMA传输,寄存器中的数值会递减。这里我们可以看看寄存器说明。
在这里插入图片描述

利用寄存器的特性,所以我们就可以自定义一个函数,如下图,完成DMA数据传输。
在这里插入图片描述

在while循环中的操作,就如下图。
在这里插入图片描述

内存到内存的传输方式比较简单,跟前面的逻辑差不多。通常来说,很少用到这种传输方式,用得比较多的是前面两种方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值