OpenEdv-开源电子网

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

STM32 UART4 DMA方式接收、数据过载错误

[复制链接]

21

主题

58

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
263
金钱
263
注册时间
2011-8-23
在线时间
31 小时
发表于 2013-3-20 09:47:00 | 显示全部楼层 |阅读模式
各位大神们!

小弟用STM32 UART4接收(用DMA方式)串口WIFI模块数据时  UART4 有时会出现过载错误

现象描述:
WIFI模块是接收/发送 实时音频传输的数据,8K采样率,每采集500个字节对方发送一次
UART4 DMA方式接收 波特率:230400  
  接收方法:当UART4总结空闲标志置1了,才去读取DMA接收到的数据

串口WIFI模块的数据量:
网络良好时: 每隔40ms有会500Byte数据
网络较差时:每隔40ms左右会有500个Byte,但500Byte可能会被分成十多次从WIFI模块串口发送出来,每次发送的间隔有几毫秒甚至底于1毫秒
                   (过载错误时基本上是在这个情况下出现的)
网络很差时:有时连续几百毫秒都没数据,突然3000左右字节连接发送过来
代码如下:
/*****************************************************
** 查询DMA接收数据的状态
** buff: 存储接收到的数据
** 返回:没有接收数据返回0
         否则返回接收到数据的个数
*****************************************************/
  1. unsigned short Receive_UART4(unsigned char *buff)
  2. {
  3. unsigned short remaining,i,num;
  4. static unsigned short count = UART4_RX_SIZE;
  5. if(USART_GetFlagStatus(UART4,USART_FLAG_IDLE))
  6. {
  7. //思想:Receive_UART4函数每隔2ms调度1次,
  8. //若两次调度期间接收到的数据的数量没有发送变化。
  9. //则串口处于空闲状态;即可复制DMA传输的数据
  10. remaining = DMA_GetCurrDataCounter(DMA2_Channel3);
  11. if((remaining == UART4_RX_SIZE) || (count != remaining))
  12. count = remaining;
  13. else
  14. {
  15. num = (UART4_RX_SIZE - remaining);
  16. //再次判断总线是否空闲
  17. if(!USART_GetFlagStatus(UART4,USART_FLAG_IDLE))
  18. return 0;
  19. DMA2_Channel3->CCR   &= ~(1 << 0); //停止DMA
  20. for(i = 0; i < num; i++)
  21. {
  22. buff = UART4_RxBuff;
  23. }
  24. DMA2_Channel3->CNDTR = UART4_RX_SIZE; //设置DMA传输大小
  25. DMA2_Channel3->CMAR  = (unsigned long)UART4_RxBuff; //设置DMA缓存
  26. DMA2_Channel3->CCR   |= (1 << 0);   //启动DMA
  27. return num;
  28. }
  29. }
  30. return 0;
  31. }


    请教各位,这种环境下如何避免UART的数据过载现象?
    另外,DMA停止后启动时间大概多长?貌似手册上没有说明











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

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2013-3-20 12:51:14 | 显示全部楼层
你的DMA缓冲设置为多大了?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

21

主题

58

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
263
金钱
263
注册时间
2011-8-23
在线时间
31 小时
 楼主| 发表于 2013-3-20 13:42:19 | 显示全部楼层
回复【2楼】 正点原子 :

你的DMA缓冲设置为多大了?
---------------------------------

缓存:2000

在前面的基础上做了修改(红色部分),采用了双缓存
UART数据益出现象少了很多。测试了一个多小时,只出现了三次。

如果每溢出一次,只丢失一个字节那还能接受。
但问题是每溢一次;则那一次的一整包数据DMA都接收不到

例如:一包数据有500个字节,若第一字节传输时使UART发生溢出,则这500个字节DMA都收不到。
非得下一包数据到来时DMA才能接收到

另外我把UART4的溢出中断打开了,溢出中断发生后,得清除溢出中断标号,否则DMA再也收到数据了。


清除溢出标号:
void UART4_IRQHander(void)
{
static u16 count = 0;
u8 i;
count++;
if(USART_GetITStatus(UART4,USART_IT_ORE))
{
i = *(volatile unsigned long *)UART4->SR;
i = UART4->DR;
printf("%d\n\r",count);
}
}









采用双缓存的代码:

/*****************************************************
** 查询DMA接收数据的状态
** buff: 存储接收到的数据
** 返回:没有接收数据返回0
         否则返回接收到数据的个数
*****************************************************/
unsigned short Receive_UART4(unsigned char *buff)
{
static unsigned short remaining,i,num;
static unsigned short count = UART4_RX_SIZE;
//缓存标记:1--->UART4_RxBuff1;1--->UART4_RxBuff2
static unsigned char flag = 1;
if(USART_GetFlagStatus(UART4,USART_FLAG_IDLE))
{
//思想:Receive_UART4函数每隔2ms调度1次,
//若两次调度期间接收到的数据的数量没有发送变化。
//则串口处于空闲状态;即可复制DMA传输的数据
remaining = DMA_GetCurrDataCounter(DMA2_Channel3);
if((remaining == UART4_RX_SIZE) || (count != remaining))
count = remaining;
else
{
num = (UART4_RX_SIZE - remaining);
//再次判断总线是否空闲
if(!USART_GetFlagStatus(UART4,USART_FLAG_IDLE))
return 0;
if(flag == 1)
{
DMA2_Channel3->CCR   &= ~(1 << 0); //停止DMA
DMA2_Channel3->CNDTR = UART4_RX_SIZE; //设置DMA传输大小
DMA2_Channel3->CMAR  = (unsigned long)UART4_RxBuff2; //设置DMA缓存
DMA2_Channel3->CCR   |= (1 << 0);   //启动DMA
flag = 2;
for(i = 0; i < num; i++)
buff = UART4_RxBuff1;
}
else
{
DMA2_Channel3->CCR   &= ~(1 << 0); //停止DMA
DMA2_Channel3->CNDTR = UART4_RX_SIZE; //设置DMA传输大小
DMA2_Channel3->CMAR  = (unsigned long)UART4_RxBuff1; //设置DMA缓存
DMA2_Channel3->CCR   |= (1 << 0);   //启动DMA
flag = 1;
for(i = 0; i < num; i++)
buff = UART4_RxBuff2;
}
return num;
}
}
return 0;
}
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2013-3-20 21:40:34 | 显示全部楼层
回复【3楼】danshi126:
---------------------------------
加入DMA接收完成中断试试.你的2ms判断结束的方法,如果2ms一直有数据接收,同时DMA又快要超了,那不是悲剧了...
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

21

主题

58

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
263
金钱
263
注册时间
2011-8-23
在线时间
31 小时
 楼主| 发表于 2013-3-21 08:41:30 | 显示全部楼层
回复【4楼】正点原子:
---------------------------------
恩!  谢谢原子;

昨天下午加入双缓存、完成中断后。基本上没出现数据溢出了
回复 支持 反对

使用道具 举报

28

主题

93

帖子

0

精华

高级会员

Rank: 4

积分
572
金钱
572
注册时间
2015-8-3
在线时间
113 小时
发表于 2018-6-30 11:21:25 | 显示全部楼层
请问楼主只是遇到了缓冲区溢出的问题吗?我用的环形缓冲区,只是没有你的溢出问题,我的和你的情况差不多,也是某些时候突然数据量比较大,这时的现象是会出现串口接收中断不再产生,当再给串口发送几次数据后就会产生硬错误,而串口发送是一直正常的
回复 支持 反对

使用道具 举报

2

主题

12

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
217
金钱
217
注册时间
2017-3-20
在线时间
34 小时
发表于 2018-6-30 14:38:52 | 显示全部楼层
不建议用环形缓冲的方法,建议用双缓冲的形式来存储数据,并且用DMA来搬移数据,开启DMA完成中断,通过判断中断完成标志位来进行数据处理
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-5-26 10:18

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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