你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32串口中断卡死

[复制链接]
aimejia 发布时间:2018-5-28 15:20
在一项目中,使用STM32作为主控,程序运行一段时间后概率出现主循环卡死现象。

问题分析如下:

1、程序USART2不停接收并处理串口数据,波特率115200;

2、主循环卡死;

3、USART1中断及TIM2中断响应函数运行正常;(USART1及TIM2中断优先级均比USART2高)

4、出现现象后,拔掉USART2的接收数据线,现象不能回复正常;

5、出现现象后,拔掉后再插入USART2的接收数据线,现象不能回复正常;

6、并未出现HardFault现象;

基于以上4点,可能原因如下:

1、USART2接收中断标志没有清除;

2、堆栈数据溢出,导致程序异常;

3、USART2中断重入导致异常;

4、USART2中断函数被异常响应;

5、USART2中断ERR;

对于以上可能原因一一分析:

1、中断接收标志清楚问题:

(1)USART2接收中断响应函数如下:
[cpp] view plain copy




  • void USART2_Istr(void)  
  • {   
  •     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  
  •     {     
  •         USART_ClearFlag(USART2, USART_FLAG_RXNE);  
  •         USART_ClearITPendingBit(USART2, USART_IT_RXNE);  
  •         Data = USART_ReceiveData(USART2);  
  •         //Process Data  
  •     }  
  • }  
[cpp] view plain copy



  • void USART2_Istr(void)  
  • {   
  •     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  
  •     {     
  •         USART_ClearFlag(USART2, USART_FLAG_RXNE);  
  •         USART_ClearITPendingBit(USART2, USART_IT_RXNE);  
  •         Data = USART_ReceiveData(USART2);  
  •         //Process Data  
  •     }  
  • }  
(2)出现现象后,通过Usart1中断获取到如下信息:
a. USART_GetITStatus(USART2,  USART_IT_RXNE)  == RESET

b. USART_GetFlagStatus(USART2,  USART_FLAG_RXNE)  == RESET

c. 执行USART_ClearFlag(USART2, USART_FLAG_RXNE)及 USART_ClearITPendingBit(USART2, USART_IT_RXNE)后无法恢复正常;

结论:与USART2 RXNE中断标志无关。

2、堆栈数据溢出,导致程序异常

(1)使用2倍栈空间,问题存在,概率不会降低;

(2)使用0.5倍栈空间,问题存在,概率不会提高;

(3)使用0.25倍栈空间,程序运行进入HardFault;

结论:与堆栈无关。

3、USART2中断重入导致异常;

(1)使用标志法,确认出现问题时,中断响应函数没有重入;

结论:中断响应函数没有重入。

4、USART2中断函数被异常响应

(1)USART2中断函数可以被正常调用,只是不停进入中断响应函数,卡死主循环;

(2)检查程序Map,没发现与中断响应函数地址相同的函数;

(3)检查中断向量表,没发现异常;

结论:中断函数没有被异常调用;

5、USART2中断ERR

(1)关闭USART2中断,主循环恢复正常;

(2)启动USART2中断,主循环卡死;

(3)获取到DR=0x0000;

(4)USART_GetITStatus取到:RXNE=0,PE=0,TXE=0,TC=0,IDLE=0,LBD=0,CTS=0,ERR=0,ORE=0,NE=0,FE=0;

(5)通过USART_ClearITPendingBit清除CTS,LBD,TXE,TC,RXNE,IDLE,ORE,NE,FE,PE均无法恢复正常;

(6)通过USART_GetFlagStatus:

  a.第一次:CTS=0,LBD=0,TXE=1,TC=1,RXNE=0,IDLE=1,ORE=1,NE=0,FE=0,PE=0

  b.第二次:CTS=0,LBD=0,TXE=1,TC=1,RXNE=0,IDLE=0,ORE=0,NE=0,FE=0,PE=0

  c.第三次:CTS=0,LBD=0,TXE=1,TC=1,RXNE=0,IDLE=0,ORE=0,NE=0,FE=0,PE=0

(7)通过USART_ClearFlag清除CTS,LBD,TXE,TC,RXNE,IDLE,ORE,NE,FE,PE均无法恢复正常;

分析:

(1)为什么通过USART_GetITStatus获取了所有中断标志,均为RESET(TC、TXE中断没开),还会进中断?

(2)为什么通过USART_ClearITPendingBit清除了所有中断标志,还会进入中断?

(3)为什么关闭USART2中断后再次启动它还会进入卡死状态?

(4)为什么通过USART_GetFlagStatus第一次和第二次读的不一样?而且USART_ClearFlag清掉所有Flag,也没法恢复正常?

带着以上几个疑问,查看了参考手册,才恍然大悟!如下:
1.png
(1)打开RXNEIE,默认会同时打开RXNE和ORE中断。

(2)必须第一时间清零RXNE,如没及时清零,下一帧数据过来时就会产生Overrun error!

(3)错误就是ORE导致的

出现错误时,读了RXNE=0,出错应该是上图打勾的情况,如下
2.jpg
(4)如文档说明,要清除ORE中断需要按顺序读取USART_SR和USART_DR寄存器!

那就是说USART_ClearFlag清掉所有Flag后,还必须读一遍USART_DR寄存器!

经过测试出现问题后依次读读取USART_SR和USART_DR,程序回复正常!

(5)那还有一个问题,为什么USART_GetITStatus读不到ORE中断标志?

读USART_GetITStatus函数就知道了,只有CR3的EIE置1且SR的ORE置1,读出来USART_GetITStatus(USART2,  USART_IT_ORE)  才是 SET。

见CR3的EIE位说明。

3.jpg

4.jpg



解决办法,出现通过接收时,通过USART_GetFlagStatus读取ORE,若不为RESET,则读取DR数据丢弃。

修改如下:
[cpp] view plain copy




  • void USART2_NewIstr(void)  
  • {   
  •     if (USART_GetFlagStatus(USART2, USART_FLAG_PE) != RESET)  
  •    {  
  •        USART_ReceiveData(USART2);  
  •      USART_ClearFlag(USART2, USART_FLAG_PE);  
  •    }  
  •       
  •    if (USART_GetFlagStatus(USART2, USART_FLAG_ORE) != RESET)  
  •    {  
  •        USART_ReceiveData(USART2);  
  •      USART_ClearFlag(USART2, USART_FLAG_ORE);  
  •    }  
  •       
  •     if (USART_GetFlagStatus(USART2, USART_FLAG_FE) != RESET)  
  •    {  
  •        USART_ReceiveData(USART2);  
  •       USART_ClearFlag(USART2, USART_FLAG_FE);  
  •    }  
  •       
  •     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  
  •     {     
  •         USART_ClearFlag(USART2, USART_FLAG_RXNE);  
  •         USART_ClearITPendingBit(USART2, USART_IT_RXNE);  
  •         Data = USART_ReceiveData(USART2);  
  •     }  
  • }  
[cpp] view plain copy



  • void USART2_NewIstr(void)  
  • {   
  •     if (USART_GetFlagStatus(USART2, USART_FLAG_PE) != RESET)  
  •    {  
  •        USART_ReceiveData(USART2);  
  •      USART_ClearFlag(USART2, USART_FLAG_PE);  
  •    }  
  •       
  •    if (USART_GetFlagStatus(USART2, USART_FLAG_ORE) != RESET)  
  •    {  
  •        USART_ReceiveData(USART2);  
  •      USART_ClearFlag(USART2, USART_FLAG_ORE);  
  •    }  
  •       
  •     if (USART_GetFlagStatus(USART2, USART_FLAG_FE) != RESET)  
  •    {  
  •        USART_ReceiveData(USART2);  
  •       USART_ClearFlag(USART2, USART_FLAG_FE);  
  •    }  
  •       
  •     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  
  •     {     
  •         USART_ClearFlag(USART2, USART_FLAG_RXNE);  
  •         USART_ClearITPendingBit(USART2, USART_IT_RXNE);  
  •         Data = USART_ReceiveData(USART2);  
  •     }  
  • }  

总结:
1、看文档!看文档!还是看文档!(重要的事情要说3遍)

2、库函数用的时候,也要注意其实现,稍有不慎就可能用错。

3、注意USART_GetFlagStatus与USART_GetITStatus的区别,还有中断响应机制。

4、任意时候都要考虑出错处理。




转载自shaynerain

收藏 1 评论2 发布时间:2018-5-28 15:20

举报

2个回答
钊钊 回答时间:2018-5-28 16:58:12
每次接收都要清掉标志位是个好习惯
stm1024 回答时间:2018-5-28 17:04:57
刚看问题的时候,我还在想,是不是和
  //Process Data  
下面的代码有关,就是这个代码也会带来中断……
结果还是老问题,没有及时清除中断标志位

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似分享

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版