打印
[应用相关]

DMA双缓冲区(也称乒乓缓冲)

[复制链接]
1183|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
回复就哭哭|  楼主 | 2023-11-25 12:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一.乒乓缓冲原理
       一般情况下,串口数据 DMA 传输到 BUF1(内存上的一片连续的缓冲区)的过程中,是不
建议对 BUF1 进行操作的。但由于串口数据是一个连续传输的过程,比如接收 GPS 数据,不
能等待 BUF1 满了才处理数据,你 CPU 在处理数据的同时,串口源源不断接收数据,此时会
造成串口数据丢失,而乒乓缓冲就完美地解决了这个问题。
       具体过程是:当串口 BUF1 满了时,DMA 的目标地址迅速切换到 BUF2,此时可以处理
BUF1 的数据;当串口 BUF2 满了时,DMA 的目标地址迅速切换到 BUF1,此时可以处理 BUF2
的数据。如此一直循环下去,就像打乒乓球一样,你推我挡,故称作乒乓缓冲。二 . DMA就不在这里班门弄斧的讲解了,分享一下程序吧。
DMA配置代码:
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                 //外设作源头

DMA_InitStructure.DMA_BufferSize = dma_len;                               //BUF 大小

DMA_InitStructure.DMA_PeripheralInc  =  DMA_PeripheralInc_Disable;  //外设地址寄存器不变

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;    //内存地址寄存器递增
这两项的配置还是很好理解的,比如在这里我们是要将内存里边的东西发到 USART1 中去,每次发送 8 位,
那么外设地址当然不能改变,而每一次发送内容都是不一样的,而且数组在内存中的存放就是递增的,所以内存地址寄存器要递增。

下边是设置数据宽度:

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为 8 位

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //正常缓存模式(非连续传输)

一些基本定义:

#define dma_len 100    //定义串口 DMA 传输数据长度(如果串口一次接收数据没有达到 dma_len 个 byte,则不会发生 DMA 中断)  

extern u8 USART1_DMA_Buf1[dma_len]; //BUF1

extern u8 USART1_DMA_Buf2[dma_len];     //BUF2

typedef enum {BUF_NO1=0,BUF_NO2=1}BUF_NO;

extern BUF_NO Free_Buf_Now;

extern bool Buf_Ok;


乒乓思想在这里体现:

void DMA1_Channel5_IRQHandler(void)

{

       if(DMA_GetITStatus(DMA1_IT_TC5))

       {

               //DataCounter = DMA_GetCurrDataCounter(DMA1_Channel5);

//获取剩余长度,一般都为 0,调试用

               DMA_ClearITPendingBit(DMA1_IT_GL5);     //清除全部中断标志                  



              //转换可操作 BUF

              if(Free_Buf_Now==BUF_NO1) //如果 BUF1 空闲,将 DMA 接收数据赋值给 BUF1

              {      

                     DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf1;

                     DMA_Init(DMA1_Channel5, &DMA_InitStructure);

                     Free_Buf_Now=BUF_NO2;

              }

              else    //如果 BUF2 空闲,将 DMA 接收数据赋值给 BUF2

              {

                     DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf2;

                     DMA_Init(DMA1_Channel5, &DMA_InitStructure);

                     Free_Buf_Now=BUF_NO1;

              }

              Buf_Ok=TRUE;  

       }

}


当发现有一个缓冲接收满的时候,可以上传数据。将另外一个缓冲作为接收数据的目的地,周而复始。屡试不爽。

使用特权

评论回复
沙发
tfqi| | 2023-12-28 16:41 | 只看该作者
双缓冲区域的大小受到什么的限制呢

使用特权

评论回复
板凳
kxsi| | 2023-12-28 17:58 | 只看该作者
所有型号的单片机都可以有这个功能是吗

使用特权

评论回复
地板
coshi| | 2023-12-28 19:11 | 只看该作者
一般双缓冲都是使用的乒乓缓冲原理吗

使用特权

评论回复
5
qcliu| | 2023-12-28 20:27 | 只看该作者
这种双缓冲机制是不是也加大了判定的复杂度啊

使用特权

评论回复
6
zljiu| | 2023-12-28 21:39 | 只看该作者
一般只有在数据传输速度比较快  数据吞吐量比较大的时候才会使用双缓冲机制吧

使用特权

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

本版积分规则

24

主题

358

帖子

0

粉丝