11.1 初学者重要提示6 C: S8 J; R9 e' X8 a; M4 {
MDK本身也是支持硬件异常分析的,就是不够直观
0 `; ?$ u) B# p! `$ m! u6 r4 U! c: D9 J' x2 v
IAR8带的硬件异常分析比较好用,在本章11.6小节有说明。8 d& L/ n- q7 p/ x: N/ R
11.2 移植方法
* W5 a% R& p$ }1 x0 \直接移植SEGGER的硬件异常代码会有错误警告,这里针对IAR和MDK版本做了些简单修改,方便大家移植到自己的工程里面。
3 u' m1 T) z& u7 L# ?4 z- z/ N. I
9 o/ j; k+ t l# n: C3 b MDK版本移植
7 Z/ L# Z6 h2 |+ n1 i% }& ?$ W) J源文件位于本章配套例子的\User\segger\HardFaultHandlerMDK文件夹,添加如下两个文件到工程里面即可。. |! d6 a, p" s$ L0 l0 J
# `* l, z8 O' @, X( y' M4 I3 R. o5 {. `/ {% I9 N
: ~% r; s+ ]9 s7 G. n
IAR版本移植
8 ^6 C+ w- ~# t+ d2 u2 j源文件位于本章配套例子的\User\segger\HardFaultHandlerIAR文件夹,添加如下两个文件到工程里面即可。% I8 T8 E( m6 j
4 D/ k* g$ A% Z1 p: j! Q4 f
& Z5 K) @' F0 z+ `8 i* N! l' y. F, z- F4 R& w% N/ U1 W5 f" [' C7 Z
在文件SEGGER_HardFaultHandler.c里面都添加了串口打印功能,方便不用编译器的调试功能时,通过串口打印提示是否进入硬件异常。& e5 X2 q0 Z4 b
6 p& e& s! I/ d; |5 s( P1 _
- #define ERR_INFO "\r\nEnter HardFault_Handler, System Halt.\r\n"
: M/ Y( C! \% f1 A: ]" _$ l- I# z: M - + d( V* u E" r6 i2 {3 y
- #if 1) _: F3 l% B0 b# v7 Y/ {
- {
h& ^& o% g" m4 y6 I( c - const char *pError = ERR_INFO;
, E5 y6 i* w, R, Y2 E0 Z$ N - uint8_t i;. g! [" b8 r. N" R
# f6 B, l5 W' ?: l# ^, p- for (i = 0; i < strlen(ERR_INFO); i++)
+ Y& ^ p1 H2 J9 H% ~ - {
/ _9 {2 B+ m0 C( N% Z0 _ - USART1->TDR = pError<i>;+ ?* n8 N8 y5 Y$ p& j
- /* 等待发送结束 */$ R. o4 t$ `5 A, g
- </i> while((USART1->ISR & USART_ISR_TC) == 0);
9 q! j6 H; ?4 g: _8 K - } & O' m3 ^. s& e- L8 l+ c. W# m$ a
- }6 e" r% I, Z# b' m
- #endif
复制代码 # Q8 \9 u, W `7 B" z# P
11.3 MDK锁定硬件异常位置方法, H @% }# v$ G6 w0 I
以本章配套的例子为大家做个说明。6 [- K3 ]) X9 b# L
1 B# U \% H- N; [/ G1、测试方法比较简单,进入调试状态,全速运行,然后按下K1按键,就会进入硬件异常中断,此时停止调试,程序就会自动定位到如下位置:% j2 I6 R4 |) [' z, E2 J
8 b+ N2 x! ^9 J' X" |
0 T. a$ f0 i" A: w8 \6 v
6 ~! F5 Z' Z9 ]8 H2、在Watch1窗口添加变量_Continue1 L. e' Z$ @. m- F& H- A
3 `3 y0 U2 m7 D2 ?" K9 @
- h3 I+ G F0 d4 \
5 F- A' a/ I+ U( f1 Y( d5 k$ s, f3、修改为任何非0数值,就可以继续单步调试。这个代码后面还有一个第1步中的while循环,也可以继续采用第2步的方法修改。退出硬件异常后就是大家进入硬件异常前下一条要执行的指令(可能还是这个函数本身,因为一个函数由多个指令完成)。定位到出问题的位置:9 u/ D k1 B9 Q o3 I, z6 i
: X, x1 v5 d, \5 _9 ^' s2 Y. L, Z
- j3 p/ j$ Z- Z( R( N' T* y# b! l' H8 i$ A. z! H, g# W' Z
11.4 IAR锁定硬件异常位置方法
' |- I" M# H( @# \以本章配套的例子为大家做个说明。: R- b2 v# V( P9 M1 S; e3 P# ~/ {) S
6 c9 q5 q V) Q' I& G( |* M
1、测试方法比较简单,进入调试状态,全速运行,然后按下K1按键,就会进入硬件异常中断,此时停止调试,程序就会自动定位到如下位置:, ^$ N7 B4 T3 N' o7 {
5 P2 |! {& q S% N0 G
2 C/ K( n! q5 s, T* ~5 h7 ]& r+ `
& O5 p. R) O* Y9 E+ F8 b3 J2、在Watch1窗口添加变量_Continue
# A1 P0 w8 Y: p9 O9 V( p) P
% D* c7 w+ q9 a) Q7 X
/ D' \4 \6 t2 W+ j7 k
& d( u2 M4 y( \$ t+ }/ ~! k, q3、修改为任何非0数值,就可以继续单步调试。这个代码后面还有一个第1步中的while循环,也可以继续采用第2步的方法修改。退出硬件异常后就是大家进入硬件异常前下一条要执行的指令(可能还是这个函数本身,因为一个函数由多个指令完成)。定位到出问题的位置:
- K/ z9 f. E0 D: W
, Q5 r+ [$ b) ?) E1 \+ Y5 W, g5 }) h& r6 X/ O( D
3 E# T' M2 F/ ?8 P4 w11.5 硬件异常原因分析" @9 S2 ]1 E+ P
SEGGER提供的这个机制查找出问题的位置比较方便,具体原因需要继续在调试界面里面添加HardFaultRegs结构变量,这个结构体变量添加了所有大家想看的东西。下面是MDK调试状态查看部分结构体数值:2 s6 M3 U) i- G& N! e
- c% M6 S# e% a( P- u$ C
0 }# r3 Z- I& H1 o
6 a, H5 B3 r/ F- d# h具体上面的变量代表什么含义呢,代码里面有注释,查阅起来没有IAR自带的硬件异常提示方便(注意,下面的代码用到了位域)。
9 g7 t- J* q. C0 Z7 U/ d5 y, R2 L% F" e7 s' Z$ Q: h2 ~% }# H- @: R4 ]
- #if DEBUG3 T1 g2 a6 t1 ~ z! f
- static volatile unsigned int _Continue; // Set this variable to 1 to run further
! b8 o, N* b4 K5 @
" `. v1 `, x+ N- static struct {
3 W8 F) A/ n4 G: K: g - struct {
/ F; |# _- U' I/ e1 q - volatile unsigned int r0; // Register R0
4 L( V$ M, o2 D7 N' d - volatile unsigned int r1; // Register R1
- H, T0 O3 u+ y. o& O6 | - volatile unsigned int r2; // Register R2
' ]5 j& b1 |9 Z8 I X - volatile unsigned int r3; // Register R3" m: A/ D' ^2 K5 D8 r. S( G: ?
- volatile unsigned int r12; // Register R121 _& I/ z+ N1 ]- l
- volatile unsigned int lr; // Link register
) ^$ z3 |* c7 B4 I8 w9 E/ _1 `5 y' o - volatile unsigned int pc; // Program counter: z9 `) B1 e, h \7 n
- union {0 }3 o7 v0 ^. t2 G5 L
- volatile unsigned int byte;
8 C: b5 H, {# k/ _: R& e$ ^ - struct {- G& F) `( p0 M9 o
- unsigned int IPSR : 8; // Interrupt Program Status register (IPSR)/ c. \2 U3 m" S6 T6 O+ E$ F/ g
- unsigned int EPSR : 19; // Execution Program Status register (EPSR)2 ?7 {5 J& }8 g' [( V$ c A
- unsigned int APSR : 5; // Application Program Status register (APSR)
5 n- g$ j; c3 \9 B - } bits;% i& X. o8 ?5 `' Q
- } psr; // Program status register.$ |2 y, K( ~ @1 x
- } SavedRegs;! P t; r4 E9 D+ k' b5 l; z
a" t3 j) h3 L+ m1 P- union {
* s% R9 T" w2 Y - volatile unsigned int byte;
9 n/ X; [6 H6 g1 ?; \ - struct {
: J7 k: e9 H3 K. a1 E$ B4 |0 r - unsigned int MEMFAULTACT : 1; // Read as 1 if memory management fault is active
8 Z5 J# l4 ^+ m f/ w7 T - unsigned int BUSFAULTACT : 1; // Read as 1 if bus fault exception is active. A d7 p+ w5 y9 N
- unsigned int UnusedBits1 : 1;
3 `- l5 G7 X+ ]" H; ~1 S - unsigned int USGFAULTACT : 1; // Read as 1 if usage fault exception is active* k$ J' M e5 b& g7 Q0 g$ e
- unsigned int UnusedBits2 : 3;( o g6 b" I! i2 K7 ?% M
- unsigned int SVCALLACT : 1; // Read as 1 if SVC exception is active! t; W6 X# P, P7 N. K7 ]4 r
- unsigned int MONITORACT : 1; // Read as 1 if debug monitor exception is active
+ K% _+ |" F0 ^/ q5 F - unsigned int UnusedBits3 : 1;6 L& R1 X4 N r* V# {+ m
- unsigned int PENDSVACT : 1; // Read as 1 if PendSV exception is active7 D2 D* ]* _( e p/ I
- unsigned int SYSTICKACT : 1; // Read as 1 if SYSTICK exception is active$ r4 w" ?4 ^ d7 h$ `
- unsigned int USGFAULTPENDED : 1; // Usage fault pended; usage fault started but was replaced by a
) H: I' ^- y$ U( n; W - higher-priority exception7 q. @* k3 ?0 [$ W
- unsigned int MEMFAULTPENDED : 1; // Memory management fault pended; memory management fault started3 Q" ~( K+ ]- H7 L1 J' Q7 @
- but was replaced by a higher-priority exception1 r, | D. k6 t% `6 B
- unsigned int BUSFAULTPENDED : 1; // Bus fault pended; bus fault handler was started but was replaced( Z- c$ k0 ~4 A
- by a higher-priority exception' g; [4 O- |& V. U$ j, ?0 v% k
- unsigned int SVCALLPENDED : 1; // SVC pended; SVC was started but was replaced by a higher-priority
) R- ~* d7 e7 W2 n3 L1 U - exception9 |- M* j% E1 g; U4 r
- unsigned int MEMFAULTENA : 1; // Memory management fault handler enable
1 L6 U1 X+ b: c; ~; a2 n" [ - unsigned int BUSFAULTENA : 1; // Bus fault handler enable
# R W! ~# t9 |1 O2 {' r - unsigned int USGFAULTENA : 1; // Usage fault handler enable
I, b9 W. M; _; Q) \. Z+ z( l - } bits;
& h) B3 Z: C- k) P2 ^# ]- B - } syshndctrl; // System Handler Control and State Register (0xE000ED24); \4 z3 \; j0 M$ U& d0 p' B
- 3 S8 u- h! ]% \7 U% E9 F
- /* 省略未写 */9 M' l% g8 k8 N# ` B* s
- ) A' B5 Y" G2 l% F4 X/ v
- volatile unsigned int afsr; // Auxiliary Fault Status Register (0xE000ED3C), Vendor controlled (optional)0 H9 A8 l B3 q8 X1 [* `) y3 a
- } HardFaultRegs;
' h1 ~, r6 D5 f! s- a: h1 A3 P, F5 O - #endif
复制代码
( O- i2 r% ]' w: G5 G11.6 IAR自带的硬件异常分析: r" h; |8 A, H
还以本章配套的例子为例,进入调试状态,全速运行,然后按下K1按键,就会进入硬件异常中断,此时停止调试,IAR还会弹出一个硬件异常错误分析,刚进来的时候也许是个空白
' l b- T" d2 a% U* O; q8 ^" G' x( V
8 g/ I' P6 K& U; ^4 z
' P, B- P5 y. e+ s/ g- z# q6 y, k
单步调试刷新下就出来了:5 W4 L, T- G- z* B
5 l/ }5 }. i- Z5 D |4 s* P5 ^
1 n6 S, i i" ^2 d) H; b/ z8 J; `4 \4 l3 T
指出了问题的原因是操作的数据地址有问题。$ k& r9 M" e; O$ e# b1 u S' n6 I; x
# ] m5 Q5 b$ c. ^- @" Q" N
11.7 实验例程0 E5 d& a1 i3 U0 g3 ]
专门为本章节配套了一个例子:V7-009_移植SEGGER的硬件异常分析机制。大家可以按照本章教程提供的方法进行测试。% S% I" X9 K1 H `3 e
5 M0 C) O$ i$ Q& U# g* I4 r
11.8 总结" V# H) [- S: s
除了SEGGER的硬件异常分析方案,建议也测试下MDK和IAR的,以后遇到硬件异常问题,解决起来可以得心应手。
, P1 z; h9 ^: d( Y9 o# N; C( y* P, L; Z# Y; r% o: P
) |% [4 x6 l( | S4 c" x |