Cortex-M3/M4/M7 芯片 Fault 分析原理与实战


一、简介

1、异常类型

HardFault(硬件错误)是一类在嵌入式系统开发中较为常见的系统异常,优先级仅低于复位和 NMI(不可屏蔽中断)。当系统运行过程中遇到了某些错误时程序就会跳转至 HardFault_Handler 函数中,引发程序故障进而影响程序的正常运行。

一般而言,我们遇到的错误有如下几种:

  • HardFault(硬件故障):默认异常,由于异常处理过程中的错误或由于任何其他异常机制无法管理异常而触发。
  • MemManage(内存管理故障):检测内存管理单元(MPU)中定义的区域的内存访问违规;例如,在一个只有读/写访问权限的内存区域中执行代码。
  • BusFault(总线故障):在指令取指、数据读/写、中断向量取指和寄存器入栈(保存/恢复)中断(进入/退出)时检测内存访问错误。
  • UsageFault(使用故障):检测未定义指令的执行,加载/存储多个未对齐的内存访问。启用时,将检测除 0 和其他非对齐内存访问。

2、异常优先级

每个异常都有一个相关联的异常号和一个相关联的优先级号。为简化软件层,CMSIS 只使用 IRQ 编号,因此对中断以外的异常使用负值。下表按优先级顺序列出故障异常:

Exception Exception Number 优先级 IRQ Number 激活方式
HardFault 3 -1 -13 -
MemManage fault 4 可配置 -12 同步
BusFault 5 可配置 -11 精确时同步,不精确时异步
UsageFault 6 可配置 -10 同步

由这张表可以看出,HardFault 异常总是启用的,并且具有固定的优先级(高于其他中断和异常,但低于不可屏蔽中断 NMI)。因此,在禁用故障异常或在执行故障异常处理程序期间发生故障的情况下,将执行 HardFault 异常。通过下面的例子来理解一下这段话。

stm32f4xx_it.c 文件中有如下几个中断服务程序:

void NMI_Handler(void);
void HardFault_Handler(void);
void MemManage_Handler(void);
void BusFault_Handler(void);
void UsageFault_Handler(void);
void SVC_Handler(void);
void DebugMon_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);

MemManage_Handler 为例,如果你没有使能这个中断的话,那它肯定也不会进入这个中断,而是会进入 HardFault_Handler,也就是硬件异常!这也是下面要讲的优先级提升

而所有其他故障异常(MemManage faultBus FaultUsage Fault)都具有可编程优先级。重置后,这些异常被禁用,可以在系统或应用软件中使用系统控制块(SCB)中的寄存器启用。

通常,异常优先级和异常掩码寄存器的值一起确定处理器是否进入错误处理程序,以及错误处理程序是否可以抢占另一个错误处理程序。在某些情况下(例如刚才的例子),具有可配置优先级的故障被视为 Hard Fault。这被称为优先级提升,即故障升级为 HardFault。升级到 HardFault 发生在:

  1. 当一个 Fault 触发时,并再次触发相同的 Fault。之所以会升级到 HardFault,是因为处理程序不能抢占自己(它必须具有与当前优先级相同的优先级)。
  2. 当一个 Fault 执行时,有一个优先级比它低或者同级的 Fault 被触发。因为新错误的处理程序不能抢占当前执行的错误处理程序。
  3. 当一个(普通的)中断在执行的时候,有一个优先级比它低或者同级的(普通的)中断触发了 Fault。
  4. 发生了 Fault,但未启用该错误的处理程序(上面介绍过的例子)。

如果在入栈过程中进入 BusFault handler 时发生 BusFaultBusFault 不会升级为 HardFault。这意味着,如果崩溃的栈导致了错误,即使处理程序的入栈失败,也会执行错误处理程序。错误处理程序正常运行,但栈内容已损坏。

注意:只有 Reset(复位中断) 和 NMI(不可屏蔽中断) 可以抢占固定优先级的 HardFaultHardFault 可以抢占除 Reset、NMI 或其他 HardFault 之外的任何异常。如下图所示:

3、同步异步问题

BusFault 错误处理程序可以使用 BFSR 来确定错误是异步的(IMPRECISERR,不精确的)还是同步的(PRECISERR,精确的)。

同步总线故障也被称为精确总线故障。何谓精确?就是总线触发异常之后,我们可以找到它触发异常的地址。如果同步总线故障发生在 NMI 或 HardFault 处理程序内,则会升级为锁定。缓存维护操作也可能触发总线故障。调试访问也可能触发总线故障。调试器的加载或存储访问是同步的,并且仅对调试器接口可见。

异步总线故障被称为为不精确总线故障,同理,就是总线触发异常之后,我们不能找到它触发异常的地址。它可能发生在处理器设计中存在写缓冲时。因此,在观察到总线错误响应之前,处理器流水线会继续执行后续的指令。当异步总线故障被触发时,总线故障异常被挂起。如果另一个高优先级的中断事件同时到达,则首先执行高优先级的中断处理程序,然后发生 BusFault。如果总线故障处理程序未启用,则挂起 HardFault。由异步总线故障引起的硬故障不会升级为锁定。异步错误通常是不可恢复的,因为你不知道是哪段代码导致了错误。

现代的芯片都是多级流水线执行的,它触发的时候,多级流水线人在执行,我们无法锁定是哪一级出了问题,也就无法找到精确的错误地址。

4、异常具体类型

下表中列出了 Fault 类型、Fault Handler、Fault status register 和故障发生的寄存器位名:

  • HardFault - HFSR
Fault type Bit Name
Bus error on a vector read error VECTTBL
Fault that is escalated to a hard fault FORCED
Fault on breakpoint escalation DEBUGEVT
  • MemManage - MMFSR
Fault type Bit Name
Fault on instruction access IACCVIOL
Fault on direct data access DACCVIOL
Context stacking, because of an MPU access violation MSTKERR
Context unstacking, because of an MPU access violation MUNSTKERR
During lazy floating-point state preservation MLSPERR
  • BusFault - BFSR
Fault type Bit Name
During exception stacking 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
  • UsageFault - UFSR
Fault type Bit Name
Undefined instruction 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 DIVBYZERO

下面就来看一下这些寄存器。

二、Fault exception registers

1、Control registers

系统控制块(SCB)提供系统实施信息和系统控制。这包括系统异常的配置、控制和报告。它的一些寄存器用于控制 Fault 异常。

这里有三个寄存器:

  • CCRThe Configuration and Control Register,配置和控制寄存器),控制 Usage Fault 的除零和非对齐内存访问的行为
  • SHPThe System Handler Priority Registers,系统处理程序优先级寄存器),控制异常优先级
  • SHCSRThe System Handler Control and State Register,系统处理程序控制和状态寄存器),使能系统处理程序,表示Bus FaultMemManage fault 和 SVC异常的待处理状态。
Address / Access Register Reset Value Description
0xE000ED14
RW privileged
CCR 0x00000000 包含捕获与 UsageFault 的除零和非对齐访问的启用位
0xE000ED18
RW privileged
SHP[12] 0x00 控制异常处理器的优先级
0xE000ED24
RW privileged
SHCSR 0x00000000 表示硬故障原因的位

1.1 CCR

  • DIV_0_TRP:在处理器执行除数为 0 的 SDIVUDIV 指令时启用 Usage Fault
    • 0:除 0 不触发;除以 0 得到的商是 0
    • 1:除 0 触发
  • UNALIGN_TRP:当对非对齐地址进行内存访问时,启用 Usage Fault
    • 0:不捕获非对齐的半字和字访问
    • 1:捕获非对齐的半字和字访问;非对齐访问会产生 Usage Fault
    • 请注意,使用 LDMSTMLDRDSTRD 指令的非对齐访问总是会产生 Usage Fault即使 UNALIGN_TRP 设置为 0

1.2 SHP

SHP 寄存器设置异常处理程序的优先级。故障异常通过以下方式控制:

  • SHP[0]:内存管理故障的优先级
  • SHP[1]:总线故障的优先级
  • SHP[2]Usage Fault 的优先级

对于编程中断和异常优先级,CMSIS 提供了 NVIC_SetPriorityNVIC_GetPriority 函数。故障异常的优先级可以修改如下:

NVIC_SetPriority (MemoryManagement_IRQn, 0x0F);
NVIC_SetPriority (BusFault_IRQn, 
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值