在一项目中,使用STM32作为主控,程序运行一段时间后概率出现主循环卡死现象。 x9 t6 h/ Q S/ C
2 T8 Z3 b U: ^. ~$ N& `问题分析如下:
6 U0 \! n) A, f3 b
3 U* a5 c, J! M; e* x" V7 t1、程序USART2不停接收并处理串口数据,波特率115200;
8 i7 [0 w8 q/ z* W
, }: d2 V6 |2 U7 _# V% P5 q3 V1 f2、主循环卡死;
# \6 g% C* V" ?
: q: d/ ?( Z: B: I5 Q3、USART1中断及TIM2中断响应函数运行正常;(USART1及TIM2中断优先级均比USART2高)
8 S$ c1 Q0 k6 `$ r
; ^% T7 a T; T" Y* @8 {! |" ]% q4、出现现象后,拔掉USART2的接收数据线,现象不能回复正常;! w; c2 P; T0 t* G8 j: h; }
Y- j) q" j0 G5、出现现象后,拔掉后再插入USART2的接收数据线,现象不能回复正常;
- Y2 R! ]( T! u5 n; i3 U, z3 X% m5 W" S
6、并未出现HardFault现象;
6 w3 r+ ^# @& l# [4 v4 ?! a( A' _
基于以上4点,可能原因如下:: Z+ x% o" Y1 ~. g
" M' s7 C$ ?5 {( W+ ?1 [1、USART2接收中断标志没有清除;
8 T9 k2 B1 R0 F/ K+ G- z
5 N% G0 g$ B, b; A; X( i/ U2、堆栈数据溢出,导致程序异常;
, G6 o( [0 y, t# ?9 ]6 J# l
! v% M* k! |3 u3、USART2中断重入导致异常;
/ W! t2 N- V) o" p9 z, D0 e: g; I U% P6 Z! A8 Q. Y! y
4、USART2中断函数被异常响应;
1 _4 u! V$ ?. X7 ?, q$ e- {6 w
/ i$ s. ]/ s7 X9 E 5、USART2中断ERR;" E# W0 N4 Q/ h4 T
; {/ @' Z9 d: {5 W
对于以上可能原因一一分析:
6 A, Y5 n8 O6 t* v8 Q% p: t
& M) m' u, S K$ a. {1 v, y A1、中断接收标志清楚问题:
3 \1 n9 D4 `2 {) D; [- K C3 U/ z6 m/ z6 H5 A5 r
(1)USART2接收中断响应函数如下:1 x2 y. B! l9 o# W8 _2 O2 z
[cpp] view plain copy
+ E$ j. H* C5 r9 T+ ]9 R
* q" c. ?, N4 {9 C, R F" u6 o
! L- O8 |) x; S4 W
3 i z! a3 T; n% G9 q& L% a$ H) d5 J
- 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
- }
- }
/ D- W; I% f) _. A! ? [cpp] view plain copy# V; r7 T! O1 B8 J7 l/ [* U
4 y6 u1 `; F. E: q4 J! ?# w3 y
1 R9 ^ H% l! M7 G1 B' ^
) I [) M7 n: ]9 X8 v- 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
- }
- } , D5 m2 B2 P3 q. B+ z
(2)出现现象后,通过Usart1中断获取到如下信息:
( M% i& @/ u/ ^4 N* c! o) @; ya. USART_GetITStatus(USART2, USART_IT_RXNE) == RESET
5 F7 Q5 T4 s8 l: l N* f
" R$ k( V M1 |! }b. USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == RESET
5 k$ k0 g& a* b* X; Q
9 e2 j. ] u& ]- X+ Dc. 执行USART_ClearFlag(USART2, USART_FLAG_RXNE)及 USART_ClearITPendingBit(USART2, USART_IT_RXNE)后无法恢复正常;. g* O$ N2 G0 @5 S$ I/ r
8 P" s, B J4 ]3 G+ h/ Q0 m9 G
结论:与USART2 RXNE中断标志无关。
& G- f, a3 @ n# p- a
7 e3 F- x* ^# T' S/ G1 {9 o, ?2、堆栈数据溢出,导致程序异常;
' P4 H1 ^5 {8 R$ v4 Z! {% O( Q, V, r8 U. d2 I! j
(1)使用2倍栈空间,问题存在,概率不会降低;3 x8 E; _$ V$ m& @7 l( e' w
* x O, ^5 U S5 w- n
(2)使用0.5倍栈空间,问题存在,概率不会提高;
, P7 e$ X2 b6 @4 y
* d6 x( b4 Q9 \* [* o(3)使用0.25倍栈空间,程序运行进入HardFault;# `2 R2 `8 S1 y3 X" X& ~- u* d. z
8 V* P8 J, s3 V9 P" O; @% d& S结论:与堆栈无关。5 p" k& h) k# D Z# A
7 u- w$ S& A9 r5 T3、USART2中断重入导致异常;8 ~6 O& u- z7 z5 S! l `
; m7 X4 p z! x, F/ @/ H(1)使用标志法,确认出现问题时,中断响应函数没有重入;
: h6 a+ y. |# V+ X2 I5 R1 Z
. n& O5 q% D+ ~# ]* n结论:中断响应函数没有重入。
% m; Q9 m1 `/ j- [: @
, ?# N$ w4 @2 y' G4 `. Q, o' K7 F4、USART2中断函数被异常响应;/ g3 S' g J1 k" p
# B9 Q/ h7 H+ T
(1)USART2中断函数可以被正常调用,只是不停进入中断响应函数,卡死主循环;( J% M8 v+ F ~- g# U& B
- v/ X3 v1 a0 B% B0 F; b/ u(2)检查程序Map,没发现与中断响应函数地址相同的函数;' ~( ^1 W/ X8 z- k( r, X
, ?* V. X: @5 P: E
(3)检查中断向量表,没发现异常;! ?* @" s# ]& z4 S3 E
7 Y3 z& |3 f2 D, s+ X) _ S
结论:中断函数没有被异常调用;. M* J; h, l6 G. v* Z7 M7 I% H" K9 c
0 T& {# d/ ?- O3 h$ Z C5、USART2中断ERR;
% v5 g8 h7 p7 Z& x# A; Z" C/ r% w1 K% Q
(1)关闭USART2中断,主循环恢复正常;
" Y/ c, P' x2 d/ C- F$ p( ` S+ g; O, D7 h5 P
(2)启动USART2中断,主循环卡死;
: |- e: U2 C, J1 c/ J+ Y, A, z5 V' o/ u/ @( o, \
(3)获取到DR=0x0000;
1 o3 s) G" u. G# k
5 m- L& h9 M0 E; J(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;
4 s' B# L2 k6 V! Z, F
% \* x6 Q8 H$ k+ F(5)通过USART_ClearITPendingBit清除CTS,LBD,TXE,TC,RXNE,IDLE,ORE,NE,FE,PE均无法恢复正常;# M' |/ x% H$ h3 w, K: ]* }
$ p/ k. f' E* {3 a' l3 Q% R(6)通过USART_GetFlagStatus:
1 P, k _6 b; h. q0 |
! J) ~ v% b3 a5 } a.第一次:CTS=0,LBD=0,TXE=1,TC=1,RXNE=0,IDLE=1,ORE=1,NE=0,FE=0,PE=0' X" E4 l8 q2 C, [) }' G
, S0 c M2 a" f9 M( E$ _* A, q b.第二次:CTS=0,LBD=0,TXE=1,TC=1,RXNE=0,IDLE=0,ORE=0,NE=0,FE=0,PE=0
# } [! A2 {0 x3 j1 }& n/ v' O
3 |" i; K1 @; Q2 N( I) _ c.第三次:CTS=0,LBD=0,TXE=1,TC=1,RXNE=0,IDLE=0,ORE=0,NE=0,FE=0,PE=0
( t" L1 m, L2 ]: p; B; U% N h0 f) s: z
(7)通过USART_ClearFlag清除CTS,LBD,TXE,TC,RXNE,IDLE,ORE,NE,FE,PE均无法恢复正常;
2 p' e, r6 K; C9 l* v' H6 l* a3 Q2 l) N* s3 b
分析:
+ h4 k3 V4 }% Q3 s E, D, @% \) l
# R D- j2 m7 X! b0 t! h5 G(1)为什么通过USART_GetITStatus获取了所有中断标志,均为RESET(TC、TXE中断没开),还会进中断?6 y) C" t0 Z U
^5 E8 K; A: p% b
(2)为什么通过USART_ClearITPendingBit清除了所有中断标志,还会进入中断?
6 v5 r- {; s7 F; t4 ^; ~0 k/ X- H$ x1 Z' |$ @: i: j
(3)为什么关闭USART2中断后再次启动它还会进入卡死状态?$ c5 l' }' v& C& B u
+ J/ ~- m6 J! ]; W( L; q; t3 l
(4)为什么通过USART_GetFlagStatus第一次和第二次读的不一样?而且USART_ClearFlag清掉所有Flag,也没法恢复正常?- M! K2 Y0 G. D; M7 m7 z1 U- \
8 ~* O/ o: Y, S带着以上几个疑问,查看了参考手册,才恍然大悟!如下:
M E* ~8 i' ~6 \9 n, p$ w
7 R4 O3 u8 L% C- M5 M. P4 {
(1)打开RXNEIE,默认会同时打开RXNE和ORE中断。, D5 n% R5 N- L8 E/ q
7 K3 B7 i. J/ y% ]! _! r, H/ A/ L(2)必须第一时间清零RXNE,如没及时清零,下一帧数据过来时就会产生Overrun error!7 g! x& J6 z8 E- C7 O; N+ p/ e3 L
3 V6 Z. c, [5 K& Q$ J(3)错误就是ORE导致的/ z8 [9 R- A [
0 X0 u" E5 C* r) c1 ~
出现错误时,读了RXNE=0,出错应该是上图打勾的情况,如下
9 C8 r7 }" T, `5 M$ X- E9 `5 w
4 Q% [# i9 p5 [8 o4 d(4)如文档说明,要清除ORE中断需要按顺序读取USART_SR和USART_DR寄存器!
# T0 G3 }' t* Q* W+ X: N* ^$ S2 U9 T
那就是说USART_ClearFlag清掉所有Flag后,还必须读一遍USART_DR寄存器!
g- y" I/ I6 q- v/ T: q$ H+ g; C1 q8 I4 t- e
经过测试出现问题后依次读读取USART_SR和USART_DR,程序回复正常!7 w. f/ D8 F+ H
+ x! K% R ~0 F
(5)那还有一个问题,为什么USART_GetITStatus读不到ORE中断标志?' y# G1 L* m6 j* J
& v, x( c8 R/ \* t+ Q0 E读USART_GetITStatus函数就知道了,只有CR3的EIE置1且SR的ORE置1,读出来USART_GetITStatus(USART2, USART_IT_ORE) 才是 SET。' W' g+ h4 d# o& V5 q n7 M
) ?6 C) Y3 S9 Z) d
见CR3的EIE位说明。% T& z( q* e! R# p- O
- p2 y( |. e/ ?" |3 ^& ~- `2 ?
! F/ m+ n* l7 K& r2 e8 L
& [- e, G/ |% @4 ]. d
0 C0 P# l5 r0 S( N1 V" J
, D0 _6 I7 @, N! N n# Z
) N* M' \- _! {! w- r: c% ?
5 l4 D3 u( C$ J1 `解决办法,出现通过接收时,通过USART_GetFlagStatus读取ORE,若不为RESET,则读取DR数据丢弃。# f8 u, P9 b' h9 x
# s* e7 W [" c5 {% {
修改如下:, O8 j7 [: l- N) S
[cpp] view plain copy
7 _" I: u7 S0 o4 C- j
1 r0 A2 M- N& m) d) c6 l* W* d B+ W7 b8 S
# ?" Y6 i( [7 J% j3 L+ f
' u, W2 D$ Q* E3 ^% O
- 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);
- }
- } + F+ o6 f( p0 ~9 ^# K* ]
[cpp] view plain copy
2 q- _4 P" p" d- y- v
$ [4 Z; T3 {4 g) o& ?) j. k
1 e4 Q* I: Y1 `1 q% d
; d" \. O: y8 G4 A x I: s- ^7 l3 s- 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);
- }
- }
) H1 H. J& x( a( O. N8 e0 Z/ A1 l
9 J) O3 }/ Z$ c4 ] z% i总结:
3 S+ l1 t7 O- E1、看文档!看文档!还是看文档!(重要的事情要说3遍)- K6 Y9 [ Z( I' `3 i3 q* ]3 g
: ^, p+ X9 C/ G+ t* e$ F2 a* `) \2、库函数用的时候,也要注意其实现,稍有不慎就可能用错。& d' m7 s. I# d1 |+ Q
9 X! K1 M- E( {; {1 g+ m. Z3、注意USART_GetFlagStatus与USART_GetITStatus的区别,还有中断响应机制。
+ x. H/ z: v( d5 V; T* h, H; \; [! S- w
4、任意时候都要考虑出错处理。
+ L t' v8 }8 b7 z0 r
0 z8 t: P( E: p
' ]" A! @! ?8 _
% J# U4 _& d0 Q* A6 Q1 k2 d& q' p9 V7 k4 H3 N
转载自shaynerain' l3 ]/ X- c7 }6 Z. E
) Z$ e0 u7 H2 A" r/ s |
//Process Data
下面的代码有关,就是这个代码也会带来中断……
结果还是老问题,没有及时清除中断标志位