STM32单片机的 Hard-Fault 硬件错误问题追踪与分析
liuian 2025-09-21 18:41 64 浏览
有过单片机开发经验的人应该都会遇到过硬件错误(Hard-Fault)的问题,对于这样的问题,有些问题比较容易查找,有些就查找起来很麻烦,甚至可能很久都找不到问题到底是出在哪里。
特别是有时候出现一次,后面观察中都很久没发现过,这样的情况是很头疼的。
对于这样的问题,我根据个人微浅的经验,分享一下怎么定位STM32出现Hard-Fault时问题所在的位置,方便尽快查找出问题所在。
我这边演示使用的是 STM32F407VET6,内核是 Cortex-M4,分析工具使用 MDK-Keil 。
1、了解STM32的寄存器组
工欲善其事必先利其器,在进行Hard-Fault的问题查找前,首先是要了解Arm Cortex 内核的寄存器组,方便进行调试。
1.1、Cortex-M3的通用寄存器组
从《Cortex-M3权威指南》中可以知道,Cortex-M3的通用寄存组有好几个,如下图:
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中的一些固定值出现的情况:
1.1.5、R15 — 程序计数器(PC)
保存的是当前正在取指的指令的地址(arm采用2级流水线,因此是当前正在执行指令的地址+8)。
因为 CM3 内部使用了指令流水线,读 PC 时返回的值是当前指令的地址+4。
1.2、Cortex‐M3 的特殊功能寄存器
这些特殊功能寄存器组只能使用专用的MSR和MRS指令访问,如下:
MRS <gp_reg>, <special_reg> ;读特殊功能寄存器的值到通用寄存器
MSR <special_reg>, <gp_reg> ;写通用寄存器的值到特殊功能寄存器
注意:这些特殊功能寄存器是没有地址的!
1.2.1、xPSR — 状态寄存器
通过 MRS/MSR 指令可以访问状态寄存器。
状态寄存器的解析如下:
一种说法:
另一种说法:
(1)标志位 —(N,Z,C,V,Q)
1)N:符号标志。结果为负数 = 1 ,否者 = 0
2)Z:零标志位。运算结果为0 = 1 ,否者 = 0
3)C:进位标志。运算结果有进位 = 1 ,否者 = 0
1>加法运算(包括比较指令 CNM):C=1:运算结果产生了进位时(无符号数溢 出);C=0:运算结果没有进位。
2>减法运算(包括比较指令 CMP):C=0:运算时产生了借位(无符号数溢出);C=1:没有借位。
3>对于包含移位操作的非加 / 减法运算指令,C 为移出值的最后一位。
4>对于其他的非加 / 减法运算指令,C 的值通常不变。
4)V:溢出标志。有溢出 = 1,否者 = 0
5)Q:DSP运算溢出标志。用于指示 DSP 运算指令是否发生了溢出。
(2)控制位 —(A,I,F,T)
A:中断禁止位(abort)
I:IRQ标志位。I=1表示禁止快速中断请求(IRQ)中断
F:FIQ标志位。F=1表示禁止外部中断请求(FIQ)中断
(3)模式位 — M[4:0]
1.2.2、中断屏蔽寄存器组
PRIMASK, FAULTMASK 和 BASEPRI 这三个寄存器用于控制异常的使能和除能。作用如下图所示:
1.2.3、控制寄存器(CONTROL)
控制寄存器用于定义特权级别,还用于选择当前使用哪个堆栈指针。如下图:
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内核的系统异常有好几个,如下图:
2.1、Hard-Fault 错误发生时的有关寄存器
当 fault 发生时,首先要弄清楚的就是 fault 源,CM3中提供了相关的寄存器保存Hard-Fault发生的原因,相关的寄存器如下:
注意:不同的内核寄存器有些差异,不过也是有很多相似的,具体的要对照芯片内核手册去分析!
2.1.1、存储器管理 fault 状态寄存器(MFSR)
地址:0xE000_ED28
2.1.2、总线 fault 状态寄存器(BFSR)
地址:0xE000_ED29
2.1.3、用法 fault 状态寄存器(UFSR)
地址:0xE000_ED2A
2.1.4、硬 fault 状态寄存器
地址:0xE000_ED2C
2.1.5、调试 fault 状态寄存器(DFSR)
地址:0xE000_ED30
2.1.6、存储管理地址寄存器(MMAR)
地址:0xE000_ED34
2.1.7、总线 fault 地址寄存器(BFAR)
地址:0xE000_ED38
2.1.8、辅助 fault 地址寄存器(AFAR)
地址:0xE000_ED3C
2.2、Hard-Fault 时定位入栈PC
定位入栈 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的错误的时候,可以使用MDK-Keil进行仿真,可以使用模拟调试仿真也可以在线调试。
(1)选择调试模式。选择调试方式如下图:
(2)进入Debug模式,选择寄存器窗口,便可以查看寄存器了。查看窗口如下:
(3)定位 Hard-Fault 问题的所在。
我这边通过打印输出寄存器的内容,可以获知硬件错误的相关信息,如下:
从图片中,可知道:
栈指针SP = 0x10004E78
连接寄存器LR = 0x08031C5D
程序计数器PC = 08031C80(4)打开Disassembly窗口,如下图:
(5)在 Disassembly 窗口鼠标右键,选择 Show Disassembly at Adress...,如下图:
然后在弹出的输入框中输入连接寄存器(LR)的值,然后选择“Go To”,如下图:
“Go To”之后就可以定位到发生错误的时候要连接的地址,即出问题的时候所在的位置。下图是我的程序中出现错误的时候所定位到的位置,如下图:
(6)查看当前堆栈指针所在的位置,如下图:
至此,已经可以找到出现问题的位置,至于是什么错误导致的Hard-Fault,就要根据程序去分析了!
相关推荐
- u盘自我保护怎么解除(怎么样取消u盘的自我保护)
-
要解除U盘保护,首先插入U盘后打开“我的电脑”,右击选择U盘图标,点击“属性”。在弹出的对话框中,选择“安全”标签,然后点击“编辑”按钮,根据自己的需要选择或取消“对于系统用户完全控制”权限,点击“确...
- 如何设置自动关机win10(windows 10如何设置自动关机)
-
Win10设置自动关机,需要以下步骤:1.按“Win+R”组合键,呼出“运行”;2.将定时关机命令设置为“shutdown-s-t7200”;3.在“运行”内输入命令,点击“确定”即可;4.如果设置错...
- 公版驱动(公版驱动和专用驱动的区别)
-
公版这个名词特指显卡本身,与驱动无关。一般采用芯片制造商自己设计的显卡,称为公版。显卡驱动只有WHQL版本、Beta版本、兼容版、定制版之分。兼容版一般称为万能驱动,不会给显卡带来多少优化,只是让你能...
- nod32是什么软件(nod32是哪个国家的)
-
起源于捷克斯洛伐克总部现在美国下面是nod32的由来:nod是根据一部电视剧(城市边缘的医院)起的,原意是“磁盘边的医院”32是源于当16-bitNOD-ICE很成熟的时候32位处理器出来了升级适应3...
- 欧拉linux系统官网(欧拉系统命令)
-
在华为欧拉服务器上配置Linux网络,首先需要编辑网络配置文件,位于/etc/sysconfig/network-scripts目录下,根据网络需求配置对应的网络接口,IP地址、子网掩码、网关等信息,...
- deepin安装显卡驱动(deepin安装显卡驱动后无法进入图形界面)
-
1、首先必须使用rufus制作U盘启动,必须选择DD格式2、从其他linux镜像比如Ubantu或其他拷贝出EFI的引导文件,具体是镜像中的EFI—boot—grubx86.efi这个文件,把这个文件...
- 小米路由器管理员初始密码(miwifi小米路由器管理员初始密码)
-
小米路由器管理员密码初始是123456。1、小米路由器的管理员初始密码是admin。2、如果输入admin路由器没有反应,说明密码错误,可以查看路由器背面的管理员登录密码,登录后可以自行修改设置账户名...
- 路由器组网具体连接方法(路由器组网教程)
-
举例:你正在用一个TP-LINK的无线路由器上网,信号不是太好,你想在下边再连一个无线路由器的话,就得在第二个路由器上设置了,先不管第一个路由器,设置步骤:把第二个无线路由器连接到电脑上(只是路...
- 雨林木风win7纯净版gho(雨林木风win7官网)
-
雨林木风WIN7光盘重装系统的步骤是将光盘放入光驱内,设置光驱为第一启动盘,打开电脑后进入光盘引导,最后将系统文件镜像到系统盘上1.你下载的雨林木风GHOSTXPSP3纯净版Y8.0是一个克隆光...
- 电脑一直正在重新启动怎么解决
-
1、电脑误删除或者是破坏了系统文件。那么需要重新安装系统。2、可能是安装的软件或者是插件跟系统兼容性冲突导致的。可以强制关机3次,然后重新启动电脑会出现恢复界面——选择安全模式——然后电脑会重新启...
-
- 如何下载ps软件免费版(ps如何下载免费版本)
-
1.在搜索引擎中输入adobe并点击搜索。2.点击adobe官网。3.点击支持并点击下载与安装。4.点击开始免费试用并点击下载。5.打开文件夹并点击打开进行安装即可。6.根据以上步骤即可下载安装ps。AdobePhotoshopCS6号...
-
2026-01-14 05:37 liuian
- 怎么判断该换硅脂了(cpu硅脂干了影响真的很大吗)
-
方法步骤如下第一,从系统软件的运行上来看,如果在运行某些大型软件,容易导致显卡发热的程序时,出现画面掉帧,或卡顿,甚至是画面卡死等情况,这大多是因为显卡散热出现问题,导致显卡自动降频,以降低功耗来减少...
- 壁纸图片2025最新款(电脑桌面壁纸图片2025最新款)
-
要更换2023最新款壁纸图片,可以按照以下步骤操作:首先,找到您想要更换的壁纸图片并下载到您的设备上。其次,进入您的设备设置,找到“壁纸”或“桌面壁纸”选项,并点击进入。然后,选择“更换壁纸”并在相册...
- 清理垃圾的神器(清理垃圾的神器是什么)
-
1、《腾讯手机管家》这款可以帮助用户进行强力的清理,加速告别空间卡顿,缓慢延迟的问题的软件当中,用户可以随时随地登录软件进行自动清理和自动清理,自动清理包括图片,视频,语音文件在内的各种换成文件,为手...
- 一周热门
-
-
飞牛OS入门安装遇到问题,如何解决?
-
如何在 iPhone 和 Android 上恢复已删除的抖音消息
-
Boost高性能并发无锁队列指南:boost::lockfree::queue
-
大模型手册: 保姆级用CherryStudio知识库
-
用什么工具在Win中查看8G大的log文件?
-
如何在 Windows 10 或 11 上通过命令行安装 Node.js 和 NPM
-
威联通NAS安装阿里云盘WebDAV服务并添加到Infuse
-
Trae IDE 如何与 GitHub 无缝对接?
-
idea插件之maven search(工欲善其事,必先利其器)
-
如何修改图片拍摄日期?快速修改图片拍摄日期的6种方法
-
- 最近发表
- 标签列表
-
- python判断字典是否为空 (50)
- crontab每周一执行 (48)
- aes和des区别 (43)
- bash脚本和shell脚本的区别 (35)
- canvas库 (33)
- dataframe筛选满足条件的行 (35)
- gitlab日志 (33)
- lua xpcall (36)
- blob转json (33)
- python判断是否在列表中 (34)
- python html转pdf (36)
- 安装指定版本npm (37)
- idea搜索jar包内容 (33)
- css鼠标悬停出现隐藏的文字 (34)
- linux nacos启动命令 (33)
- gitlab 日志 (36)
- adb pull (37)
- python判断元素在不在列表里 (34)
- python 字典删除元素 (34)
- vscode切换git分支 (35)
- python bytes转16进制 (35)
- grep前后几行 (34)
- hashmap转list (35)
- c++ 字符串查找 (35)
- mysql刷新权限 (34)
