mirror of
https://github.com/QuantumLeaps/qpcpp.git
synced 2025-02-04 06:13:00 +08:00
269 lines
12 KiB
C
269 lines
12 KiB
C
/*********************************************************************
|
|
* SEGGER Microcontroller GmbH & Co. KG *
|
|
* The Embedded Experts *
|
|
**********************************************************************
|
|
* *
|
|
* (c) 1995 - 2017 SEGGER Microcontroller GmbH & Co. KG *
|
|
* *
|
|
* Internet: segger.com Support: support_embos@segger.com *
|
|
* *
|
|
**********************************************************************
|
|
* *
|
|
* embOS * Real time operating system for microcontrollers *
|
|
* *
|
|
* Please note: *
|
|
* *
|
|
* Knowledge of this file may under no circumstances *
|
|
* be used to write a similar product or a real-time *
|
|
* operating system for in-house use. *
|
|
* *
|
|
* Thank you for your fairness ! *
|
|
* *
|
|
**********************************************************************
|
|
* *
|
|
* OS version: 4.34.1 *
|
|
* *
|
|
**********************************************************************
|
|
|
|
----------------------------------------------------------------------
|
|
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 lits an error LED.
|
|
-------- END-OF-HEADER ---------------------------------------------
|
|
*/
|
|
|
|
#include "RTOS.h"
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Defines
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
#define SYSHND_CTRL (*(volatile unsigned int*) (0xE000ED24u)) // System Handler Control and State Register
|
|
#define NVIC_MFSR (*(volatile unsigned char*) (0xE000ED28u)) // Memory Management Fault Status Register
|
|
#define NVIC_BFSR (*(volatile unsigned char*) (0xE000ED29u)) // Bus Fault Status Register
|
|
#define NVIC_UFSR (*(volatile unsigned short*)(0xE000ED2Au)) // Usage Fault Status Register
|
|
#define NVIC_HFSR (*(volatile unsigned int*) (0xE000ED2Cu)) // Hard Fault Status Register
|
|
#define NVIC_DFSR (*(volatile unsigned int*) (0xE000ED30u)) // Debug Fault Status Register
|
|
#define NVIC_BFAR (*(volatile unsigned int*) (0xE000ED38u)) // Bus Fault Manage Address Register
|
|
#define NVIC_AFSR (*(volatile unsigned int*) (0xE000ED3Cu)) // Auxiliary Fault Status Register
|
|
|
|
#ifndef OS_DEBUG // Should be overwritten by project settings
|
|
#define OS_DEBUG (0) // in debug builds
|
|
#endif
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Prototypes
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
void HardFaultHandler(unsigned int* pStack);
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Static data
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
#if OS_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 byte;
|
|
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 byte;
|
|
struct {
|
|
unsigned int MEMFAULTACT : 1; // Read as 1 if memory management fault is active
|
|
unsigned int BUSFAULTACT : 1; // Read as 1 if bus fault exception is active
|
|
unsigned int UnusedBits1 : 1;
|
|
unsigned int USGFAULTACT : 1; // Read as 1 if usage fault exception is active
|
|
unsigned int UnusedBits2 : 3;
|
|
unsigned int SVCALLACT : 1; // Read as 1 if SVC exception is active
|
|
unsigned int MONITORACT : 1; // Read as 1 if debug monitor exception is active
|
|
unsigned int UnusedBits3 : 1;
|
|
unsigned int PENDSVACT : 1; // Read as 1 if PendSV exception is active
|
|
unsigned int SYSTICKACT : 1; // Read as 1 if SYSTICK exception is active
|
|
unsigned int USGFAULTPENDED : 1; // Usage fault pended; usage fault started but was replaced by a higher-priority exception
|
|
unsigned int MEMFAULTPENDED : 1; // Memory management fault pended; memory management fault started but was replaced by a higher-priority exception
|
|
unsigned int BUSFAULTPENDED : 1; // Bus fault pended; bus fault handler was started but was replaced by a higher-priority exception
|
|
unsigned int SVCALLPENDED : 1; // SVC pended; SVC was started but was replaced by a higher-priority exception
|
|
unsigned int MEMFAULTENA : 1; // Memory management fault handler enable
|
|
unsigned int BUSFAULTENA : 1; // Bus fault handler enable
|
|
unsigned int USGFAULTENA : 1; // Usage fault handler enable
|
|
} bits;
|
|
} syshndctrl; // System Handler Control and State Register (0xE000ED24)
|
|
|
|
union {
|
|
volatile unsigned char byte;
|
|
struct {
|
|
unsigned char IACCVIOL : 1; // Instruction access violation
|
|
unsigned char DACCVIOL : 1; // Data access violation
|
|
unsigned char UnusedBits : 1;
|
|
unsigned char MUNSTKERR : 1; // Unstacking error
|
|
unsigned char MSTKERR : 1; // Stacking error
|
|
unsigned char UnusedBits2 : 2;
|
|
unsigned char MMARVALID : 1; // Indicates the MMAR is valid
|
|
} bits;
|
|
} mfsr; // Memory Management Fault Status Register (0xE000ED28)
|
|
|
|
union {
|
|
volatile unsigned int byte;
|
|
struct {
|
|
unsigned int IBUSERR : 1; // Instruction access violation
|
|
unsigned int PRECISERR : 1; // Precise data access violation
|
|
unsigned int IMPREISERR : 1; // Imprecise data access violation
|
|
unsigned int UNSTKERR : 1; // Unstacking error
|
|
unsigned int STKERR : 1; // Stacking error
|
|
unsigned int UnusedBits : 2;
|
|
unsigned int BFARVALID : 1; // Indicates BFAR is valid
|
|
} bits;
|
|
} bfsr; // Bus Fault Status Register (0xE000ED29)
|
|
volatile unsigned int bfar; // Bus Fault Manage Address Register (0xE000ED38)
|
|
|
|
union {
|
|
volatile unsigned short byte;
|
|
struct {
|
|
unsigned short UNDEFINSTR : 1; // Attempts to execute an undefined instruction
|
|
unsigned short INVSTATE : 1; // Attempts to switch to an invalid state (e.g., ARM)
|
|
unsigned short INVPC : 1; // Attempts to do an exception with a bad value in the EXC_RETURN number
|
|
unsigned short NOCP : 1; // Attempts to execute a coprocessor instruction
|
|
unsigned short UnusedBits : 4;
|
|
unsigned short UNALIGNED : 1; // Indicates that an unaligned access fault has taken place
|
|
unsigned short DIVBYZERO : 1; // Indicates a divide by zero has taken place (can be set only if DIV_0_TRP is set)
|
|
} bits;
|
|
} ufsr; // Usage Fault Status Register (0xE000ED2A)
|
|
|
|
union {
|
|
volatile unsigned int byte;
|
|
struct {
|
|
unsigned int UnusedBits : 1;
|
|
unsigned int VECTBL : 1; // Indicates hard fault is caused by failed vector fetch
|
|
unsigned int UnusedBits2 : 28;
|
|
unsigned int FORCED : 1; // Indicates hard fault is taken because of bus fault/memory management fault/usage fault
|
|
unsigned int DEBUGEVT : 1; // Indicates hard fault is triggered by debug event
|
|
} bits;
|
|
} hfsr; // Hard Fault Status Register (0xE000ED2C)
|
|
|
|
union {
|
|
volatile unsigned int byte;
|
|
struct {
|
|
unsigned int HALTED : 1; // Halt requested in NVIC
|
|
unsigned int BKPT : 1; // BKPT instruction executed
|
|
unsigned int DWTTRAP : 1; // DWT match occurred
|
|
unsigned int VCATCH : 1; // Vector fetch occurred
|
|
unsigned int EXTERNAL : 1; // EDBGRQ signal asserted
|
|
} 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 (NVIC_HFSR & (1u << 31)) {
|
|
NVIC_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 OS_DEBUG
|
|
//
|
|
// Read NVIC registers
|
|
//
|
|
HardFaultRegs.syshndctrl.byte = SYSHND_CTRL; // System Handler Control and State Register
|
|
HardFaultRegs.mfsr.byte = NVIC_MFSR; // Memory Fault Status Register
|
|
HardFaultRegs.bfsr.byte = NVIC_BFSR; // Bus Fault Status Register
|
|
HardFaultRegs.bfar = NVIC_BFAR; // Bus Fault Manage Address Register
|
|
HardFaultRegs.ufsr.byte = NVIC_UFSR; // Usage Fault Status Register
|
|
HardFaultRegs.hfsr.byte = NVIC_HFSR; // Hard Fault Status Register
|
|
HardFaultRegs.dfsr.byte = NVIC_DFSR; // Debug Fault Status Register
|
|
HardFaultRegs.afsr = NVIC_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.byte = 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 ****************************/
|