11.1 初学者重要提示$ h* h* k/ A% s' Q0 r3 K$ ~5 A" Q
MDK本身也是支持硬件异常分析的,就是不够直观/ \) A3 U6 E U$ A8 j
9 }4 d# M- S4 P5 a, E( b
IAR8带的硬件异常分析比较好用,在本章11.6小节有说明。- N3 |; ^% v1 {! B/ b8 b
11.2 移植方法
, [( ]6 j% m2 R2 l; N; p: p: @; c直接移植SEGGER的硬件异常代码会有错误警告,这里针对IAR和MDK版本做了些简单修改,方便大家移植到自己的工程里面。7 Z6 `- F$ R U7 Y* J
3 v% s, ~: d4 V4 X
MDK版本移植! f* g; }( _2 k1 d7 ^
源文件位于本章配套例子的\User\segger\HardFaultHandlerMDK文件夹,添加如下两个文件到工程里面即可。& Y. ]. Z. n5 Z6 R+ n8 z w; J
( ^1 O! E+ u+ p, u0 H
" R/ Q3 n/ @8 N. k5 n7 o& v* G1 [
$ z5 Q; {$ X# }& I& K# D IAR版本移植! L/ @( w) i& } g; A M; `! c- U
源文件位于本章配套例子的\User\segger\HardFaultHandlerIAR文件夹,添加如下两个文件到工程里面即可。2 F: n9 k+ @$ A
0 ^6 w: {0 V: \' J, \# u7 L6 w
1 \# e9 O+ }( P6 K! b8 `$ v
. f) e% W3 S- Q0 z% g0 M! k% ]在文件SEGGER_HardFaultHandler.c里面都添加了串口打印功能,方便不用编译器的调试功能时,通过串口打印提示是否进入硬件异常。6 M: t! u6 N2 i: l9 t
3 R2 [7 {+ U3 ]4 A( R; t- #define ERR_INFO "\r\nEnter HardFault_Handler, System Halt.\r\n"- G% l+ [& G+ d3 d$ B
$ Z! ]+ ?) _; T5 Y8 r. A$ D- #if 1+ ^- d9 x. i3 {1 w. A* h$ `
- {2 E0 M' K _( P/ ?/ C
- const char *pError = ERR_INFO;* c% @) {: h* }8 p& X/ _) |
- uint8_t i;! P+ f% o3 [% Y: x3 E+ [4 ^
/ R$ Z/ Z& v! c: i! J) E- for (i = 0; i < strlen(ERR_INFO); i++)
X) x% i/ d, f, b; h: v; f - {. {5 Z" Y4 O+ D5 O$ ~ ]
- USART1->TDR = pError<i>;
5 P9 c8 _5 `7 L; i" E- A3 U g - /* 等待发送结束 */
! Q4 s( V0 c2 n- H - </i> while((USART1->ISR & USART_ISR_TC) == 0);
3 \* p1 T' t" f* I# M1 X) ~ - } / x, Y2 Z% X) { N) G
- }
S( x- o8 N; U$ [# u% T/ a - #endif
复制代码
" v4 b1 _: Y1 e/ L11.3 MDK锁定硬件异常位置方法$ W: ]$ ~( U& L) m( l% L' _
以本章配套的例子为大家做个说明。
* X: g% `! v$ v+ u! t3 d7 c2 l, J" Q
1、测试方法比较简单,进入调试状态,全速运行,然后按下K1按键,就会进入硬件异常中断,此时停止调试,程序就会自动定位到如下位置:8 d9 I& | d ^
+ B5 [4 F7 r4 I; n( l3 A2 V; `, p6 y7 i& z! z% _9 M
1 U s* I L$ ?9 W2、在Watch1窗口添加变量_Continue1 |0 o# I n* A1 r$ G9 ~
' F8 j% p0 `9 z* n% W7 I$ }
+ h7 Q, c- s0 E; _, l) K1 z$ S- y& Y$ d1 Q
3、修改为任何非0数值,就可以继续单步调试。这个代码后面还有一个第1步中的while循环,也可以继续采用第2步的方法修改。退出硬件异常后就是大家进入硬件异常前下一条要执行的指令(可能还是这个函数本身,因为一个函数由多个指令完成)。定位到出问题的位置:1 ], A+ p& h( k C7 Y" O2 A2 k. G
9 P( F1 o! u+ J3 e- F
! i, I0 z" X6 M* h( q F5 q& w6 T* k# ?" U1 C, P5 D$ S3 f& Y
11.4 IAR锁定硬件异常位置方法 t; p( a+ [, Q" X- l- ?0 g/ `: Y
以本章配套的例子为大家做个说明。! X! [; M7 f) x4 U) ^5 i
! f! d- L. ?( d2 F$ {
1、测试方法比较简单,进入调试状态,全速运行,然后按下K1按键,就会进入硬件异常中断,此时停止调试,程序就会自动定位到如下位置:
2 g. @% \% A+ k! Q
, _- d9 i1 u" Z1 b3 s2 g5 H. l4 v# f( x& M
- U z$ Z8 j, L2、在Watch1窗口添加变量_Continue0 ~0 K; Z9 v/ d
5 P6 ?% b% O6 h' Q
6 K; N, f; O5 |2 S/ m( c8 \0 j. ^$ w/ Y7 C- c0 x) m
3、修改为任何非0数值,就可以继续单步调试。这个代码后面还有一个第1步中的while循环,也可以继续采用第2步的方法修改。退出硬件异常后就是大家进入硬件异常前下一条要执行的指令(可能还是这个函数本身,因为一个函数由多个指令完成)。定位到出问题的位置:" p) [- j' x# ^* i4 M( X
! O% J3 v( e2 V3 l1 {& M9 J
8 a8 }8 U# L2 X/ F e
4 j0 ~8 `, R; O. n11.5 硬件异常原因分析
# E, u, C, Q- R0 k1 B9 ASEGGER提供的这个机制查找出问题的位置比较方便,具体原因需要继续在调试界面里面添加HardFaultRegs结构变量,这个结构体变量添加了所有大家想看的东西。下面是MDK调试状态查看部分结构体数值:' p" P& H% i* m% Q) S$ V
0 V; g) M4 G2 j/ P, ~9 t% ?4 ~1 d/ I% ]4 O6 |" j$ ]
& d* J2 ^3 o& n k: V$ i具体上面的变量代表什么含义呢,代码里面有注释,查阅起来没有IAR自带的硬件异常提示方便(注意,下面的代码用到了位域)。: M2 Z9 R: d0 g# @3 P! H
. {& G+ W; A3 f. M! K! ^6 e- #if DEBUG
8 N4 |* @" M8 f+ ]0 j9 p - static volatile unsigned int _Continue; // Set this variable to 1 to run further
' L. s- t9 `* c: g1 H: e7 @/ {
3 Y) v$ z' |- ]( k& t- static struct {1 Q* T$ s& P$ b- C0 j* M8 r
- struct {
- f6 r) _ V) n- s5 Z- v2 }8 ^ - volatile unsigned int r0; // Register R0+ l) U- c( o' }
- volatile unsigned int r1; // Register R1
, f2 p4 R, l9 m9 N! H1 ^. D - volatile unsigned int r2; // Register R2' W* D' z0 X5 \3 V7 k+ ]
- volatile unsigned int r3; // Register R3
z* c+ g( l& H- x; T' k - volatile unsigned int r12; // Register R12
/ F5 f) i4 Q- v3 b5 o0 E1 q - volatile unsigned int lr; // Link register
- ^' {/ t: ?4 ~% o - volatile unsigned int pc; // Program counter
- W+ q$ k5 S9 w: f% a - union {- D: q; X5 |- z: j8 I
- volatile unsigned int byte;9 r% ?/ H y4 h4 y1 |* d5 k0 F2 ~
- struct {
' N' J. u6 }) ~2 P - unsigned int IPSR : 8; // Interrupt Program Status register (IPSR). Y3 X( a. `& N" ]% z( V, ~) C
- unsigned int EPSR : 19; // Execution Program Status register (EPSR)
( \. ^2 a: @ K8 L9 K% t" h a - unsigned int APSR : 5; // Application Program Status register (APSR)
* `% m, T) U! K- ] z2 K6 A - } bits;' c' K* M% d6 i' N3 ?: d
- } psr; // Program status register.
6 A$ ?4 d3 P4 p8 b. M4 K( U - } SavedRegs;
+ e7 p g# {3 d4 q; ^2 T' b8 P
& _. |' ]4 D, a. H d7 v- union {
. g$ ^+ R* B# t% E$ w - volatile unsigned int byte;
) F3 H7 u* D- t/ d- w9 g3 J2 O - struct {
" K% x2 l& @6 w# P% s - unsigned int MEMFAULTACT : 1; // Read as 1 if memory management fault is active
' O8 n1 S+ o9 h. \- M - unsigned int BUSFAULTACT : 1; // Read as 1 if bus fault exception is active$ F& k8 E8 S$ U" @
- unsigned int UnusedBits1 : 1;
" \0 P( g3 R' i$ K! G7 N - unsigned int USGFAULTACT : 1; // Read as 1 if usage fault exception is active
7 y& Q8 j. {+ J( j" O7 |) R - unsigned int UnusedBits2 : 3;
( T/ v2 k+ y2 m( L! b% L3 D5 R - unsigned int SVCALLACT : 1; // Read as 1 if SVC exception is active" o7 C+ X/ x+ R2 U% R8 E
- unsigned int MONITORACT : 1; // Read as 1 if debug monitor exception is active0 l( V7 i3 `5 s
- unsigned int UnusedBits3 : 1;2 s1 Y: R; c# x1 p4 F/ e: u" g
- unsigned int PENDSVACT : 1; // Read as 1 if PendSV exception is active' V6 P { @. S$ w8 h" q0 H
- unsigned int SYSTICKACT : 1; // Read as 1 if SYSTICK exception is active
9 _! {6 ?. Y+ r4 b - unsigned int USGFAULTPENDED : 1; // Usage fault pended; usage fault started but was replaced by a& v2 p$ S8 L% g' Z( C
- higher-priority exception$ t( V( F! p, B0 n' N9 ?
- unsigned int MEMFAULTPENDED : 1; // Memory management fault pended; memory management fault started# b& [8 v& X, d5 {+ s
- but was replaced by a higher-priority exception+ R( {8 X h L: B. ~
- unsigned int BUSFAULTPENDED : 1; // Bus fault pended; bus fault handler was started but was replaced7 L& _* n1 Z( I7 o& x
- by a higher-priority exception
4 G) z# C* M6 ?/ d - unsigned int SVCALLPENDED : 1; // SVC pended; SVC was started but was replaced by a higher-priority
- P) {& N9 I- ]& q- k# s. U% Q9 x# g+ @ - exception
& k6 C: k2 T7 A# O2 u' i - unsigned int MEMFAULTENA : 1; // Memory management fault handler enable
1 x+ C; ?. J& i+ v: h0 {/ W' ~ - unsigned int BUSFAULTENA : 1; // Bus fault handler enable8 }7 b" O, H& Q9 R* ~
- unsigned int USGFAULTENA : 1; // Usage fault handler enable
7 b3 R$ C3 G1 C6 Q0 N) k5 K - } bits;
- A- o/ W3 z6 A% Q" N - } syshndctrl; // System Handler Control and State Register (0xE000ED24)
: E R1 C4 T0 h, b - 3 O& W9 w1 S! m3 V9 q8 t6 ?7 r+ C
- /* 省略未写 */" o% s% a3 Y/ W: W- H- x
- / |, Z; k. ^/ K" X$ I9 x R) K
- volatile unsigned int afsr; // Auxiliary Fault Status Register (0xE000ED3C), Vendor controlled (optional)' B+ o1 }1 Z2 D: q" _
- } HardFaultRegs;
5 V( } `4 g8 h3 k- I - #endif
复制代码
+ ~2 u; h% G/ ]( |; P8 v3 y11.6 IAR自带的硬件异常分析
. Q+ O7 f; W3 m* Z6 @! P还以本章配套的例子为例,进入调试状态,全速运行,然后按下K1按键,就会进入硬件异常中断,此时停止调试,IAR还会弹出一个硬件异常错误分析,刚进来的时候也许是个空白+ n' ?4 z* ]. N3 `" I7 k6 I
; d' Q' K4 Q4 z" T0 H2 L$ Z5 u; P C* C, g- d
, {' k* f) E* d& j6 P单步调试刷新下就出来了:
* N* d. U$ U# Y: o' U% C2 n
* ~3 N; e3 \" p% }% X
# e, j# S% b8 y7 T G5 B3 _( ]8 t. ?. U9 {: I6 J
指出了问题的原因是操作的数据地址有问题。( @, q0 j! w* ]- i. j( m E
4 R& U. [: j3 N# Q
11.7 实验例程1 a3 W' S/ A" R1 n2 b+ f
专门为本章节配套了一个例子:V7-009_移植SEGGER的硬件异常分析机制。大家可以按照本章教程提供的方法进行测试。+ T% ] U M5 S- g. ~2 W( r
3 I- y* K/ W2 h9 U
11.8 总结
; c( T! y: _% ]4 h/ f: p2 t* \除了SEGGER的硬件异常分析方案,建议也测试下MDK和IAR的,以后遇到硬件异常问题,解决起来可以得心应手。
! |( x- k3 X5 p3 @ c! H! ]: B, p
8 L( k; h) S9 V1 V' n; Y8 H8 U# _2 y2 _
|