你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

Ubuntu下开发STM32---11.HardFault,div0

[复制链接]
qianfan 发布时间:2015-12-5 16:36
本帖最后由 QianFan 于 2015-12-5 16:43 编辑 5 k* n7 b+ j- q9 F
* Q8 D/ ?/ ?! m/ ?( `9 Z% S
   看了creep发的一篇帖子https://www.stmcu.org.cn/module/forum/forum.php?mod=viewthread&tid=602444&highlight=hardfault,讲解的是如何找出程序中的HardFault。creep的帖子中提到了一个老外的链接http://blog.feabhas.com/2013/02/developing-a-generic-hard-fault-handler-for-arm-cortex-m3cortex-m4/,讲解的是如何使用keil mdk找出因除0导致的HardFault。keil mdk自然是挺好用的,可是linux下开发调试和windows下开发调试稍有不同。下面就在linux环境下讲解一下如何进行调试。" V% N- I$ n1 }7 C7 \

# m8 [+ L# |% x3 J    工程使用的是硬件浮点。要注意的是,如果是小数除法,不管是不是打开了DIV_0_TRP,结果在使用printf输出的时候都是inf。只有整数除法在开启DIV_0_TRP的时候,才会触发HardFault。下面是main函数的测试代码:
; K9 q# v! ^  t! V) [- _! j
  1. ' i' H7 ?% q- P% I. Z5 E4 W
  2. int main(void); b! V% t" A( X: M( s
  3. {& r) G6 p4 u( G& P: N: [
  4.         int a=3,b=2;
    5 B5 u2 d. y( F5 J3 m# ?
  5.         printf("Try test div0 before set CCR:%d\n",a/0);
    6 Q: ]7 F9 C& l2 M
  6.         . x2 B. `  [1 Q1 Z5 l0 a$ v: ?
  7.         printf("\nSet SCB->CCR |= 0x10\n");
    & l. z% P' q% P4 _5 h. M
  8.         SCB->CCR |= 0x10;' \- Q; U9 U( c, Y# p  I6 \8 [
  9.         
    8 {1 N- }% e7 M$ F$ j9 O
  10.         printf("Try test div0 after set DIV_0_TRP,the result is:");( `3 c( u, q; V2 k3 u7 P5 t
  11.         printf("%d\n",a/0);) C& K4 p1 ]7 K3 x% N0 V
  12.         0 g2 C* z0 K8 }+ U8 e! N7 c
  13.         return 0;9 F% v' u! @: \# `* a! d8 @/ a
  14. }
    6 }& T! o% E+ w$ B' V

  15. $ R3 r/ R* \" j& U5 Y# Y2 f' X
  16. void HardFault_Handler(void)8 U. Y/ r- I  C( s% }; |  G
  17. {1 x: Z% x) }, c5 Y5 C- e# z
  18.         __asm__ __volatile__ ("mrs r0,MSP");. N" I' M% @# d! G% Q, g
  19.         __asm__ __volatile__ ("bl print_sp");: _) J4 A6 i* j$ U, d
  20.         
    1 a. _( c0 h7 y5 a& L. @. v
  21.         while(1) ;
    8 s# Y" k2 e. m+ R% V
  22. }
    - M3 i0 ~9 C* b* Z2 T

  23. ! T! G. P$ |. X* f; }
  24. void print_sp(unsigned int *sp)( H  |, x9 N$ l, m0 R: e% H
  25. {% h' ~4 c3 E" A. M, Z$ h: J  m
  26.         printf("the sp address is :%x\n",(unsigned int)sp);
    ( y6 a+ z  ]! @+ I" C1 W
  27.         for(int i=0;i<9;i++)
    ; }8 y7 Y" T# G
  28.                 printf("sp[%d]=%x\n",i,sp[i]);
    $ G- C  e: h* [: X
  29. }$ V& W- Q! C2 c

  30. % @& g, u& H4 T+ n$ }( v2 @1 L9 |& z
复制代码

2 U# @% g' \1 ?) c4 i+ }1 Z    将代码编译好之后,使用gdb进行调试。先在HardFault_Handler处点一个断点:之后输入continue。使代码继续运行。这时候,在开启' V% ^. i0 x; ]( ?# y/ Z, q. t0 ^
DIV_0_TRP之前,进行除0运算的结果是0。没有引发HardFault。当开启了DIV_0_TRP之后,进入了HardFault。这时候可以使用info reg查看一下相关的寄存器。& D" N2 T8 ]- o* r
2015-12-05 16:07:26屏幕截图.png ! c* D  ?- l9 D8 X3 @

6 O" T8 [  _0 I% [    查看reg发现LR寄存器的数值是0xFFFF_FFF9。具体为什么是这个值,可以查看creep的原帖。7 L/ h+ r  h6 I$ G
2015-12-05 16:10:45屏幕截图.png 5 _1 z( X: K5 M* j' q

- B* Q; e: J. G0 n( y$ c1 H7 A+ Z    进入中断之后,需要知道是什么原因导致了HardFault。有两个相关的寄存器。分别是SCB->HFSR, SCB->CFSR.他们的地址分别是0xE000_ED2C,0xE000_ED28.使用x命令查看这两个地址:(从0xE000_ED28出查看了两个字)。关于这两个寄存器的详细解释请参考网址:HFSR和CFSR。说明问题是由除0导致的。具体导致这个HardFault的地址在入栈的PC处。: Y8 s, B0 O, h. M2 u& t

) i1 d) L" O) E- T; O 2015-12-05 16:14:18屏幕截图.png 1 p1 B' r: T5 l. n+ H& W. P
! ~$ A  s6 K/ i9 |: c8 Q+ c
2015-12-05 16:17:58屏幕截图.png
0 v, g; t" `9 M  z$ L( N) f
6 c& r/ f8 A% p    从info reg的信息中,我们可以找到进入HardFault的时候栈的地址。同样,使用x命令从sp的地方读取几个字看看:ARM在发生异常的时候会在SP中将R0-R3,R12,LR,PC,PSR进行压栈。只要我们找出栈中的PC,这个值也就是导致异常的代码处。你可能会从0x2000_FFF0开始数,认为他是R0。但是在ARM GCC中,这样是不对的。
6 C' Y  B! k2 S# S6 ~8 u  { 2015-12-05 16:22:39屏幕截图.png * T" u4 q, x/ s1 I" ~5 T! f
3 o: i& U3 v2 n- _! H) H- a
" }9 A* k, w6 s- N. j( ]
    使用disasseble查看当前位置的汇编代码:发现在当前的位置(也就是图中=>指向的位置)之前,已经发生过一次push了。因此sp中最新的一个数据应该是push的R7。所以x/10xw读出来的第一个数据是进入HardFault之后push的R7。从0x30处开始的数据才是进入中断之前自动压栈的。这样说,读出的PC也就是0x0800_2686.
5 K! B1 A: p$ ` 2015-12-05 16:28:58屏幕截图.png 5 g/ L# Z9 G9 H& D8 B, k2 c& u2 \

1 @  ]6 q9 J% C" w  k' s# ?- f0 N1 Y* e' l" @* ?, N+ x
对elf文件进行反汇编,查看0x0800_2686处的指令:从这个地方可以找到我们的硬件除法的指令。因为除0导致的HardFault。2 Q3 A% H& \; Y/ _) Z$ ]1 s
2015-12-05 16:34:56屏幕截图.png 7 p7 C- f  C& _

6 N' X( q' _* _( O- V( ]/ [$ f4 T 2015-12-05 16:35:45屏幕截图.png
" K* R" O9 v2 N' k- m* i
7 A5 c/ W+ g- @3 d& j9 a( V0 ~$ K! W7 X5 M& W% J3 l
整个Makefile的工程在附件中可以下载。3 ]. M# c. B" ~0 \+ U: v1 g
另外,感到ARM GCC比较任性。看HardFault_Handler的代码,因为代码最后是一个死循环,代码索性连之前push的R7也不pop了。8 t& d1 Q) F6 L7 y+ _

div0_hardfault.zip

下载

594.59 KB, 下载次数: 38

评分

参与人数 1 ST金币 +20 收起 理由
沐紫 + 20

查看全部评分

赞 收藏 2 评论5 发布时间:2015-12-5 16:36

举报

5个回答
斜阳 回答时间:2015-12-5 16:56:50
mark一下
orima 回答时间:2015-12-6 11:06:59
' @8 n1 n7 _5 E9 ?+ u# K
谢谢分享
qwe775208732 回答时间:2015-12-6 18:58:06
不觉明厉,不懂LINUX下玩,有没有教程
qianfan 回答时间:2015-12-6 19:00:21
qwe775208732 发表于 2015-12-6 18:58
9 d& I8 ^; D. j6 I不觉明厉,不懂LINUX下玩,有没有教程
* t; K& R6 j( ~: Y( @
https://www.stmcu.org.cn/module/forum/thread-603753-1-1.html
埃斯提爱慕 回答时间:2015-12-7 19:57:56
提示: 作者被禁止或删除 内容自动屏蔽
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版