STM32 Cortex-M3 HardFault异常定位

目录

1 Fault类异常

1.1 总线Fault

1.2 存储器管理Fault

1.3 用法Fault

1.4 硬件Fault

2 Core Registers

2.1 R14(LR)寄存器

2.2 R15(PC)寄存器

3 HardFault处理原理

4 真实项目调试


1 Fault类异常

Cortex-M3的Fault异常分为:

  • 总线Fault
  • 存储器管理Fault
  • 用法Fault
  • 硬件Fault

1.1 总线Fault

这里引用《Cortex-M3权威指南》说法:

可以通过地址0xe000ed29查看具体是什么异常。

1.2 存储器管理Fault

这里引用《Cortex-M3权威指南》说法:

可以通过地址0xe000ed28查看具体是什么异常。

1.3 用法Fault

这里引用《Cortex-M3权威指南》说法:

可以通过地址0xe000ed2a查看具体是什么异常。

1.4 硬件Fault

硬件Fault也就是我们所说的HardFault,只要产生了总线、存储器管理、用法Fault其中之一,就会上报给硬件Fault,所以,最终的Falut我们都可以通过HardFault查看。

可以通过地址0xe000ed2c查看具体是什么异常。

2 Core Registers

讲了几种Fault之后,我们需要了解一些基本的内核寄存器,后续查找Fault提供帮助。

2.1 R14(LR)寄存器

R14(LR):连接寄存器,当呼叫一个子程序时,由R14存储返回地址。

当只有一级子程序的时候:把返回地址直接存储在R14寄存器中,这样就无需访问内存(堆栈内存,进栈和出栈),从而提高子程序的调用效率;

当子程序多于一级的时候:前一级存储在R14的返回地址值压到堆栈里,保留最后一级的返回地址在R14里面;

注意:在RAM上编程时,应尽量只使用寄存器保存中间结果,迫不得已时才访问内存。

  1. 如图所示,当程序执行到0x08001224地址的时候,CM3内核会把0x08001228存到LR中(实际存入的是0x08001229,因为是Thumb-2指令),并在进入子程序之后把LR压栈(因为子程序里面存在子程序,如果子程序不存在子程序,就不会压栈);
  2. 当程序执行到0x08001400的时候,由于LR已经压栈,所以LR的值就会重新存储0x08001404,当执行完NVIC_Init程序之后,BL LR(LR的值为0x08001404)就会无条件跳转到0x08001404处继续执行(此时需要把LR出栈,出栈的值是0x08001228);
  3. 最后执行完NVIC_Configuration之后,就会执行BL LR返回到0x08001228处继续执行代码。

2.2 R15(PC)寄存器

R15:程序计数寄存器,指向下一次要执行的程序地址。必须保证PC的数值是奇数,用于表示在Thumb状态下执行。

当中断来临的时候,R0-R3、R12、LR、PC、xPRS寄存器会自动的压栈,如果中断中使用了其它寄存器,在进入中断之前,也会对使用到的寄存器自动的压栈。

3 HardFault处理原理

如果程序进入hardfault,那么首先找到SP指针的值,然后根据SP指针的值,找出对应地址所存放的寄存器(CM0和CM3目前这些地址存放的寄存器相同)。

然后主要是定位LR和PC的值,LR指的是发生异常前本来要执行的下一条指令的地址,但是由于异常的产生,不会执行这条指令(只需要在这个地址之前打一个断点,根据条件来找寻出错的点),PC是发生异常前紧接着执行的地址。

4 真实项目调试

真实项目中,我们大多不必关心Fault状态寄存器的值,因为只要我们定位到错误的代码的位置,我们大致都能知道是什么错误了。

1. 首先工程跑到hardfault了;

2. 通过SP指针找到PC的值为0x08000046,LR的值为0x08001DEB,可知程序在执行了0x08000046指令之后就进入了HardFault,此时程序不会执行0x08001DEB这条指令。如果程序没有进入HardFault,那么子函数就会返回0x08001DEB这条指令。

3. 找到LR和PC指针指向地址的程序位置,可知道PC指针的值是中断向量表,这里又没用开PVD中断,所以断定是这里出错了;

4. 在LR地址的前一条指令的位置打上断点,确定程序在这里执行完之后,就出错了;

5. 通过发现是(*pEpInt_IN[EPindex-1])();函数的位置出错,所以把watch窗口打开,查看这个函数的地址和返回值,发现返回值是0x08000046,所以这个值出错了,因为返回值成功是0,失败不可能是0x08000046(从调试信息可知,此函数的地址是0x20000018,所以返回值写入的是0x20000018);

6. 增加条件断点,当0x20000018地址的值被修改了之后产生断点,捕捉哪里把0x20000018的值修改为了0x08000046,通过断点可知,在下面代码的时候导致了hardfault,进一步得知是数组溢出导致。

  • 25
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

binhaoPro

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值