打印
[技术问答]

Cortex-M 处理器 hardfault 定位方法和步骤

[复制链接]
4061|56
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
pentruman|  楼主 | 2024-8-12 10:16 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

一. 问题的产生

  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 */  }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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;     }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

三. 人工查找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 方法和步骤

  实际环境中,由于测试时产品常常无法连接调试器,故需要代码来定位目标语句地址,并通过一定手段保存


使用特权

评论回复
沙发
geraldbetty| | 2024-8-12 20:40 | 只看该作者
可以检查Call Stack来确定错误发生的具体位置。

使用特权

评论回复
板凳
robincotton| | 2024-8-12 22:18 | 只看该作者

未初始化硬件即开始操作              

使用特权

评论回复
地板
班杰明| | 2024-8-12 22:44 | 只看该作者
初始化的问题吗

使用特权

评论回复
5
claretttt| | 2024-8-13 02:04 | 只看该作者
检查中断服务函数是否正确处理和退出。

使用特权

评论回复
6
mollylawrence| | 2024-8-13 05:43 | 只看该作者
在发生异常时会被设置。通过分析这些寄存器的状态,可以判断出是哪个具体的Fault导致了Hard Fault。

使用特权

评论回复
7
louliana| | 2024-8-13 13:30 | 只看该作者
访问无效内存地址
任务堆栈溢出              

使用特权

评论回复
8
i1mcu| | 2024-8-13 18:25 | 只看该作者
时钟、复位和电源管理电路是否正常工作。

使用特权

评论回复
9
micoccd| | 2024-8-14 15:17 | 只看该作者
单片机开发最怕遇到hardfault

使用特权

评论回复
10
macpherson| | 2024-8-14 21:49 | 只看该作者
使用断点来暂停程序执行,然后检查寄存器和堆栈信息。

使用特权

评论回复
11
tifmill| | 2024-8-15 12:08 | 只看该作者
在调试器中查看异常发生时的 Cortex-M 处理器 状态,包括寄存器值、堆栈内容和程序计数器(PC)。

使用特权

评论回复
12
mmbs| | 2024-8-15 15:50 | 只看该作者
需要确保硬件没有问题。这包括检查电源、时钟、复位信号等是否正常工作。

使用特权

评论回复
13
pl202| | 2024-8-17 11:50 | 只看该作者
使用未初始化的指针              

使用特权

评论回复
14
plsbackup| | 2024-8-17 14:11 | 只看该作者
无中断服务函数等              

使用特权

评论回复
15
albertaabbot| | 2024-8-17 16:21 | 只看该作者
确保所有数组访问都在其定义范围内。

使用特权

评论回复
16
deliahouse887| | 2024-8-17 18:24 | 只看该作者
可以在Keil的Watch窗口中查看这些全局变量的值

使用特权

评论回复
17
tabmone| | 2024-8-17 22:35 | 只看该作者
可以编写代码来保存栈信息到全局变量中。

使用特权

评论回复
18
macpherson| | 2024-8-18 09:39 | 只看该作者
需要确保硬件没有问题。这包括检查电源、时钟、复位信号等是否正常工作。

使用特权

评论回复
19
jonas222| | 2024-8-18 12:50 | 只看该作者
简化代码,逐步添加功能,以确定问题的根源

使用特权

评论回复
20
pentruman|  楼主 | 2024-8-18 16:40 | 只看该作者
检查是否存在内存泄漏、数组越界访问等问题。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

27

主题

1282

帖子

1

粉丝