11.1 初学者重要提示% y3 }, j6 {3 ] `6 ~6 x- S; F
MDK本身也是支持硬件异常分析的,就是不够直观
) `3 z L1 P( L J3 d* u5 i0 o' ^$ E5 ?, I
IAR8带的硬件异常分析比较好用,在本章11.6小节有说明。
3 ^+ N% k: }* w' Z7 {9 e' l11.2 移植方法2 d8 f/ T, |& F2 ^7 t4 o
直接移植SEGGER的硬件异常代码会有错误警告,这里针对IAR和MDK版本做了些简单修改,方便大家移植到自己的工程里面。
3 Y) J8 o" \$ P' z B( N- i! T/ K- C* b, Y. E' u/ M0 K( N2 ?
MDK版本移植5 [; @; X* z, Y' T% s- u( r! j
源文件位于本章配套例子的\User\segger\HardFaultHandlerMDK文件夹,添加如下两个文件到工程里面即可。9 U2 K% ~- t! w8 `+ f7 V' Y& m4 Y
& }* W* D9 b6 C3 h* m5 O0 s. N
- p& B4 z* y% ?8 c) N
1 t4 e1 @- ]$ f6 U; `) I# s3 v IAR版本移植0 B# ]) X4 l$ L
源文件位于本章配套例子的\User\segger\HardFaultHandlerIAR文件夹,添加如下两个文件到工程里面即可。 p. m% y7 t4 B9 i
! z- H/ B& M7 f* d2 F: v6 L0 P6 G; {7 B, x$ ?1 C3 E
9 b. o+ b. T. a在文件SEGGER_HardFaultHandler.c里面都添加了串口打印功能,方便不用编译器的调试功能时,通过串口打印提示是否进入硬件异常。9 w1 L1 w0 y) O6 s3 U" \
6 y' y) b8 k. e' ^. C
- #define ERR_INFO "\r\nEnter HardFault_Handler, System Halt.\r\n". G, @- P( r$ J& Y' E) F" X2 M
$ J4 n, X. `! j) i' T+ }- #if 11 n: `" W4 ]0 I( ~1 @% Q; _
- {
/ l. P& o/ b7 @5 Z5 h9 ?5 l& A - const char *pError = ERR_INFO;5 g, E7 u: r5 }- ?5 j
- uint8_t i;
& K2 r9 u5 k1 t% f8 Y& V - 8 s$ y5 E, G" \: q
- for (i = 0; i < strlen(ERR_INFO); i++)
8 N4 d; d8 z+ S9 a3 X! e - {7 Y' P7 O/ B, p+ Y# b
- USART1->TDR = pError<i>;
- h1 ^8 c0 q; l* E% B2 r& [ - /* 等待发送结束 */
- `. f; a4 _; |, g* g& m - </i> while((USART1->ISR & USART_ISR_TC) == 0);" X; w( Z; r, T
- }
* |3 _% N/ r6 V9 b4 s% W - }
( m V c* b" H* D: i( L - #endif
复制代码
[ l a6 v# I0 h0 ]11.3 MDK锁定硬件异常位置方法! Q! O4 J7 u1 j6 v! P
以本章配套的例子为大家做个说明。
5 U3 e2 @6 g% s: {8 G. Q) ^. b
- ^" |9 L' {+ [4 E5 I/ c7 v* s1、测试方法比较简单,进入调试状态,全速运行,然后按下K1按键,就会进入硬件异常中断,此时停止调试,程序就会自动定位到如下位置:5 T" ^: m) J3 @3 d' g) u }+ K
. z+ d. B7 A7 n
0 X+ `4 X2 N6 W5 S" z- L+ s. B- c7 i9 F% E
2、在Watch1窗口添加变量_Continue2 u2 g3 a- V9 Y5 G+ | K: Z! B% I
3 {7 b6 V4 {: w; O+ t( Z$ X, P- F
3 _% B- I. ]6 ?* }" V3 d$ ~
& e4 v3 K3 e/ K: n0 o3、修改为任何非0数值,就可以继续单步调试。这个代码后面还有一个第1步中的while循环,也可以继续采用第2步的方法修改。退出硬件异常后就是大家进入硬件异常前下一条要执行的指令(可能还是这个函数本身,因为一个函数由多个指令完成)。定位到出问题的位置:& O0 X( @ U6 H! o0 K$ s: i7 ^4 C
3 h8 b9 _8 Z6 L( ~3 J* E5 C0 n% }' N/ @ V& G$ @; [
" O; ~" [' F2 U) R( ?
11.4 IAR锁定硬件异常位置方法
, p% J2 F/ L2 h4 [; S$ c$ X: ]以本章配套的例子为大家做个说明。
( v- X5 c4 P; }. T6 I$ b: K; W2 Q9 ]( \- ^3 z! _: s
1、测试方法比较简单,进入调试状态,全速运行,然后按下K1按键,就会进入硬件异常中断,此时停止调试,程序就会自动定位到如下位置:: m9 i* [, |+ [
$ g. p& b! x2 y% G. `6 g
% I+ j* A& i" y8 v* ~
2 x0 K* `3 G; d- \+ o2、在Watch1窗口添加变量_Continue
; h- R' v$ m; I% j0 Z. W
3 o% u: N, w$ C, G& ]; ?+ L5 R% R( L9 X# N
! w1 R. N" ~) C( [8 n" v4 ~6 D3、修改为任何非0数值,就可以继续单步调试。这个代码后面还有一个第1步中的while循环,也可以继续采用第2步的方法修改。退出硬件异常后就是大家进入硬件异常前下一条要执行的指令(可能还是这个函数本身,因为一个函数由多个指令完成)。定位到出问题的位置:
' d: u1 w7 e! [7 U; F% i; L" k
9 z1 q/ S% o9 w* o1 T
" C8 b. Q4 G3 m( ~9 U# I/ P
7 F7 _- r0 g! W z- _11.5 硬件异常原因分析
3 P- ?: ^8 F6 I, C7 V; l% s# PSEGGER提供的这个机制查找出问题的位置比较方便,具体原因需要继续在调试界面里面添加HardFaultRegs结构变量,这个结构体变量添加了所有大家想看的东西。下面是MDK调试状态查看部分结构体数值:
5 | W$ e, e$ C2 ?) d6 X
) e& `" W* Q8 ^! y# F D
+ ?6 b {3 H0 `- Q4 q" T9 R$ ]4 \- r; {7 T0 L( @0 F# o% X$ ~
具体上面的变量代表什么含义呢,代码里面有注释,查阅起来没有IAR自带的硬件异常提示方便(注意,下面的代码用到了位域)。& U& Y1 O7 R3 B6 N: w
5 c: {- K2 _$ C% ^7 q
- #if DEBUG! o* b* D" j/ U6 k B. t
- static volatile unsigned int _Continue; // Set this variable to 1 to run further
! a& Y$ q3 ]2 _: M$ M; u2 L
3 ]! I. ?+ f5 g8 K& Z- static struct {- E9 _3 W$ C1 u
- struct {
3 [7 ^) N/ k3 Y+ S6 d - volatile unsigned int r0; // Register R0* \& v9 h& ?$ o: Y' |/ K" p: X
- volatile unsigned int r1; // Register R19 [; F1 ?. p0 \, d! Q5 @
- volatile unsigned int r2; // Register R2" R4 D q A1 g
- volatile unsigned int r3; // Register R3) R& _- E7 O+ p7 W g9 n& K' x& Q
- volatile unsigned int r12; // Register R12. Q/ ~, o1 R3 F) L% U3 c
- volatile unsigned int lr; // Link register
; h" k6 `* k6 x/ V/ q o - volatile unsigned int pc; // Program counter6 Z3 E4 s+ [, _2 b$ ~3 w
- union {9 @7 e$ Q7 e0 _: _$ G& X8 R
- volatile unsigned int byte;4 |( q( U$ w4 K1 i" k9 j
- struct {# Y8 t. O. @0 `* u) j7 }: A+ C9 t
- unsigned int IPSR : 8; // Interrupt Program Status register (IPSR). k$ O3 @/ j7 I* v" t5 i
- unsigned int EPSR : 19; // Execution Program Status register (EPSR)" c2 U6 L' x0 l
- unsigned int APSR : 5; // Application Program Status register (APSR)
7 M$ g& R& |1 Y$ w$ M& N$ [& @+ ^ - } bits;
) d* ~) o* m8 K* M4 \ - } psr; // Program status register.; S% a" [# G( P1 Z7 n; j5 r% }
- } SavedRegs;: ^! s( v9 A( t
) \0 a4 b( T1 H- union {' O" `4 X) a X; j
- volatile unsigned int byte;
; z0 d7 Z0 X* g$ V. u6 T - struct { |4 x$ l" h+ _: J& C7 \: p) F
- unsigned int MEMFAULTACT : 1; // Read as 1 if memory management fault is active D" p: U H0 Y
- unsigned int BUSFAULTACT : 1; // Read as 1 if bus fault exception is active
+ Z d& L' ]; P; Y - unsigned int UnusedBits1 : 1;
# \* T" b% Q1 B x - unsigned int USGFAULTACT : 1; // Read as 1 if usage fault exception is active- P$ m! \ m3 x0 ?- z
- unsigned int UnusedBits2 : 3;
# F2 G L2 u( q: ^" v# v0 D0 n0 F3 e - unsigned int SVCALLACT : 1; // Read as 1 if SVC exception is active
! p( Z8 n* h; u0 k - unsigned int MONITORACT : 1; // Read as 1 if debug monitor exception is active
2 [' x' `, S$ H2 P% G1 Q - unsigned int UnusedBits3 : 1;! ?' F3 x; Z+ n" O/ T
- unsigned int PENDSVACT : 1; // Read as 1 if PendSV exception is active
7 z' e$ D2 [. \! f' w4 }: L - unsigned int SYSTICKACT : 1; // Read as 1 if SYSTICK exception is active5 p* f. C1 L( ]1 w0 P3 H2 t
- unsigned int USGFAULTPENDED : 1; // Usage fault pended; usage fault started but was replaced by a
+ T+ t# F* g# A; {+ @, y9 B* c/ q+ Z2 y X - higher-priority exception- R- U4 b j6 _; e
- unsigned int MEMFAULTPENDED : 1; // Memory management fault pended; memory management fault started
6 P7 R/ l, k: d6 F - but was replaced by a higher-priority exception
* F+ V; o; @$ R3 J3 e: U - unsigned int BUSFAULTPENDED : 1; // Bus fault pended; bus fault handler was started but was replaced
2 ? ?( X2 A- C. \7 y6 j9 h# ]& O% Y - by a higher-priority exception6 o5 a: s- o0 w5 z
- unsigned int SVCALLPENDED : 1; // SVC pended; SVC was started but was replaced by a higher-priority4 k: y: _" \; @: q# w$ Q" L
- exception
( ^: e9 Q3 d7 E( a( s6 {% d - unsigned int MEMFAULTENA : 1; // Memory management fault handler enable
) d6 h2 Q. t8 j" y! K: \7 e - unsigned int BUSFAULTENA : 1; // Bus fault handler enable
6 U7 D2 i3 @ r3 K - unsigned int USGFAULTENA : 1; // Usage fault handler enable1 b/ ^6 F8 z {9 Z7 k/ q' G
- } bits;
: k) _4 U% T# k w# x - } syshndctrl; // System Handler Control and State Register (0xE000ED24)
. s2 K8 A5 t; h7 V6 Q
8 \4 P r! @" t- M* J8 e x- /* 省略未写 */
2 W: t2 r0 ?% M6 ~) { - " {) h! E1 J- S! M f7 c& x0 u; }
- volatile unsigned int afsr; // Auxiliary Fault Status Register (0xE000ED3C), Vendor controlled (optional)
1 E$ W9 _, ^4 P1 g - } HardFaultRegs;) N; s% e/ Z) |5 O+ a
- #endif
复制代码 9 h, W" L9 d5 Y- ]& Y& J; m
11.6 IAR自带的硬件异常分析
0 j% p! { w9 Y/ J9 _# X还以本章配套的例子为例,进入调试状态,全速运行,然后按下K1按键,就会进入硬件异常中断,此时停止调试,IAR还会弹出一个硬件异常错误分析,刚进来的时候也许是个空白
6 k' J% H- W$ g& t8 S- r% I0 `3 k2 m- G. f* w1 q7 K! `
; c* f2 K1 [: B- ?; u; d3 P$ C6 Q- l6 m
6 P0 m/ p1 d: m% b3 o! s
单步调试刷新下就出来了:- ~$ r# N) J! p+ _* `8 y, p+ D" @
d5 U) W; ?0 i7 H- C$ J3 y
" U' _' `: @' w+ |: X! f9 W# m/ Q8 e3 Q% t4 j9 t
指出了问题的原因是操作的数据地址有问题。
. S4 M+ R7 O& O, x2 \
% D8 n* R% B) g' B/ _# s- s11.7 实验例程+ W8 _( ?- u( T$ p3 f
专门为本章节配套了一个例子:V7-009_移植SEGGER的硬件异常分析机制。大家可以按照本章教程提供的方法进行测试。
* g5 [# t. {" p! A0 A; o& `' w+ l+ ~' C4 T; L. `
11.8 总结1 ~% k. k9 g d d
除了SEGGER的硬件异常分析方案,建议也测试下MDK和IAR的,以后遇到硬件异常问题,解决起来可以得心应手。- `# L2 p" O- }" T/ J
4 S& m6 C) l2 Y5 A+ e% v
* ?+ L* U' E9 C4 i9 K |