打印

stm32 DMA 的 buffersize 意义与设置?

[复制链接]
18833|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
yinguangwei|  楼主 | 2010-12-10 11:23 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Buffersize 具体指代缓冲区的大小(多少字节大小的缓冲区)还是缓冲区的数目(多少个指定宽度(DMA_PeripheralDataSize 或DMA_MemoryDataSize)的缓冲区)呢?

手册中给出:

Specifies the buffer size, in data unit, of the specified Channel. The data unit is equal to the configuration set in DMA_PeripheralDataSize or DMA_MemoryDataSize members depending in the transfer direction


比如2通道AD规则通道转换的16位结果存在AD_DR中,设置DMA_PeripheralDataSize
和DMA_MemoryDataSize的大小都为16位,  Buffersize怎么设置呢?  
这三者之间有什么关系,设置时需要考虑哪些因素?
沙发
yinguangwei|  楼主 | 2010-12-16 18:04 | 只看该作者
没人回答呀?

使用特权

评论回复
板凳
香水城| | 2010-12-16 18:07 | 只看该作者
那段英文很清楚呀。

如果你有32字节数据:
datasize=1  ==> buffersize = 32
datasize=2  ==> buffersize = 16
datasize=4  ==> buffersize = 8

使用特权

评论回复
地板
yinguangwei|  楼主 | 2010-12-28 09:46 | 只看该作者
3# 香水城

突然明白了:buffersize 只是一个要传输数据量的大小!  buffer 不是客观存在的一段内存空间, 当外设或者RAM的数据宽度宽时,在同样的数据数据情况下,数据宽度越宽,buffersize越小!

使用特权

评论回复
5
TinySnail| | 2014-10-14 20:12 | 只看该作者
香水城 发表于 2010-12-16 18:07
那段英文很清楚呀。

如果你有32字节数据:

ST官方库ADC RegSimulDualMode例程中,datasize = word,buffersize =16。看不懂。你的意思是两者的乘积是32吗?

使用特权

评论回复
6
TinySnail| | 2014-10-14 20:14 | 只看该作者
yinguangwei 发表于 2010-12-28 09:46
3# 香水城

突然明白了:buffersize 只是一个要传输数据量的大小!  buffer 不是客观存在的一段内存空间 ...

我不懂啊,怎么设置呢?

使用特权

评论回复
7
TinySnail| | 2014-10-14 20:28 | 只看该作者
香水城 发表于 2010-12-16 18:07
那段英文很清楚呀。

如果你有32字节数据:

看到好几个程序,buffersize都设置的等于通道数。

使用特权

评论回复
8
huzi2099| | 2014-10-14 21:07 | 只看该作者
TinySnail 发表于 2014-10-14 20:28
看到好几个程序,buffersize都设置的等于通道数。

不会啊,buffersize指的是一轮dma传送的数据量,实际就是计数值.

使用特权

评论回复
9
TinySnail| | 2014-10-15 08:05 | 只看该作者
huzi2099 发表于 2014-10-14 21:07
不会啊,buffersize指的是一轮dma传送的数据量,实际就是计数值.

不懂啥意思

使用特权

评论回复
10
xlsbz| | 2014-10-15 21:39 | 只看该作者
MA尺k

使用特权

评论回复
11
81190865| | 2015-1-22 11:59 | 只看该作者
看库函数中
DMAy_Channelx->CNDTR = DMA_InitStruct->DMA_BufferSize;
而CNDTR即数据传输数量 (Number of data to transfer)
数据传输数量为0至65535。这个寄存器只能在通道不工作(DMA_CCRx的EN=0)时写入。通
道开启后该寄存器变为只读,指示剩余的待传输字节数目。寄存器内容在每次DMA传输后递
减。
数据传输结束后,寄存器的内容或者变为0;或者当该通道配置为自动重加载模式时,寄存
器的内容将被自动重新加载为之前配置时的数值。
当寄存器的内容为0时,无论通道是否开启,都不会发生任何数据传输。

使用特权

评论回复
12
81190865| | 2015-2-9 16:14 | 只看该作者
mark一下,看过一次又忘了

使用特权

评论回复
13
aaron12| | 2015-4-4 17:34 | 只看该作者
最近也在学习,个人见解。

1、DMA_BufferSize到底是什么?

Specifies the buffer size, in data unit, of the specified Channel. The data unit is equal to the configuration set in DMA_PeripheralDataSize or DMA_MemoryDataSize members depending in the transfer direction

其实,这个缓冲区概念不是很准确,准确的应该是每次DMA传输的数据数量。在库函数stm32f10x_dma.c中可以找到:

DMAy_Channelx->CNDTR = DMA_InitStruct->DMA_BufferSize;

那这个 CNDTR 是什么呢?在STM32参考手册里有说明, Number of data to be transferred (0 up to 65535). The transfer stops once the DMA_CNDTRx register reaches zero. 它就是一个计数器,这个计数器的值就是DMA_BufferSize,每传送一个数据就减一,变成0的时候,从ADC外设到内存的传输(或相反)停止。此时可产生中断信号。假设DMA_BufferSize=10,那么ADC采集10次后,DMA就停止传输ADC的采集数据了。

那为啥取名叫buffer 呢,我猜是为了和DMA_MemoryInc_Enable配合。虽然传输计数是减少的,但是内存地址是增长的。在声明DMA_MemoryBaseAddr时候,其实DMA的就指向(是指向,不是开辟!)一个大小为DMA_BufferSize的数组,数组的开始地址为DMA_MemoryBaseAddr。这个数组就是缓冲区。

每次ADC采样后,就通过DMA把数据放在内存中,从DMA_MemoryBaseAddr+0地址开始放,直到DMA_MemoryBaseAddr+DMA_BufferSize-1,此时CNDTR变成0,传输结束。

2、DMA_BufferSize的大小应该取多少?

上面的讨论很多同学就疑惑了,这个大小应该取多少呢?暂时我建议你需要多少数据就写多少。

__IO uint16_t ADC_ConvertedValue[NUM];

一般,我们会定义一个变量存我们的数据,然后

DMA_InitStruct.DMA_BufferSize = NUM;

DMA_InitStruct.DMA_MemoryBaseAddr = (u32)&ADC_ConvertedValue;

这时候,缓冲区的大小和我们定义的数组一致,也方便我们操作。

但是如果DMA_BufferSize大于NUM会怎么样?根据上面问题1的解释,缓冲区地址其实就是我们的ADC_ConvertedValue地址,如果DMA_BufferSize为NUM+N,其实缓冲区就是ADC_ConvertedValue[NUM+N],再说一遍,Buffer的首地址和ADC_ConvertedValue相同,如果我们用指针访问,可以很好的验证。

__IO uint16_t *p;
p=ADC_ConvertedValue;

////省略代码,printf是串口通信改写的函数….

printf(“%4x\n”,ADC_ConvertedValue[NUM-1]);
printf(“%4x\n”,*(p+NUM));

printf(“%4x\n”,*(p+NUM+1));

你会很吃惊的发现,*(p+NUM)里面也有我们采样的数据。如果我们用ADC_ConvertedValue[NUM]访问则会出错,因为超出数组范围了。也就是说DMA_BufferSize可以大于NUM,但是大于NUM的地址属于不被定义的内容。从编程角度,它使用了未知的区域,如果这个地址定义别的变量,那么就会误操作这个变量。

__IO uint16_t ADC_ConvertedValue[NUM];
__IO uint16_t a[N];

比如我们定义时候,紧跟ADC_ConvertedValue定义一个a;一般编译器会把这两个变量的地址连在一起。那么在运行程序时候:

printf(“%4x\n”,ADC_ConvertedValue[NUM-1]);
printf(“%4x\n”,*(p+NUM));



printf(“%4x\n”,ADC_ConvertedValue[NUM-1]);
printf(“%4x\n”,a[0]);

是一样的数据。

很危险吧。a[0]的数据就被DMA覆盖了。

使用特权

评论回复
14
toney163| | 2015-5-19 15:23 | 只看该作者
我的理解是一次传输多个数据,不管你的数据是8位,16位还是32位,也就相当于你接收数据部分缓存的数据量。buf[buf_size],就是这个bufe_size。

使用特权

评论回复
15
化雨眠66| | 2015-10-6 18:23 | 只看该作者
香水城 发表于 2010-12-16 18:07
那段英文很清楚呀。

如果你有32字节数据:

单通道adc连续转换模式
开启dma,buffer_size=10,循环采集模式
我的疑问是:每次转换完成后采集10个数据 or 每次转换完成采集1个,连续循环采集10次?
谢谢香版主了~

使用特权

评论回复
16
aaron12| | 2015-11-24 21:23 | 只看该作者
化雨眠66 发表于 2015-10-6 18:23
单通道adc连续转换模式
开启dma,buffer_size=10,循环采集模式
我的疑问是:每次转换完成后采集10个数据 ...

3、ADC多通道DMA的真正采样顺序是什么?

很多同学想ADC多通道采样,比如两个通道,每个通道采10次。那么,到底是先把通道1采集10次,再轮到通道2采集10次。还是通道1和2轮流采集,第一次,先通道1,再通道2。第二次,先通道1,再通道2。直到第10次。这里假设的通道1比通道2优先级高。

很简单,ADC手册里写了,是通道1和2轮流采集。

你也可以做个实验,定义ADC_ConvertedValue[NUM],把两个通道接到不同电平,然后依次输出ADC_ConvertedValue,很明显可以看到数值交替。

4、ADC多通道内存数组为何定义为?

一般我们定义二维数组来存放采集的数据。如:

ADC_ConvertedValue[Sample_Num][Channel_Num]

那么为啥是这么写呢?不能是ADC_ConvertedValue[Channel_Num][Sample_Num]吗?

这个翻翻C语言的教材,C数组是按行存储的。加上ADC是轮流采样通道的,因此ADC_ConvertedValue[Sample_Num][Channel_Num]刚好每一列都是通道采样值。

使用特权

评论回复
17
玛尼玛尼哄| | 2015-11-24 22:37 | 只看该作者
如果你有32字节数据:
datasize=1  ==> buffersize = 32
datasize=2  ==> buffersize = 16
datasize=4  ==> buffersize = 8
这个是根据什么座的,乘积是要=32???好像理解对了

使用特权

评论回复
18
一条大河波浪宽| | 2015-12-8 09:54 | 只看该作者
MARK

使用特权

评论回复
19
yaoxihua| | 2016-4-17 13:19 | 只看该作者
aaron12 发表于 2015-4-4 17:34
最近也在学习,个人见解。

1、DMA_BufferSize到底是什么?

very good!

使用特权

评论回复
20
研发工程师| | 2017-10-13 11:37 | 只看该作者
13楼正解

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

10

主题

101

帖子

1

粉丝