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

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  
下面的代码有关,就是这个代码也会带来中断……
结果还是老问题,没有及时清除中断标志位

所属标签

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