stm32 出现 hard fault 的排查记录
参考链接:https://blog.csdn.net/qq_43118572/article/details/132759626
1、先验知识
先验知识1: cortex m3 在中断/异常时,会把 8 个寄存器(xPSR、PC、LR、R12 以及R3-R0)的值压入栈。入栈顺序以及入栈后堆栈中的内容如下(CM4 是从低地址到搞地质):
地址 | 寄存器 | 被保存的顺序 |
---|---|---|
旧 ISP(N-0) | 原先已压入栈的内容 | - |
(N-4) | xPSR | 2 |
(N-8) | PC | 1 |
(N-12) | LR | 8 |
(N-16) | R12 | 7 |
(N-20) | R3 | 6 |
(N-24) | R2 | 5 |
(N-28) | R1 | 4 |
新 SP(N-32) | R0 | 3 |
先验知识2: 在 Keil 项目的 Options for Target 'Target 1' 的Target 选项,将 Floating Port Hardware 选项设置为 Not Use,这样的好处是在后续查看堆栈寄存器信息时,不会看到其他浮点寄存器,好根据地址推断存储的是哪个寄存器的值。
> 参考链接:https://blog.csdn.net/qq_20553613/article/details/80118444
先验知识3: map 文件可以查看符号表(Symbol Table)。符号表可用于确定变量或函数在内存中的位置。
2、正文
由于 arm/cortex 仅支持对齐访问,否则会出现 hard fault。我们以下述访问不对齐的代码为例,产生 Hard Fault 并进行逐一排查:(假设我们不知道是哪里出现 hard fault)
int main(void)
{
int a = 1;
int b = 1;
int c = a + b;
int *p = (int *)0xF000 0000;
int d = *p;
while (*p) { // line 11
(*p)++; // 将在此处陷入 Hard Fault line12
}
return 0;
}
Step 1:查看 map 我们可以发现栈顶位置为 0x2000 0660
Step 2:当程序陷入异常时,我们能发现当前使用的是 MSP,SP 对应的地址为 0x2000 0640,所以压入了 32/4 = 8 个寄存器(一个寄存器 32 位,即 4 个字节)。根据物理地址,发现上次压入的 PC 值为 0x0800 0336
。换而言之,陷入异常的上一条指令地址为 0x0800 0336
。
Step 3:点击导航栏的 “Disasembly Window”,打开反汇编界面。右键并选择 “Disassembly at Address” 选项,输入 0x0800 0336
并输入 “go to”,就会跳转到该条指令。
备注: Call Stack 跟 Memory 窗口可以查看很多信息
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!