OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5131|回复: 3

关于UART+DMA接收问题,求解

[复制链接]

5

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2017-1-22
在线时间
20 小时
发表于 2019-10-30 16:16:50 | 显示全部楼层 |阅读模式
10金钱
UART+DMA实现是一件挺普通的事情了,不外乎串口空闲中断+DMA接收完成中断来处理。实际调试时发现了几个问题,这里向各位求助一下。
1.当检测到串口空闲中断时,这个时候需要DISABLE DMA读出数据后再ENABLE DMA。如果在这段时间内来数据了怎么办?各位有什么好办法?如果这个问题解决不了,还不如直接用接收中断来处理了。亦或者是DMA功能的应用场景就不适合这种会有数据突发传输的情况?仅适合于周期性数据传输的情况?
2.stm32f0系列是没有DMA双缓冲功能的,但之前看到过人工做两个buffer,在触发DMA完成中断里切换DMA内存基地址,进行人工的双缓冲buffer。但我实际测试时发现效果并不理想。
3.我使用XCOM串口调试助手,以10ms间隔不停发送100byte数据时,发现DMA接收到的数据周期性丢失2~3byte.我怀疑是描述的问题1导致的。但是按道理来讲,如果是问题1的情况,应该会触发ORE中断吧?但是并不是每次都能检测到ORE中断。
各位大佬,有什么想法???
代码如下:
  1. //初始化
  2. void UartRecvDMACommInit(UART_EXT_INTERFACE* pMe)
  3. {
  4.         DMA_InitTypeDef DMA_InitStructure;
  5.         DMA_DeInit(pMe->pDMARecv->channel);
  6.         USART_ITConfig(pMe->USARTx, USART_IT_IDLE, ENABLE);
  7.         DMA_RemapConfig(pMe->pDMARecv->DMAy, pMe->pDMARecv->map);
  8.         /* Common DMA configuration */
  9.         DMA_InitStructure.DMA_BufferSize = pMe->pDMARecv->maxLen;
  10.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  11.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  12.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  13.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  14.         DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  15.         DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  16.         /* DMA1 Channel1 configuration */
  17.         DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)pMe->pDMARecv->buf;
  18.         DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  19.         DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
  20.         DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(pMe->USARTx->RDR));
  21.         DMA_Init(pMe->pDMARecv->channel, &DMA_InitStructure);
  22.         USART_DMACmd(pMe->USARTx, USART_DMAReq_Rx, ENABLE);// ??DMA?????????
  23.         DMA_ClearFlag(pMe->pDMARecv->flagGL);  // clear all DMA flags
  24.         DMA_ITConfig(pMe->pDMARecv->channel,DMA_IT_TC,ENABLE);  //open DMA send inttrupt
  25.         DMA_Cmd(pMe->pDMARecv->channel, ENABLE);
  26. }
复制代码

  1. //串口中断
  2. if(USART_GetFlagStatus(pMe->USARTx, USART_FLAG_ORE) != RESET)
  3.         {
  4.                 USART_ClearITPendingBit(pMe->USARTx,USART_IT_ORE);
  5.                 USART_ReceiveData(pMe->USARTx);
  6.                 UartTest.ORECnt++;
  7.         }
  8.         if(USART_GetITStatus(USART1,USART_IT_IDLE)!= RESET)
  9.         {
  10.                
  11.                 pMe->USARTx->ISR;//??SR,???DR????
  12.                 pMe->USARTx->RDR;
  13.                 //tem=tem;
  14.                 pMe->rxStatus = UART_IDLE;
  15.                 DMA_Cmd(pMe->pDMARecv->channel, DISABLE);
  16.                 pMe->curRecvLen = pMe->pDMARecv->maxLen - pMe->pDMARecv->channel->CNDTR;// ??buf??????buf??,??????????
  17.                 if(pMe->curRecvLen != 100)
  18.                         pMe->curRecvLen = pMe->curRecvLen;
  19.                 UartTest.recvLen += pMe->curRecvLen;
  20.                 if(PushBytesInQueue_Q(pMe->pQueue, pMe->pDMARecv->buf, pMe->curRecvLen))
  21.                         UartTest.recvPushInLen += pMe->curRecvLen;
  22.                 //memset(pMe->pDMARecv->buf, 0, pMe->pDMARecv->maxLen);
  23.                 pMe->pDMARecv->channel->CNDTR        =        pMe->pDMARecv->maxLen ;
  24.                 DMA_Cmd(pMe->pDMARecv->channel, ENABLE);
  25.                
  26.                 USART_ClearITPendingBit(pMe->USARTx, USART_IT_IDLE);
  27.         }
复制代码
  1. //DMA接收完成中断
  2. if(DMA_GetITStatus(pMe->pDMARecv->flagTC) != RESET)
  3.         {
  4.                 DMA_ClearFlag(pMe->pDMARecv->flagGL);  
  5.                 pMe->rxStatus = UART_IDLE;
  6.                 DMA_Cmd(pMe->pDMARecv->channel, DISABLE);
  7.                 pMe->curRecvLen = pMe->pDMARecv->maxLen - pMe->pDMARecv->channel->CNDTR;
  8.                 UartTest.recvLen += pMe->curRecvLen;
  9.                 if(PushBytesInQueue_Q(pMe->pQueue, pMe->pDMARecv->buf, pMe->curRecvLen))
  10.                         UartTest.recvPushInLen += pMe->curRecvLen;
  11.                 //memset(pMe->pDMARecv->buf, 0, pMe->pDMARecv->maxLen);
  12.                 pMe->pDMARecv->channel->CNDTR        =        pMe->pDMARecv->maxLen ;
  13.                 DMA_Cmd(pMe->pDMARecv->channel, ENABLE);
复制代码


正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

17

主题

46

帖子

0

精华

初级会员

Rank: 2

积分
136
金钱
136
注册时间
2020-1-15
在线时间
39 小时
发表于 2020-4-20 14:31:00 | 显示全部楼层
一进入中断,立即memcpy(缓存, RX_BUF, SIZE );然后memset (RX_BUFF, 0 ,SIZE ),然后不用开关DMA,而是将DMA count归零。
也就是只有三行代码,猜测串口空闲时间应该够3行代码执行吧。
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手上路

积分
23
金钱
23
注册时间
2018-11-28
在线时间
6 小时
发表于 2021-6-1 22:43:22 | 显示全部楼层
我也碰到了这个问题,楼主怎么解决的
回复

使用道具 举报

13

主题

179

帖子

0

精华

高级会员

Rank: 4

积分
829
金钱
829
注册时间
2018-12-19
在线时间
169 小时
发表于 2021-6-2 12:39:37 | 显示全部楼层
准备入坑DMA串口接收
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-23 07:51

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表