lihui710884923
认证:VIP会员
所在专题目录 查看专题
基于单片机的LCD菜单框架设计(附源码)
单片机为啥要用结构体?
单片机驱动LCD的编程思想
stm32的PWM如何驱动RBG灯带
DMA之“乒乓缓冲”
STM32 硬件CRC和软件CRC速度比拼
作者动态 更多
单片机RTC的中断剖析
03-09 15:28
串口通讯的来龙去脉
02-14 17:32
stm32单片机的USB烧录程序
2023-09-08 22:48
基于CUBEMX的HID双向通讯
2023-08-24 20:46
单片机的增量编码器正交解码
2023-08-24 20:17

DMA之“乒乓缓冲”

在这几天学习F407单片机中,的确好多功能比F1好多了,以下简单总结。

举个例子,串口数据传输到flash,从而解释了乒乓缓冲。

串口的数据DMA 传输进BUF1 的过程中,是不建议对BUF1 进行操作的.但由于串口数据是不会等待的直传,所以你总不能等BUF1 满了,才往FLASH 上写,因为这时候串口数据依旧是源源不断.于是,使用双缓冲就变的理所当然了.当BUF1 满了的时候,就马上设置DMA的目标为BUF2,并且BUF1的数据往25F080上灌.当串口DMA写满了BUF2的时候,再设置DMA的目标为BUF1,如此一直循环,就好像打乒乓球那样吧,所以就叫乒乓缓冲.用这个方法的速度极限就是,你必须确保两点a.DMA 灌满了BUF1 的时候,会发生中断,此时切换DMA 的目标缓冲为BUF2,而且切换的过程必须在新的串口数据溢出之前完成.b.在DMA的BUF1满之前,另外一个有数据的BUF2必须能全部写进flash。

就是切换DMA存储的数组,因为F1单片机没有DMA硬件缓冲区。

但是在学习F4单片机时,看手册:

其实大家不要误解,我差点就上当了,这是dma的FIFO模式,与双缓存没联系。

双缓冲模式,只有在F2/F4/F7,H7等系列才有这个功能。相比单缓冲的数据流,双缓冲多了一个DMA存储区和相应的存储指针;如果使能DMA双缓冲,硬件会自动使能DMA的循环传输模式;每一批数据传输结束,或者说每次传输事务结束时通过交换存储指针实现更换存储区的目的。DMA双缓冲模式仅在外设与存储器间进行,不支持memoryto Memory间的传输。

F4单片机DMA具备双缓冲机制,可以让数据在传输时候不断流,也就是我们所谓的PING-PONG-BUFFER即乒乓缓冲,也就是说有AB两个BUFFER,DMA访问A时候,CPU访问B,DMA访问B时候,CPU访问A.这种实现导致总线矩阵相对复杂,所以,一般低端MCU也不会有这个机制

手册也有介绍:

1:开辟两个缓冲区
#define DMA_Meo_Size 100
u8 Buffer0[DMA_Meo_Size]={0x00};
u8 Buffer1[DMA_Meo_Size]={0x00};


2:配置双缓冲模式
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  
//其余和单缓冲模式一样
//内存0 即Buffer0先被传输
DMA_DoubleBufferModeConfig(DMA2_Stream1,(uint32_t)&Buffer1,DMA_Memory_0);
DMA_DoubleBufferModeCmd(DMA2_Stream1,ENABLE);

在每个缓冲区满了后会产生传输完成中断
硬件自动切换缓冲区。

3:根据CT标志查看DMA正在访问哪一个缓冲区

/**
  * @brief  Returns the current memory target used by double buffer transfer.
  * @param  DMAy_Streamx: where y can be 1 or 2 to select the DMA and x can be 0
  *          to 7 to select the DMA Stream.
  * @retval The memory target number: 0 for Memory0 or 1 for Memory1. 
  */
uint32_t DMA_GetCurrentMemoryTarget(DMA_Stream_TypeDef* DMAy_Streamx)
{
  uint32_t tmp = 0;

  /* Check the parameters */
  assert_param(IS_DMA_ALL_PERIPH(DMAy_Streamx));

  /* Get the current memory target */
  if ((DMAy_Streamx->CR & DMA_SxCR_CT) != 0)
  {
    /* Current memory buffer used is Memory 1 */
    tmp = 1;
  }  
  else
  {
    /* Current memory buffer used is Memory 0 */
    tmp = 0;    
  }
  return tmp;
}

DMA_GetCurrentMemoryTarget(DMA2_Stream1);
如果返回值为1,说明DMA正在访问缓冲区1,则CPU可以访问缓冲区0的数据
if(DMA_GetCurrentMemoryTarget(DMA2_Stream1) == 1)

归根结底还是要建立两个缓冲区的数组。

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 3
收藏 4
关注 191
成为作者 赚取收益
全部留言
0/200
成为第一个和作者交流的人吧