基于STM32介绍DMA的双缓冲模式

发布者:快乐旋律最新更新时间:2024-08-19 来源: cnblogs关键字:STM32  DMA  双缓冲模式 手机看文章 扫描二维码
随时随地手机看文章

目前STM32家族中有些系列支持DMA的双缓冲模式,比如STM32F2/STM32F4/STM32F7等系列。尤其随着人们对STM32F4/F7系列应用不断拓宽和加深,在设计中运用到DMA双缓冲的场合也越来越多。STM32芯片中的DMA又可分为两大类,一类是通用DMA,一类是专用DMA,比如用于USB,TFT LCD,ETHERNET等外设应用上的DMA。这里要谈的是基于通用DMA的话题,不妨以STM32F4系列芯片为例。


关于STM32F4的DMA双缓冲传输在STM32F4系列的参考手册里做了简单描述。因为它是基于介绍了单缓冲模式的DMA介绍之后接着介绍的,稍显言简意赅。


相比单缓冲的数据流,双缓冲多了一个DMA存储区和相应的存储指针;

如果使能DMA双缓冲,硬件会自动使能DMA的循环传输模式;

每一批数据传输结束,或者说每次传输事务结束时通过交换存储指针实现更换存储区的目的。

4.DMA双缓冲模式仅在外设与存储器间进行,不支持memoryto Memory间的传输。

基于STM32介绍DMA的双缓冲模式

基于DMA双缓冲模式的的特点,不难理解在应用中必须开辟两个存储区以及存放两个存储区首地址的存储寄存器,DMA_SxM0AR和DMA_SxM1AR。

DMA_SxM0AR:指向存储区0,单缓冲模式下默认使用该寄存器做存储区指针。

DMA_SxM1AR:指向存储区1,仅在DMA双缓冲模式下才能使用。

DMA正在访问的当前存储区由CT@DMA_SxCR位表示

CT = 0:DMA正在访问存储区0,CPU可以访问存储区1

CT = 1:DMA正在访问存储区1,CPU可以访问存储区0

基于STM32介绍DMA的双缓冲模式

使用DMA双缓冲传输,既可以减少CPU的负荷,又能最大程度地实现DMA数据传输和CPU数据处理互不打扰又互不耽搁,同时也给应用开发也带来方便。比如,假设你使用DMA单存储缓冲,有些情况下可能是等待DMA搬完了数据,CPU才过来处理;有些情况下可能是DMA一边传输,CPU也一边来访问,这时往往会使用到环形存放和读取,代码实现起来稍显繁琐也容易出纰漏。如果改为DMA双缓冲模式,应用上实现起来也就简洁很多。再加上DMA双缓冲模式的循环特性,使用它对存储区的空间容量要求也会大大降低。尤其在大批量数据传送时,你只需开辟两个合适大小的存储区,能满足DMA在切换存储区时的当前新存储区空出来就好,并不一定要开辟多大多深的存储空间。有过这方面应用经验的工程师可能就有体会,单纯一味地加大双缓冲区的深度并不明显改善数据传输状况。

关于这点不妨打个比方,某茶馆有俩芳名分别为CPU和DMA的伺茶MM,,每人手里有个同样茶壶。DMA负责把她手里的茶壶装满茶水就好,CPU就负责用从DMA手里接过装满茶水的壶给客人倒茶,倒完了用空壶与DMA交换装满茶水的壶继续工作。显然,只要保证CPU妹妹茶壶里总有茶水,至于那两个茶壶选多大容积并不是很重要。倒是那个茶壶进出口径对整个事情的效率有影响。

关于DMA双缓冲话题,我们也不妨看看一个具体的案例加深下印象。案例来自网络,为了尽量压缩篇幅,我省却了部分配置代码,留下需要交流的关键语句。

&&&&&&&&&&&&&&&&&

F407 DMA的double Buffer mode上卡了好久了!大家看看配置哪里出问题了?

uint8_tBuffer0[] = {0x11,0x22,0x33,0x44}; //无符号的8位整型数

uint8_tBuffer1[] = {0xaa,0xbb,0xcc,0xdd}; //无符号的8位整型数

voidUSART3_DMA1_Configuration(void)

{

......

DMA_InitStructure.DMA_PeripheralBaseAddr= USART3_DR_Addr; //外设首地

DMA_InitStructure.DMA_Memory0BaseAddr= (uint32_t)Buffer0; //内存区首地址(1)

DMA_InitStructure.DMA_DIR= DMA_DIR_MemoryToPeripheral; //内存->外设

DMA_InitStructure.DMA_BufferSize= 8; //*****传输数据个数为8 *****(2)

DMA_InitStructure.DMA_PeripheralInc= DMA_PeripheralInc_Disable;

DMA_InitStructure.DMA_MemoryInc= DMA_MemoryInc_Enable; //

DMA_InitStructure.DMA_PeripheralDataSize= DMA_PeripheralDataSize_Byte;

DMA_InitStructure.DMA_MemoryDataSize= DMA_MemoryDataSize_Byte;

DMA_InitStructure.DMA_Mode= DMA_Mode_Circular; //循环传输

……

DMA_DoubleBufferModeConfig(DMA1_Stream3,(uint32_t)Buffer1, DMA_Memory_1);//(3)

DMA_DoubleBufferModeCmd(DMA1_Stream3,ENABLE);//(4)enable double buffle

DMA_Init(DMA1_Stream3,&DMA_InitStructure);

DMA_Cmd(DMA1_Stream3,ENABLE); //使能 DMA1_Stream3通道

DMA_ClearITPendingBit(DMA1_Stream3,DMA_IT_TCIF3);

DMA_ITConfig(DMA1_Stream3,DMA_IT_TC, ENABLE);

}

&&&&&&&&&&&&&&&&&

发帖者述说,如果将蓝色语句(3)的DMA_Memory_1改成DMA_Memory_0的话,就能正常打印出 11 22 33 44 aa bb cc dd,如果换成DMA_Memory_1的话,现象就不对了!输出的结果却是aa bb cc dd 15 00 08 52。请问是怎么回事?

显然发帖者使用STM32F4系列芯片DMA的双缓冲功能,应该只是做做实验而已。他开辟了两个长度均为4字节的缓冲存储区BUFFER0和BUFFER1。从基于ST固件库函数代码配置角度看,双缓冲模式相比单缓冲模式,就是多了(3)(4)两句,其它都一样。这里我们特别留意下其中(1)(2)(3)句配置代码。

绿色语句(1)配置了存储区0指针指向的地址;

红色代码语句(2)处给出了DMA每轮的传输数据个数8;

蓝色代码语句(3)处配置存储区1的地址和选择第一个当前存储区;

整体上看,该配置都配置了。结合我们上面的原理介绍,可以看出红色代码语句(2)配置每轮DMA传输个数为8有点问题,传输的数据宽度为BYTE,两个缓冲区各自空间大小为4 BYTE。也就是说每传输4个BYTE数据就轮换存储区重开下一轮传输,每轮DMA传输的数据个数应该是4而不是8。

现在发帖者反馈的是调整语句(3)便会呈现不同的结果,当把第(3)句的当前存储区改为Memory0时就会呈现貌似正确的结果。那是为什么呢?

其实这个貌似正确的结果是种巧合的假象。巧合的是在定义BUFFER0和BUFFER1时,因为二者紧邻在一起定义,编译器刚好把二者安排在连续的8个字节存储单元。而发帖者又刚好将每轮DMA传输数据个数定义为8个缓冲单元,这意味着每传输8个缓冲单元数据才切换缓冲区。当从Memory0即BUFFER0开始传输时,连续的8个数据在第一轮就读了出来,也就是说这8个数据并未经过缓冲区的切换就读出来了。而当发帖者把第(3)句的第一次使用的当前存储区改为Memory1时就没那么幸运了。因为这次DMA从BUFFER1开始连续读取8个数据单元,读完BUFFER1内的4个单元后,后面的4个缓存单元就是些不确定的数据,自然一眼就看出结果不对了。

基于STM32介绍DMA的双缓冲模式

实际上,当把上面红色代码语句(2)处的DMA传输数据个数调整为4时就结果正常了,至于第(3)句的起始当前缓冲区的选择无关紧要。

有人在使用DMA双缓冲模式时,经常为这个传输个数纠结,尤其从单缓冲模式转为双缓冲模式时。其实,不管单缓冲还是双缓冲模式,对于整体需要传输的数据个数是不会增减的,只是双缓冲模式由之前的单缓冲模式变成双缓冲循环。一般来讲对于那些无需循环的小数量数据传输没必要使用DMA双缓冲模式。

相比单缓冲DMA传输,双缓冲模式在设置DMA传输数据个数时应更为灵活。比方之前单缓冲DMA传输时,每轮传输数据个数假设为1024。当改为双缓冲循环模式时,对应每个缓冲区的DMA传输数据个数并不一定要设置为1024,可能设置50、100就能满足要求,因为这里有两个存储区且是不停轮换的。不过,对于这个DMA传输数据个数的设置和使用要注意几点:

1.该数据不要太小,因为DMA传输过程中往往伴随DMA传输完成中断,如果过小会导致中断频繁和切换频繁,并非好事。

2.该数据也不必过大,上面也提过,一味加大缓冲容量对提升传输速度并无实质改善。同时也得考虑芯片内存容量的限制与合理使用。

3.尽管DMA双缓冲模式基于循环传输,但实际应用中DMA传输请求总有中止或停止的时候。比如,一副图像数据,完全可能不是刚好结束在事先设置的DMA传输数据个数的整数倍的位置点。那么,最后的这批缓冲数据因为未满而不会发生缓冲交换请求或传输完成请求。此时如果不做适当的处理,这批缓冲数据就可能被无意中丢弃掉。所以,我们在程序中需要设计些基于两次缓冲切换的超时机制,及时收取最后一批缓冲区的数据,以防因不能产生传输完成或缓冲切换事件而导致数据丢失的现象。


关键字:STM32  DMA  双缓冲模式 引用地址:基于STM32介绍DMA的双缓冲模式

上一篇:003_STM32程序移植之_W25Q64
下一篇:STM32微控制器的工作原理和应用 STM32微控制器的命名规则

推荐阅读最新更新时间:2024-11-12 11:04

45.串口IAP基本原理
学习这个教程前首先需要了解Flash的编程原理。 一。stm32 IAP介绍 1. stm32的编程方式 2. stm32的启动模式选择 BOOT1置0,BOOT0置1,程序从系统存储器中执行启动程序BootLoader代码,也就是从串口中下载程序到主存储器中。 BOOT0置0,BOOT1不管是置0还是置1,主闪存存储器被选为启动区域,即执行写入的应用程序。 3. IAP下载程序流程 注:自己写的BootLoader程序与系统的BootLoader程序是不同的。需要先通过ICP下载到BootLoader存储区域中。然后跳转到应用程序执行。 4.一般程序的执行流程 0x08000000中存放栈顶
[单片机]
45.串口IAP基本原理
【菜鸟入门】stm32 之 ADC 模数转换
今天对ADC进行了研究,个人感觉,ADC的配置相对也对比较复杂一点,因为需要配置的寄存器是比较多的! 在datasheet 关于ADC的简介中,明确说明ADC的输入时钟不得超过14M,他是有PCLK2经过分频得来的 这次我们选用ADC1_IN0作为讲解的对象,ADC1_IN0 -- PA0 所以在配置时钟的时候要配置PA0和ADC1,关于怎么配置,已经说的很清楚了。 在配置PA0的输入模式方面我要说明一下,有好多人在这个地方还是很郁闷的 在8.1.11 外设GPIO的配置中每种配置都说的很清楚,如果我们对那中模式配置有疑问,我们都可以直接在这里查找 这里的ADC我们采用模拟输入模式: 所以我们这里需要
[单片机]
【菜鸟入门】<font color='red'>stm32</font> 之 ADC 模数转换
stm32 RTC实时时钟[操作寄存器+库函数]
RTC 是Real Time Clock 的简称,意为实时时钟。stm32提供了一个秒中断源和一个闹钟中断源。 RTC的技术器是一个32位的计数器,使用32.768khz的外部晶振。 2038年问题  在计算机应用上,2038年问题可能会导致某些软件在2038年无法正常工作。所有使用UNIX时间表示时间的程序都将受其影响,因为它们以自1970年1月1日经过的秒数(忽略闰秒)来表示时间。这种时间表示法在类Unix(Unix-like)操作系统上是一个标准,并会影响以其C编程语言开发给其他大部份操作系统使用的软件。 在大部份的32位操作系统上,此“time_t”数据模式使用一个有正负号的32位元整数(signedint
[单片机]
STM32 NVIC笔记
看了一天的stm32的中断配置,对NVIC有了基本的了解(要了解NVIC,可以看《cortex M3权威指南》)。总结为3步: 1.设置中断分组寄存器 AIRCR 共0~4五组。地址:0xe000E_d00C 2.设置对应中断优先级 NVIC- IPR x=0~15配置60个中断优先级,每个中断一字节控制,只用到高4位 地址:0xE000_E400 3.使能对应中断 NVIC- ISER x=0~1 每一位对应一个外部中断使能 地址:0xE00_E100 void exti_init()//外部中断15~10 中断编号:40 { RCC- APB2ENR|=1 0; //开启复用时钟 RCC- APB2ENR
[单片机]
MSP430程序库<十四>DMA程序库
直接存储器存取(DMADirect Memory Access)方式是用硬件实现存储器与存储器之间或存储器与IO设备之间直接进行高速数据传送,不需要CPU的干预。这种方式通常用来传送数据块。MSP430f16x系列单片机内部含有DMA模块,而且几乎内部所有外设都可以触发DMA开始存取数据。这里实现了这个模块的程序通用的函数库,方便使用。 硬件介绍: MSP430F15X/16X 系列单片机具有DMA 控制器,从而能够为数据高速传输提供保证。例如,通过DMA控制器可以直接将ADC 转换存贮器的内容传到RAM 单元。 MSP430系列单片机扩展的DMA具有来之所有外设的触发器,不需要CPU的干预即可提供先进的可配置的数据传输能
[单片机]
MSP430程序库<十四><font color='red'>DMA</font>程序库
STM32的“外部中断”和“事件”区别和理解
凡从事过ST MCU应用开发的人往往会遇到事件、中断事件 中断三个概念或术语。这三个概念彼此关联,有时会让人有点混淆或犯迷糊。 先拿一件生活中的事情打比方对上述三个概念做个基本的粗略理解,之后再分享一个STM32 GPIO外部中断配置案例。 比如一老师在教室里给学生们上课。课堂上的学生可能做出各种行为动作,比方做笔记、打哈气、翻书包、讲小话等,我们把这些行为统称为事件,其中有些行为老师往往只是视而不见,继续他的上课;而有些行为可能导致老师的上课中止,比方讲小话,并对学生的相关行为予以警告、批评或纠正等,然后继续上课。我们把老师因为学生的某些行为而中止授课,并产生后续动作,之后接着上课的这个过程理解为中断或中断响应。我们把可能导致老
[单片机]
STM32的各种时钟系统的应用解析
时钟系统是处理器的核心,所以在学习STM32所有外设之前,认真学习时钟系统是必要的,有助于深入理解STM32。 重要的时钟: PLLCLK,SYSCLK,HCKL,PCLK1,PCLK2 之间的关系要弄清楚; 1、HSI:高速内部时钟信号 STM32单片机内带的时钟 (8M频率) 精度较差 2、HSE:高速外部时钟信号 精度高 来源(1)HSE外部晶体/陶瓷谐振器(晶振) (2)HSE用户外部时钟 3、LSE:低速外部晶体 32.768kHz 主要提供一个精确的时钟源 一般作为RTC时钟使用 在STM32中,有五个时钟源,为HSI、HSE、LSI、LSE、PLL。 ①、HSI是高速内部时钟,RC振荡器,频率为8MHz。 ②
[单片机]
STM32系列是大端还是小端?
ARM的手册上有关于大小端的描述,如下: The processor can access data words in memory in little-endian format or big-endian format. It always accesses code in little-endian format. Note: Little-endian is the default memory format for ARM processors. STM32是固定配置为小端的 The bytes are coded in memory in Little Endian format. The lowest number
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved