使用Cortex-M3-M4-M7故障异常2

使用Cortex-M3/M4/M7故障异常2、项目不足、文档说明不足的地方或者有问题地方,可以通过邮件联系本人;

  1. 故障定位代码在:请点击此处

一. 文件系统移植说明

1. 文件系统移植

  1. 工程下载后,会有如下目录的文件。

  2. 需要移植的文件夹主要是fault_location,将此文件移植到自己的工程中去;fault_location目录下有如下文件夹

  3. 工程中需要包含该目录下inc的文件路径

2. 配置说明

  1. 主要的配置项分布在这两个文件中FaultLocation_config.hFaultLocation.h;FaultLocation_config.h主要是faultLocation代码的全局设置,而FaultLocation.h只是FaultLocation.c文件中部分的配置项目。

  2. FaultLocation.h文件配置的项目只有CCR_REGISTERSHCSR_REGISTER;

  3. 如果需要修改CCR_REGISTER参数,CCR_REGISTER只能配置这两个选项CCR_DIV_0_TRPCCR_UNALIGN_TRP;

  4. 如果需要修改SHCSR_REGISTER参数,SHCSR_REGISTER只能配置这三个选项SHCSR_MEMFAULTENASHCSR_BUSFAULTENASHCSR_USGFAULTENA;
    当不明白CCR_REGISTERSHCSR_REGISTER为何只能配置这些时候,可以通过下面的三.状态寄存器说明 2.配置和控制寄存器CCR3.系统处理程序控制和状态寄存器 SHCSR 理解;

  5. 关于FaultLocation_config.h的配置,通过文件查看,有相关的提示

  6. 处理故障完成后,如果用户需要调用其他的处理函数,可以将函数写入到FaultLoca_Hook.c文件中的FaultHook函数内部;

3. 编译报错问题

  1. 工程添加到项目后,可能会出现编译出错,如下图所示:

    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).
  2. 解决方案,我们直接打开stm32f4xx_it.c文件,注释如下函数:

    1
    2
    3
    4
    5
    6
    7
    8
    void UsageFault_Handler(void)
    {}
    void BusFault_Handler(void)
    {}
    void MemManage_Handler(void)
    {}
    void HardFault_Handler(void)
    {}

    如果用户在这些故障函数里面有需要执行的代码,可以添加到FaultLoca_Hook.c文件中的FaultHook函数内部;

4. 移植成功说明

当程序移植成功后,如果代码中配置了串口程序,那么会打印Fault Location Vx.xx代表版本。

二. 标识符说明

标志说明
F 表示故障信息寄存器名字
E 表示故障信息寄存器中故障位
A 表示故障准确信息地址
1.开启MPU,如果是MPU保护引起的,那么会显示MPU保护地址
IT 表示读取中断向量表时候出错
G 表示故障没有准确故障地址,这个地址是推测
1.如果遇到的地址是个函数,那么可以搜索该函数调用处,并且结合LR(R14)寄存器查看
2.如果遇到函数内部代码,那么查看该程序地址和向上一至两条程序。

示例一:代码运行在cortex-m4内核,并开启了MPU功能,MPU管理地址是0x20002000,设置该区域只能读取,不能写入。如下图

在0x20002000创建一个数组,然后写入数据,就会报错:

1
2
3
4
Fault Location V0.1 ------->这是版本信息
F:MMFSR(故障寄存器) E:DACCVIOL(这是MMFSR故障位) G:0x8001da0(猜测程序有故障地址)
E:MMARVALID(这是MMFSR故障位) A:0x20002000(手册上描述这是有效故障地址,可以通过手册查询)

如果需要查看具体故障位置,可以进入调试模式,然后停止程序运行,将 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

图 1 SCB->CCR 寄存器的位分配

CCR 寄存器的以下位控制使用故障的行为:
DIV_0_TRP 当处理器执行除数为 0 SDIV UDIV 指令时启用 UsageFault
0 = 不陷阱除以 0 除以 0 返回商 0
1 = 陷阱除以 0
UNALIGN_TRP: 对未对齐地址执行内存访问时启用 UsageFault
0 = 不捕获未对齐的半字和字访问
1 = 捕获未对齐的半字和字访问; 未对齐的访问会生成 UsageFault
请注意,即使 UNALIGN_TRP 设置为 0,使用 LDMSTMLDRD STRD 指令的未对齐访问也始终会生成 UsageFault

3. 系统处理程序控制和状态寄存器 SHCSR

图 2 SCB->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 以禁用。
尽管可以写入 SHCSR 寄存器的所有位,但在大多数软件应用程序中,只有写入使能位才有意义。 可以使用以下语句启用内存管理故障、总线故障和使用故障异常:
1
2
3
SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk | 	\
SCB_SHCSR_BUSFAULTENA_Msk | \
SCB_SHCSR_MEMFAULTENA_Msk; //enable Usage-/Bus-/MPU Fault

4. HardFault 状态寄存器 HFSR 寄存器

图 3 SCB->HSFR 寄存器的位分配

硬故障状态寄存器指示 CPU 指令的错误使用,并具有以下状态位:
VECTTBL: 指示异常处理期间读取向量表时出现总线故障:
0 =
读取向量表时没有总线故障
1 =
读取向量表时出现总线故障。
当该位置位时,为异常返回而堆叠的 PC 值指向被异常抢占的指令。 此错误始终是硬故障。
FORCED: 表示强制硬故障,由具有可配置优先级的故障升级生成,该故障由于优先级或被禁用而无法处理:
0 = 无强制硬故障
1 =
强制硬故障。
当该位置位时,硬故障处理程序必须读取其他故障状态寄存器以查找故障原因。
DEBUGEVT: 保留用于调试。 写入寄存器时,您必须向该位写入 0,否则行为是不可预测的。

5. MemManage (内存管理)故障状态和地址寄存器 (MMFSR; MMFAR)

  1. MemManage (内存管理)状态寄存器 (MMFSR)
    MemManage (内存管理)故障状态寄存器 (MMFSR) 指示内存保护单元 (MPU) 检测到的内存访问违规。 仅允许特权访问。 非特权访问会产生总线故障BusFault
    图 5 MMFSR 位分配
    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 故障处理程序时出现问题。
  2. MemManage (内存管理)地址寄存器 (MMFAR)
    BFAR 地址与精确的数据访问(总线故障) BusFault 相关联。 仅允许特权访问。 非特权访问会产生总线故障 BusFault
    图 6 MMFAR 位分配
    ADDRESS: 内存管理故障的数据地址。 该寄存器使用产生 MemManage 故障的位置的地址进行更新。 MMFSR 显示故障原因。 此字段仅在设置 MMFSR.MMARVALID 时有效。 在没有唯一 BFAR 和 MMFAR 寄存器的实现中,如果设置了 BFSR.BFARVALID,则该寄存器的值是 UNKNOWN。

6. BusFault 总线故障状态和地址寄存器(BFSR;BFAR)

  1. BusFault 总线故障状态寄存器 (BFSR)
    总线故障状态寄存器显示因取指令和数据访问导致的总线错误状态,并指示在总线操作期间检测到的存储器访问故障。 只允许特权访问。 非特权访问将产生总线故障。
    图 7 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 值已被覆盖的堆叠活动总线故障处理程序时出现问题。
  2. BusFault总线故障地址寄存器 (BFAR)
    BFAR 地址与精确的数据访问总线故障相关联。 仅允许特权访问。 非特权访问会产生总线故障。
    图 8 BFAR 位分配
    ADDRESS: 精确总线故障的数据地址。 该寄存器使用产生总线故障的位置的地址进行更新。 BFSR 显示故障原因。 该字段仅在设置了 BFSR.BFARVALID 时有效。 在没有唯一 BFAR 和 MMFAR 寄存器的实现中,如果设置了 MMFSR.MMARVALID,则该寄存器的值是 UNKNOWN。

7. UsageFault使用故障状态寄存器 (UFSR)

图 9 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 位的设置如何,未对齐的 LDMSTMLDRD STRD 指令总是出错。
DIVBYZERO: 被零除使用错误:
0 = 没有被零除错误,或被零除陷阱未启用
1 =
处理器执行了除数为 0 SDIV UDIV 指令。
当处理器将此位设置为
1 时, 为异常返回堆叠的 PC 值指向执行除以零的指令。 通过将 CCR 中的 DIV_0_TRP 位设置为 1 来启用除以零的捕获。

请注意,UsageFault使用故障状态寄存器的位是粘性的。 这意味着,当发生一个或多个故障时,相关位设置为 1。设置为 1 的位仅通过向该位写入 1 或通过复位清除为 0。

8. 辅助总线故障状态寄存器 ABFSR 寄存器(仅限 Cortex-M7)

图 10 ABFSR 位分配
辅助总线故障状态寄存器 (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:这些接口可能不存在于您的实现中。