1.续谈前提:
我们在上一个文章中,
了解到DMA_BufferSize的基本概念,
且前提是:
注:这里我们假设的ADC配置为:
单次触发/不连续转换,扫描模式,单adc模式,两个通道,且数据对齐
且:我们先不用给DMA_BufferSize或者其他下定义,我们先来看看咋么回事!
2.疑惑——》加深对于配置间的理解
但当我们碰到 ,如连续转换,多通道的双/三adc模式,数据不对齐的情况,以及ADC_DMAAccessMode 配置不同的情况,我们ADC转换的数据和我们需要显示的数据情况的不同(这与数据对齐与否有关),等等等等的问题/需求时,或许我们的理解也需要加深了
3.我们分情况来
情况1:
我们需要多通道,且由外部触发来进行ADC转换,并用单ADC模式,数据对齐,扫描模式,单次触发(这里的外部触发,先暂时指:TIM定时器更新事件触发)
这里的希望或许是:
我们需要在一定的时间段中,来检测多个需要检测的电压目标,并显示出。
(这里的重点在于:外部触发的一定时间间隔,来查看多个待检测目标的变化情况)
这里我们使用DMA的目的是: 防止数据覆盖
原因是:
使用规则组的多通道进行目标检测时,数据存储在DR寄存器中,会造成数据覆盖,如此我们就查看不到这段时间的测量变化情况,若不使用DMA进行数据搬运,则我们每次读取到的数据只是最近的通道转换的数据。
因此,我们这里使用DMA数据搬运,解决/缓解了两个问题:
1.检测到的数据情况,我们能够根据外部触发的时间间隔来,间歇地查看这段时间中的检测变化情况,以便做出下一步的处理工作
2.我们能够查看多个规则组通道的数据,而不至于我们每次读取到的数据只是最近的通道转换的数据。
我们回到讨论中,在这里 ,我们DMA_BufferSize这一配置可以是:M*N
为什么突然给出个这个结论呢? 听我慢慢道来
1.回顾: DMA 事务由给定数目的数据传输序列组成。
2.这里的M,我给的定义是:进行多少轮这样的数据传输序列转换过程
3.这里配置的为不连续转换/单次外部触发,因此这里的M:1
(这里的M也就是侧重体现了手册DMA事务中的数据传输序列)
4.接着,N我给的定义是:每一轮需要传输的数据数目个数
5.这里配置的为7个通道,且数据对齐,且单adc模式,因此这里的N:7
(这里的N也就是侧重体现了手册DMA事务中的给定数目的数据)
6.因此,这里的DMA_BufferSize:1*7
注意:这里的DMA_BufferSize并不等同于DMA请求,有关这个我们在上一篇已讨论了一部分
7.执行过程:
当我们外设能够被外部触发的更新事件触发转换后,而使能了DMA请求,那么每一轮的DMA请求,都会使DMA_BufferSize中的7减1,直到7——》0,本次的DMA请求结束,外设释放DMA控制总线。
(这里还不需要讨论外设的DMA请求的优先级问题)
情况2:
我们需要多通道,且由外部触发来进行ADC转换,并用单ADC模式,数据对齐,扫描模式,单次触发,但连续转换(这里的外部触发,先暂时指:TIM定时器更新事件触发)
(这里的一般情况是:外部触发一次,而我们来配置 DMA 事务 进而来改变M(情况1中的)
当然根据不同情况,我们也可以改变N,这涉及到许多情况,另论)
我们或许希望的是:
在TIM定时器外部触发的某一次中,我们需要检测的目标,在连续的极小时间中是否电压稳定
因此这里的DMA作用为:搬运在某次TIM定时器外部触发的给定数目的数据传输序列的数据量,并显示出,从而知道在这段极小的时间内,会不会出现电压的波动如何,是否稳定
因此,我们这里的DMA_BufferSize依旧是:M*N
(不过这里的N,我们不会常常变化)
情况3:
我们需要多通道,且由软件触发来进行ADC转换,并用双/三ADC模式,规则组同步,数据对齐,扫描模式,(可连续转换/不)
(我们先忽然上述的16 通道的规则同时模式:双重 ADC 模式的种种细节)
我们先再对标题的情况进行设置上的补充说明:
ADC1,转换4个通道,通道为1 ,2,3,4,顺序为1 ,2,3,4。
ADC2,转换4个通道,通道为1 ,2,3,4,顺序为1 ,2,3,4。
因此,转换的执行情况参考上述图 44. 16 通道的规则同时模式:双重 ADC 模式
我们首先得知道当多重adc转换时,数据是存储在
适用于双重和三重模式的 ADC 通用规则数据寄存器(ADC_CDR)中
也即;我们可以理解为32 = 16 +16
结合上述三个图片来说:
当这个设置为ADC_DMAAccessMode2的时候,ADC转换完成后发送一个32位的DMA请求,假设我们的内存(存储搬运的数据)的大小为32位,也即数据对齐。
一次ADC_CDR满的执行过程:
当ADC1转换了一个通道时,同时ADC2也转换了一个通道,两种的数据分别存放在ADC_CDR寄存器的高低16位,而后发送DMA请求。(DDS会的配置会先发送DMA请求,而不会再转换而覆盖ADC_CDR)
这里我们回到
DMA_BufferSize是:M*N,这一预先的定义——尽管它是鲁莽的!
那么我们这里的DMA 事务由给定数目的数据传输序列组成 ,该如何理解呢?
我认为,还是
M :进行多少轮这样的数据传输序列转换过程 这里为1
而N 之前 我给的定义是:每一轮需要传输的数据数目个数
在这里我们可以对其有了更深的理解,
对之前的补充:
其数据数目指的是:每个通道进行adc转换后的数据存储到DR寄存器中,这样的数据有多少个
那么这里也继续扩展:
其数据数目指的是:每个通道进行adc转换后的数据存储到CDR寄存器中,这样的数据有多少个
(也就是说,我们这里的数据已经进行了一次打包,将ADC1 ADC2一次规则组同时转换不同通道的数据打包在一个寄存器CDR中,分别是高16位,和低16位)
因此在DMA_BufferSize是:M*N,这一预先的定义中,我们似乎能够补充/遗漏了一个参数
L:一个数据包的大小,一般整合了两个数据(16位的)
(16位为一个单位,以后或许有不同,如8位,再说)
N:变成了 N/L
因此这里的DMA_BufferSize是:M*L*N =M*L*(N/L)
//或许结果一样,但逻辑执行过程和细节部分就已大不同了
注:这里的和上述的情况1,均为数据对齐(为了讨论方便起见,一步一步来),但不同
就是说,情况1中的数据存储到SRAM的大小为16位,情况3的数据存储到SRAM的大小为32位
扩展再论!当这个设置为ADC_DMAAccessMode1的时候,ADC转换完成后发送一个32位的DMA请求,假设我们的内存(存储搬运的数据)的大小为32位,也即数据对齐
ADC_DMAAccessMode1时,就是说我们是ADC1或者ADC2转换后,发送一个16位的DMA请求,即一个一个的传输数据,数据大小位16位,这类应用其实比较少,但还需要讨论
注:我们这里探讨其出现的问题即可
(这里的情况和我们有些不同,因为这里是7路的通道,且涉及到数据大小对齐的问题)
我们以这篇文章为例
我先谈文章中数据错位的问题,并尝试扩展说说
在我看来,造成数据错位的原因:
1.一次软件触发的连续转换问题
2.且SRAM的数据大小为16位,总的数据不对齐
1,2同时满足,而造成数据错位
这里我们谈谈解决方法及可能的应用和问题:
1.不用连续转换
则按照,我们之前谈及的DMA_BufferSize为 1*1*7
(一次触发转换,16位数据大小(SRAM),7个通道)
(其实这里和情况1很类似,区别在于是双/多ADC模式,且数据存储在CDR寄存器中)
但话又说回来,若是这样,那么我们使用双/多ADC模式且交替/同时模式转换的应用意义就不大,甚至于没有,效率自然就没有提高。
2.使一次的DMA事务/DMA_BufferSize为8
(稍等一下,我们写着写着又有疑惑了:若按照这样的配置,则DMA_SxNDTR 寄存器似乎达不到0,即无法通过这一条件来终止本次外设请求传输,就是说,我们没办法空出来的那位16位数据大小,应该是会被再次转换到的ADC数据填上)
(上述,待定:需要阅读和理解:对于本次外设请求传输终止的条件,以及双ADC模式且同时转换模式)
这样就与下一轮的转换数据分开了,因为相当于空出了一个16位大小来标识,就不会发生错位的情况
但1的问题依旧存在,且造成了16位的存储空间浪费(每一轮转换)
补充上述紫色说明:
1.我们在下图找到了双重ADC且规则同时模式的终止条件和标志位
2.我们在DMA的外设到存储器中找到了DMA请求传输终止的条件,下图,如果那句
因此,我们上述紫色背景的地方,是我们的猜想错误!!!
情况4:
我们需要多通道,且由软件触发来进行ADC转换,并用双/多ADC模式,规则组同步,不数据对齐,扫描模式,(连续转换/不),且 ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_2;
1.引到简要 我们上述
情况3 中探讨的得出的结果DMA_BufferSize是:M*L*N =M*L*(N/L)
2.当但我们做了实验发现,这里我们还是忽略了一个关于DMA关于9.3.10 可编程数据宽度、封装/解封、字节序的相关介绍细节。
先看下列图
上述我们汇总地说:
我们配置的NDT/DMA_SxNDTR 寄存器的数据传输数目,等于外设需要传输的数目(这里先指一次转换)
这是什么意思呢?
我结合之前提到的DMA_BufferSize并用通俗的话说:
就是我们之前数据打包的单元L:一个数据包的大小,一般整合了两个数据(16位的),之前我们是将其和通道数联系在一起说的。
而这里,我们需要联系外设SRAM的一个数据大小单元来说:
即是说,我们的数据大小(CDR寄存器)为32位,而外设SRAM的一个数据大小单元为16位
(为什么如此设置,和传输数据呢?)
1.由于我们是双/多ADC模式,数据存储在CDR中,当配置为ADC_DMAAccessMode_2时,即CDR两个数据项满了,触发DMA请求,这样效率高
2.但由于1的存储方式,我们无法判断或者显示出,哪些为ADC1转换的或者其他,因此一般我们在DMA搬运到SRAM中,以两个数据项分开来显示
(在多ADC模式下,第一次的是ADC1和ADC2的数据项,而后面的就不同了,这要更为精妙的程序或者设计来解决,我们这里先不探讨,先提出)
如下图
我们接着上面说:
我们只需要考虑一次转换要传输的数据单元L,当数据不对齐的情况下,要在以上的基础上用考虑一个传输问题,即:外设的一次传输的DMA搬运数据单元L,到SRAM中需要多少个单元(用S来表示)来存储(侧重S<L),或者能够存储多少外设数据单元L(侧重S>L)
并配置下列参数
// 外设数据大小
DMA_InitStructure.DMA_PeripheralDataSize =
// 存储器数据大小
DMA_InitStructure.DMA_MemoryDataSize =
那么,我们又回到了DMA_BufferSize
其实,我们上述 情况3 DMA_BufferSize是:M*L*N =M*L*(N/L)
其中L是用16位,为一个单元/单位的,不太严谨,在以后我们会碰到8位的,或者其他
(当然这一点再说,可以,但要注意)(这里就以16位单元吧,和之前一样)
我们拓展情况3中的DMA_BufferSize
我们这里也把传输的数据单元L和SRAM中需要多少个单元(用S来表示),换算为16位为基本单元
因此在情况4的讨论中
DMA_BufferSize是:M*L*N =M*L*(N/L)*(S/L)
简要说明:
以后对于情况N的讨论还会继续,如若是一个ADC为外部触发(多种情况的触发源),另一个为软件触发或者其他等等等等,这或许会引到其他参数和逻辑执行关系的探讨,
附录和更新补充:
(对于情况3的扩展再论!)
由那个7路通道的文章细想引出
1.若是数据对齐的情况下,双adc模式下,如果是交替转换,数据存储在CDR寄存器中,且触发DMA请求为一个数据项(16位)
那么就不存在,数据错位的情况,因为当最后一个通道转换完成后(一次转换),触发DMA请求,将其搬运到SRAM的数据单元中
2.如果上述改为是触发DMA请求为两个数据项,且还是交替模式,其他不变,
那么我们需要8个的SRAM数据存储单元来存储吗?
这里其实很不对劲,因为最后一个通道转换后,是无法触发DMA请求的,因为才一个数据项
3.最后的计算公式是对的
即:buffer_size为 M*L*(N/L)*(S/L)
4.当DMA将DR或者CDR的数据传输走后,那么对应的DR和CDR位为0吗,还是多少?
5.当通道7的buffer_size为4时,且SRAM数据存储单元为8个,触发DMA请求为两个数据项,那么这不是还是一样有这2的问题存在吗
6.当通道7的buffer_size为4时,且SRAM数据存储单元为7个,触发DMA请求为两个数据项,就算能够搬运,那这样会出现什么问题呢
(等于说32位的外设数据单元,本来是要搬运到SRAM数据存储单元中的两个,尽管其中一个没有数据——回到4)
7.若为同时转换模式,那就不存在触发DMA请求为一个数据项的情况,除非是最后一个通道转换
那这里还是那个问题——回到2
跟数据对齐好像没有关系了
8.如果为是连续转换,交替转换,触发DMA请求为一个数据项,且我们才存在数据对齐的错位的问题,因为要区分每一轮的数据,因此buffer_size为8
(这里我们需要思考一下,并不能简单的按照计算公式来)
9.若是在8的基础上,改为同时转换,那么我们如何在存储两个数据前,就抢先触发DMA请求
这是如何可能的?
当有一个数据项时,就触发DMA请求
但同时转换模式下,不是直接就生成两个数据项到CDR中了吗
这两者如何可能,如何协同工作呢?
(上述这些问题,待补充和探讨)