一. 问题的产生 Hard fault (硬错误,也有译为硬件错误的)是在STM32上编写程序中所产生的错误,造成Hard Fault错误的可能原因较多,排除硬件问题,如何在代码量较大的情况下,快速定位造成的hardfault的问题代码,就成为比较关键的问题。 本文将基于STM32处理器(stm32f091),keil-MDK开发环境,总结hardfault的调试定位方法。在其他Cortex-M0 (m3,m4)内核处理器,和其他开发环境下,也可作为参考。 二. Cortex-M 处理器内核异常中断简介 1)错误种类 对于Cortex-M内核,架构采用错误异常的机制来检测问题,当核心检测到一个错误时,异常中断会被触发,并且核心会跳转到相应的异常终端处理函数执行,错误异常的终端分为以下四种: HardFault
MemManage
BusFault
UsageFault 其中hardfault为最常见的错误类型,并且,在没有开启其他异常处理的情况下,默认进入hardfault异常中断处理函数: void HardFault_Handler(void){ /* USER CODE BEGIN HardFault_IRQn 0 */ /* USER CODE END HardFault_IRQn 0 */ while (1) { /* USER CODE BEGIN W1_HardFault_IRQn 0 */ /* USER CODE END W1_HardFault_IRQn 0 */ }}2) 可能的原因 从软件角度,产生hardfault的可能原因有: (1) 数组越界
(2)野指针
(3)未初始化硬件却开始操作,或无中断服务函数等 (4)任务堆栈溢出 《ARM Cortex-M0权威指南》中提到,关于 Cortex M0+内核主要有以下几点引起 HardFault 的原因:
非法存储器访问
非对齐数据访问
从总线返回错误
异常处理中的栈被破坏
程序在某些 C 函数中崩溃
意外地试图切换至 ARM 状态
在错误的优先级上执行系统服务调用指令(SVC)
下面将以一个stm32f091上运行的数组越界代码为例,具体阐述定位步骤: 产生越界的代码段: void StackFlow(void){ int a[3],i; for(i=0; i<10000; i++) { a=1; }}三. 人工查找hardfault 方法和步骤 方法1.查看寄存器 1)查看fault种类 通过菜单栏Peripherals >Core Peripherals >Fault Reports打开fault reports
2)调试定位步骤 查看fault种类有时可能对解决问题并没有直接帮助,关键是如何定位在进入异常中断前执行的代码段,步骤如下: a. 确定当前使用堆栈是MSP还是PSP 异常发生后会把进入异常前的 R0-R3,R12, LR, PC,PSR 寄存器值栈入 Main Stack 或Process Stack(取决于异常发生时使用的哪个栈)。 进入异常后链接寄存器 LR 中存放异常返回值 EXC_RETURN, 如果其 bit 2=0 那么用的就是 Main Stack,如果 bit 2=1,那么用的就是 Process Stack。 由下图可以看出,当前使用的堆栈为PSP b.找到异常发生代码地址 在memory中,定位到堆栈地址:0x200020E0,依据:R0~R3、R12、LR、PC、XPRS 顺序,找到LR的值,即第6个寄存器值 LR = 0x0800632B PC = 0x08006300 c.Disassembly中,查找定位代码 在反汇编窗口中点击右键,选中show disassembly at address 。 输入LR地址:为发生异常后调用的下一条指令的地址,可看到发生异常的为StackFlow()函数 输入PC地址:可以定位到发生异常的调用语句 方法2:调试步骤
在仿真状态下,调出Call Stack Window,可直接跳转到调用代码 四. 程序查找hardfault 方法和步骤 实际环境中,由于测试时产品常常无法连接调试器,故需要代码来定位目标语句地址,并通过一定手段保存
|