This article is the second in a series on the new debug features in SOMNIUM DRT. The first one was about the live expression view.
Debugging is difficult, especially when unexpected errors cause the program to behave unpredictably, such as writing to an invalid area of memory or executing an illegal instruction. The ARM architecture includes an exception mechanism to trap such faults. This is a powerful feature but it can be difficult to understand the information available.
SOMNIUM DRT includes features to support debugging embedded systems. One of these is a Fault Diagnosis tool that presents the fault information in a human-readable format. I have written briefly about the Fault Diagnosis view in DRT before. This article goes into a bit more detail about how to make the best use of it.
SOMNIUM DRT is is a set of development tools for ARM Cortex-M based devices such as SMART devices from Atmel, Kinetis and LPC devices from NXP, and STM32 devices from STMicroelectronics. It is fully compatible with industry-standard tools such as the GNU toolchain and Eclipse IDE. DRT uses our patented techniques to produce highly optimized code by exploiting information about the embedded processor, the memory system and other peripherals to deliver improved performance, lower code size and reduced energy use.
ARM processors raise an exception when a fault occurs. If the exception handler triggers a breakpoint, then you can use this when debugging to find errors in the program. In a live system, the exception handler could attempt to correct for the cause of the error and then restart execution.
There are four types of faults that are detected by Cortex-M3 and Cortex-M4 processors. These trap errors such as illegal memory accesses or attempting to execute non-existent instructions.
- Bus Fault: An error during instruction fetch or data read/write. The amount of information available about the fault depends on whether the fault is "precise" or "imprecise". Precise bus faults are caused by the last instruction to execute. For example, data read faults are precise because the instruction cannot complete until the data has been read. In this case more detail about the instruction that caused the fault will be displayed. Imprecise bus faults are caused by an instruction that completed several cycles earlier and so the exact instruction that caused the problem is no longer known.
- Memory Management Fault: For example, attempting to execute an instruction from a non-executable area of memory.
- Usage Fault: An exception that occurs because of a fault related to instruction execution such as attempting to execute and undefined instruction.
- Hard Fault: A hard fault is normally caused by one of the other types of fault occurring when the appropriate fault handler cannot be executed for some reason. In this case, the Fault Diagnosis view will display the original cause of the fault, when possible.
In the case of the Cortex-M0 processor, only hard faults are available.
To make best use of
the Fault Diagnosis view, you should make sure that your program is
set up to catch any faults when they occur. There are two steps to
1. Enable all
relevant fault handlers
2. Add a breakpoint to the fault handler(s) to stop execution immediately
There are various
ways to ensure a breakpoint occurs when a fault handler is triggered.
Perhaps the simplest, for occasional use, is to add a breakpoint to
the default exception handler code. This is defined in the file
A more flexible
approach is to define your own exception handler. For example:
void __attribute__((naked)) HardFault_Handler(void)
The names of the
other fault handlers are:
Using this approach allows you to quickly see what type of error
occurred. You can also use this as the basis for a more complete
exception handler that attempts to continue execution after the
The next step is to
enable all the necessary fault handlers.
Note that only the
hard-fault handler is enabled by default. Also, fault handling is not
enabled by default for for unaligned memory accesses and divide by
zero errors, Therefore you should make sure that the exception
handlers and fault types you need are enabled. To enable exception
handlers for all the above, you can add the following code where you
do most of your initialization (for example, at the start of the
// Enable all exception handlers
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk
// Enable divide by zero and unaligned access faults
SCB->CCR |= SCB_CCR_DIV_0_TRP_Msk
The hardware records
information about the cause of the fault in various system registers.
Different levels of detail are available depending on the
architecture and the type of the fault.
The DRT Fault
Diagnosis tool will automatically extract this information, decode it
and display it in a readable form, relating it to the program source
code (when possible). This is much easier than looking at register
values, decoding bit-fields and referring to the ARM architecture
The Fault Diagnosis view will display the source of the error (including the file name and line number, when available). You can display the source or the disassembly view of the code that caused the error, and see the values of the main registers when the error occurred.
For more information
on the information displayed, see the DRT Reference Manual.
A free trial of DRT
is available. DRT is able to automatically import projects from other
development tools, making it simple to migrate your projects to DRT
so you can quickly see the benefits for yourself. Download your free
trial today and try out these powerful debug features for yourself.