The hard fault status register (HFSR) in ARM processors is used to provide information about the cause of a hard fault exception. A hard fault occurs when the processor encounters an unexpected event or illegal operation that it cannot handle gracefully. The HFSR allows software to examine the state of the processor at the time of the fault to help determine the root cause.
Overview of the Hard Fault Status Register
The HFSR is a 32-bit register that is accessed through the system control block. It contains a number of bit fields that categorize the type of fault that occurred:
- VECTTBL: Indicates a BusFault was triggered by a vector table read on exception entry
- FORCED: Indicates a forced hard fault was triggered by the processor itself
- DEBUGEVT: Indicates the fault was triggered by a debug event
- reserved: Bits reserved for future use
- VECTBL: Indicates a MemManage fault occurred on a table walk or table access
- BFARVALID: Indicates the bus fault address register contains a valid fault address
- UNDEFINSTR: Indicates an undefined instruction was attempted to be executed
- INVSTATE: Indicates an instruction was attempted with an illegal EPSR or SPDR state
- INVPC: Indicates an exception return integrity check failed
- NOCP: Indicates a coprocessor instruction was attempted without a coprocessor present
- STKERR: Indicates a derived bus fault has occurred on exception entry
- UNSTKERR: Indicates a derived bus fault has occurred on exception return
- IMPRECISERR: Indicates a imprecise data access error has occurred
- PRECISERR: Indicates a precise data access error has occurred
- IBUSERR: Indicates an instruction bus error has occurred
By examining these flag bits, the fault handler can quickly categorize the type of fault and determine the appropriate recovery strategy. The valid fault address contained in the BFARVALID field can also be used to identify the instruction or data access that caused a bus fault.
Hard Fault Status Register in Cortex-M Devices
In ARM Cortex-M series microcontrollers, the HFSR is implemented as described in the ARMv7-M architecture reference manual. In addition to the bit fields described above, there are some differences compared to the HFSR in ARM application processors:
- The FORCED bit is not implemented in Cortex-M as there is no concept of “forced” hard faults.
- The DEBUGEVT bit is used to indicate faults triggered during debug exception entry or return.
- The STKERR and UNSTKERR bits indicate stack overflows on exception entry and return.
- The BFARVALID bit indicates the MMFAR register contains a valid fault address, not the BFAR used in application processors.
So in summary, while the overall purpose of the HFSR is similar across ARM devices, the exact implementation differs slightly between application processors and Cortex-M microcontrollers.
Reading the HFSR
To read the HFSR, software simply needs to access the register at the memory mapped location 0xE000ED2C within the system control block. For example: // Read HFSR uint32_t hfsr = SCB->HFSR;
This reads the value directly from the register into a variable that can then be analyzed. Individual bit fields can be examined by masking and shifting. For example, to check the precise data access error bit: if (hfsr & (1<<26)) { // Precise data access error occurred }
Clearing the HFSR
Typically the HFSR will be cleared at the start of the hard fault exception handler prior to reading it, in order to ensure the values reflect the state when the exception was first entered and not any subsequent operations. This is done by writing 1 to the bit position to clear it: SCB->HFSR |= (1<<30); // Clear the HFSR
Then the HFSR can be read and analyzed without worrying the flags have changed since the initial exception entry.
Using the HFSR in Fault Handlers
Typical usage of the HFSR in a hard fault handler involves:
- Clearing the HFSR on exception entry
- Reading the HFSR into a variable
- Examining the bit fields to categorize the fault type
- Performing appropriate fault recovery actions
- Clearing managed fault status bits before exit
For example: void HardFault_Handler(void) { // Clear HFSR SCB->HFSR |= (1<<30); // Read HFSR uint32_t hfsr = SCB->HFSR; // Check fault type flags if (hfsr & (1<<30)) { // Handle bus fault } else if (hfsr & (1<<25)) { // Handle undefined instruction } else { // Handle other fault } // Clear serviced faults SCB->HFSR |= (1<<1); }
This allows the fault handler to quickly determine the cause of the fault based on the HFSR flags and handle it appropriately. The BFARVALID bit can also be checked to see if a precise bus fault address is available in the BFAR or MMFAR register on Cortex-M.
Role of the HFSR in Debugging
The HFSR plays an important role during debugging and post-mortem analysis of crashes or unexpected exceptions. By examining the register contents, the exact cause of a hard fault can potentially be identified to fix software issues. Some examples include:
- An undefined instruction fault could indicate unauthorized memory access or use of unsupported instructions
- A bus fault during exception processing could indicate stack corruption
- A data access bus fault may be caused by illegal memory access outside RAM boundaries
- Precise data bus faults allow identification of the crashing instruction and data address
Saving the HFSR contents along with the stack frame and processor context in non-volatile memory on faults can provide invaluable data for post-mortem crash analysis. The HFSR combined with other ARM fault status registers give a comprehensive view of the exception state.
Configuring Fault Behavior
On Cortex-M devices, additional fault status registers are available to provide more granular fault information. The Configuration and Control Register (CCR) is used to enable/disable reporting of additional fault conditions in these registers. For example, to enable more bus and usage faults to be reported: SCB->CCR |= SCB_CCR_BFHFNMIGN_Msk | SCB_CCR_DIV_0_TRP_Msk;
Consult the reference manual for the exact processor implementation for details of available CCR configuration options. This can provide more diagnostic data for specific fault conditions.
Limitations of the Hard Fault Status Register
While the HFSR provides useful information on the nature of a fault, there are some limitations:
- Only a single fault status is recorded, multiple simultaneous faults are not detected.
- Not all fault conditions are recorded, priority is given to the highest urgent fault.
- Only provides categorization of the fault type, further debugging may be needed to determine root cause.
- Precise bus fault addresses are not available on all processor variants.
Additional care may be needed during code development and debugging to help uncover the true root cause of unexplained hard faults. Enabling debug features like code breakpoints can help in stepping through handling of a specific fault case.
Conclusion
The hard fault status register is a key component in ARM’s fault exception handling mechanism. By categorizing the type of fault, the HFSR allows software to respond appropriately to handle or recover from fault events. The information it provides is useful for both real-time exception handling and post-mortem debugging of crashes. Proper usage of the HFSR and related fault registers is essential for developing robust and reliable software on ARM platforms.