In this article I will cover how to instrument the application to perform general software tracing on Cortex-M devices (such as STM32, Kinetis, LPC or EFM32) using the Instrumentation Trace Macrocell (ITM), which is part of the Serial Wire Viewer (SWV) real-time tracing module in the ARM CoreSight debugger technology.
Using ITM, the application can “print” arbitrary data to a debugger console using the JTAG probe/cable, thus offering a very useful insight into the internal behavior of a Cortex-M system running at full speed. By reading this article you will learn how to leverage this capability to instrument your application with “trace points” and see what your application does without stopping execution.
My earlier blog posts in this article series has covered an introduction to SWV event- and data tracing, as well as single-channel and multi-channel printf() re-direction using ITM. The two articles on printf() re-direction focused on printing human readable strings to a console view in the debugger. The previous articles all provide a good background leading up to the information shared in this article.
Since the previous articles on ITM focused on how to setup printf() to write human readable strings to a debugger console, this article will focus on using ITM for a more technical, less human readable, purpose. As writing a byte from a Cortex-M application to the debugger console over ITM only uses one write cycle, the performance penalty of introducing multiple ITM writes in the application is negligible. ITM data writes can thus be used for software instrumented trace using ITM writes as “trace points”.
The article on single-channel printf() re-direction outlined how ITM_SendChar() can be used to output a data byte to the debugger using ITM port/channel 0; while the article on multi-channel printf() re-direction outlined how ITM_Out() can be used to output a data byte using any ITM port/channel (out of the possible 0-31).
For example trace points can be inserted into the application by adding code lines like these:
// Send ASCII code 65 = ’A’ to port/channel 0
ITM_SendChar( 65 );
// Send ASCII code 66 = ’B’ to port/channel 7
ITM_Out( 7, 66 );
To build software instrumented tracing using ITM writes as “trace points”, we quite simply perform data byte writes using ITM_SendChar() or ITM_Out() at interesting places in the code. By assigning certain meaning to specific values, software trace points can easily tell the developer what happens, and in what order.
For example, a machine control application might define ITM writes as follows:
‘A‘ – Key press detected: Start auto-mode button
‘B’ – System is ready
‘C’ – Oven temperature is reached
‘D’ – Key press detected: Increase temperature button
‘E’ – Gluing process started
‘F’ – Key press detected: Stop button
When the application is run, this may generate output like this in the debugger SWV Console view (provided the debugger supports this and that SWV/ITM is configured correctly):
By studying the SWV Trace Log view (available in the Atollic TrueSTUDIO C/C++ IDE), it is also possible to see the ITM writes in a more “trace looking” way (the screenshot below use different data compared to the screenshot above):
The SWV Trace Log view in Atollic TrueSTUDIO have the additional benefit of also showing the time stamp of the different ITM writes, thus also presenting the timing of the different trace point events. This can be taken one step further, by utilizing the SWV ITM Timeline Graph view in Atollic TrueSTUDIO, which shows the ITM writes graphically in a real-time graph on a timeline:
By utilizing the Instrumentation Trace Macrocell in Cortex-M devices, it is not only possible to do printf() re-direction to an ITM debugger console, but also to do more advanced types of software tracing using trace trigger events. The real-time performance for this is negligible and instrumentation can typically remain in the shipping products. Many developers would probably benefit from putting this debugging technique into the portfolio of commonly used debugger tricks.
SWV and ITM can normally not be used with standard ECLIPSE and GNU/GDB tools, although commercial high-end tools provide these capabilities.
In our Atollic TrueSTUDIO C/C++ IDE for example, the SWV Console view, the SWV Trace Log view and the SWV ITM Timeline Graph view can be used with good benefit for this purpose. In Atollic TrueSTUDIO, SWV and ITM tracing works with both the SEGGER J-Link and the ST-LINK debugger probes.
These capabilities are supported in any device using a Cortex-M core with the appropriate H/W support (such as Cortex-M3 and Cortex-M4 cores); including STM32 from STMicroelectronics, Freescale Kinetis, SiLabs/EnergyMicro EFM32 and NXP LPC.
Later, I will continue the SWV article series by explaining how Serial Wire Viewer tracing can be used for other advanced Cortex-M debugging capabilities, including:
- Event trace (log and timeline graph)
- Exception trace (log and timeline graph)
- Exception nesting analysis
- Interrupt statistics graph
- Real-time data and memory watch
- Data trace and memory access history log
- Data trace graph (real-time “oscilloscope plot” visualisations of data)
- Speed performance analysis (statistical profiling graph)
- Execution time measurement
In case you want to get a good overview of Serial Wire Viewer real-time tracing on Cortex-M cores (in particular with the GNU gcc/g db tools on Eclipse), you can also read this white paper on the subject: