#技术问题分析#
前些天,一个小伙伴告诉我,他用DMA搬运ADC的数据,刚开始的时候,数据是好好的,每个通道的数据都在DMA缓存上好好地排着对,在什么都没有动的情况下,缓存中的数据队列乱了,像是多了某个通道的数据或少了某个通道的数据。
正常情况下的缓存队列:
错误情况下缓存队列:
对比数据,发现错误时,DMA缓存中的队列乱了,虽然错误的位置是随机的,而且还没有错误的数值。
后来小伙伴还告诉我,他没有再复现出缓存中队列发生错位的现象。这与当时给我展示的,几分钟内就出现缓存错位的现象严重不符。
我们来看一下DMA搬运的过程,DMA的搬运是需要触发的,如果没有触发,那就在ADC转化的过程中,就会搬运数据,那将得到一堆错乱无效的数据。既然是需要得到正确的采样结果,那只有是在转换完成后才能触发DMA搬运数据,而且,DMA搬运完成后,触发信号需要清除。说到这,或许已经有人知道我说的是哪个标记位了,是的,没错,就是转换完成标记位。
会不会是谁动了这个标记位,导致了DMA没有触发信号,然后DMA少读了数据,造成了队列错误的情况呢?
答案是有的!!!
我们看下这个标记位,是在写 0 或读取ADC_RDR 以清除该位,首先可以代码中排除了认为给EOC赋值或操作ADC 状态寄存器的可能,就剩下读取ADC_RDR的可能了。
但是在代码中,没有人为地读取ADC_RDR寄存器,那到底是谁读了寄存器呢。这让我想到了debug下的ADC寄存器窗口。
心细的小伙伴就会发现,debug下,该窗口下的值是会跳动的,也就是DMK在不断的读取ADC模块的寄存器的值。
想到这,我立马寻找小半伙,问他前些天出现DMA错位的现象,是不是出现问题的时候,是有查看ADC寄存器,后来没有复现到问题的时候,是没有查看ADC寄存器状态的。小伙伴给我的答案是肯定的。
于是我打开前几天跑了一晚上没复现DMA缓存错位的工程,默默的将ADC寄存器窗口打开,发现一下子就能把问题给浮现了。
DMA缓存中数据错误,就是由于MDK开了ADC寄存器窗口,读取了ADC_RDR,造成了EOC标记被清,DMA没有得到触发而少搬运数据造成的。
发散:由此看来,调试其他模块DMA搬运时,打开了DMA搬运的外设寄存器,都会造成MDK读取对应的data寄存器,会把对应标记位清楚,DMA得不到触发,没有搬运数据,造成DMA缓存中的数据错位。
如何避免?
1. 不要打开DMA搬运的外设;
2. 不要在watch窗口输入DMA搬运的寄存器或地址;
3. 不要在memory窗口读取外设的地址。
|
是他,就是他,是他,就是他,我们的朋友 小那托