The purpose of this Technical Note is to show how HardFault errors can be debugged using IAR Embedded Workbench for ARM.
HardFault refers to all classes of faults that cannot be handled by any of the other exception mechanisms. Typically, HardFault is used for unrecoverable system failures.
Different fault scenarios are described in the examples below.
In this example, the CPU clock on a Cortex-M3 board has been set to a very high frequency. This leads to HardFault exceptions at "random" places, at instructions that are normally valid.
In the Call Stack window, you can see which line of code that was executed when the HardFault occurred.
In the Register window, the NVIC:CFSR (Configurable Fault Status Register) shows that an imprecise data access error has occurred. (BusFault Status Register, BFSR). IMPRECISERR = 1 = Imprecise data access error has occurred.
Because the error is imprecise, it is not possible to see the address of the offending data access. In this specific case, it is very difficult to find the actual reason for the problem, because it has to do with a CPU running at an incorrect frequency. See the screenshot below:
This example shows how to catch division by zero errors, by enabling the DIV_0_TRP bit in the CCR register. In the Call Stack window, you can see the source code line where the invalid division occurred. Looking at the Register window, you can see that the NVIC:CFSR flag DIVBYZERO is set. See the screenshot below:
In this example, invalid memory is accessed. In the Call Stack window, you can see where the illegal access was made. In the Register window, the NVIC:CFSR flags show a PRECISERR. A precise data access error has occurred, and the processor has written the erroneous address to the BFAR register. See the screenshots below:
In this example, an invalid function pointer is called. In the Register window, the NVIC:CFSR flags show: UNDEFINSTR = 1. The processor has attempted to execute an undefined instruction.
In the Call Stack window, you can see from where the illegal instruction was called.
There are several ways to continue:
1. Set a breakpoint on the illegal instruction, and run your application again. When you get to the breakpoint, use the Call Stack window to find the calling function.
2. In the Register window, look at the CPU:LR register to find where the previous call was made. Use the address from the LR register in the Disassembly window, and "Go to" that address. This is where the previous call was made. See the screenshots below:
To make it easier to identify exactly which type of HardFault your application has encountered, there is a debugger macro available in recent versions of IAR Embedded Workbench for ARM. The macro file is located in the installation directory:
Choose to load the macro. When a HardFault is triggered, the macro will produce useful output in the Debug Log window. See the screenshot below:
The information in the Register window might look different from the screenshots above, depending on what type of Cortex-M device you are using. Cortex-M0 devices also do not have all the fault status registers available on larger Cortex-M devices.
If you have complex code in the fault handlers, it might be a good idea to set a breakpoint early in the handler, so that registers and buffers do not lose any vital information when the execution continues. By setting a breakpoint early, execution will stop immediately when the fault handler is called.
The above information does not cover how to use Trace to debug the problem. See our articles on Trace in the Resources section on www.iar.com.
You can debug a HardFault using several methods and windows in IAR Embedded Workbench for ARM. To make it easier to find the reason for a HardFault, there is also a debugger macro file available. For more information about faults, see the chapter "Fault types" in the "Cortex-M3 Devices Generic User Guide".
All product names are trademarks or registered trademarks of their respective owners.