By Jamie Packer- VP of Customer Engineering
When developing and debugging a program you may find it hits a fault condition such as an illegal memory access or division by zero. These and a number of other software errors are trapped by the ARM Cortex M processor as exceptions. These are handled by the hardware in a similar way to interrupts: the processor saves the current state and jumps (via a table) to an exception handler.
This is great because you know an error has occurred but identifying what caused the fault can be complicated. Relevant information needs to be extracted from a number of different processor registers and memory locations. And then the significance of the various bits in the registers needs to be decoded by reference to the ARM architecture manuals -- this may indicate that further registers or status bits need to examined to narrow down the cause. This process is tedious and error prone. I suspect that at this point a lot of developers give up, which is a shame because a lot of useful information can be obtained from the fault handler.
SOMNIUM DRT includes a tool to detect when a fault occurs, collect and decode the necessary information, and present it in a readable form. This greatly eases the task of debugging a program which hits a fault condition.
This article introduces the way faults are handled in Cortex M processors and the software support in DRT for analysing the cause of the fault.
SOMNIUM DRT Fault Diagnosis Tool
The SOMNIUM DRT Fault Diagnosis Tool collects and analyses information about the cause of a fault when it occurs and presents it in a human-readable way -- this saves digging around in registers and reference manuals to find all the necessary information.
If a fault occurs while your program is running, the Fault Diagnosis tool will display a dialog asking whether you would like to open the fault diagnosis view and see the information about the fault.
The information provided by the SOMNIUM DRT Fault Diagnosis Tool is summarized below:
- Fault type: The generic fault type (for example, bus or usage), fault code and the specific fault type (for example, undefined instruction). The type of fault determines what information is available to help diagnose the problem. For Cortex-M0 cores, all faults cause a Hard Fault and so only limited information is available. In this case the fault diagnosis tool reports the cause as unknown.
- Causes of the fault: A list of possible causes of the fault. If information is provided by the hardware about the specific cause of the fault, then this will be displayed. For example, this could be the instruction and the address that the processor was trying to read or write when a precise bus fault occurred.
- Location of fault: The address, function and source code line (if available) which caused the fault will be displayed.
- Possible solutions: Based on the analysis, the tool will make suggestions for resolving or avoiding the problem.
- Register values: The values of registers on the stack when the fault occurred. If the values of the registers may not be reliable then a message to this effect is displayed.
When certain types of error occur, a fault is triggered and the processor starts executing an exception handler.
The error conditions that can cause a fault are listed in the SOMNIUM DRT Reference Manual. A brief summary of some of the common causes is listed below. Refer to the ARM Cortex-M architecture manuals for more information. However, it is clear that if your program ends up in a fault handler then there is something wrong!
Bus Fault: This indicates an error occurred during instruction fetch, data read/write, stack push/pop in interrupt processing, reading of an interrupt vector address. The amount of information that can be gathered about the fault depends on whether the fault is ìpreciseî (caused by the last instruction to execute) or ìimpreciseî (caused by an unknown instruction executed earlier)
Usage Fault: A fault related to instruction execution. This includes attempting to execute an undefined instruction or division by zero.
Hard Fault: A hard fault can be triggered by a number of conditions, such as the escalation of another fault type because it cannot be handled, or a fault occurring when reading the vector table.
Information about faults
Information about the cause of a fault can be found in the following status registers in the processor:
- Memory management fault status register (MMSR)
- Bus fault status register (BFSR)
- Usage fault status register (UFSR)
- Hard fault status register (HFSR)
- Debug fault status register (DFSR)
- Auxiliary fault status register (AFSR)
Bits in these registers are set depending on the cause of the fault. However, using the debugger to read the contents of these registers and then looking up what they mean in the ARM Technical Reference Guide is time consuming. The SOMNIUM DRT Fault Diagnosis tool automatically collects the relevant information and presents it in a readable way.
Cortex M processors save the current context on the stack when handling an interrupt or exception. When a fault occurs, several registers are pushed on to the stack. This allows the state of the CPU at the time the fault occurred to be analysed by the DRT Fault Diagnosis tool.
- The program counter, PC, indicates which instruction was executing when the fault occurred.
- The general purpose registers, R0 to R3 and R12, and the program status registers, xPSR, provide further information about the instruction being executed when the fault occurred.
- The link register, LR, typically points to the calling function and can be used to reconstruct the call stack.
Debugging fault conditions can be tricky because much of the important state is in several different system registers and memory locations. The SOMNIUM DRT Fault Diagnosis Tool presents all the relevant information, in a way that is easy to understand, allowing you to fix the problem and get on with more productive work.