nRF5 SDK v15.2.0
HardFault handling library

The HardFault handling library provides basic HardFault processing. The library can be used as is for default HardFault handling, or it can be extended to provide custom HardFault processing.

Some SDK examples contain a HardFault_Handler function similar to the following code snippet:

void HardFault_Handler(void)
{
while (1)
{
// Should not happen
}
}

This kind of code can be useful in development, but it should never be used in production. The problem with this code is the assumption that this HardFault should never happen; it might happen because of a code error, electromagnetic interference (EMI) near the device, or glitches on power lines. In this case, the microcontroller will hang in an endless loop until the next reset, unless a watchdog is used in the code.

To avoid such error-prone code, this library implements a minimalistic HardFault handling that can be used in released code. When compiled with the DEBUG_NRF flag set, the library places a software breakpoint inside the HardFault_Handler code and adds functionality that helps to determine the problem that causes the HardFault exception.

Using the library

After including the HardFault handling library in the project, a new HardFault call stack is implemented according to the following picture:

hardfault_callstack.svg
HardFault call stack implemented in the library

In most applications, it is sufficient to use the default HardFault_process function that is implemented in the library. This function restarts the whole application using the NVIC_SystemReset function.

If the application requires more security, you can implement your own HardFault_process function and, for example, try to recover from HardFault exceptions or log these events.

If the DEBUG_NRF flag is defined for the preprocessor, a software breakpoint is set in HardFault_c_handler just before calling HardFault_process.

Stack pointer

The HardFault_Handler function processes the stack pointer at the time the HardFault exception occurs and passes it to the other functions.

Processing differs depending on the stack that was used at the time the HardFault exception was generated.

Process stack

If the HardFault exception occurs when the process stack is used, the address of the last data that was pushed is passed directly to the HardFault_c_Handler function.

The address is then cast to a stack pointer (HardFault_stack_t). This type is a structure that represents the expected stack frame, which should help to debug the reason of the exception.

If no DEBUG_NRF flag is defined, this stack pointer is directly passed to the HardFault_process function. If the DEBUG_NRF flag is defined, the stack pointer is written to a global, volatile variable named HardFault_p_stack. In this way, the HardFault frame can be checked in the debugger independently of the selected compilation optimization.

Main stack

If the HardFault exception occurs when the main stack is selected, processing is more complicated.

The main stack is used during the HardFault exception processing, and in some specific cases, a HardFault exception might be generated because of a stack overrun. If such a stack overrun occurs when HardFault_c_handler is executed, another HardFault exception might be generated.

To avoid such situations, the stack pointer value is validated if the main stack was selected when the HardFault exception was generated. During validation, the library checks if the pointer points inside the defined stack area. If the pointer value is invalid, the stack pointer for the exception processing is set back to the default value.

If such a situation occurs, the value passed to the HardFault_process function as stack pointer argument is NULL.


Documentation feedback | Developer Zone | Subscribe | Updated