这几天在尝试用DMA实现规则通道多通道的ADC采集,遇到了不少问题,在这记录一下我遇到的问题,一方面理顺一下思路,也希望后人少走弯路。
一开始按照开发板资料中的程序源码编写,但无论如何配置,也无法实现功能。而后参考了CSDN和b站上上的不少文章和视频,感觉大佬们配置都很顺畅,没什么问题。(b站上的大佬主要用cube对DMA和ADC进行配置,CSDN和我一样用库函数配置)看完了网上的文章,也没啥收获。
最后,看了ST公司写的库函数(主要是stm32f4xx_dma.c, stm32f4xx_adc.c以及他们的头文件),我发现其实网上很多教程都是以ST公司给的文件为基础写的,大家可以摒弃写程序先百度的学习方法,养成先看ST公司写的库函数,再写代码的习惯,相信大家会对STM32F4有更深刻的认识。
我遇到的问题是:ADC可以正常采样,但DMA传输到内存的值一直是0(也就是说DMA没有在正常工作),昨天看了一天,也看不出问题。今天又仔细看了一遍,首先一个问题是时钟配置错误
RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_DMA1, ENABLE);
大家可以看看这个代码有几个问题。
第一个问题是ADC1对应的DMA是DMA2的数据流0,第二个问题是开启外设时钟的函数应该是RCC_AHB1PeriphClock()。很低级的错误。
把错误都改了,还是不行。我在debug的时候把DMA2_Stream0添加到观察窗中观察,单步运行。发现在初始化DMA之后,DMA2_Stream0的寄存器并没有被写入,我们知道,DMA在ENABLE状态的时候(也就是DMA2_Stream0的CR寄存器的第0位不能为1),DMA相关寄存器是不能写入的。因此,在对DMA寄存器进行配置之前,要先失能DMA,即插入如下代码:
while (DMA_GetCmdStatus(DMA2_Stream0) != DISABLE){}
但这段代码其实一直都有。而且我从观察窗中发现,在进入DMA_Init()这个函数之前,DMA2_Stream0的CR寄存器的第0位是0,执行完这个函数之后,DMA2_Stream0的CR寄存器的第0位变成1了。单步运行DMA_Init(),会发现,DMA_InitStruct->DMA_MemoryBurst 的缺省值的第0位是1,这就导致DMA2_Stream0的CR寄存器的第0位被设置成1,DMA进入ENABLE状态,不能写入值。而我不懂MemoryBurst的意义是什么,网上的教程有的也没设置这个寄存器,我也没设置。
而后在DMA初始化时,随便设置了一下DMA_MemoryBurst 的值,代码就能运行啦,至此,问题解决。