在本次项目中,限于空间要求我们选用了STM32F030F4作为控制芯片。这款MCU不但封装紧凑,而且自带的Flash空间也非常有限,所以我们选择了LL库实现。在本文中我们将介绍基于LL库的ADC的DMA采集方式。
1、概述
这次我们使用DMA方式实现对AD的采集,在遗忘我们使用HAL库和标准库都做过,这次我们使用LL库来实现。接下来我们简单了解一下STM32F030F4中的ADC和DMA。
首先看一看ADC,STM32F030F4是12位的ADC。它有多达19个多路复用通道,允许它测量来自16个外部和2个内部源的信号。各种通道的A/D转换可采用单通道、连续通道、扫描通道或不连续通道进行。ADC的结果存储在左对齐或右对齐的16位数据寄存器中。ADC结构图如下:
这次我们只使用第1路外部输入。接下来说一说DMA,直接内存访问(DMA)用于在外设和内存以及内存到内存之间提供高速数据传输。DMA可以在没有任何CPU操作的情况下快速移动数据。这使CPU资源可以用于其他操作。STM32F030F4中的DMA控制器有5个通道,每个通道用于管理来自一个或多个外围设备的内存访问请求。它有一个仲裁器来处理DMA请求之间的优先级。DMA结构图如下:
这次我们也使用DMA的第1通道。
2、ADC配置
在使用之前我们需要对ADC和DMA的相关寄存器惊醒必要的配置,才能实现我们想要的功能。我们来看看ADC需要配置的寄存器。ADC需要注意的寄存器主要有两个:ADC控制寄存器(ADC_CR)和ADC配置寄存器1(ADC_CFGR1)。首先我们来说说ADC控制寄存器(ADC_CR),器结构如下:
关于ADC控制寄存器(ADC_CR),有几个设置需要说明一下。
ADCAL:ADC校准,设置该位可以软件启动校准,校准完成硬件会复位掉这一位。需要注意的是只有ADC处于失能状态,软件对ADCAL的操作才是有效的。也就是说软件对ADCAL操作时,ADC控制寄存器(ADC_CR)必须是全复位状态,即ADCAL=0,ADSTART=0,ADSTP=0, ADDIS=0和 ADEN=0。
ADSTART: ADC启动转换命令。需要注意只有在ADC已启用,并且没有禁用ADC的挂起请求。也就是说ADEN=1和ADDIS=0时,软件对ADSTART的操作才有效。
ADEN: ADC使能命令。只有在ADC控制寄存器(ADC_CR)处于全复位状态,即ADCAL=0,ADSTART=0,ADSTP=0,ADDIS=0 和 ADEN=0下,软件对ADEN的操作才有效。这就有一个问题,如果你使用了ADCAL必须等校准完成,才能使能,否则无效。
接下来我们看一看ADC配置寄存器1(ADC_CFGR1),其结构如下:
关于ADC配置寄存器1(ADC_CFGR1),我们需要关注:CONT(转换模式)、EXTEN[1:0](外部触发使能)、DMACFG(DMA访问配置)、DMAEN(DMA访问使能)。需要说明的是,这几个配置都必须在启动转换前完成配置,即配置时ADSTART=0。
3、DMA配置
配置了ADC还需要配置DMA才能实现我们的想法。关于DMA的配置我们主要说一下4个寄存器:DMA通道配置寄存器(DMA_CCRx)、DMA通道数据数量寄存器(DMA_CNDTRx)、DMA通道外设地址寄存器(DMA_CPARx)、DMA通道内存地址寄存器(DMA_CMARx)。
首先,我们来看看DMA通道配置寄存器(DMA_CCRx),其结构如下:
对于DMA通道配置寄存器(DMA_CCRx),我们需要关注如下位:MSIZE[1:0](内存大小)、PSIZE[1:0] (外设大小)、MINC(内存的增加模式)、PINC(外设增加模式)、CIRC(循环模式)、DIR(数据传输方向)、EN(通道使能)。除通道使能外,其它均可通过初始化函数进行配置。
接下来,我们来看看DMA通道数据数量寄存器(DMA_CNDTRx),其结构如下:
其实DMA通道数据数量寄存器(DMA_CNDTRx)用于配置传送数据的个数,如果是往内存中写,就是内存缓冲区的大小,单位与配置寄存器中MSIZE和PSIZE有关。接下来,我们来看一看DMA通道外设地址寄存器(DMA_CPARx),其结构如下:
对于DMA通道外设地址寄存器(DMA_CPARx),就是存储外设的地址,如果我们的外设是ADC,那就是ADC的地址。最后,我们来看一看DMA通道内存地址寄存器(DMA_CMARx),其结构如下:
对于DMA通道内存地址寄存器(DMA_CMARx),其存储的就是对应的变量在内存中的地址,就是我们开辟的数据缓存区的首地址。
4、软件实现
我们已经说明了ADC和DMA的配置,在这一小节,我们将根据我们前面的分析实现代码。首先来实现ADC的配置代码。
配置后,ADC的寄存器如下:
配置后,DMA的寄存器如下:
其实,到这里ADC采集世纪上已经实现了,DMA已经将数据从ADC读出来存到了指定的内存区域,后续的处理就很简单了。
5、总结
我们已经实现了基于LL库使用DMA方式获取ADC的数据。下面我们就下载到目标设备并检测一下结果。测试结果如下:
上图中,上部是计算完成的物理量值,下部则是DMA写到内存缓存区的ADC的原始码值。