使用Cortex-M3-M4-M7故障异常2
使用Cortex-M3/M4/M7故障异常2、项目不足、文档说明不足的地方或者有问题地方,可以通过邮件联系本人;
- 故障定位代码在:请点击此处
一. 文件系统移植说明
1. 文件系统移植
工程下载后,会有如下目录的文件。
需要移植的文件夹主要是
fault_location
,将此文件移植到自己的工程中去;fault_location
目录下有如下文件夹工程中需要包含该目录下
inc
的文件路径
2. 配置说明
主要的配置项分布在这两个文件中
FaultLocation_config.h
、FaultLocation.h
;FaultLocation_config.h
主要是faultLocation
代码的全局设置,而FaultLocation.h
只是FaultLocation.c
文件中部分的配置项目。FaultLocation.h
文件配置的项目只有CCR_REGISTER
、SHCSR_REGISTER
;如果需要修改
CCR_REGISTER
参数,CCR_REGISTER
只能配置这两个选项CCR_DIV_0_TRP
、CCR_UNALIGN_TRP
;如果需要修改
SHCSR_REGISTER
参数,SHCSR_REGISTER
只能配置这三个选项SHCSR_MEMFAULTENA
、SHCSR_BUSFAULTENA
、SHCSR_USGFAULTENA
;
当不明白CCR_REGISTER
、SHCSR_REGISTER
为何只能配置这些时候,可以通过下面的三.状态寄存器说明 2.配置和控制寄存器CCR、3.系统处理程序控制和状态寄存器 SHCSR 理解;关于
FaultLocation_config.h
的配置,通过文件查看,有相关的提示处理故障完成后,如果用户需要调用其他的处理函数,可以将函数写入到
FaultLoca_Hook.c
文件中的FaultHook
函数内部;
3. 编译报错问题
工程添加到项目后,可能会出现编译出错,如下图所示:
1
2
3
4
5
6
7
8..\OBJ\UART.axf: Error: L6200E: Symbol BusFault_Handler multiply defined (by fualtloca.o and stm32f4xx_it.o).
..\OBJ\UART.axf: Error: L6200E: Symbol HardFault_Handler multiply defined (by fualtloca.o and stm32f4xx_it.o).
..\OBJ\UART.axf: Error: L6200E: Symbol MemManage_Handler multiply defined (by fualtloca.o and stm32f4xx_it.o).
..\OBJ\UART.axf: Error: L6200E: Symbol UsageFault_Handler multiply defined (by fualtloca.o and stm32f4xx_it.o).
Not enough information to list image symbols.
Not enough information to list load addresses in the image map.
Finished: 2 information, 0 warning and 4 error messages.
"..\OBJ\UART.axf" - 4 Error(s), 2 Warning(s).解决方案,我们直接打开
stm32f4xx_it.c
文件,注释如下函数:1
2
3
4
5
6
7
8void UsageFault_Handler(void)
{}
void BusFault_Handler(void)
{}
void MemManage_Handler(void)
{}
void HardFault_Handler(void)
{}如果用户在这些故障函数里面有需要执行的代码,可以添加到
FaultLoca_Hook.c
文件中的FaultHook
函数内部;
4. 移植成功说明
当程序移植成功后,如果代码中配置了串口程序,那么会打印Fault Location Vx.x
,x
代表版本。
二. 标识符说明
标志说明 | |
F | 表示故障信息寄存器名字 |
E | 表示故障信息寄存器中故障位 |
A |
表示故障准确信息地址 1.开启MPU,如果是MPU保护引起的,那么会显示MPU保护地址 |
IT | 表示读取中断向量表时候出错 |
G | 表示故障没有准确故障地址,这个地址是推测 1.如果遇到的地址是个函数,那么可以搜索该函数调用处,并且结合LR(R14)寄存器查看 2.如果遇到函数内部代码,那么查看该程序地址和向上一至两条程序。 |
示例一:代码运行在cortex-m4内核,并开启了MPU功能,MPU管理地址是0x20002000,设置该区域只能读取,不能写入。如下图
在0x20002000创建一个数组,然后写入数据,就会报错:
1 | Fault Location V0.1 ------->这是版本信息 |
如果需要查看具体故障位置,可以进入调试模式,然后停止程序运行,将 G:中0x8001da0
复制到PC寄存器中,然后就可以看到如下图,不精确的故障地址了:
说明 当G:后面跟着两个或多个地址,那么都可以尝试去查看;如果A输出的地址很符合程序运行的地址,那么也可以尝试把A的地址复制到PC寄存器中。
三. 状态寄存器说明
1. 故障类型
下表显示了故障类型、故障处理程序、故障状态寄存器以及指示发生了哪个故障的寄存器位名称。 位名称与 μVision 调试故障报告对话框中显示的字段相关。 详细信息在寄存器描述部分进一步描述。
Fault type 故障类型 |
Handler 处理程序 |
Status Register 状态寄存器 |
Bit Name 位名称 |
Bus error on a vector read error 矢量读取错误上的总线错误 |
HardFault 硬故障 |
HFSR |
VECTTBL |
Fault that is escalated to a hard fault 升级为硬故障的故障 |
FORCED 强制 |
||
Fault on breakpoint escalation 断点升级故障 |
DEBUGEVT 调试 |
||
Fault on instruction access 指令访问故障 |
MemManage 内存管理 |
MMFSR |
IACCVIOL 艾克维奥尔 |
Fault on direct data access 直接数据访问故障 |
DACCVIOL 达克维尔 |
||
Context stacking, because of an MPU access violation 上下文堆叠,因为 MPU 访问冲突 |
MSTKERR 默克尔 |
||
Context unstacking, because of an MPU access violation 由于 MPU 访问冲突,上下文取消堆叠 |
MUNSTKERR 蒙斯特克尔 |
||
During lazy floating-point state preservation 在惰性浮点状态保存期间 |
MLSPERR |
||
During exception stacking 在异常堆栈期间 |
BusFault 总线故障 |
BFSR | STKERR 斯特克尔 |
During exception unstacking 在异常取消堆栈期间 |
UNSTKERR |
||
During instruction prefetching, precise 在指令预取期间,精确 |
IBUSERR |
||
During lazy floating-point state preservation 在惰性浮点状态保存期间 |
LSPERR |
||
Precise data access error, precise 精确的数据访问错误,精确 |
PRECISERR 更精密 |
||
Imprecise data access error, imprecise 不精确的数据访问错误,不精确 |
IMPRECISERR 不精确 |
||
Undefined instruction 未定义指令 |
UsageFault 使用故障 |
UFSR |
UNDEFINSTR 未定义 |
Attempt to enter an invalid instruction set state 尝试进入无效指令集状态 |
INVSTATE 投资状态 |
||
Failed integrity check on exception return 异常返回时完整性检查失败 |
INVPC |
||
Attempt to access a non-existing coprocessor 尝试访问不存在的协处理器 |
NOCPC |
||
Illegal unaligned load or store 非法未对齐加载或存储 |
UNALIGNED 未对齐 |
||
Stack overflow 堆栈溢出 |
STKOF |
||
Divide By 0 除以 0 |
DIVBYZERO |
2. 配置和控制寄存器CCR
CCR 寄存器的以下位控制使用故障的行为: | |
DIV_0_TRP: | 当处理器执行除数为 0 的 SDIV 或 UDIV 指令时启用 UsageFault: 0 = 不陷阱除以 0; 除以 0 返回商 0。 1 = 陷阱除以 0。 |
UNALIGN_TRP: | 对未对齐地址执行内存访问时启用 UsageFault: 0 = 不捕获未对齐的半字和字访问 1 = 捕获未对齐的半字和字访问; 未对齐的访问会生成 UsageFault。 请注意,即使 UNALIGN_TRP 设置为 0,使用 LDM、STM、LDRD 和 STRD 指令的未对齐访问也始终会生成 UsageFault。 |
3. 系统处理程序控制和状态寄存器 SHCSR
SHCSR 寄存器的以下位属于故障异常: | |
MEMFAULTACT: | 内存管理故障异常激活位,如果异常激活则读为 1。 |
BUSFAULTACT: | BusFault 异常激活位,如果异常激活则读为 1。 |
USGFAULTACT: | UsageFault 异常激活位,如果异常激活则读为 1。 |
USGFAULTPENDED: | UsageFault 异常挂起位,如果异常挂起,则读为 1。 |
MEMFAULTPENDED: | 内存管理故障异常挂起位,如果异常挂起,则读为 1。 |
BUSFAULTPENDED: | BusFault 异常挂起位,如果异常挂起,则读为 1。 |
MEMFAULTENA: | 内存管理故障异常使能位,置1使能; 设置为 0 以禁用。 |
BUSFAULTENA: | BusFault异常使能位,置1使能; 设置为 0 以禁用。 |
USGFAULTENA: | UsageFault异常使能位,置1使能; 设置为 0 以禁用。 |
1 | SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk | \ |
4. HardFault 状态寄存器 HFSR 寄存器
硬故障状态寄存器指示 CPU 指令的错误使用,并具有以下状态位: | |
VECTTBL: | 指示异常处理期间读取向量表时出现总线故障: 0 = 读取向量表时没有总线故障 1 = 读取向量表时出现总线故障。 当该位置位时,为异常返回而堆叠的 PC 值指向被异常抢占的指令。 此错误始终是硬故障。 |
FORCED: | 表示强制硬故障,由具有可配置优先级的故障升级生成,该故障由于优先级或被禁用而无法处理: 0 = 无强制硬故障 1 = 强制硬故障。 当该位置位时,硬故障处理程序必须读取其他故障状态寄存器以查找故障原因。 |
DEBUGEVT: | 保留用于调试。 写入寄存器时,您必须向该位写入 0,否则行为是不可预测的。 |
5. MemManage (内存管理)故障状态和地址寄存器 (MMFSR; MMFAR)
- MemManage (内存管理)状态寄存器 (MMFSR)
MemManage (内存管理)故障状态寄存器 (MMFSR) 指示内存保护单元 (MPU) 检测到的内存访问违规。 仅允许特权访问。 非特权访问会产生总线故障BusFault
。MMFSR 具有以下状态位: IACCVIOL: 指令访问违规标志:
0 = 没有指令访问违规故障
1 = 处理器尝试从不允许执行的位置获取指令。
为异常返回堆叠的 PC 值指向错误指令。处理器尚未将故障地址写入 MMFAR。此故障条件发生在任何尝试向 XN(从不执行)区域取指令时,即使 MPU 被禁用或不存在。潜在原因:
a) 分支到未在 MPU 中定义或定义为不可执行的区域。
b) 由于堆栈内容损坏而导致无效返回。
c) 异常向量表中的条目不正确。DACCVIOL: 数据访问违规标志:
0 = 没有数据访问违规故障
1 = 处理器尝试在不允许操作的位置进行加载或存储。
为异常返回堆叠的 PC 值指向错误指令。处理器已将尝试访问的地址加载到 MMFAR。MUNSTKERR: MemManage 因异常返回而取消堆栈时出错:
0 = 没有取消堆栈错误
1 = 异常返回的取消堆栈已导致一个或多个访问冲突。
此故障链接到处理程序,这意味着原始返回堆栈仍然存在。
处理器没有根据失败的返回调整 SP,也没有执行新的保存。处理器尚未将故障地址写入 MMFAR。潜在原因:
a) 堆栈指针已损坏
b) 堆栈的 MPU 区域在异常处理程序执行期间更改。MSTKERR: MemManage 异常条目堆栈错误:
0 = 无堆栈错误
1 = 异常条目的堆栈导致一个或多个访问冲突。
SP 仍在调整,但堆栈上的上下文区域中的值可能不正确。处理器尚未将故障地址写入 MMFAR。潜在原因:
a) 堆栈指针损坏或未初始化
b) 堆栈到达 MPU 未定义为读/写内存的区域。MLSPERR: 浮点惰性状态保存期间的 MemManage 故障(仅具有 FPU 的 Cortex-M4):
0 = 浮点惰性状态保存期间未发生故障
1 = 浮点惰性状态保存期间发生故障MMARVALID: MemManage 故障地址寄存器 (MMFAR) 有效标志:
0 = SCB->MMFAR 中的值不是有效故障地址
1 = SCB->MMFAR 保持有效故障地址。
如果发生 MemManage 故障并由于优先级而升级为 HardFault,则 HardFault 处理程序必须将此位设置为 0.这可以防止在返回到 SCB->MMFAR 值已被覆盖的堆叠活动 MemManage 故障处理程序时出现问题。 - MemManage (内存管理)地址寄存器 (MMFAR)
BFAR 地址与精确的数据访问(总线故障) BusFault 相关联。 仅允许特权访问。 非特权访问会产生总线故障BusFault
。ADDRESS: 内存管理故障的数据地址。 该寄存器使用产生 MemManage 故障的位置的地址进行更新。 MMFSR 显示故障原因。 此字段仅在设置 MMFSR.MMARVALID 时有效。 在没有唯一 BFAR 和 MMFAR 寄存器的实现中,如果设置了 BFSR.BFARVALID,则该寄存器的值是 UNKNOWN。
6. BusFault
总线故障状态和地址寄存器(BFSR;BFAR)
BusFault
总线故障状态寄存器 (BFSR)
总线故障状态寄存器显示因取指令和数据访问导致的总线错误状态,并指示在总线操作期间检测到的存储器访问故障。 只允许特权访问。 非特权访问将产生总线故障。BFSR 状态位是: IBUSERR: 指令总线错误。 记录指令预取时是否发生总线故障。
0 = 无指令总线错误
1 = 指令总线错误。
处理器在预取指令时检测到指令总线错误,但仅当它尝试发出错误指令时才将 IBUSERR 标志设置为 1。 当处理器设置该位时,它不会将故障地址写入 BFAR。 潜在原因:
a) 跳转到无效内存区域,例如由不正确的函数指针引起。
b) 由于堆栈指针或堆栈内容损坏而导致无效返回。
c) 异常向量表中的条目不正确。PRECISERR: 精确的数据总线错误:
0 = 没有精确的数据总线错误
1 = 发生了数据总线错误,并且为异常返回堆叠的 PC 值指向导致故障的指令。
当处理器设置该位时,它将故障地址写入 BFAR。IMPRECISERR: 不精确的数据总线错误:
0 = 没有不精确的数据总线错误
1 = 发生了数据总线错误,但堆栈帧中的返回地址与导致错误的指令无关。
当处理器设置该位时,它不会将故障地址写入 BFAR。这是一个异步故障。因此,如果在当前进程的优先级高于 BusFault 优先级时检测到,则 BusFault 变为挂起状态,只有在处理器从所有更高优先级的进程返回时才变为活动状态。如果在处理器进入不精确总线故障的处理程序之前发生精确故障,则处理程序检测到设置为 1 的 IMPRECISERR 和设置为 1 的精确故障状态位之一。UNSTKERR: 从异常返回的解栈总线故障:
0 = 没有解栈故障
1 = 异常条目的堆栈已导致一个或多个总线故障。
此故障链接到处理程序。这意味着当处理器设置该位时,原始返回堆栈仍然存在。处理器不根据失败的返回调整 SP,不执行新的保存,也不向 BFAR 写入故障地址。STKERR: 异常条目的堆栈总线故障:
0 = 没有堆栈故障
1 = 异常条目的堆栈已导致一个或多个 BusFaults。
当处理器设置该位时,SP 仍会调整,但堆栈上的上下文区域中的值可能不正确。处理器不会将故障地址写入 BFAR。潜在原因:
a) 堆栈指针已损坏或未初始化
b) 堆栈到达未定义的内存区域。LSPERR: 浮点惰性状态保存期间的总线故障(仅当 FPU 存在时):
0 = 浮点惰性状态保存期间未发生故障
1 = 浮点惰性状态保存期间发生故障BFARVALID: 总线故障地址寄存器 (BFAR) 有效标志:
0 = BFAR 中的值不是有效的故障地址
1 = BFAR 保持有效的故障地址。
处理器在地址已知的总线故障后设置该位。 其他故障可以将此位设置为 0,例如稍后发生的 MemManage 故障。 如果发生总线故障并由于优先级而升级为硬故障,则硬故障处理程序必须将此位设置为 0。这可以防止返回到 BFAR 值已被覆盖的堆叠活动总线故障处理程序时出现问题。BusFault
总线故障地址寄存器 (BFAR)
BFAR 地址与精确的数据访问总线故障相关联。 仅允许特权访问。 非特权访问会产生总线故障。ADDRESS: 精确总线故障的数据地址。 该寄存器使用产生总线故障的位置的地址进行更新。 BFSR 显示故障原因。 该字段仅在设置了 BFSR.BFARVALID 时有效。 在没有唯一 BFAR 和 MMFAR 寄存器的实现中,如果设置了 MMFSR.MMARVALID,则该寄存器的值是 UNKNOWN。
7. UsageFault
使用故障状态寄存器 (UFSR)
使用故障状态寄存器 UFSR 包含一些指令执行故障和数据访问的状态。 仅允许特权访问。 非特权访问会产生总线故障。
该寄存器分配了以下位: | |
UNDEFINSTR: | 未定义指令。 0 = 没有未定义的指令 1 = 处理器已尝试执行未定义的指令。 当该位置位时,为异常返回堆叠的 PC 值指向未定义指令。 未定义指令是处理器无法解码的指令。 潜在原因: a) 使用了 Cortex-M 设备不支持的指令。 b) 错误或损坏的内存内容。 |
INVSTATE: | 无效状态: 0 = 无无效状态 1 = 处理器试图执行非法使用执行程序状态寄存器 (EPSR) 的指令。 当该位置位时,为异常返回而堆积的 PC 值指向试图非法使用 EPSR 的指令。 潜在原因: a) 将 LSB=0 的分支目标地址加载到 PC。 b) 堆栈 PSR 在异常或中断处理期间损坏。 c) 向量表包含一个 LSB=0 的向量地址。 |
INVPC: | 无效的 PC 加载使用错误,由无效的 EXC_RETURN 值引起: 0 = 没有无效的 PC 加载 1 = 由于上下文切换无效,处理器试图将非法的 EXC_RETURN 值加载到 PC。 当该位置位时,为异常返回而堆栈的 PC 值指向试图执行 PC 非法加载的指令。 潜在原因: a) 由于堆栈指针、链接寄存器 (LR) 或堆栈内容损坏而导致无效返回。 b) PSR 中的 ICI/IT 位对一条指令无效。 |
NOCP: | 没有协处理器。 处理器不支持协处理器指令: 0 = 未因尝试访问协处理器而导致使用错误 1 = 处理器已尝试访问不存在的协处理器。 |
UNALIGNED: | 未对齐访问使用错误: 0 = 没有未对齐访问错误,或未启用未对齐访问陷阱 1 = 处理器进行了未对齐内存访问。 通过设置 CCR 中的 UNALIGN_TRP 位启用未对齐访问的捕获。 无论 UNALIGN_TRP 位的设置如何,未对齐的 LDM、STM、LDRD 和 STRD 指令总是出错。 |
DIVBYZERO: | 被零除使用错误: 0 = 没有被零除错误,或被零除陷阱未启用 1 = 处理器执行了除数为 0 的 SDIV 或 UDIV 指令。 当处理器将此位设置为 1 时, 为异常返回堆叠的 PC 值指向执行除以零的指令。 通过将 CCR 中的 DIV_0_TRP 位设置为 1 来启用除以零的捕获。 |
请注意,UsageFault
使用故障状态寄存器的位是粘性的。 这意味着,当发生一个或多个故障时,相关位设置为 1。设置为 1 的位仅通过向该位写入 1 或通过复位清除为 0。
8. 辅助总线故障状态寄存器 ABFSR 寄存器(仅限 Cortex-M7)
辅助总线故障状态寄存器 (ABFSR) 存储有关异步总线故障源的信息。 如果发生了总线故障,故障处理程序可以读取该寄存器以确定哪个总线接口触发了故障,如果源是 AXIM 接口,则接收到哪种错误类型。 ABFSR[4:0] 字段保持有效,直到通过向 ABFSR 写入任何值来清除。 ASBFSR 位分配为:
AXIMTYPE: | 指示 AXIM 接口上的故障类型。 这些值仅在 AXIM=1 时有效。 0b00 = 好的 0b01 = EXOKAY 0b10 = SLVERR 0b11=减速 |
EPPB: | EPPB 接口异步故障 |
AXIM: | AXIM 接口上的异步故障 |
AHBP: | AHBP接口异步故障 |
DTCM: | DTCM接口异步故障 |
ITCM: | ITCM 接口上的异步故障 |
Note:这些接口可能不存在于您的实现中。 |