The HFSR (HardFault Status Register) is one of the key registers in the ARM Cortex series of processors that provides information about HardFault exceptions. When a HardFault exception occurs, the processor automatically saves information about the exception into the HFSR register. This information is crucial for understanding what caused the HardFault and can help developers debug and fix issues in their code.
In a nutshell, the HFSR register records the source and type of the fault that triggered the HardFault exception. By examining the HFSR, you can determine things like whether the fault was caused by an instruction execution error, a failed bus access, or other system faults. The register contents provide a snapshot of the processor state right when the fault occurred.
Details of the HFSR Register
The HFSR register is generally 30 bits wide but the exact implementation can vary across different ARM Cortex variants. There are some common bitfields however that provide useful information:
- VECTBL – Indicates a BusFault was triggered by a failed vector table read during exception processing. This is bit 1 of the register.
- FORCED – Set to 1 if a forced HardFault was triggered using the software HardFault exception mechanism. Located in bit 30.
- DebugEVT – Indicates a debug event triggered the HardFault. Bit 31.
The next set of bits provide insight into the source of the fault:
- ICFSR – Bits 7-0 – Holds a copy of the fault status flags in the MMFSR register. This identifies one of several possible fault sources like memory management faults, bus errors, usage faults etc.
- MMARVALID – Bit 7 – Indicates the MMAR register has a valid address for the fault.
- MSTKERR – Bit 4 – Set if stacking for an exception entry failed, likely due to a memory fault.
- MUNSTKERR – Bit 3 – Indicates unstacking during exception return failed.
- DACCVIOL – Bit 1 – Data access violation error such as an MPU fault.
- IACCVIOL – Bit 0 – Instruction access violation fault.
The HFSR thus contains layered information – the type of fault, and the sources of the fault down to specific kinds of access violations. This helps greatly when debugging HardFault causes.
When is the HFSR Register Updated?
The processor automatically populates the HFSR when a fault occurs. When a HardFault exception entry is made, the core saves the HFSR contents along with other context state information like register contents and the stack pointer. The faults could be triggered by:
- Execution of an undefined instruction
- Failed memory access instructions
- Reads from invalid memory
- Writes to read-only memory
- Unaligned memory accesses
- Invalid exception returns
- Memory management faults (MPU violations etc.)
In the exception handler, the HFSR contents can be analyzed to determine the type of fault. The other saved context state also provides clues about the instruction and memory access patterns leading up to the fault.
Retrieving the HFSR Contents in Code
To read the HFSR in code, simply read from the memory mapped location of the register. For example: uint32_t hfsr = SCB->HFSR;
This loads the value of the HFSR into the variable ‘hfsr’. The register is generally available in the System Control Block registers under the SCB peripheral memory map.
Once the HFSR is read, application developers can check the bit patterns and flags to determine the cause of the HardFault. Typical steps would be:
- Read the HFSR into a variable
- Check FORCED bit to see if HardFault was triggered manually via software
- Check VECTBL bit to identify vector table issues
- Check DebugEVT bit to see if a debug event caused it
- Analyze ICFSR field combined with MMARVALID to identify the specific fault reason
- Clear HFSR after analysis if desired
Based on the fault reasons, the offending code or memory access can be corrected. The processor state saved on the stack can also be used to determine the prior instruction sequence.
Clearing and Re-Enabling HardFaults
The HFSR contents are not cleared automatically after a HardFault exception is serviced. The fault flags remain set in the register unless explicitly cleared in software. To clear the HFSR: SCB->HFSR = 0xFFFFFFFF;
Writing the value 0xFFFFFFFF will clear all the existing fault flags and information. This would typically be done after the fault causes have been analyzed.
HardFault exceptions are disabled automatically after one occurs. This prevents repeated HardFaults from a persistent issue. To re-enable HardFaults, the FAULTMASK register needs to be cleared: SCB->FAULTMASK = 0;
This will re-enable HardFault exception generation when the next fault event occurs. The FAULTMASK is also used to disable HardFaults preemptively if desired.
Tips for Using HFSR Contents
Here are some tips when working with HFSR register contents:
- Always analyze HFSR first when debugging HardFault causes.
- A debugger can automatically capture HFSR on faults, otherwise retrieve it manually.
- Combine HFSR data with stack contents for better context.
- Clear HFSR after analysis to prevent stale data in later faults.
- Re-enable HardFaults once root cause is fixed via the FAULTMASK register.
- Check for vector table issues and memory faults if HFSR shows no obvious causes.
- MEMFAULTACT in Auxiliary Fault Status Register indicates fault was escalated from a lower level exception.
- HFSR not populated for faults escalated to HardFault via MemManage or BusFault.
- HardFaults are useful for fail-safe handling of lower level faults.
Having a solid understanding of the HFSR register contents and behavior is invaluable for diagnosing those tricky HardFault exceptions that can occur in embedded software on ARM Cortex processors.
Using HFSR Contents for Post-Mortem Crash Analysis
The HFSR contents are enormously helpful for post-mortem analysis of code crashes. When an embedded system crashes and reboots without any debug messages, the HFSR can provide hints about what went wrong. Some techniques include:
- Dump HFSR register contents along with other CPU registers to non-volatile storage on crash.
- Retrieve HFSR and other register dumps in subsequent boots or from external host.
- Static HFSR analysis can identify MemManage faults, bus errors, stack overflows etc.
- Recreate crash scenario in debugger or development environment using register contents.
- Combine multiple HFSR reports from the field to isolate common root causes of crashes.
- Unattended remote devices can send HFSR crash reports to cloud servers for automated analysis.
The HFSR forms a key part of a solid crash reporting and post-mortem analysis framework for embedded systems. It provides a concise indicator of the fault reason without requiring extensive logging.
Typical HFSR Values
Here are some typical example values observed in the HFSR register for common fault scenarios: HardFault due to invalid memory write: HFSR = 0x40000000 HardFault caused by unstacking exception return error: HFSR = 0x200000 HardFault from illegal opcode execution: HFSR = 0x00010000 HardFault due to vector table read error: HFSR = 0x00000002
The bit patterns clearly indicate the source and type of fault – memory access violation, stacking error, illegal instruction, and debug event respectively.
Debugging HardFaults
When debugging HardFault causes, follow these general steps:
- Try to reproduce the HardFault scenario.
- Capture HFSR contents and stack pointers on fault.
- Examine HFSR to shortlist the potential fault reasons.
- Review code to find flawed sequences matching HFSR data.
- Configure MemManage and BusFault debug to get more insight.
- Fix root causes based on analysis.
- Retest code to confirm HardFaults are resolved.
- Perform fuzz testing and stress testing for corner case defects.
HardFaults can often be tricky to fix, but methodically analyzing the HFSR contents can point you in the right direction. The cues in HFSR combined with the exception entry stack frame provide a wealth of hints on what could have gone wrong in the code flow or memory handling.
Toolchain Support
Most ARM compiler toolchains provide some level of support for retrieving and decoding HFSR register contents. For example, ARM Keil MDK has a __get_HFSR() intrinsic to easily read the register. IAR EWARM similarly provides access via intrinsics. Even the GCC ARM embedded toolchains allow direct access to the register using the SCB peripheral memory map.
Debuggers and IDEs for ARM Cortex MCUs also integrate with HFSR registers and often show the contents automatically after a HardFault exception occurs. Popular choices like Segger Ozone, STM32CubeIDE, Keil uVision all surface HFSR information readily when debugging crashes.
Using HFSR for Diagnostics
In some cases, the HFSR can be leveraged manually as a diagnostics or health monitoring register. For example:
- Deliberately trigger a HardFault to set HFSR FORCED bit as an indicator that code reached an expected state.
- Mask HardFaults but monitor HFSR for illegal memory accesses or failed bus operations as cues to memory subsystem health.
- Seed known instruction sequences to generate HardFaults and observe if HFSR matches expected fault reasons.
These types of techniques allow stress testing systems and trapping corner case issues by using HardFaults and the HFSR register in innovative ways beyond just debugging.
HFSR Support in ARM Cores
The HFSR register is supported across the entire range of ARM Cortex processors including:
- Cortex-M0 / M0+
- Cortex-M3
- Cortex-M4
- Cortex-M7
- Cortex-M23
- Cortex-M33
- Cortex-R Series
Any ARM core that implements the full ARMv7-M architecture or later provides HFSR as part of the System Control Block registers. Older ARMv6-M cores have similar fault status registers but not the consolidated HFSR.
This wide compatibility makes the HFSR a useful resource when debugging and analyzing HardFaults across ARM’s Cortex microcontroller families.
Conclusion
In summary, the HardFault Status Register (HFSR) is a key component of ARM’s fault exception mechanisms. It provides a snapshot of the fault reason and type that caused a HardFault exception entry. By examining the HFSR bits and fields, developers can quickly narrow down defects that triggered crashes or memory faults. The register integrates closely with toolchain and IDE features, making HardFault diagnosis seamless. With some innovative thinking, the HFSR can also be leveraged for code diagnostics and health monitoring. Overall, mastering HFSR analysis is an invaluable skill for any embedded developer working with ARM Cortex CPUs.