串口接收DMA双缓冲

2019-07-20 17:26发布

本帖最后由 hi我歌月徘徊 于 2016-11-18 14:56 编辑

使用了串口接收DMA,DMA初始化
[mw_shl_code=c,true]重新贴一下代码
[mw_shl_code=applescript,true]DMA_InitTypeDef  DMA_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    if((u32)DMA_Streamx>(u32)DMA2)
    {
      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
         
    }else
    {
      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);
    }
  DMA_DeInit(DMA_Streamx);
     
    while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}
     

  DMA_InitStructure.DMA_Channel = chx;
  DMA_InitStructure.DMA_PeripheralBaseAddr = par;
  DMA_InitStructure.DMA_Memory0BaseAddr = mar;                                    //(1)
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//串口接收--内存
  DMA_InitStructure.DMA_BufferSize = ndtr;
  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_Normal;//使能双缓冲模式,将会自动设置为循环模式,参考手册9.3.8提到了
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_Init(DMA_Streamx, &DMA_InitStructure);
     
    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream5_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;      
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         
    NVIC_Init(&NVIC_InitStructure);
     
    DMA_DoubleBufferModeConfig(DMA2_Stream5,(uint32_t)RxBuff2, DMA_Memory_0);    //(2)设置第二缓冲区地址和选定当前缓冲区
  DMA_DoubleBufferModeCmd(DMA2_Stream5,ENABLE);                                          // (3) 使能

    DMA_ITConfig(DMA2_Stream5,DMA_IT_TC,ENABLE);//发送完成中断 当DMA_BufferSize =0才算发送完成
               
  DMA_Cmd(DMA2_Stream5,ENABLE);[/mw_shl_code]
不好意思[/mw_shl_code]

双缓冲模式只需要增加代码中的(2)(3),即可。
两个缓冲区,buff1和buff2,当dma完成以后,自动切换buff2当中继续存储
比如 buff1【1000】,buff2【1000】,DMA_BufferSize =100;发送100个字节到到了buff1,dma就自动将目标地址设为buff2,那么你在发送100字节就到了buff2当中了,如此循环。

但是假如我换一种方式,每当串口来一次数据,我就换一次缓冲区,
比如第一次数据,dma到了buf1;第二次数据,dma到了buf2,第三次数据,又到了buf1,但是buf1当中第一次的数据就会被覆盖。怎么样才能不被覆盖呢?

打开了串口空闲中断,
每当串口空闲中断的时候,都会将当前buff切换,比如初始化dma时,当前buff为buff1,那么空闲中断中将当前buff设为buff2第一次串口助手发送:0 1 2 3
接收:

          buff1:0 1 2 3
          buff2:0 0 0 0
空闲中断,设置当前buff为 buff2

第二次串口助手发送:0 1 2 3
          buff1:0 1 2 3  (第一次发送的值)
          buff1 : 0 1 2 3
空闲中断,设置当前buff为buff1

第三次串口助手发送:0 1 2 3
          buff1:0 1 2 3       此时buff1中收到的值被更新覆盖,其实我想达到的效果为  buff1:0 1 2 3 0 1 2 3   数组指针后移,本来设置的就是内存地址自增(同一个缓冲区内存是自增的),但是一切换缓冲区,内存地址都会从0开始的!!!
          buff1 : 0 1 2 3 (第二次发送的值)
怎么解决这个问题呢??  总不能每次中断都把数据取出来吧?这样也太浪费时间了。还有一种方法,就是在指定缓冲区的时候,把内存基地址在指定一下(buf1地址+上一次收到的数据个数),简单试了一下:
                        DMA_Cmd(DMA2_Stream5, DISABLE);
                        rx_num=SEND_BUF_SIZE-DMA_GetCurrDataCounter(DMA2_Stream5);//获得接收数据项数
                        DMA2_Stream5->CR |= (uint32_t)(DMA_SxCR_CT); /* Set Memory 1 as current memory address */
                        DMA2_Stream5->M0AR=(uint32_t)&RxBuff2+rx_num;     当前buff存储位置=buff2基地址+上一次接收数据个数
                        DMA_Cmd(DMA2_Stream5, ENABLE);  

这样也可实现,但是数据如果多了 感觉很麻烦了。。。。
请问大神有没有什么好的办法呢? 感激不尽
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。