历史上的今天
返回首页

历史上的今天

今天是:2025年05月31日(星期六)

2018年05月31日 | STM32串口中断卡死主循环问题分析

2018-05-31 来源:eefocus

在一项目中,使用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接收中断响应函数如下:

  1. void USART2_Istr(void)  

  2. {    

  3.     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  

  4.     {     

  5.         USART_ClearFlag(USART2, USART_FLAG_RXNE);  

  6.         USART_ClearITPendingBit(USART2, USART_IT_RXNE);  

  7.         Data = USART_ReceiveData(USART2);  

  8.         //Process Data  

  9.     }  

  10. }  



(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)打开RXNEIE,默认会同时打开RXNE和ORE中断。


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


(3)错误就是ORE导致的

出现错误时,读了RXNE=0,出错应该是上图打勾的情况,如下


(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位说明。




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

修改如下:

  1. void USART2_NewIstr(void)  

  2. {    

  3.     if (USART_GetFlagStatus(USART2, USART_FLAG_PE) != RESET)  

  4.    {  

  5.        USART_ReceiveData(USART2);  

  6.      USART_ClearFlag(USART2, USART_FLAG_PE);  

  7.    }  

  8.       

  9.    if (USART_GetFlagStatus(USART2, USART_FLAG_ORE) != RESET)  

  10.    {  

  11.        USART_ReceiveData(USART2);  

  12.      USART_ClearFlag(USART2, USART_FLAG_ORE);  

  13.    }  

  14.       

  15.     if (USART_GetFlagStatus(USART2, USART_FLAG_FE) != RESET)  

  16.    {  

  17.        USART_ReceiveData(USART2);  

  18.       USART_ClearFlag(USART2, USART_FLAG_FE);  

  19.    }  

  20.       

  21.     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  

  22.     {     

  23.         USART_ClearFlag(USART2, USART_FLAG_RXNE);  

  24.         USART_ClearITPendingBit(USART2, USART_IT_RXNE);  

  25.         Data = USART_ReceiveData(USART2);  

  26.     }  

  27. }  



总结:

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

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

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

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


查了一下 ,也有人遇到了相同的情况,可参考:

http://blog.csdn.net/love_maomao/article/details/8234039


推荐阅读

史海拾趣

CUI Devices公司的发展小趣事

在压电警报器领域,CUI Devices凭借其卓越的技术和产品质量,赢得了全球市场的广泛认可。根据最新的行业报告,CUI Devices在全球压电警报器市场中位列第一梯队,与SATEP、Adafruit Industries LLC和Challenge Electronics等核心厂商共同占据了可观的市场份额。这一成绩的取得,离不开公司多年来的技术创新和市场拓展。

Global Components & Controls公司的发展小趣事
选择质量可靠、性能稳定的元件,以确保电路的稳定性和可靠性。
成都成电硅海公司的发展小趣事

随着技术的不断成熟和市场的不断扩大,成都成电硅海公司开始寻求更广阔的市场空间。公司积极参加国内外各种行业展会和论坛,与业界同行进行深入的交流和合作。同时,公司还加大了对海外市场的开拓力度,成功将产品打入欧美等发达国家市场。这一系列的市场拓展举措,使得成都成电硅海公司的知名度不断提升,市场份额也逐渐扩大。

芯佰微(Corebai)公司的发展小趣事

随着技术的不断发展,芯佰微逐步拓展了自己的产品线,覆盖了放大器、接口电路、电源管理、时间数字转换器、DAC数模转换、ADC模数转换等多个领域。同时,公司积极开拓国内外市场,与众多知名企业建立了合作关系,将产品广泛应用于手持移动终端、消费类电子产品、个人电脑及周边设备、网络通信设备、医疗设备、办公设备等多个领域。这些努力使得芯佰微的产品在市场上获得了广泛认可。

Eastman Kodak Company公司的发展小趣事

进入21世纪后,随着数码技术的迅速崛起,传统摄影市场遭受了巨大的冲击。面对这一挑战,伊士曼柯达公司开始尝试向数码领域转型。然而,由于公司在数码技术方面的积累相对较少,转型过程并不顺利。尽管如此,柯达仍然坚持创新,不断推出新的数码产品,以应对市场的变化。同时,公司还加强了与数码技术公司的合作,共同研发新产品,以提高市场竞争力。

ALCOA公司的发展小趣事

ALCOA,全称美国铝业公司,其发展历程可追溯至19世纪末。当时,铝在地球上蕴藏丰富,但提炼单质的铝却十分困难。年轻的查尔斯·霍尔(Charles Hall)发明了用电解方式生产单质铝的方法,并于1889年获得专利。随后,他与艾尔弗雷德·亨特(Alfred E. Hunt)船长合作,投资建厂,开始批量生产铝。这一技术创新不仅推动了铝产量的快速上升,还使得铝这种曾经比金子还贵的金属逐渐走进了人们的日常生活。

问答坊 | AI 解惑

玩转12864液晶(2)--显示图片,画点,画任意直线

通过上一篇的实验,相信大家都掌握了显示字符的基本用法。 下面我们来看一下12864液晶更高级的用法。 首先是它的绘图功能 。 让我们先来显示一整副的图片吧,也就是128x64大小。 在使用绘图功能时,先要打开扩充指令集,然后再打开绘图功能。 ...…

查看全部问答>

assertion failed! afxcmn2.inl 110行

在winXP下 VC写的SOCKET通信的程序可以正常运行,但是在EVC写进行改写,Wince上运行出现了assertion failed! afxcmn2.inl 110行 请教一下,这是什么错误?…

查看全部问答>

WINCE 下判断IO口状态

我想在WINCE下判断某一个IO口是否被拉低,,怎么实现呀…

查看全部问答>

ARM芯片有没有实模式和保护模式一说?

摸了好久S3C2410这个芯片,突然想了这个奇怪问题。…

查看全部问答>

ST让我如何相信你?

                                 申请 付费 的样片几个月了(答应3月底)还是音信全无啊?!…

查看全部问答>

如何编写testbench的总结

1.激励的设置 相应于被测试模块的输入激励设置为reg型,输出相应设置为wire类型,双向端口inout在测试中需要进行处理。 方法1:为双向端口设置中间变量inout_reg作为该inout的输出寄存,inout口在testbench中要定义为wire型变量,然后用输出 ...…

查看全部问答>

用ftp下载vxworks镜像到目标机的时候,网络有问题,求助各位前辈

通过ftp将vxworks镜像从PC机下到目标机的时候,是通过ftpXfer这个函数从PC机读取文件,每次读完镜像之后关闭套接字,但套接字指定的端口变成就会time_wait状态,就要等一段时间才能通过这个函数,从PC机再次通过ftp下载镜像,但这段时间有一分半钟 ...…

查看全部问答>

引脚

哪位大神指教下XFILT、YFILT是什么意思?…

查看全部问答>

【建议】C2000 LaunchPad一学二做

现在坛子里相信有很多人拥有C2000 LaunchPad,给学习C2000带来了方便。如果能组织一下编写它的学习及应用方面的文章,将会给广大网友、特别是以后入门C2000的人带来福音。 我建议: 1、写学习经验。    组织有使用经验的人,写出系 ...…

查看全部问答>

在zigbee协议栈定时器中断问题

不加入协议栈时,定时器能正常工作,加入协议栈后定时器不能正常工作,求指点 这是我的定时器吃时候函数 void Timer1_Init(void) {      /*设置P1.0为输出模式*/   P1DIR = 0xff; //  P1_0=0; &n ...…

查看全部问答>