Recently on the MCU on the Eclipse website saw Erich Styger wrote an article about through the SWD tracking interface SWO get ARM cortex-m related information, the article structure is clear, explain thoroughly, I deeply inspired, deliberately translate it for your colleagues reference. Of course limited to the individual level, there are improper, please correct me. Original URL: https://mcuoneclipse.com/2016/10/17/tutorial-using-single-wire-output-swo-with-arm-cortex-m-and-eclipse/
As a standard procedure, I add some console features to my embedded application. So I have a command-line interface that can check and modify the target system. An interesting hardware feature of ARM cortex-m is the single-wire output (SWO), which allows data (such as strings) to be sent to 32 different excitation ports via a single line.
SWO pin on ARM debugger connector
Debug trace output? SWO!
I use normal Uart/sci as the standard text and command line interface with the target board. However, on many boards, the UART is used by the application.
There is a semihosting (semi-managed), but it is very slow and depends on the debugger and Toolchain/library, plus the need to consume flash and RAM, so I don't recommend using semihosting under any circumstances.
"Note"semihosting is a mechanism for the ARM target machine, which can be based on the input / output request of the application code , Communicates with the host running the Debug function. This technology allows hosts to provide host resources for target hardware that typically does not have input and output capabilities.
There is also a USB CDC, but this requires a USB interface, a USB stack and a USB-capable microcontroller. Not applicable to all situations.
There is also a Segger RTT, which is small, fast, and the best is not requiring any special pins. But only works on Segger debug detectors.
ARM SWO
But there's another thing: ARM SWO tracking ports are defined by arm for CORTEXM-M. Technically speaking, the SWO is a single tracking pin that is used to send packets from the CPU core clock to extract a specific clock frequency. You can consider SWO as a UART TX pin that sends packets using a special format. Up to 32 types of packages (or incentives) can be used. What data is sent depends on the application and requires little CPU processing or code.
Common SWO usages are:
- Send debug information by string
- Record interrupted entry and exit
- Logging function entry and exit
- Periodic PC-Value sampling
- Event hints
- Variable or memory unit modification timeout
One of the most common uses is the first: use SWO to print debug messages from the target using the UART style. And that's exactly what I'm going to say in this article. There is another code (Manchester code) that is not introduced here.
ARM CoreSight
SWO is part of the arm coresight debug function block, while arm coresight is typically part of the CORTEX-M3,M4,M7:
Coresight function block (from: http://www.arm.com/files/pdf/AT_-_Advanced_Debug_of_Cortex-M_Systems.pdf)
As shown, trace messages via Swo (or SWV) ITM and DWT can be sent. 4 additional trace pins are required for command tracking
SWO Pin
The precondition for using SWO is that the pin can be used in the debug header. This is the case of my twr-k64f120m board:
Trace Swo pin (from: twr-k64f120m schematic)
As shown, the SWO trace pin is shared with the JTAG TDO pin. This means that SWO cannot be used in Jtag, but only in SWD.
So carefully check your board's schematic to determine whether he supports SWO. For example, frdm-k64f (a previous version of twr-k64f120m), its swo is not led to the debug header:
There's no swo on frdm-k64f.
Debug probe with SWO
To be able to use SWO, I need a debug probe capable of reading the SWO pin. For example, the FREESCALE/NXP OPENSDA on the freedom and tower modules onboard debug interface hardware does not support SWO.
However, the external Segger J-link supports the SWO pin. Below I have a j-link edu connect to the Debug and trace ports of the TWR-K64F120M board:
J-link edu connection to the trace port
through SWO PIN to send debug information source
In order to write debug messages to the host through SWO, a small piece of code is required. There is an example project with a complete code available on GitHub:
Https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/TWR-K64F120M/TWR-K64F120M_Demo/Sources
External tools, such as the Segger RTT Viewer, can set swo in hardware. My recommendation is to initialize it from the application. Because the SWO trace output clock is derived from the CPU clock, the initialization function requires this clock plus the SWO port number to initialize. Here is the code I used to initialize the SWO output, which defaults to 64k baud rate:
/*!
* \brief Initialize the SWO trace port for debug message printing
* \param portbits Port bit mask to be configured
* \param cpucorefreqhz CPU Core clock frequency in Hz
*/
void Swo_init (uint32_t portbits, uint32_t cpucorefreqhz) {
uint32_t swospeed = 64000; /* Default 64k baud rate */
uint32_t Swoprescaler = (cpucorefreqhz/swospeed)-1; /* Swospeed in Hz, note this cpucorefreqhz is expected to be match the CPU core clock */
COREDEBUG->DEMCR = Coredebug_demcr_trcena_msk; /* Enable trace in core Debug */
* (Volatile unsigned *) (itm_base + 0x400f0)) = 0x00000002; /* "Selected PIN Protocol Register": Select which Protocol to use for trace output (2:swo NRZ, 1:swo Manchester encoding ) */
* (Volatile unsigned *) (itm_base + 0x40010)) = Swoprescaler; /* "Async Clock prescaler Register". Scale the baud rate of the asynchronous output */
* (Volatile unsigned *) (itm_base + 0x00fb0)) = 0xc5acce55; /* ITM Lock Access Register, C5acce55 enables more write access to Control Register 0xe00:: 0xFFC */
ITM->TCR = Itm_tcr_tracebusid_msk | Itm_tcr_swoena_msk | Itm_tcr_syncena_msk | Itm_tcr_itmena_msk; /* ITM Trace Control Register */
ITM->TPR = Itm_tpr_privmask_msk; /* ITM Trace Privilege Register */
Itm->ter = portbits; /* ITM Trace Enable Register. Enabled tracing on stimulus ports. One bit per stimulus port. */
* (Volatile unsigned *) (itm_base + 0x01000)) = 0x400003fe; /* Dwt_ctrl */
* (Volatile unsigned *) (itm_base + 0x40304)) = 0x00000100; /* Formatter and Flush Control Register */
}
In my main application, I initialize it like this (for a system with a 24MHz core clock):
#define CPU_CORE_FREQUENCY_HZ 120000000/* CPU CORE FREQUENCY in HZ */
Swo_init (0x1, cpu_core_frequency_hz);
Finish printing in the Swo_printchar () function:
/*!
* \brief sends a character over the SWO channel
* \param C Character to be sent
* \param PortNo SWO channel number, value in the range of 0 to 31
*/
void Swo_printchar (char C, uint8_t PortNo) {
volatile int timeout;
/* Check if Trace Control Register (ITM->TCR at 0XE0000E80) is set */
if (itm->tcr&itm_tcr_itmena_msk) = = 0) {/* check Trace Control Register if ITM trace is enabled*/
Return /* not enabled? */
}
/* Check If the requested channel stimulus port (Itm->ter at 0xe0000e00) is enabled */
if ((Itm->ter & (1ul<<portno)) ==0) {/* check Trace Enable Register If requested port is enabled */
Return /* Requested port not enabled? */
}
Timeout = 5000; /* Arbitrary timeout value */
while (itm->port[0].u32 = = 0) {
/* Wait until STIMX is ready and then send data */
timeout--;
if (timeout==0) {
Return /* Not able to send */
}
}
Itm->port[0].u16 = 0x08 | (C<<8);
}
The above code uses a very simple timeout mechanism: The important point is that if SWO is not enabled or the SWO port is not ready, then the application will be blocked.
To make it easier to print a string, I use the following function:
/*!
* \brief sends a string over SWO to the host
* \param s String to send
* \param portnumber Port number, 0-31, use 0 for normal debug strings
*/
void swo_printstring (const char *s, uint8_t portnumber) {
while (*s!= ') {
Swo_printchar (*s++, portnumber);
}
}
To send a "hello" through SWO, it is as simple as this:
Swo_printstring ("Hello World with Swo\r\n", 0);
The first parameter is the string to send, and the second is the SWO trace channel number.
GNU ARM Eclipse Viewer
To receive the SWO trace output on the host, the GNU ARM Eclipse plugin has built-in SWO support for the Segger J-link detector.
The SWO supports only SWD (single-line debugging) mode and does not support JTAG mode. So make sure that SWD is selected as the Debug protocol:
SWD Commissioning
In the GNU ARM Eclipse Debug Configuration, enable SWO and specify the CPU frequency and SWO frequency (see the documentation for frequencies on http://gnuarmeclipse.github.io/debug/jlink/). I have to provide the CPU frequency (in my case, with a frequency of 0 MHz), and I can set the SWO rate to a speed of about J-link automatically. Specifies the port used in the port mask (as a bitmask), so 0x1 is used for Port 0:
Settings for SWO
In this way, running the application on the target board displays the output in the Eclipse console view:
Eclipse Console View
Segger SWO Viewer
The Segger has a special swo Viewer (command line and GUI version).
In the GUI version, I specified the device used, which can sense the tracking clock:
Segger GUI Swo Viewer
In the viewer, I can open/close the port and view the received data:
Segger J-link SWO Viewer
Telnet:putty
However, there is no fancy viewer or eclipse that needs to see the SWO data. Segger uses port 2332 by default:
SEGGER SWO Port
I can configure any Telnet client (for example, putty) to open the session on port 2332:
Putty Telnet Session Settings
The output I get in putty:
SWO output in putty
Review
The ARM SWO tracking pin allows tracing messages to be sent to the host. A common use is to send debugging or other messages to the host. The SWO requires only one pin, only for SWD (not JTAG), and requires very little code and resources on the target. Unfortunately, many boards do not route the SWO tracking pin to the debug header, so if you are working on your own design, you should at least consider routing the SWO to the debug header.
Although the SWO trace output is large, but limited to high-end cortex-m, I did not find it in cortex-m0 (+), it is just the output and requires a debug probe/interface to support it. At least with the eclipse and GNU ARM Eclipse plug-in combined with the Segger J-link probe SWO output is great for me.
Segger RTT, on the other hand, is more versatile and very fast. It is suitable for all arm Cortex and, most importantly, does not require additional pins. However, it requires more overhead and RAM resources on the target system. In addition, it allows data to be sent and received. So for serial debug message printing, Segger RTT sounds a better solution to me.
The next is the happy SWO!
RELATED LINKS
- SWO on kinetis:https://community.nxp.com/thread/318058
- Swo with GNU ARM Eclipse Plugin: http://gnuarmeclipse.github.io/debug/jlink/
- Segger SWO Viewer:https://www.segger.com/j-link-swo-viewer.html
- GNU ARM Eclipse Plugin: http://gnuarmeclipse.github.io/debug/
- Eclipse RXTX plug-in for parsing SWO data: http://forum.segger.com/index.php? page=thread&threadid=1010
- ARM coresight Overview: http://www.arm.com/files/pdf/at_-_advanced_debug_of_cortex-m_systems.pdf
- Sample code on GitHub: https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/TWR-K64F120M/TWR-K64F120M_Demo/Sources
Welcome attention:
SWO single bus output based on arm cortex-m and Eclipse