STM32单片机的 Hard-Fault 硬件错误问题追踪与分析

这篇具有很好参考价值的文章主要介绍了STM32单片机的 Hard-Fault 硬件错误问题追踪与分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1、了解STM32的寄存器组

1.1、Cortex-M3的通用寄存器组

1.1.1、通用目的寄存器 R0-R7

1.1.2、通用目的寄存器 R8-R12

1.1.3、R13 — 堆栈指针(SP)

1.1.4、R14 — 连接寄存器(LR)

1.1.5、R15 — 程序计数器(PC)

1.2、Cortex‐M3 的特殊功能寄存器

1.2.1、xPSR — 状态寄存器

1.2.2、中断屏蔽寄存器组

1.2.3、控制寄存器(CONTROL)

2、CM3系统的异常类型 & 可能原因

2.1、Hard-Fault 错误发生时的有关寄存器

2.1.1、存储器管理 fault 状态寄存器(MFSR)

2.1.2、总线 fault 状态寄存器(BFSR)

2.1.3、用法 fault 状态寄存器(UFSR)

2.1.4、硬 fault 状态寄存器

2.1.5、调试 fault 状态寄存器(DFSR)

2.1.6、存储管理地址寄存器(MMAR)

2.1.7、总线 fault 地址寄存器(BFAR)

2.1.8、辅助 fault 地址寄存器(AFAR)

2.2、Hard-Fault 时定位入栈PC

2.3、发生Hard-Fault的可能原因

2.3.1、MemManage fault 的可能原因

2.3.2、总线 fault 的可能原因

2.3.3、用法 fault 的可能原因

2.3.4、硬 fault 的可能原因

2.3.5、调试 fault 的可能原因

3、使用 MDK-Keil 查找 Hard-Fault 的操作


       

        有过单片机开发经验的人应该都会遇到过硬件错误(Hard-Fault)的问题,对于这样的问题,有些问题比较容易查找,有些就查找起来很麻烦,甚至可能很久都找不到问题到底是出在哪里。

        特别是有时候出现一次,后面观察中都很久没发现过,这样的情况是很头疼的。

        对于这样的问题,我根据个人微浅的经验,分享一下怎么定位STM32出现Hard-Fault时问题所在的位置,方便尽快查找出问题所在。

        我这边演示使用的是 STM32F407VET6,内核是 Cortex-M4,分析工具使用 MDK-Keil 。

1、了解STM32的寄存器组

        工欲善其事必先利其器,在进行Hard-Fault的问题查找前,首先是要了解Arm Cortex 内核的寄存器组,方便进行调试。

1.1、Cortex-M3的通用寄存器组

从《Cortex-M3权威指南》中可以知道,Cortex-M3的通用寄存组有好几个,如下图:

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

1.1.1、通用目的寄存器 R0-R7

        R0‐R7 被称为低组寄存器。所有指令都能访问它们。它们的字长全是 32 位,复位后的初始值是不可预料的。

1.1.2、通用目的寄存器 R8-R12

        R8‐R12 被称为高组寄存器。只有很少的16位 Thumb 指令能访问它们,32位的指令则不受限制。它们也是 32 位字长,且复位后的初始值是不可预料的。

1.1.3、R13 — 堆栈指针(SP)

        R13 这个寄存器是CM3内核中的堆栈指针,用于指向(保存)当前程序运行的堆栈地址。它支持两个堆栈 — 主堆栈指针(MSP)、进程堆栈指针(PSP)。

1)主堆栈指针(MSP)

        MSP(主堆栈指针),是缺省的堆栈指针。当程序复位后(开始运行后),直到main函数运行时用的是MSP。

        如果搭载了操作系统,线程发生调度之后,堆栈指针SP就指向了该堆栈的首地址。

2)进程堆栈指针(PSP)

        PSP(进程堆栈指针),指向的是运行的线程首地址,即线程的堆栈地址。

        补充:

        Cortex‐M3 使用的是“向下生长的满栈”模型。堆栈指针 SP 指向最后一个被压入堆栈的 32位数值。在下一次压栈时,SP 先自减 4,再存入新的数值。

1.1.4、R14 — 连接寄存器(LR)

        R14 用于保存所调用的程序的返回地址。简而言之就是保存程序跳转(子程序调用,中断跳转)后,准备执行的下一条指令的地址。它保存的内容可以归纳为两种:

        1)保存子程序返回地址。比如上一个函数退出时的地址或者上一条执行结束后准备执行下一条的指令地址。

        2)当异常发生时,异常模式的r14用来保存异常返回地址。

LR中的一些固定值出现的情况:

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

1.1.5、R15 — 程序计数器(PC)

        保存的是当前正在取指的指令的地址(arm采用2级流水线,因此是当前正在执行指令的地址+8)。

        因为 CM3 内部使用了指令流水线,读 PC 时返回的值是当前指令的地址+4。

1.2、Cortex‐M3 的特殊功能寄存器

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

          

        这些特殊功能寄存器组只能使用专用的MSR和MRS指令访问,如下:

MRS <gp_reg>, <special_reg> ;读特殊功能寄存器的值到通用寄存器
MSR <special_reg>, <gp_reg> ;写通用寄存器的值到特殊功能寄存器

        注意:这些特殊功能寄存器是没有地址的!

1.2.1、xPSR — 状态寄存器

        通过 MRS/MSR 指令可以访问状态寄存器。

        状态寄存器的解析如下:

        一种说法:

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

        另一种说法:

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

(1)标志位 —(N,Z,C,V,Q)

1N:符号标志。结果为负数 = 1 ,否者 = 0
2Z:零标志位。运算结果为0 = 1 ,否者 = 0
3C:进位标志。运算结果有进位 = 1 ,否者 = 0
    1>加法运算(包括比较指令 CNM):C=1:运算结果产生了进位时(无符号数溢      出);C=0:运算结果没有进位。
    2>减法运算(包括比较指令 CMP):C=0:运算时产生了借位(无符号数溢出);C=1:没有借位。
    3>对于包含移位操作的非加 / 减法运算指令,C 为移出值的最后一位。
    4>对于其他的非加 / 减法运算指令,C 的值通常不变。
4V:溢出标志。有溢出 = 1,否者 = 0
5QDSP运算溢出标志。用于指示 DSP 运算指令是否发生了溢出。

(2)控制位 —(A,I,F,T)

A:中断禁止位(abort
IIRQ标志位。I=1表示禁止快速中断请求(IRQ)中断
FFIQ标志位。F=1表示禁止外部中断请求(FIQ)中断

(3)模式位 — M[4:0]

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

1.2.2、中断屏蔽寄存器组

        PRIMASK, FAULTMASK 和 BASEPRI 这三个寄存器用于控制异常的使能和除能。作用如下图所示:

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

1.2.3、控制寄存器(CONTROL)

        控制寄存器用于定义特权级别,还用于选择当前使用哪个堆栈指针。如下图:

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

CONTROL[1]:

        在 Cortex‐M3 的 handler 模式中,CONTROL[1]总是 0。在线程模式中则可以为 0 或 1。仅当处于特权级的线程模式下,此位才可写,其它场合下禁止写此位。改变处理器的模式也有其它的方式:在异常返回时,通过修改 LR 的位 2,也能实现模式切换。

CONTROL[0]:

        仅当在特权级下操作时才允许写该位。一旦进入了用户级,唯一返回特权级的途径,就是触发一个(软)中断,再由服务例程改写该位。

CONTROL 寄存器也是通过 MRS 和 MSR 指令来操作的:

MRS R0, CONTROL
MSR CONTROL, R0

补充:Cortex‐M3 支持 2 个模式和两个特权等级。

2个模式:handler模式、线程模式;
2个特权等级:用户级、特权级。

2、CM3系统的异常类型 & 可能原因

        从权威指南上可以获知,CM3内核的系统异常有好几个,如下图:

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

2.1、Hard-Fault 错误发生时的有关寄存器

        当 fault 发生时,首先要弄清楚的就是 fault 源,CM3中提供了相关的寄存器保存Hard-Fault发生的原因,相关的寄存器如下:

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

        注意:不同的内核寄存器有些差异,不过也是有很多相似的,具体的要对照芯片内核手册去分析!

2.1.1、存储器管理 fault 状态寄存器(MFSR)

地址:0xE000_ED28

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

2.1.2、总线 fault 状态寄存器(BFSR)

地址:0xE000_ED29

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

2.1.3、用法 fault 状态寄存器(UFSR)

地址:0xE000_ED2A

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

2.1.4、硬 fault 状态寄存器

地址:0xE000_ED2C

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

2.1.5、调试 fault 状态寄存器(DFSR)

地址:0xE000_ED30

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

2.1.6、存储管理地址寄存器(MMAR)

地址:0xE000_ED34

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

2.1.7、总线 fault 地址寄存器(BFAR)

地址:0xE000_ED38

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

2.1.8、辅助 fault 地址寄存器(AFAR)

地址:0xE000_ED3C

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

2.2、Hard-Fault 时定位入栈PC

定位入栈 PC 的流程如下图:

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

2.3、发生Hard-Fault的可能原因

2.3.1、MemManage fault 的可能原因

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

2.3.2、总线 fault 的可能原因

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

2.3.3、用法 fault 的可能原因

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

2.3.4、硬 fault 的可能原因

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

2.3.5、调试 fault 的可能原因

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

3、使用 MDK-Keil 查找 Hard-Fault 的操作

        当出现了Hard-Fault的错误的时候,可以使用MDK-Keil进行仿真,可以使用模拟调试仿真也可以在线调试。

(1)选择调试模式。选择调试方式如下图:

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

(2)进入Debug模式,选择寄存器窗口,便可以查看寄存器了。查看窗口如下:

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

(3)定位 Hard-Fault 问题的所在。

我这边通过打印输出寄存器的内容,可以获知硬件错误的相关信息,如下:

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

从图片中,可知道:

栈指针SP = 0x10004E78

连接寄存器LR = 0x08031C5D

程序计数器PC = 08031C80

(4)打开Disassembly窗口,如下图:

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

(5)在 Disassembly 窗口鼠标右键,选择 Show Disassembly at Adress...,如下图:

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

然后在弹出的输入框中输入连接寄存器(LR)的值,然后选择“Go To”,如下图:

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

“Go To”之后就可以定位到发生错误的时候要连接的地址,即出问题的时候所在的位置。下图是我的程序中出现错误的时候所定位到的位置,如下图:

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

(6)查看当前堆栈指针所在的位置,如下图:

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

        至此,已经可以找到出现问题的位置,至于是什么错误导致的Hard-Fault,就要根据程序去分析了!

hard fault,STM32学习,项目开发与调试,单片机,stm32,嵌入式硬件,arm

 文章来源地址https://www.toymoban.com/news/detail-540544.html

到了这里,关于STM32单片机的 Hard-Fault 硬件错误问题追踪与分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包