Cortex-M Fault

Cortex-M CPU 会在系统发生故障时引发异常。非法内存写入和读取、访问未通电的外设、执行无效指令、除以零以及其他问题都可能导致此类异常。通常在所有情况下都会引发 HardFault 异常。对于某些故障,可以启用不同的异常来专门处理这些情况。
在这里插入图片描述

Cortex-M 故障异常

Cortex-M 处理器实现了不同的故障异常。

HardFault 异常

HardFault 是默认异常,在任何与其他(启用的)异常无关的错误上引发。

HardFault 的优先级固定为 -1,即它的优先级高于除 NMI 之外的所有其他中断和异常。因此,当应用程序代码、中断或其他异常中发生错误时,总是可以进入 HardFault 异常处理程序。HardFault 是向量表中的异常编号 3,IRQ 编号为 -13。

内存管理异常

MemManage 异常可利用内存保护单元 (MPU) 来引发内存访问违规异常。

MemManage 是向量表中的异常编号 4,IRQ 编号 -12,并且具有可配置的优先级。

总线故障异常

任何内存访问错误都会引发 BusFault 异常。例如,非法读取、写入或向量捕获。

BusFault 是向量表中的异常编号 5,IRQ 编号为 -11,具有可配置的优先级。BusFault 可以在系统控制块 (SCB) 中明确启用。当 BusFault 未启用时,会引发 HardFault。

UsageFault 异常

执行错误时会引发 UsageFault 异常。加载/存储多个指令上的未对齐访问始终会被捕获。其他未对齐访问以及除以零的异常可在 SCB 中额外启用。

UsageFault 是向量表中的异常编号 6,IRQ 编号为 -10,具有可配置的优先级。当未启用 UsageFault 时,将改为引发 HardFault。

异常处理
发生任何异常时,都会调用从向量表读取的异常处理程序,就像中断一样。异常处理通常在开发和生产固件过程中以不同的方式进行。

开发过程中的异常处理

在固件开发过程中,可能会发生错误。开发人员通常希望分析问题所在以解决错误。

Cortex-M NVIC 提供了各种寄存器来分析崩溃的原因。此外,在大多数情况下,可以恢复崩溃发生位置的调用堆栈和寄存器内容。

调试器可以提供特殊功能来帮助分析。在这种情况下,无需向代码添加任何特殊异常处理程序。调试器只需在向量捕获或断点处中断并进行分析即可。

无需调试器的帮助,异常处理程序可以包含开发代码来收集所需信息,以便轻松地在调试器中使用它们。下面列出的 SEGGER HardFault Handler 读取相应的故障寄存器,并使其在结构中轻松可用。

生产固件中的异常处理

发布固件中也可能出现异常,应该将其捕获。

有些异常可能不是由错误引起的。例如,在未连接调试器的情况下执行 BKPT 指令会导致 HardFault。对于这些异常,固件可以简单地返回并继续执行程序。

系统可能还想从某些错误(但不是崩溃)的情况中恢复。在异常处理程序中,可以分析错误原因并从错误中恢复系统,例如通过终止导致错误的任务。

如果发生崩溃,只需重置系统即可恢复。在更高级的情况下,可以在重置之前生成崩溃转储,以便在重启时发送或保存。

异常分析

可以使用上面描述的 HardFault Handler 分析导致异常的系统状态。此外,一些调试器(例如 Ozone)提供了特殊功能来简化分析。

当 Ozone 检测到目标系统崩溃时,它会自动分析目标状态并提供所有必要的信息。异常窗口显示崩溃的原因以及发生的位置和附加 NVIC 寄存器。调用堆栈窗口还可以从异常中展开,以便轻松导航到错误的位置,即使跨多个异常也是如此。

有关更多信息,请参阅使用臭氧分析 Cortex-M 故障

故障状态寄存器

Cortex-M 系统控制块 (SCB) 包含一些寄存器,可以配置异常并提供有关故障的信息。

硬故障状态寄存器 (HFSR)

HFSR 位于地址 0xE000ED2C 的 SCB 中。它是一个 32 位寄存器。

位域:

[31] DEBUGEVT - 保留供调试器/调试探测器使用。始终写入 0[30] FORCED - 如果为 1,则由于禁用或优先级原因,HardFault 是由另一个异常升级引起的。
[1] VECTTBL - 如果为 1,则在读取异常处理向量表时发生 BusFault。

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

UFSR 是一个 16 位伪寄存器,是地址 0xE000ED28 处可配置故障状态寄存器 (CFSR) 的一部分。也可以通过半字访问 0xE000ED2A 直接访问它。

位域:

[9] DIVBYZERO - 如果为 1,则使用除数 0 执行 SDIV 或 UDIV 指令。
[8] UNALIGNED - 如果为 1,则在未对齐地址上执行 LDM、STM、LDRD 或 STRD,或者在启用陷阱时执行单个加载或存储。
[3] NOCP - 如果为 1,则访问不受支持的(例如不可用或未启用)协处理器。
[2] INVPC - 如果为 1,则将非法或无效的 EXC_RETURN 值加载到 PC。
[1] INVSTATE - 如果为 1,则在无效状态下执行。例如,EPSR 中的 Thumb 位未设置,或者 EPSR 中的 IT 状态无效。
[0] UNDEFINSTR - 如果为 1,则执行未定义的指令。

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

BFSR 是 CFSR 中的一个 8 位伪寄存器。它可以通过从 0xE000ED29 开始的字节访问直接访问。BFAR 是一个位于 0xE000ED38 的 32 位寄存器。

位域:

[7] BFARVALID - 如果为 1,则 BFAR 包含导致 BusFault 的地址。
[5] LSPERR - 1f 1,浮点惰性堆栈保存期间发生故障。
[4] STKERR - 如果为 1,则异常入口的堆栈故障。
[3] UNSTKERR - 如果为 1,则异常返回时出栈故障。
[2] IMPRECISERR - 如果为 1,则返回地址与故障无关,例如之前导致的故障。
[1] PRECISERR - 如果为 1,则返回地址指令导致故障。
[0] IBUSERR - 如果为 1,则指令获取故障。

MemManage 故障状态寄存器 (MMFSR) 和 MemManage 故障地址寄存器 (MMFAR)

MMFSR 是 CFSR 中的一个 8 位伪寄存器。它可以通过从 0xE000ED28 开始的字节访问直接访问。MMFAR 是一个位于 0xE000ED34 的 32 位寄存器。

位域:

[7] MMARVALID - 如果为 1,则 MMFAR 包含导致 MemManageFault 的地址。
[5] MLSPERR - 1f 1,浮点惰性堆栈保存期间发生故障。
[4] MSTKERR - 如果为 1,则异常进入堆栈时发生故障。
[3] MUNSTKERR - 如果为 1,则异常返回时出栈时发生故障。
[1] DACCVIOL - 如果为 1,则数据访问违规。
[0] IACCVIOL - 如果为 1,则指令访问违规。

堆栈恢复

在异常入口处,异常处理程序可以检查发生故障时使用了哪个堆栈。当 EXC_RETURN[2] 位被设置时,使用 MSP,否则使用 PSP。

堆栈可用于恢复 CPU 寄存器的值。

CPU寄存器恢复

在异常进入时,一些 CPU 寄存器存储在堆栈中,可以从那里读取以进行错误分析。以下寄存器是可恢复的:

r0 = pStack[0]; // 寄存器 R0 
 r1 = pStack[1]; // 寄存器 R1 
 r2 = pStack[2]; // 寄存器 R2 
 r3 = pStack[3]; // 寄存器 R3 
 r12 = pStack[4]; // 寄存器 R12 
 lr = pStack[5]; // 链接寄存器 LR 
 pc = pStack[6]; // 程序计数器 PC 
 psr.byte = pStack[7]; // 程序状态字 PSR

故障分析示例

以下示例显示了某些故障是如何/为何发生的,以及如何分析它们。此处提供了一个用于测试这些故障的项目。

BusFault 示例

非法内存写入

/**************************************************************************** 
* 
* _IllegalWrite() 
* 
* 函数说明
* 通过写入保留地址来触发 BusFault 或 HardFault。
* 
* 附加信息
* 写入指令后执行某些指令会引发 BusFault。
* 故障时相关寄存器:
* HFSR = 0x40000000 
* FORCED = 1 - BusFault 升级为 HardFault(当 BusFault 未激活时)
* BFSR = 0x00000004 
* IMPRECISERR = 1 - 不精确的数据访问违规。返回地址与故障无关
* BFARVALID = 0 - BFAR 无效
*/ 
static  int  _IllegalWrite ( void )  { 
  int  r ; 
  volatile  unsigned  int *  p ; 

  r  =  0 ; 
  p  =  ( unsigned  int * ) 0x00100000 ;        // 0x00100000-0x07FFFFFF 在 STM32F4 上保留
  // F44F1380 mov.w r3, #0x00100000 
  * p  =  0x00BADA55 ; 
  // 4A03 ldr r2, =0x00BADA55 
  // 601A str r2, [r3] <- 此处执行了非法写入
  return  r ; 
  // 9B00 ldr r3, [sp] 
  // 4618 mov r0, r3 
  // B002 add sp, sp, #8 <- 此处可能会引发故障
  // 4770 bx lr 
}

非法内存读取

/**************************************************************************** 
* 
* _IllegalRead() 
* 
* 功能说明
* 通过从保留地址读取来触发 BusFault 或 HardFault。
* 
* 附加信息
* 读取指令后立即触发 BusFault。
* 故障时相关寄存器:
* HFSR = 0x40000000 
* FORCED = 1 - BusFault 升级为 HardFault 
* BFSR = 0x00000082 
* PRECISERR = 1 - 精确数据访问违规
* BFARVALID = 1 - BFAR 有效
* BFAR = 0x00100000 - 读取的地址
*/ 
static  int  _IllegalRead ( void )  { 
  int  r ; 
  volatile  unsigned  int *  p ; 

  p  =  ( unsigned  int * ) 0x00100000 ;         // 0x00100000-0x07FFFFFF 在 STM32F4 上保留
  // F44F1380 mov.w r3, #0x00100000 <- 读取地址。将在 BFAR 中找到
  r  =  * p ; 
  // 681B ldr r3, [r3] <- 此处发生非法读取并引发 BusFault 
  // 9300 str r3, [sp] 

  return  r ; 
}

非法函数执行

/**************************************************************************** 
* 
* _IllegalFunc() 
* 
* 功能说明
* 通过在保留地址执行来触发 BusFault 或 HardFault。
* 
* 附加信息
* 在无效地址执行时触发 BusFault。
* 故障时相关寄存器:
* HFSR = 0x40000000 
* FORCED = 1 - BusFault 升级为 HardFault 
* BFSR = 0x00000001 
* IBUSERR = 1 - 指令预取时发生 BusFault 
*/ 
static  int  _IllegalFunc ( void )  { 
  int  r ; 
  int  ( * pF )( void ); 

  pF  =  ( int ( * )( void )) 0x00100001 ;          // 0x00100000-0x07FFFFFF 在 STM32F4 上保留
  // F44F1380 mov.w r3, #0x00100001 
  r  =  pF (); // 4798 blx r3 <- 分支到非法地址,导致从 0x00100000 获取并返回故障异常
  return r ; 
  } 

UsageFault 示例

未定义指令执行

/**************************************************************************** 
* 
* _UndefInst() 
* 
* 函数说明
* 执行未定义的指令时触发 UsageFault 或 HardFault。
* 
* 附加信息
* 在无效地址执行时触发 UsageFault。
* 硬故障的相关寄存器:
* HFSR = 0x40000000 
* FORCED = 1 - UsageFault 升级为 HardFault 
* UFSR = 0x0001 
* UNDEFINSTR = 1 - 执行了未定义的指令
*/ 
static  int  _UndefInst ( void )  { 
  static  const  unsigned  short  _UDF [ 4 ]  =  { 0xDEAD ,  0xDEAD ,  0xDEAD ,  0xDEAD };  // 0xDEAD: UDF #<imm> (永久未定义) 
  int  r ; 
  int  ( * pF )( void ); 

  pF  =  ( int ( * )( void ))((( char * ) & _UDF )  +  1 ); 
  // 4B05 ldr r3, =0x08001C18 <_UDF> <- 加载“RAM Code”指令的地址
  // 3301 添加 r3, #1 <- 确保 Thumb 位已设置
  r  =  pF (); 
  // 4798 blx r3 <- 调用“RAM Code”,将执行 UDF 指令并引发异常
  // 9000 str r0, [sp] 
  return  r ; 
}

非法状态

/**************************************************************************** 
* 
* _NoThumbFunc() 
* 
* 功能说明
* 执行未设置 thumb 位的地址时触发 UsageFault 或 HardFault。
* 
* 附加信息
* 在无效地址执行时触发 UsageFault。
* 硬故障的相关寄存器:
* HFSR = 0x40000000 
* FORCED = 1 - UsageFault 升级为 HardFault 
* UFSR = 0x0002 
* INVSTATE = 1 - 以无效状态执行指令
*/ 
static  int  _NoThumbFunc ( void )  { 
  int  r ; 
  int  ( * pF )( void ); 

  pF  =  ( int ( * )( void )) 0x00100000 ;          // 0x00100000-0x07FFFFFF 在 STM32F4 上保留
  // F44F1380 mov.w r3, #0x00100000 <- 请注意,位 [0] 未设置。
  r  =  pF (); 
  // 4798 blx r3 <- 分支交换,模式更改为 ARM,但 Cortex-M 仅支持 Thumb 模式。
  return  r ; 
}

被零除

/**************************************************************************** 
* 
* _DivideByZero() 
* 
* 函数说明
* 通过除以零触发 UsageFault 或 HardFault。
* 
* 附加信息
* 在除法指令上立即触发 UsageFault。
* 硬故障上的相关寄存器:
* HFSR = 0x40000000 
* FORCED = 1 - UsageFault 升级为 HardFault 
* UFSR = 0x0200 
* DIVBYZERO = 1 - 除以零故障
*/ 
static  int  _DivideByZero ( void )  { 
  int  r ; 
  volatile  unsigned  int  a ; 
  volatile  unsigned  int  b ; 
  a  =  1 ; 
  // 2301 movs r3, #1 <- Load divided into a decimal error 
  b  =  0 ; 
  // 2300 movs r3, #0 <- 加载除数
  r  =  a  /  b ; 
  // FBB2F3F3 udiv r3, r2, r3 <- 除以 0 引发故障异常
  return  r ; 
}

未对齐访问

/**************************************************************************** 
* 
* _UnalignedAccess() 
* 
* 函数说明
* 通过未对齐的字访问触发 UsageFault 或 HardFault。
* 
* 附加信息
* 在读取或写入指令时立即触发 UsageFault。
* 故障时相关寄存器:
* HFSR = 0x40000000 
* FORCED = 1 - UsageFault 升级为 HardFault 
* UFSR = 0x0100 
* UNALIGNED = 1 - 未对齐的内存访问
*/ 
static  int  _UnalignedAccess ( void )  { 
  int  r ; 
  volatile  unsigned  int *  p ; 

  p  =  ( unsigned  int * ) 0x20000002 ; 
  // 4B04 ldr r3, =0x20000002 <- 未字对齐的地址
  r  =  * p ; 
  // 681B ldr r3, [r3] <- 从未对齐的地址加载字会引发异常
  // 9300 str r3, [sp] 
  return  r ; 
}

HardFault 示例

非法向量表获取

/**************************************************************************** 
* 
* _IllegalVector() 
* 
* 函数说明
* 使用非法向量表通过中断触发 HardFault。
* 
* 附加信息
* 故障时相关寄存器:
* HFSR = 0x00000002 
* VECTTBL = 1 - 向量表读取故障
*/ 
static  int  _IllegalVector ( void )  { 
  int  r ; 

  SCB -> VTOR  =  0x001000000 ;             // 将向量表重定位到非法地址  
  // 4B09 ldr r3, =0xE000ED00 
  // F04F7280 mov.w r2, #0x1000000 
  // 609A str r2, [r3, #8] 
  SCB -> ICSR  =  SCB_ICSR_PENDSVSET_Msk ;  // 触发 PendSV 异常以读取无效向量
  // 4B07 ldr r3, =0xE000ED00 
  // F04F5280 mov.w r2, #0x10000000 
  // 605A str r2, [r3, #4] 
  __ISB (); 
  // F3BF8F6F isb <- 将执行 PendSV 异常。尝试从非法地址 0x00100038 读取 PendSV 向量导致故障异常
  // BF00 nop 
  __DSB (); 
  // F3BF8F4F dsb sy 
  // BF00 nop 
  return  r ; 
}

文件列表

SEGGER 硬故障处理程序

;/*********************************************************************
 ;*
 ;*      HardFault_Handler()
 ;*
 ;*  Function description
 ;*    Evaluates the used stack (MSP, PSP) and passes the appropiate
 ;*    stack pointer to the HardFaultHandler "C"-routine.
 ;*
 ;*  Notes
 ;*    (1) Ensure that HardFault_Handler is part of the exception table
 ;*/
 HardFault_Handler:
 BusFault_Handler:
 UsageFault_Handler:
 MemManage_Handler:
 #if (defined (__IAR_SYSTEMS_ASM__) && (__ARM6M__) && (__CORE__ == __ARM6M__)) || \
     (defined(__CC_ARM) || (defined __clang__)) && (__TARGET_ARCH_6S_M)        || \
     (defined (__GNUC__) && ((__ARM_ARCH_6M__) || (__ARM_ARCH_8M_BASE__)))
         ;// This version is for Cortex M0
         movs   R0, #4
         mov    R1, LR
         tst    R0, R1            ;// Check EXC_RETURN in Link register bit 2.
         bne    Uses_PSP
         mrs    R0, MSP           ;// Stacking was using MSP.
         b      Pass_StackPtr
 Uses_PSP:
         mrs    R0, PSP           ;// Stacking was using PSP.
 Pass_StackPtr:
         ldr    R2,=HardFaultHandler
         bx     R2                ;// Stack pointer passed through R0. 
 #else
         ;// This version is for Cortex M3, Cortex M4 and Cortex M4F
         tst    LR, #4            ;// Check EXC_RETURN in Link register bit 2.
         ite    EQ
         mrseq  R0, MSP           ;// Stacking was using MSP.
         mrsne  R0, PSP           ;// Stacking was using PSP.
         b      HardFaultHandler  ;// Stack pointer passed through R0.
 #endif
         .end
/*********************************************************************
 *                     SEGGER Microcontroller GmbH                    *
 *                        The Embedded Experts                        *
 **********************************************************************
 *                                                                    *
 *            (c) 2014 - 2023 SEGGER Microcontroller GmbH             *
 *                                                                    *
 *           www.segger.com     Support: support@segger.com           *
 *                                                                    *
 **********************************************************************
 *                                                                    *
 * All rights reserved.                                               *
 *                                                                    *
 * Redistribution and use in source and binary forms, with or         *
 * without modification, are permitted provided that the following    *
 * conditions are met:                                                *
 *                                                                    *
 * - Redistributions of source code must retain the above copyright   *
 *   notice, this list of conditions and the following disclaimer.    *
 *                                                                    *
 * - Neither the name of SEGGER Microcontroller GmbH                  *
 *   nor the names of its contributors may be used to endorse or      *
 *   promote products derived from this software without specific     *
 *   prior written permission.                                        *
 *                                                                    *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             *
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,        *
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           *
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           *
 * DISCLAIMED.                                                        *
 * IN NO EVENT SHALL SEGGER Microcontroller GmbH BE LIABLE FOR        *
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR           *
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  *
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;    *
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF      *
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT          *
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE  *
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *
 * DAMAGE.                                                            *
 *                                                                    *
 **********************************************************************
 
 -------------------------- END-OF-HEADER -----------------------------
 File    : SEGGER_HardFaultHandler.c
 Purpose : Generic SEGGER HardFault handler for Cortex-M
 Literature:
   [1]  Analyzing HardFaults on Cortex-M CPUs (https://www.segger.com/downloads/appnotes/AN00016_AnalyzingHardFaultsOnCortexM.pdf)
 
 Additional information:
   This HardFault handler enables user-friendly analysis of hard faults
   in debug configurations.
   If a release configuration requires a HardFault handler,
   a specific HardFault handler should be included instead,
   which for example issues a reset or turns on an error LED.
 --------  END-OF-HEADER  ---------------------------------------------
 */
 
 /*********************************************************************
 *
 *       Defines
 *
 **********************************************************************
 */
 #define SCB_SHCSR  (*(volatile unsigned int*)  (0xE000ED24u))  // System Handler Control and State Register
 #define SCB_MMFSR  (*(volatile unsigned char*) (0xE000ED28u))  // MemManage Fault Status Register
 #define SCB_BFSR   (*(volatile unsigned char*) (0xE000ED29u))  // Bus Fault Status Register
 #define SCB_UFSR   (*(volatile unsigned short*)(0xE000ED2Au))  // Usage Fault Status Register
 #define SCB_HFSR   (*(volatile unsigned int*)  (0xE000ED2Cu))  // Hard Fault Status Register
 #define SCB_DFSR   (*(volatile unsigned int*)  (0xE000ED30u))  // Debug Fault Status Register
 #define SCB_MMFAR  (*(volatile unsigned int*)  (0xE000ED34u))  // MemManage Fault Manage Address Register
 #define SCB_BFAR   (*(volatile unsigned int*)  (0xE000ED38u))  // Bus Fault Address Register
 #define SCB_AFSR   (*(volatile unsigned int*)  (0xE000ED3Cu))  // Auxiliary Fault Status Register
 
 #ifndef   DEBUG         // Should be overwritten by project settings
   #define DEBUG   (0)   // in debug builds
 #endif
 
 /*********************************************************************
 *
 *       Prototypes
 *
 **********************************************************************
 */
 #ifdef __cplusplus
   extern "C" {
 #endif
 void HardFaultHandler(unsigned int* pStack);
 #ifdef __cplusplus
   }
 #endif
 
 /*********************************************************************
 *
 *       Static data
 *
 **********************************************************************
 */
 #if DEBUG
 static volatile unsigned int _Continue;  // Set this variable to 1 to run further
 
 static struct {
   struct {
     volatile unsigned int r0;            // Register R0
     volatile unsigned int r1;            // Register R1
     volatile unsigned int r2;            // Register R2
     volatile unsigned int r3;            // Register R3
     volatile unsigned int r12;           // Register R12
     volatile unsigned int lr;            // Link register
     volatile unsigned int pc;            // Program counter
     union {
       volatile unsigned int word;
       struct {
         unsigned int IPSR :  8;          // Interrupt Program Status register (IPSR)
         unsigned int EPSR : 19;          // Execution Program Status register (EPSR)
         unsigned int APSR :  5;          // Application Program Status register (APSR)
       } bits;
     } psr;                               // Program status register.
   } SavedRegs;
 
   union {
     volatile unsigned int word;
     struct {
       unsigned int MEMFAULTACT       :  1;   // [0]  Read as 1 if memory management fault is active
       unsigned int BUSFAULTACT       :  1;   // [1]  Read as 1 if bus fault exception is active
       unsigned int HARDFAULTACT      :  1;   // [2]  Read as 1 if hard fault exception is active (ARMv8-M)
       unsigned int USGFAULTACT       :  1;   // [3]  Read as 1 if usage fault exception is active
       unsigned int SECUREFAULTACT    :  1;   // [4]  Read as 1 if secure fault exception is active (ARMv8-M)
       unsigned int NMIACT            :  1;   // [5]  Read as 1 if NMI exception is active (ARMv8-M)
       unsigned int                   :  1;
       unsigned int SVCALLACT         :  1;   // [7]  Read as 1 if SVC exception is active
       unsigned int MONITORACT        :  1;   // [8]  Read as 1 if debug monitor exception is active
       unsigned int                   :  1;
       unsigned int PENDSVACT         :  1;   // [10] Read as 1 if PendSV exception is active
       unsigned int SYSTICKACT        :  1;   // [11] Read as 1 if SYSTICK exception is active
       unsigned int USGFAULTPENDED    :  1;   // [12] Usage fault pending; higher priority exception active
       unsigned int MEMFAULTPENDED    :  1;   // [13] Memory management fault pending; higher priority exception active
       unsigned int BUSFAULTPENDED    :  1;   // [14] Bus fault pending; higher priority exception active
       unsigned int SVCALLPENDED      :  1;   // [15] SVC pending; higher priority exception active
       unsigned int MEMFAULTENA       :  1;   // [16] Memory management fault exception enable
       unsigned int BUSFAULTENA       :  1;   // [17] Bus fault exception enable
       unsigned int USGFAULTENA       :  1;   // [18] Usage fault exception enable
       unsigned int SECUREFAULTENA    :  1;   // [19] Secure fault exception enable (ARMv8-M)
       unsigned int SECUREFAULTPENDED :  1;   // [20] Secure fault exception pending; higher priority exception active (ARMv8-M)
       unsigned int HARDFAULTPENDED   :  1;   // [21] Hard fault exception pending (ARMv8-M)
       unsigned int                   : 10;
     } bits;
   } shcsr;                                   // System Handler Control and State Register (0xE000ED24)
 
   union {
     volatile unsigned char byte;
     struct {
       unsigned int IACCVIOL    :  1;     // [0] Instruction access violation
       unsigned int DACCVIOL    :  1;     // [1] Data access violation
       unsigned int             :  1;
       unsigned int MUNSTKERR   :  1;     // [3] Unstacking error
       unsigned int MSTKERR     :  1;     // [4] Stacking error
       unsigned int MLSPERR     :  1;     // [5] MemManage fault during FP lazy state preservation
       unsigned int             :  1;
       unsigned int MMARVALID   :  1;     // [7] Indicates the MMAR is valid
       unsigned int             : 24;
     } bits;
   } mmfsr;                               // MemManage Fault Status Register  (0xE000ED28)
   volatile unsigned int mmfar;           // MemManage Fault Address Register (0xE000ED34)
 
   union {
     volatile unsigned char byte;
     struct {
       unsigned int IBUSERR      :  1;      // [0] Instruction access violation
       unsigned int PRECISERR    :  1;      // [1] Precise data access violation
       unsigned int IMPRECISERR  :  1;      // [2] Imprecise data access violation
       unsigned int UNSTKERR     :  1;      // [3] Unstacking error
       unsigned int STKERR       :  1;      // [4] Stacking error
       unsigned int LSPERR       :  1;      // [5] Bus fault during FP lazy state preservation
       unsigned int              :  1;
       unsigned int BFARVALID    :  1;      // [7] Indicates BFAR is valid
       unsigned int              : 24;
     } bits;
   } bfsr;                                // Bus Fault Status Register  (0xE000ED29)
   volatile unsigned int bfar;            // Bus Fault Address Register (0xE000ED38)
 
   union {
     volatile unsigned short halfword;
     struct {
       unsigned int UNDEFINSTR :  1;      // [0] Attempts to execute an undefined instruction
       unsigned int INVSTATE   :  1;      // [1] Attempts to switch to an invalid state (e.g., ARM)
       unsigned int INVPC      :  1;      // [2] Attempts to do an exception with a bad value in the EXC_RETURN number
       unsigned int NOCP       :  1;      // [3] Attempts to execute a coprocessor instruction
       unsigned int STKOF      :  1;      // [4] Indicates whether a stack overflow error has occurred (ARMv8-M)
       unsigned int            :  3;
       unsigned int UNALIGNED  :  1;      // [8] Indicates that an unaligned access fault has taken place
       unsigned int DIVBYZERO  :  1;      // [9] Indicates a divide by zero has taken place (can be set only if DIV_0_TRP is set)
       unsigned int            : 22;
     } bits;
   } ufsr;                                // Usage Fault Status Register (0xE000ED2A)
 
   union {
     volatile unsigned int word;
     struct {
       unsigned int             :  1;
       unsigned int VECTTBL     :  1;     // [1] Indicates hard fault is caused by failed vector fetch
       unsigned int             : 28;
       unsigned int FORCED      :  1;     // [30] Indicates hard fault is taken because of bus fault/memory management fault/usage fault
       unsigned int DEBUGEVT    :  1;     // [31] Indicates hard fault is triggered by debug event
     } bits;
   } hfsr;                                // Hard Fault Status Register (0xE000ED2C)
 
   union {
     volatile unsigned int word;
     struct {
       unsigned int HALTED   :  1;        // [0] Halt requested in NVIC
       unsigned int BKPT     :  1;        // [1] BKPT instruction executed
       unsigned int DWTTRAP  :  1;        // [2] DWT match occurred
       unsigned int VCATCH   :  1;        // [3] Vector fetch occurred
       unsigned int EXTERNAL :  1;        // [4] EDBGRQ signal asserted
       unsigned int PMU      :  1;        // [5] PMU counter overflow event has occurred
       unsigned int          : 26;
     } bits;
   } dfsr;                                // Debug Fault Status Register (0xE000ED30)
 
   volatile unsigned int afsr;            // Auxiliary Fault Status Register (0xE000ED3C), Vendor controlled (optional)
 } HardFaultRegs;
 #endif
 
 /*********************************************************************
 *
 *       Global functions
 *
 **********************************************************************
 */
 
 /*********************************************************************
 *
 *       HardFaultHandler()
 *
 *  Function description
 *    C part of the hard fault handler which is called by the assembler
 *    function HardFault_Handler
 */
 void HardFaultHandler(unsigned int* pStack) {
   //
   // In case we received a hard fault because of a breakpoint instruction, we return.
   // This may happen when using semihosting for printf outputs and no debugger is connected,
   // i.e. when running a "Debug" configuration in release mode.
   //
   if (SCB_HFSR & (1u << 31)) {
     SCB_HFSR |=  (1u << 31);      // Reset Hard Fault status
     *(pStack + 6u) += 2u;         // PC is located on stack at SP + 24 bytes. Increment PC by 2 to skip break instruction.
     return;                       // Return to interrupted application
   }
 #if DEBUG
   //
   // Read NVIC registers
   //
   HardFaultRegs.shcsr.word    = SCB_SHCSR;  // System Handler Control and State Register
   HardFaultRegs.mmfsr.byte    = SCB_MMFSR;  // MemManage Fault Status Register
   HardFaultRegs.mmfar         = SCB_MMFAR;  // MemManage Fault Address Register
   HardFaultRegs.bfsr.byte     = SCB_BFSR;   // Bus Fault Status Register
   HardFaultRegs.bfar          = SCB_BFAR;   // Bus Fault Manage Address Register
   HardFaultRegs.ufsr.halfword = SCB_UFSR;   // Usage Fault Status Register
   HardFaultRegs.hfsr.word     = SCB_HFSR;   // Hard Fault Status Register
   HardFaultRegs.dfsr.word     = SCB_DFSR;   // Debug Fault Status Register
   HardFaultRegs.afsr          = SCB_AFSR;   // Auxiliary Fault Status Register
   //
   // Halt execution
   // If NVIC registers indicate readable memory, change the variable value to != 0 to continue execution.
   //
   _Continue = 0u;
   while (_Continue == 0u) {
   }
   //
   // Read saved registers from the stack.
   //
   HardFaultRegs.SavedRegs.r0       = pStack[0];  // Register R0
   HardFaultRegs.SavedRegs.r1       = pStack[1];  // Register R1
   HardFaultRegs.SavedRegs.r2       = pStack[2];  // Register R2
   HardFaultRegs.SavedRegs.r3       = pStack[3];  // Register R3
   HardFaultRegs.SavedRegs.r12      = pStack[4];  // Register R12
   HardFaultRegs.SavedRegs.lr       = pStack[5];  // Link register LR
   HardFaultRegs.SavedRegs.pc       = pStack[6];  // Program counter PC
   HardFaultRegs.SavedRegs.psr.word = pStack[7];  // Program status word PSR
   //
   // Halt execution
   // To step out of the HardFaultHandler, change the variable value to != 0.
   //
   _Continue = 0u;
   while (_Continue == 0u) {
   }
 #else
   //
   // If this module is included in a release configuration, simply stay in the HardFault handler
   //
   (void)pStack;
   do {
   } while (1);
 #endif
 }
 
 /*************************** End of file ****************************/

Exception Test Application

/*********************************************************************
 *                    SEGGER Microcontroller GmbH                     *
 *                        The Embedded Experts                        *
 **********************************************************************
 *                                                                    *
 *            (c) 2014 - 2020 SEGGER Microcontroller GmbH             *
 *                                                                    *
 *           www.segger.com     Support: support@segger.com           *
 *                                                                    *
 **********************************************************************
 *                                                                    *
 * All rights reserved.                                               *
 *                                                                    *
 * Redistribution and use in source and binary forms, with or         *
 * without modification, are permitted provided that the following    *
 * conditions are met:                                                *
 *                                                                    *
 * - Redistributions of source code must retain the above copyright   *
 *   notice, this list of conditions and the following disclaimer.    *
 *                                                                    *
 * - Neither the name of SEGGER Microcontroller GmbH                  *
 *   nor the names of its contributors may be used to endorse or      *
 *   promote products derived from this software without specific     *
 *   prior written permission.                                        *
 *                                                                    *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             *
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,        *
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           *
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           *
 * DISCLAIMED.                                                        *
 * IN NO EVENT SHALL SEGGER Microcontroller GmbH BE LIABLE FOR        *
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR           *
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  *
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;    *
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF      *
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT          *
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE  *
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *
 * DAMAGE.                                                            *
 *                                                                    *
 **********************************************************************
 
 -------------------------- END-OF-HEADER -----------------------------
 
 Purpose : Cortex-M Fault Exception test application.
 
 */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include "STM32F4xx.h"
 
 
 #define _USE_DISTINCT_FAULTS    // If defined, enable usage fault, bus fault, and mem manage fault
 #define _NICE_CALL_STACK        // If defined, generate a "useful" call stack to test stack unwinding
 
 
 /*********************************************************************
 *
 *       Local functions, generate fault with nice call stack
 *
 **********************************************************************
 */
 #ifdef _NICE_CALL_STACK
 #include <string.h>
 
 static const char _abLogo[128*32];
 static const char _abIcon[32*32];
 
 #define _NUM_IMAGES 2
 static struct {
   const char* sName;
   int         Width;
   int         Height;
   const char* pData;
 } _aImg[_NUM_IMAGES] = {
   {"Logo.bmp", 128, 32, _abLogo},
   {"Icon.bmp", 32,  32, _abIcon}
 };
 
 /*********************************************************************
 *
 *       _GetPixel()
 *
 *  Function description
 *   Get one pixel within an image.
 */
 static char _GetPixel(const char* pImg, int x, int y, int Width, int Height) {
   return *(pImg +  (y * Width) + x);
 }
 
 /*********************************************************************
 *
 *       _GetImage()
 *
 *  Function description
 *   Find the given image and get its informaiton.
 *
 *  Return value
 *    == NULL: Image not found. Width and height not valid.
 *    != NULL: Pointer to the image data.
 */
 static const char* _GetImage(const char* sName, int* pWidth, int* pHeight) {
   int i;
 
   for (i = 0; i < _NUM_IMAGES; i++) {
     if (strcmp(sName, _aImg[i].sName) == 0) {
       *pWidth   = _aImg[i].Width;
       *pHeight  = _aImg[i].Height;
       return  _aImg[i].pData;
     }
   }
 
   return NULL;
 }
 
 /*********************************************************************
 *
 *       _GetFrameBuf()
 *
 *  Function description
 *   Get the frame buffer and its dimensions.
 */
 static char* _GetFrameBuf(int* pWidth, int* pHeight) {
   
   *pWidth = 1920;
   *pHeight = 1080;
 
   return (char*)0x20000000;
 }
 
 /*********************************************************************
 *
 *       _RenderImage()
 *
 *  Function description
 *   Render an image to be written to the display.
 */
 static void _RenderImage(void) {
   const char* pImg;
   char* pFrameBuf;
   char  Pixel;
   unsigned Width;
   unsigned Height;
   unsigned x;
   unsigned y;
 
   pFrameBuf = _GetFrameBuf(&Width, &Height);
   pImg = _GetImage("logo.bmp", &Width, &Height);
 
   for (y = 0; y < Height; y++) {
     for (x = 0; x < Width; x++) {
       Pixel = _GetPixel(pImg, x, y, Width, Height);
       *pFrameBuf = Pixel;
     }
   }
 }
 #endif
 
 /*********************************************************************
 *
 *       Local functions, Bus faults
 *
 **********************************************************************
 */
 
 /*********************************************************************
 *
 *       _IllegalRead()
 *
 *  Function description
 *   Trigger a bus fault or hard fault by reading from a reserved address.
 *
 *  Additional Information
 *    Bus fault is immediately triggered on the read instruction.
 *    Related NVIC registers on hard fault:
 *      NVIC.HFSR = 0x40000000
 *        FORCED = 1           - bus fault/memory management fault/usage fault escalated to hard fault
 *      NVIC.BFSR = 0x00000082
 *        PRECISERR = 1        - Precise data access violation
 *        BFARVALID = 1        - BFAR is valid
 *      NVIC.BFAR = 0x00100000 - The address read from
 */
 static int _IllegalRead(void) {
   int r;
   volatile unsigned int* p;
 
   p = (unsigned int*)0x00100000;  // 0x00100000-0x07FFFFFF is reserved on STM32F4
   r = *p;
 
   return r;
 }
 
 /*********************************************************************
 *
 *       _IllegalWrite()
 *
 *  Function description
 *   Trigger a bus fault or hard fault by writing to a reserved address.
 *
 *  Additional Information
 *    Bus fault is triggered some instructions after the write instruction.
 *    Related NVIC registers on hard fault:
 *      NVIC.HFSR = 0x40000000
 *        FORCED = 1           - bus fault/memory management fault/usage fault escalated to hard fault
 *      NVIC.BFSR = 0x00000004
 *        IMPRECISERR = 1      - Imprecise data access violation
 *        BFARVALID   = 0      - BFAR not valid
 */
 static int _IllegalWrite(void) {
   int r;
   volatile unsigned int* p;
 
   p = (unsigned int*)0x00100000;  // 0x00100000-0x07FFFFFF is reserved on STM32F4
   *p = 0x00BADA55;
 
   return r;
 }
 
 /*********************************************************************
 *
 *       _IllegalFunc()
 *
 *  Function description
 *   Trigger a bus fault or hard fault by executing at a reserved address.
 *
 *  Additional Information
 *    Bus fault is triggered on execution at the invalid address.
 *    Related NVIC registers on hard fault:
 *      NVIC.HFSR = 0x40000000
 *        FORCED = 1           - bus fault/memory management fault/usage fault escalated to hard fault
 *      NVIC.BFSR = 0x00000001
 *        IBUSERR = 1          - Bus fault on instruction prefetch
 */
 static int _IllegalFunc(void) {
   int r;
   int (*pF)(void);
 
   pF = (int(*)(void))0x00100000;  // 0x00100000-0x07FFFFFF is reserved on STM32F4
   
   r = pF();
 
   return r;
 }
 
 /*********************************************************************
 *
 *       Local functions, Usage Faults
 *
 **********************************************************************
 */
 
 /*********************************************************************
 *
 *       _NoThumbFunc()
 *
 *  Function description
 *   Trigger a usage fault or hard fault by executing an address without thumb bit set.
 *
 *  Additional Information
 *    Usage fault is triggered on execution at the invalid address.
 *    Related NVIC registers on hard fault:
 *      NVIC.HFSR = 0x40000000
 *        FORCED = 1           - bus fault/memory management fault/usage fault escalated to hard fault
 *      NVIC.UFSR = 0x0002
 *        INVSTATE = 1         - Instruction execution with invalid state
 */
 static int _NoThumbFunc(void) {
   int r;
   int (*pF)(void);
 
   pF = (int(*)(void))0x00000000;
   
   r = pF();
 
   return r;
 }
 
 /*********************************************************************
 *
 *       _UndefInst()
 *
 *  Function description
 *   Trigger a usage fault or hard fault by executing an undefined instruction.
 *
 *  Additional Information
 *    Usage fault is triggered on execution at the invalid address.
 *    Related NVIC registers on hard fault:
 *      NVIC.HFSR = 0x40000000
 *        FORCED = 1           - bus fault/memory management fault/usage fault escalated to hard fault
 *      NVIC.UFSR = 0x0001
 *        UNDEFINSTR = 1       - Undefined instruction executed
 */
 static int _UndefInst(void) {
   static const unsigned short _UDF[4] = {0xDEAD, 0xDEAD, 0xDEAD, 0xDEAD};
   int r;
   int (*pF)(void);
 
   pF = (int(*)(void))(((char*)&_UDF) + 1);
   
   r = pF();
 
   return r;
 }
 
 /*********************************************************************
 *
 *       _UnalignedAccess()
 *
 *  Function description
 *   Trigger a usage fault or hard fault by an unaligned word access.
 *
 *  Additional Information
 *    Usage fault is triggered immediately on the read or write instruction.
 *    Related NVIC registers on hard fault:
 *      NVIC.HFSR = 0x40000000
 *        FORCED = 1           - bus fault/memory management fault/usage fault escalated to hard fault
 *      NVIC.UFSR = 0x0100
 *        UNALIGNED = 1        - Unaligned memory access
 */
 static int _UnalignedAccess(void) {
   int r;
   volatile unsigned int* p;
 
   p = (unsigned int*)0x20000002;  // 0x00100000-0x07FFFFFF is reserved on STM32F4
   r = *p;
 
   return r;
 }
 
 /*********************************************************************
 *
 *       _DivideByZero()
 *
 *  Function description
 *   Trigger a usage fault or hard fault by dividing by zero.
 *
 *  Additional Information
 *    Usage fault is triggered immediately on the divide instruction.
 *    Related NVIC registers on hard fault:
 *      NVIC.HFSR = 0x40000000
 *        FORCED = 1           - bus fault/memory management fault/usage fault escalated to hard fault
 *      NVIC.UFSR = 0x0200
 *        DIVBYZERO = 1        - Divide-by-zero fault
 */
 static int _DivideByZero(void) {
   int r;
   volatile unsigned int a;
   volatile unsigned int b;
 
   a = 1;
   b = 0;
   r = a / b;
 
   return r;
 }
 
 /*********************************************************************
 *
 *       Local functions, Hard faults
 *
 **********************************************************************
 */
 
 /*********************************************************************
 *
 *       _IllegalVector()
 *
 *  Function description
 *   Trigger a hard fault by interrupt with illegal vector table.
 *
 *  Additional Information
 *    Related NVIC registers on hard fault:
 *      NVIC.HFSR = 0x00000002
 *        VECTTBL = 1           - Vector table read fault
 */
 static int _IllegalVector(void) {
   int r;
 
   SCB->VTOR = 0x001000000;            // Relocate vector table to illegal address  
   SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; // Trigger PendSV exception to read invalid vector
 
   __ISB();
   __DSB();
 
   return r;
 }
 
 /*********************************************************************
 *
 *       Global functions
 *
 **********************************************************************
 */
 /*********************************************************************
 *
 *       main()
 *
 *  Function description
 *   Application entry point.
 */
 #include <time.h>
 
 void main(void) {
   int r;
   //
   // Enable fault on divide-by-zero and unaligned access
   //
   SCB->CCR   |= SCB_CCR_DIV_0_TRP_Msk
              |  SCB_CCR_UNALIGN_TRP_Msk;
 
 #ifdef _USE_DISTINCT_FAULTS
   //
   // Enable usage fault, bus fault, and mem manage fault
   //
   SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk 
              |  SCB_SHCSR_BUSFAULTENA_Msk
              |  SCB_SHCSR_MEMFAULTENA_Msk; // enable Usage-/Bus-/MPU Fault
 #endif
 
 #ifdef _NICE_CALL_STACK // Generate a "useful" call stack to test stack unwinding
   _RenderImage();
 #endif
   //
   // Un-comment one of the following function calls to test the corresponding fault
   //
   //r = _UndefInst();
   //r = _NoThumbFunc();
   //r = _IllegalFunc();
   //r = _UnalignedAccess();
   //r = _DivideByZero();
   //r = _IllegalWrite();
   //r = _IllegalRead();
   //r = _IllegalVector();
 
   do {
     r++;
   } while (1);
 }
 
 /*************************** End of file ****************************/
  • 13
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瑟寒凌风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值