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

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

[复制链接]
qianfan 发布时间:2015-12-5 16:36
本帖最后由 QianFan 于 2015-12-5 16:43 编辑
! }' ~( D9 O. o# s5 e
( W2 k5 i( u1 A   看了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环境下讲解一下如何进行调试。
: }# h7 U/ y+ I) K% t/ p( [0 i( _3 k9 a
: s. G' L6 v( r, }% u; `/ ?% ?( M    工程使用的是硬件浮点。要注意的是,如果是小数除法,不管是不是打开了DIV_0_TRP,结果在使用printf输出的时候都是inf。只有整数除法在开启DIV_0_TRP的时候,才会触发HardFault。下面是main函数的测试代码:  W; }( r5 y4 e' b* K

  1. 8 _0 f7 v% Y7 y  a
  2. int main(void)
    9 B# H% q! o$ B7 m: h: K8 Y
  3. {, t, N( B; I2 r, s
  4.         int a=3,b=2;0 u& H$ \1 {7 c/ w; x" U8 i$ j
  5.         printf("Try test div0 before set CCR:%d\n",a/0);. v& z, q+ K* X7 i
  6.         
    ! k( q  o( o  e+ }
  7.         printf("\nSet SCB->CCR |= 0x10\n");% h' U# ?- E2 z6 @# ]
  8.         SCB->CCR |= 0x10;
    - N+ g, V( `7 ~! B. z
  9.         
    6 i7 D7 Z9 p0 F( s$ {' l' k
  10.         printf("Try test div0 after set DIV_0_TRP,the result is:");& c+ {' Y1 K) c5 U* o
  11.         printf("%d\n",a/0);
    3 V% v$ l4 F' {+ L3 I" y3 T
  12.         
    $ _" [( |, _! H. q7 ~. Q0 A4 T
  13.         return 0;
    : P) p* w: z+ }; V
  14. }
    + D+ b! A  p( D7 Q, f0 v! I
  15. ! m$ F: ?$ w& K* g' w6 O
  16. void HardFault_Handler(void)
    + D6 E& |/ w9 w* q& J/ e  T
  17. {
    0 e$ }9 t0 O3 i
  18.         __asm__ __volatile__ ("mrs r0,MSP");
    # B- x7 O9 W& a! f  Y* Y
  19.         __asm__ __volatile__ ("bl print_sp");
    8 n+ n4 Q) V! e. g/ p" F$ @; ~
  20.         
    9 t1 U5 e6 |' V7 {* A0 C
  21.         while(1) ;
    # l% C9 ^- Y1 s) L) h4 D' i
  22. }
    ( r; i, ]0 }2 [0 O9 C! v
  23. " Q/ D  }% c' N3 n4 d: z5 d
  24. void print_sp(unsigned int *sp)1 W$ _1 D; V" F$ P9 `3 q
  25. {
    : i) ?. @9 t% V% X- Q* f8 I$ }
  26.         printf("the sp address is :%x\n",(unsigned int)sp);  H% Q2 H* @$ D
  27.         for(int i=0;i<9;i++)
    4 b, C8 c% B  B! O8 Z9 @% |6 g
  28.                 printf("sp[%d]=%x\n",i,sp[i]);  ]4 T$ h: c& B4 x* V) A4 T* T; ?
  29. }, c8 ]/ E# p/ n. R5 y" X6 F5 p. A/ _

  30. % A; J2 _2 o1 q: w$ `. |
复制代码
, V) @! g/ f/ E2 B
    将代码编译好之后,使用gdb进行调试。先在HardFault_Handler处点一个断点:之后输入continue。使代码继续运行。这时候,在开启
" {; D; k0 F- _- gDIV_0_TRP之前,进行除0运算的结果是0。没有引发HardFault。当开启了DIV_0_TRP之后,进入了HardFault。这时候可以使用info reg查看一下相关的寄存器。
, s( ?& j. j/ y* d 2015-12-05 16:07:26屏幕截图.png
1 q% F# D& _# r  w$ m( @  s4 {( L2 v! P0 w: E8 H7 g6 W) V2 ^
    查看reg发现LR寄存器的数值是0xFFFF_FFF9。具体为什么是这个值,可以查看creep的原帖。
* Y$ t5 `7 F! Z' ?: n* ~ 2015-12-05 16:10:45屏幕截图.png + d# |1 G$ |, h4 b$ Z
' d. m4 X- O* j0 o( X& y" a
    进入中断之后,需要知道是什么原因导致了HardFault。有两个相关的寄存器。分别是SCB->HFSR, SCB->CFSR.他们的地址分别是0xE000_ED2C,0xE000_ED28.使用x命令查看这两个地址:(从0xE000_ED28出查看了两个字)。关于这两个寄存器的详细解释请参考网址:HFSRCFSR。说明问题是由除0导致的。具体导致这个HardFault的地址在入栈的PC处。
1 s! M  [( |- @1 X3 t9 e. C8 n8 ]. g0 k5 e6 e
2015-12-05 16:14:18屏幕截图.png   C% |/ r* o6 f8 q5 y
  }2 N8 j) N, ^" }  u
2015-12-05 16:17:58屏幕截图.png ' o6 r. R$ ]% w5 B# z

) r# f0 ~$ h1 |    从info reg的信息中,我们可以找到进入HardFault的时候栈的地址。同样,使用x命令从sp的地方读取几个字看看:ARM在发生异常的时候会在SP中将R0-R3,R12,LR,PC,PSR进行压栈。只要我们找出栈中的PC,这个值也就是导致异常的代码处。你可能会从0x2000_FFF0开始数,认为他是R0。但是在ARM GCC中,这样是不对的。4 |$ x5 h' e5 \$ M6 [
2015-12-05 16:22:39屏幕截图.png ) x9 j# y4 \6 p5 C) u4 Y

7 x; e# s% N% l/ K& P6 B: {, N# j1 X! w9 Z; k4 `8 a: V. S( l+ [
    使用disasseble查看当前位置的汇编代码:发现在当前的位置(也就是图中=>指向的位置)之前,已经发生过一次push了。因此sp中最新的一个数据应该是push的R7。所以x/10xw读出来的第一个数据是进入HardFault之后push的R7。从0x30处开始的数据才是进入中断之前自动压栈的。这样说,读出的PC也就是0x0800_2686." s) M$ j" m$ p; m
2015-12-05 16:28:58屏幕截图.png
2 [# }2 ^7 f0 f
4 T" \3 Q9 R( l" d
3 G! Q4 g( w- r. ]- j/ a对elf文件进行反汇编,查看0x0800_2686处的指令:从这个地方可以找到我们的硬件除法的指令。因为除0导致的HardFault。% s. ~7 V) Z! {. K6 m2 B) }
2015-12-05 16:34:56屏幕截图.png , Q. U4 b; T1 ?+ V7 X' U# H/ \4 Y2 K

& u/ r9 }% D- q8 G5 { 2015-12-05 16:35:45屏幕截图.png
, Q, D! z; ]& D+ n+ b( D8 o- V5 A) g
+ m: m- b  @9 d+ t4 y  Y9 [" H( V  r, }2 ?$ T0 Z/ s+ E4 ^2 b
整个Makefile的工程在附件中可以下载。; U8 \# g+ B/ w' K7 j! }( y
另外,感到ARM GCC比较任性。看HardFault_Handler的代码,因为代码最后是一个死循环,代码索性连之前push的R7也不pop了。
5 t2 ]9 K, A/ ]- {) J

div0_hardfault.zip

下载

594.59 KB, 下载次数: 37

评分

参与人数 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

/ a" k% B5 K! u! a# F. m; C谢谢分享
qwe775208732 回答时间:2015-12-6 18:58:06
不觉明厉,不懂LINUX下玩,有没有教程
qianfan 回答时间:2015-12-6 19:00:21
qwe775208732 发表于 2015-12-6 18:58
9 E# ^. ~4 s  W) C不觉明厉,不懂LINUX下玩,有没有教程
8 Q" a' V8 Z2 V! [, e( O# ?! e! P
https://www.stmcu.org.cn/module/forum/thread-603753-1-1.html
埃斯提爱慕 回答时间:2015-12-7 19:57:56
提示: 作者被禁止或删除 内容自动屏蔽

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版