原文地址:http://www.51hei.com/bbs/dpj-39846-1.html


  看到有朋友遇到Hard Fault 异常错误,特地找到一篇飞思卡尔工程师写的一片经验帖,定位Hard Fault 异常。

  Kinetis MCU 采用 Cortex-M4 的内核,该内核的 Fault 异常可以捕获非法的内存访问和非法的编程行为。Fault异常能够检测到以下几类非法行为:
  总线 Fault: 在取址、数据读/写、取中断变量、进入/退出中断时寄存器堆栈操作(入栈/出栈)时检测到内存访问错误。
  存储器管理 Fault: 检测到内存访问违反了内存保护单元(MPU, MemoryProtection Unit)定义的区域。
  用法 Fault: 检测到未定义的指令异常,未对其的多重加载/存储内存访问。如果使能相应控制位,还可以检测出除数为零以及其他未对齐的内存访问。
  硬 Fault: 如果上述的总线 Fault、存储器管理 Fault、用法 Fault 的处理程序不能被执行(例如禁能了总线 Fault、存储器管理Fault、用法Fault 的异常或者在这些异常处理程序中又出现了新的Fault)则触发硬Fault。
  
  在 MQX 操作系统启动的时候会安装上默认的异常中断处理函数,当系统异常时会产生一个“unexpected”中断,内核就会自动调用异常处理函数,同时也将运行用户自定义的处理函数,来实现特殊故障的定位方法。
  默认情况下,MQX把出现异常的任务挂起,避免故障进一步扩大。通过TAD 任务感知调试插件的Task summary 功能,我们可以观察到出现异常的任务情况。
  

  
  开发人员在调试期间,需要弄清楚系统异常触发了哪类Fault,由什么原因触发了Fault 以及定位触发Fault 的代码。在这种情况下,可以利用自定义的Fault 中断处理程序来分析Fault 出错原因。
  
  为了解释所述的 Fault 中断处理程序的原理,这里重述一下当系统产生异常时 MCU 的处理过程:
  1. 有一个压栈的过程,若产生异常时使用 PSP(进程栈指针),就压入到 PSP 中,若产生异常时使用MSP(主栈指针),就压入MSP 中。
  2. 会根据处理器的模式和使用的堆栈,设置 LR 的值(当然设置完的LR 的值再压栈)。
  3. 异常保存,硬件自动把 8 个寄存器的值压入堆栈(8 个寄存器依次为 xPSR、PC、LR、R12以及 R3~R0)。如果异常发生时,当前的代码正在使用PSP,则上面8 个寄存器压入PSP; 否则就压入MSP。

  当系统产生异常时,我们需要两个关键寄存器值,一个是 PC ,一个是 LR (链接寄存器),通过 LR找到相应的堆栈,再通过堆栈找到触发异常的PC 值。将产生异常时压入栈的 PC 值取出,并与反汇编的代码对比就能得到哪条指令产生了异常。
  这里解释一下关于 LR 寄存器的工作原理。如上所述,当 Cortex-M4 处理器接受了一个异常后,寄存器组中的一些寄存器值会被自动压入当前栈空间里,这其中就包括链接寄存器(LR )。这时的 LR 会被更新为异常返回时需要使用的特殊值(EXC_RETURN)。
  关于EXC_RETURN 的定义如下,其为 32 位数值,高 28 位置 1,第 0 位到第三位则提供了异常返回机制所需的信息,如下表所示。可见其中第 2 位标示着进入异常前使用的栈是 MSP还是PSP。在异常处理过程结束时,MCU 需要根据该值来分配 SP 的值。这也是本方法中用来判断所使用堆栈的原理,其实现方法可以从后面_init_hardfault_isr 中看到。
  

  另外,我们可以利用 MQX 的控制台串口输出Fault 异常信息来帮助调试。编写Fault 处理程序时,将启动代码中默认的Fault 处理程序跟换成自己需要的Fault 处理程序。需要注意的是,由于是在中断中进行打印输出,MQX的控制台串口只能使用POLL 轮询模式的驱动,不能使用中断模式的驱动。
  用户可以编写自定义的硬 Fault 处理程序_int_hardfault_isr,修改 MQX 的中断向量定义vector.c,把里面的DEFAULT_VECTOR 代码段换成下面的代码。当系统出现硬Fault 异常时,将会调用自定义的Fault 处理_int_hardfault_isr函数。在这个函数,我们可以通过StackTrace-back 回溯出现问题的代码。
  

  我们可以在_int_hardfault_isr 函数里将出现异常时的寄存器、堆栈、状态寄存器等信息打印出来。如果系统出现异常时,一般情况都会通过串口控制台打印出LR,PC的值。然后根据编译器生成的map 文件,找到出现问题的具体函数。
  

  从上图的串口输出我们可以看到 PC 和 LR 寄存器值,PC 的值为 0x56c6,我们根据汇编代码可以找到出现问题的指令。从而大大缩小了查找出现问题的范围,可以帮助开发人员快速定位问题的根本原因。

  附录Fault异常中断处理代码:

// hard fault handler in C,
// with stack frame location as input parameter
void hard_fault_handler_c (unsigned int * hardfault_args)
{unsigned int stacked_r0;unsigned int stacked_r1;unsigned int stacked_r2;unsigned int stacked_r3;unsigned int stacked_r12;unsigned int stacked_lr;unsigned int stacked_pc;unsigned int stacked_psr;stacked_r0 = ((unsigned long)hardfault_args[0]);stacked_r1 = ((unsigned long)hardfault_args[1]);stacked_r2 = ((unsigned long)hardfault_args[2]);stacked_r3 = ((unsigned long)hardfault_args[3]);stacked_r12 = ((unsigned long)hardfault_args[4]);stacked_lr = ((unsigned long)hardfault_args[5]);stacked_pc = ((unsigned long)hardfault_args[6]);stacked_psr = ((unsigned long) hardfault_args[7]);printf ("\n\n[Hard faulthandler - all numbers in hex]\n");printf ("R0 = %x\n",stacked_r0);printf ("R1 = %x\n",stacked_r1);printf ("R2 = %x\n",stacked_r2);printf ("R3 = %x\n",stacked_r3);printf ("R12 = %x\n",stacked_r12);printf ("LR [R14] = %x  subroutine call return address\n",stacked_lr);printf ("PC [R15] = %x  program counter\n", stacked_pc);printf ("PSR = %x\n",stacked_psr);/******************* Add yourdebug trace here ***********************/_int_kernel_isr();
}/* hard fault interrupt handler */
void _int_hardfault_isr( )
{__asm("TST LR, #4");__asm("ITE EQ");__asm("MRSEQ R0,MSP");__asm("MRSNE R0,PSP");__asm("Bhard_fault_handler_c");
}

HardFault 异常定位相关推荐

  1. stm32进入HardFault的异常定位方法

    在用Keil对STM32的程序进行仿真时程序有时会跑飞,停止仿真程序会停在HardFault_Handler函数里的死循环while(1)中.这说明STM32出现了硬件错误. STM32出现硬件错误可 ...

  2. ARM 之十二 Cortex-M 内核异常处理、异常定位方法、在线调试、Keil MDK-ARM 的使用

      Cortex-M 内核本身提供了非常强大的异常处理机制.它可以非常有效的捕捉非法的内存访问以及其他一些异常.而我们常用的开发工具的异常处理就是使用了 Cortex-M 核的异常处理机制.   在 ...

  3. (五)stm32工程代码HardFault异常查错调试方法

    (五)stm32工程代码HardFault异常查错调试方法 参考文章: (1)(五)stm32工程代码HardFault异常查错调试方法 (2)https://www.cnblogs.com/zhan ...

  4. FreeRTOS 中断优先级嵌套错误引发HardFault异常解决

    最近在使用FreeRTOS的时候,突然发现程序在运行了几分钟之后所有的任务都不再调用了,只有几个中断能正常使用,看来是系统挂掉了,连续测试了几次想找出问题,可是这个真的有点不知所措. 我先看了下文档里 ...

  5. WinCE中的Data/ Prefetch Abort异常定位

    WinCE中的Data/ Prefetch Abort等异常定位 在调试WinCE程序的时候,有时候会碰到Data/Prefetch Abort的异常,相信从事过WinCE开发的人对这种异常信息应该都 ...

  6. linux异常级别,linux性能异常定位之进程级别

    [前言] 本文和大家分享:linux系统下常见得性能异常,怎样定位到进程级别.说简单点,就是:linux性能出问题了,我们需要确定哪些进程影响了linux的性能. 本文主要涉及的linux的常见的性能 ...

  7. 异动分析(一)如何快速进行异常定位

    异动分析(一)如何快速进行异常定位 小P:小H,最近X(某指标)下降的有点狠啊,帮忙找找看原因呗- 小O:小H,今天Y(某指标)怎么没数据了,帮忙查查呗,急- 小H:- 相信大家对这些话应该很熟悉吧, ...

  8. c++程序异常定位方法

    文章目录 (一).core.dump (二).dmesg (三).pstack (四).strace (五).valgrind 对于c++程序来说,以segment fault为代表的程序异常行为前奇 ...

  9. 《异常检测——从经典算法到深度学习》20 HotSpot:多维特征 Additive KPI 的异常定位

    <异常检测--从经典算法到深度学习> 0 概论 1 基于隔离森林的异常检测算法 2 基于LOF的异常检测算法 3 基于One-Class SVM的异常检测算法 4 基于高斯概率密度异常检测 ...

  10. GD32F30x Keil 环境下在 FreeRTOS 任务中使用浮点运算报 HardFault 异常的问题(二)

    文章目录 1 问题描述 1. 1 环境 1. 2 问题 2 参考资料 3 来龙去脉 3.1 定位问题 3.2 xPortPendSVHandler 3.3 EXC_RETURN 3.4 寄存器 3.5 ...

最新文章

  1. 华为harmonyos 2.0,华为王成录博士:HarmonyOS 2.0给消费者不一样的体验
  2. [Python]再学 socket 之非阻塞 Server
  3. 页面浏览事件之 $AppViewScreen 全埋点
  4. 学习 TTreeView [8] - AlphaSort、CustomSort、SortType
  5. CodeFrist基础_迁移更新数据
  6. 机器学习笔记(了解)
  7. Nginx笔记-使用Nginx给vue应用设置一个代理
  8. 磁盘分区格式化及交换分区
  9. 《软件需求模式》05
  10. jQuery学习整理 (3) 使用jQuery操作元素的属性与样式
  11. mysql怎么查看记录时间戳_mysql TIMESTAMP(时间戳)详解——查询最近一段时间操作的记录...
  12. java 同余法产生随机数_线性同余法生成为随机数
  13. 关于 java中的换行符
  14. 一款强大的通讯录管理软件,Cardhop让你管理和编辑联系人更加方便和多样化
  15. ThingJS图表整合
  16. 传说中的考研神校,考研人数究竟有多高?
  17. Simulink 环境基础知识(二十一)--优化、估计和扫描模块参数值
  18. teach sex java_java反射机制
  19. 2015 android 5.0 手机排行榜,智能手机排行榜2015前十名 2015智能手机排行榜
  20. 【sdx62】QCMAP_CLI手动拨号操作说明

热门文章

  1. 【5G核心网】5GC核心网之网元UPF
  2. 显示器知识:分辨率1080P、2K、4K、8K相关知识介绍,看完你就懂了!
  3. 新个税计算html、以及java源代码
  4. 个人安卓学习笔记---搭建Androd开发环境
  5. java包装类string_Java学习之String类与包装类
  6. 聚沙成塔--爬虫系列(四)(爬取糗事百科段子)
  7. 微信小助手:专为mac微信3.1.0发行!支持发朋友圈!支持僵尸粉清理
  8. TCP/IP协议族的数据链路层基础(1)——MTU
  9. RPC系列协议--rfc1191--Path MTU Discovery
  10. poi 5.2.2 操作word合集之【页眉页脚】