Cortex-M Fault

From SEGGER Wiki
Jump to: navigation, search
Ozone Fault Analysis

Cortex-M CPUs raise an exception on a fault in the system. Illegal memory writes and reads, access to unpowered peripherals, execution of invalid instructions, division by zero, and other issues can cause such exceptions. Usually in all cases a HardFault exception is raised. For certain faults a different exception can be enabled to specifically handle these cases.

Cortex-M Fault Exceptions

Cortex-M processors implement different fault exceptions.

HardFault Exception

The HardFault is the default exception, raised on any error which is not associated with another (enabled) exception.

The HardFault has a fixed priority of -1, i.e. it has a higher priority than all other interrupts and exceptions except for NMI. Therefore a HardFault exception handler can always be entered when an error happens in application code, an interrupt, or another exception. The HardFault is exception number 3 in the vector table with IRQ number -13.

MemManage Exception

The MemManage exception is available with the use of a Memory Protection Unit (MPU) to raise an exception on memory access violations.

The MemManage is exception number 4 in the vector table, IRQ Number -12, and has a configurable priority.

BusFault Exception

The BusFault exception is raised on any memory access error. E.g. by illegal read, write, or vector catch.

The BusFault is exception number 5 in the vector table, IRQ number -11, and has configurable priority. BusFaults can explicitly be enabled in the system control block (SCB). When BusFault is not enabled, a HardFault is raised.

UsageFault Exception

The UsageFault exception is raised on execution errors. Unaligned access on load/store multiple instructions are always caught. Exceptions on other unaligned access, as well as division by zero can be additionally enabled in the SCB.

The UsageFault is exception number 6 in the vector table, IRQ number -10, and has configurable priority. When UsageFault is not enabled, a HardFault is raised instead.

Exception Handling

On any exception the exception handler as read from the vector table is called, just like on interrupts. Exception handling is usually done differently during development and in production firmware.

Exception Handling during Development

During development of a firmware, errors can happen. Developers usually want to analyze what went wrong to resolve the error.

The Cortex-M NVIC provides various registers to analyze the reason of a crash. Additionally, in most cases the call stack and the register contents of where the crash happened can be restored.

A debugger can provide special features to help with the analysis. In this case, no special exception handler needs to be added to the code. The debugger simply breaks on a vector catch or breakpoint and does the analysis.

Without the help of a debugger, the exception handler can contain development code to gather the required information, to easily make them available in a debugger. The SEGGER HardFault Handler listed below reads the corresponding fault registers and makes them easily available in a struct.

Exception Handling in productive Firmware

Exceptions might also occur in release firmwares and should be caught.

Some exceptions might not be caused by an error. For example executing a BKPT instruction when no debugger is connected causes a HardFault. From these exceptions, the firmware can simply return and continue program execution.

The system might also want to recover from certain cases which are errors, but not a crash. In the exception handler the error reason can be analyzed and recover the system from the error, for example by terminating the task which caused the error.

In the case of a crash, the system can recover by simply resetting it. In more advanced scenarios, a crash dump could be generated before the reset, to be sent or saved on reboot.

Exception Analysis

The system state that led to an exception can be analyzed with the HardFault Handler described above. Additionally some debuggers, such as Ozone provide special features to simplify the analysis.

When Ozone detects that the target system has crashed, it automatically analyzes the target state and provides all necessary information. The Exception Window displays the reason for the crash along with where it happened and the additional NVIC registers. The Call Stack Window can also unwind from an exception to enable easy navigation to the location of error, even across multiple exceptions.

For more information refer to Analyzing Cortex-M Faults with Ozone

Fault Status Registers

The Cortex-M System Control Block (SCB) contains some registers which enable configuration of exceptions and provide information about faults.

HardFault Status Register (HFSR)

The HFSR is in the SCB at address 0xE000ED2C. It is a 32-bit register.

Bitfields:

[31] DEBUGEVT - Reserved for use by debugger/debug probe. Always write 0.
[30] FORCED   - If 1, HardFault has been caused by escalation of another exception, because it is disabled or because of priority.
[1]  VECTTBL  - If 1, a BusFault occurred by reading the vector table for exception processing.

UsageFault Status Register (UFSR)

The UFSR is a 16-bit pseudo-register, part of the Configurable Fault Status Register (CFSR) at address 0xE000ED28. It can also be directly accessed with halfword access to 0xE000ED2A.

Bitfields:

[9] DIVBYZERO  - If 1, SDIV or UDIV instruction executed with divisor 0.
[8] UNALIGNED  - If 1, LDM, STM, LDRD, STRD on unaligned address executed, or single load or store executed when enabled to trap.
[3] NOCP       - If 1, access to unsupported (e.g. not available or not enabled) coprocessor.
[2] INVPC      - If 1, illegal or invalid EXC_RETURN value load to PC.
[1] INVSTATE   - If 1, execution in invalid state. E.g. Thumb bit not set in EPSR, or invalid IT state in EPSR.
[0] UNDEFINSTR - If 1, execution of undefined instruction.

BusFault Status Register (BFSR) and BusFault Address Register (BFAR)

The BFSR is a 8-bit pseudo-register in the CFSR. It can be directly accessed with byte access ad 0xE000ED29. The BFAR is a 32-bit register at 0xE000ED38.

Bitfields:

[7] BFARVALID   - If 1, the BFAR contains the address which caused the BusFault.
[5] LSPERR      - 1f 1, fault during floating-point lazy stack preservation.
[4] STKERR      - If 1, fault on stacking for exception entry.
[3] UNSTKERR    - If 1, fault on unstacking on exception return.
[2] IMPRECISERR - If 1, return address is not related to fault, e.g. fault caused before.
[1] PRECISERR   - If 1, return address instruction caused the fault.
[0] IBUSERR     - If 1, fault on instruction fetch.

MemManage Fault Status Register (MMFSR) and MemManage fault Address Register (MMFAR)

The MMFSR is a 8-bit pseudo-register in the CFSR. It can be directly accessed with byte access ad 0xE000ED28. The MMFAR is a 32-bit register at 0xE000ED34.

Bitfields:

[7] MMARVALID - If 1, the MMFAR contains the address which caused the MemManageFault.
[5] MLSPERR   - 1f 1, fault during floating-point lazy stack preservation.
[4] MSTKERR   - If 1, fault on stacking for exception entry.
[3] MUNSTKERR - If 1, fault on unstacking on exception return.
[1] DACCVIOL  - If 1, data access violation.
[0] IACCVIOL  - If 1, instruction access violation.

Stack Recovery

On exception entry, the exception handler can check which stack has been used when the fault happened. When bit EXC_RETURN[2] is set, MSP has been used, otherwise PSP has been used.

The stack can be used to recover the CPU register values.

CPU Register Recovery

On exception entry, some CPU registers are stored on the stack and can be read from there for error analysis. the following registers are recoverable:

 r0       = pStack[0];  // Register R0
 r1       = pStack[1];  // Register R1
 r2       = pStack[2];  // Register R2
 r3       = pStack[3];  // Register R3
 r12      = pStack[4];  // Register R12
 lr       = pStack[5];  // Link register LR
 pc       = pStack[6];  // Program counter PC
 psr.byte = pStack[7];  // Program status word PSR

Example Fault Analysis

The following examples show how/why some faults can be caused, and how to analyze them. A project to test the faults is available here.

BusFault Examples

Illegal Memory Write

/*********************************************************************
*
*       _IllegalWrite()
*
*  Function description
*   Trigger a BusFault or HardFault by writing to a reserved address.
*
*  Additional Information
*    BusFault is raised some instructions after the write instruction.
*    Related registers on fault:
*      HFSR = 0x40000000
*        FORCED = 1           - BusFault escalated to HardFault (when BusFault is not activated)
*      BFSR = 0x00000004
*        IMPRECISERR = 1      - Imprecise data access violation. Return address not related to fault
*        BFARVALID   = 0      - BFAR not valid
*/
static int _IllegalWrite(void) {
  int r;
  volatile unsigned int* p;

  r = 0;
  p = (unsigned int*)0x00100000;       // 0x00100000-0x07FFFFFF is reserved on STM32F4
  //  F44F1380    mov.w r3, #0x00100000
  *p = 0x00BADA55;
  //  4A03        ldr r2, =0x00BADA55
  //  601A        str r2, [r3]         <- Illegal write is done here
  return r;
  //  9B00        ldr r3, [sp]
  //  4618        mov r0, r3
  //  B002        add sp, sp, #8       <- Fault might be raised here 
  //  4770        bx lr
}

Illegal Memory Read

/*********************************************************************
*
*       _IllegalRead()
*
*  Function description
*   Trigger a BusFault or HardFault by reading from a reserved address.
*
*  Additional Information
*    BusFault is immediately triggered on the read instruction.
*    Related registers on fault:
*      HFSR = 0x40000000
*        FORCED = 1           - BusFault escalated to HardFault
*      BFSR = 0x00000082
*        PRECISERR = 1        - Precise data access violation
*        BFARVALID = 1        - BFAR is valid
*      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
  //  F44F1380    mov.w r3, #0x00100000 <- The read address. Will be found in BFAR
  r = *p;
  //  681B        ldr r3, [r3]          <- Illegal read happens here and raises BusFault
  //  9300        str r3, [sp]

  return r;
}

Illegal Function Execution

/*********************************************************************
*
*       _IllegalFunc()
*
*  Function description
*   Trigger a BusFault or HardFault by executing at a reserved address.
*
*  Additional Information
*    BusFault is triggered on execution at the invalid address.
*    Related registers on fault:
*      HFSR = 0x40000000
*        FORCED = 1           - BusFault escalated to HardFault
*      BFSR = 0x00000001
*        IBUSERR = 1          - BusFault on instruction prefetch
*/
static int _IllegalFunc(void) {
  int r;
  int (*pF)(void);

  pF = (int(*)(void))0x00100001;         // 0x00100000-0x07FFFFFF is reserved on STM32F4
  //  F44F1380    mov.w r3, #0x00100001
  r = pF();
  //  4798        blx r3                 <- Branch to illegal address, causes fetch from 0x00100000 and fault exception
  return r;
}

UsageFault Examples

Undefined Instruction Execution

/*********************************************************************
*
*       _UndefInst()
*
*  Function description
*   Trigger a UsageFault or HardFault by executing an undefined instruction.
*
*  Additional Information
*    UsageFault is triggered on execution at the invalid address.
*    Related registers on hard fault:
*      HFSR = 0x40000000
*        FORCED = 1           - UsageFault escalated to HardFault
*      UFSR = 0x0001
*        UNDEFINSTR = 1       - Undefined instruction executed
*/
static int _UndefInst(void) {
  static const unsigned short _UDF[4] = {0xDEAD, 0xDEAD, 0xDEAD, 0xDEAD}; // 0xDEAD: UDF #<imm> (permanently undefined)
  int r;
  int (*pF)(void);

  pF = (int(*)(void))(((char*)&_UDF) + 1);
  //  4B05        ldr r3, =0x08001C18 <_UDF> <- Load address of "RAM Code" instructions
  //  3301        adds r3, #1                <- Make sure Thumb bit is set
  r = pF();
  //  4798        blx r3                     <- Call "RAM Code", will execute UDF instruction and raise exception
  //  9000        str r0, [sp]
  return r;
}

Illegal State

/*********************************************************************
*
*       _NoThumbFunc()
*
*  Function description
*   Trigger a UsageFault or HardFault by executing an address without thumb bit set.
*
*  Additional Information
*    UsageFault is triggered on execution at the invalid address.
*    Related registers on hard fault:
*      HFSR = 0x40000000
*        FORCED = 1           - UsageFault escalated to HardFault
*      UFSR = 0x0002
*        INVSTATE = 1         - Instruction execution with invalid state
*/
static int _NoThumbFunc(void) {
  int r;
  int (*pF)(void);

  pF = (int(*)(void))0x00100000;         // 0x00100000-0x07FFFFFF is reserved on STM32F4
  //  F44F1380    mov.w r3, #0x00100000  <- Note that bit [0] is not set.
  r = pF();
  //  4798        blx r3                 <- Branch exchange with mode change to ARM, but Cortex-M only supports Thumb mode.
  return r;
}

Division By Zero

/*********************************************************************
*
*       _DivideByZero()
*
*  Function description
*   Trigger a UsageFault or HardFault by dividing by zero.
*
*  Additional Information
*    UsageFault is triggered immediately on the divide instruction.
*    Related registers on hard fault:
*      HFSR = 0x40000000
*        FORCED = 1           - UsageFault escalated to HardFault
*      UFSR = 0x0200
*        DIVBYZERO = 1        - Divide-by-zero fault
*/
static int _DivideByZero(void) {
  int r;
  volatile unsigned int a;
  volatile unsigned int b;
  a = 1;
  //  2301        movs r3, #1       <- Load dividend
  b = 0;
  //  2300        movs r3, #0       <- Load divisor
  r = a / b;
  //  FBB2F3F3    udiv r3, r2, r3   <- divide by 0 raises fault exception
  return r;
}

Unaligned Access

/*********************************************************************
*
*       _UnalignedAccess()
*
*  Function description
*   Trigger a UsageFault or HardFault by an unaligned word access.
*
*  Additional Information
*    UsageFault is triggered immediately on the read or write instruction.
*    Related registers on fault:
*      HFSR = 0x40000000
*        FORCED = 1           - UsageFault escalated to HardFault
*      UFSR = 0x0100
*        UNALIGNED = 1        - Unaligned memory access
*/
static int _UnalignedAccess(void) {
  int r;
  volatile unsigned int* p;

  p = (unsigned int*)0x20000002;
  //  4B04        ldr r3, =0x20000002  <- Not word aligned address
  r = *p;
  //  681B        ldr r3, [r3]         <- Load word from unaligned address raises exception
  //  9300        str r3, [sp]
  return r;
}

HardFault Examples

Illegal Vector Table Fetch

/*********************************************************************
*
*       _IllegalVector()
*
*  Function description
*   Trigger a HardFault by interrupt with illegal vector table.
*
*  Additional Information
*    Related registers on fault:
*      HFSR = 0x00000002
*        VECTTBL = 1           - Vector table read fault
*/
static int _IllegalVector(void) {
  int r;

  SCB->VTOR = 0x001000000;            // Relocate vector table to illegal address  
  //  4B09        ldr r3, =0xE000ED00
  //  F04F7280    mov.w r2, #0x1000000
  //  609A        str r2, [r3, #8]
  SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; // Trigger PendSV exception to read invalid vector
  //  4B07        ldr r3, =0xE000ED00
  //  F04F5280    mov.w r2, #0x10000000
  //  605A        str r2, [r3, #4]
  __ISB();
  //  F3BF8F6F    isb                 <- PendSV exception is to be executed. PendSV vector is tried to be read from illegal address 0x00100038 causes fault exception
  //  BF00        nop
  __DSB();
  //  F3BF8F4F    dsb sy
  //  BF00        nop
  return r;
}

File Listings

SEGGER HardFault Handler

 ;/*********************************************************************
 ;*
 ;*      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 ****************************/