DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • How to Debug the Spring Boot Application in Eclipse? [Video]
  • 10 Most Popular Tools to Monitor and Debug Serverless Applications
  • Building a Serverless Application on AWS With AWS SAM
  • An Introduction to BentoML: A Unified AI Application Framework

Trending

  • Endpoint Security Controls: Designing a Secure Endpoint Architecture, Part 1
  • Next Evolution in Integration: Architecting With Intent Using Model Context Protocol
  • Building Resilient Networks: Limiting the Risk and Scope of Cyber Attacks
  • Unlocking Data with Language: Real-World Applications of Text-to-SQL Interfaces
  1. DZone
  2. Coding
  3. Frameworks
  4. Single Wire Output With the ARM Cortex-M and Eclipse

Single Wire Output With the ARM Cortex-M and Eclipse

Follow along to learn more about Single Wire Output on the ARM Cortex-M. See how you can set up trace output messaging (and more) all from a single pin.

By 
Erich Styger user avatar
Erich Styger
·
Oct. 18, 16 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
9.7K Views

Join the DZone community and get the full member experience.

Join For Free

As a standard procedure, I add some console functionality to my embedded applications. That way, I have a command line interface and can inspect and influence the target system. One interesting hardware feature of the ARM Cortex-M is Single Wire Output (SWO): It allows you to send out data (e.g. strings) over up to 32 different stimulus ports, over a single wire.

swo-pin-on-arm-debug-header

Debug Trace Output? SWO!

As the standard text and command line interface to my target boards, I’m using a normal UART/SCI. However, on many boards, the UART’s are used by the application.

There is semihosting, but this is very slow, depends on the debugger and toolchain/library used, plus it's a waste of FLASH and RAM, so I don’t recommend using semihosting at all.

There is USB CDC, but this requires a USB connector, a USB stack, and a microcontroller capable of USB. Not applicable in all cases.

There is Segger RTT, which is small, fast, and best of all, does not need any special pins. But it only works with Segger debugging probes.

ARM SWO

But there is yet another option: the ARM SWO trace port as defined by ARM for Cortex-M. Technically, SWO is a single trace pin that is used to stream out data packets with a certain clock rate, derived from the CPU core clock. You can think of SWO as a kind of UART TX pin using a special format to send out data packets. Up to 32 packet types (or stimuli) can be used, and you only need very little CPU processing power or code.

Common SWO usages are:

  • Sending debug messages as strings.
  • Recording interrupt entry/exit.
  • Recording function entry/exit.
  • Periodic PC value sampling.
  • Event notification.
  • Variable or memory cell change over time.

One of the most common uses is the first one: using SWO to print debug messages from the target in a UART style. And this is what I’m going to show in this article. There is another encoding method out there (Manchester encoded), which is not covered here.

ARM CoreSight

SWO is part of the ARM CoreSight Debug block, which is usually part of Cortex-M3, M4, and M7:

Image title


As shown in that overview slide, over SWO (or SWV), ITM and DWT trace messages can be sent. For instructions, up to four extra trace pins are required (see “First Steps with Ozone and the Segger J-Link Trace Pro” for more info on that).

SWO Pin

The precondition to use SWO is that the this pin is available on the debug header. This is the case for my TWR-K64F120M board:

trace_swo_pin


As shown above, the SWO trace pin is shared with the JTAG TDO pin. So this means that SWO cannot be used with JTAG, it only can be used with SWD (see "SWD Debugging with the FRDM-KL25Z Board").

Carefully check your board schematics to see if it supports SWO. For example, on the FRDM-K64F (same device as on the above TWR-K64F120M), the SWO pin is *not* routed to the debug header:

no-swo-on-frdm-k64f

Debug Probe and SWO

In order to use SWO, I need a debug probe capable of reading the SWO pin. For example, the Freescale/NXP OpenSDA onboard debug interface hardware on the Freedom and Tower modules does not support SWO (see “Solving “The connected emulator does not support serial wire output (SWO)”).

The external Segger J-Link, however, does support the SWO pin. Below I have a J-Link EDU connected to the debug and trace port of the TWR-K64F120M board:

j-link-edu-connected-to-trace-port

Source Code to Send Debug Messages Over SWO Trace Pin

In order to write debug message over SWO to the host, a small piece of code is needed.

An example project with all the sources is available on GitHub: https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/TWR-K64F120M/TWR-K64F120M_Demo/Sources

External tools (like the Segger RTT viewer) can set up SWO in the hardware. My recommendation is to initialize it from the application. Because the SWO trace output clock is derived from the CPU clock, the Init function needs that clock, plus the SWO port number to be initialized. Below is the code I’m using to initialize the SWO output to a default of 64k baud:

/*!
* \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 that 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 */
}

From my main application, I initialize it like this (for a system with a 24 MHz core clock):

#define CPU_CORE_FREQUENCY_HZ 120000000 /* CPU core frequency in Hz */

SWO_Init(0x1, CPU_CORE_FREQUENCY_HZ);

The printing is done in SWO_PrintChar():

/*!
* \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, 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 not to block it if SWO is not enabled or if the SWO port is not ready. Otherwise, the application will blocked.

To make it easier to print a string, I’m using 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!='\0') {
        SWO_PrintChar(*s++, portNumber);
    }
}

To send a ‘hello’ over SWO, it's as easy as:

SWO_PrintString("hello world with SWO\r\n", 0);

The first parameter is the string to send, 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 plugins have built-in SWO support for the Segger J-Link probes.

SWO only is supported in SWD (Single Wire Debug) mode, and not in JTAG mode. So make sure that SWD is selected as debugging protocol:

swd-debug


In the GNU ARM Eclipse debug configuration, enable SWO and specify the CPU frequency and the SWO frequency (see the documentation about the frequencies). I have to provide the CPU frequency (120 MHz in my case) and can leave the SWO freqenzy at 0 so the J-Link will automatically determine the speed). Specify in the port to mask the ports (as bitmask) used, so 0x1 is for port 0:

swo-settings


With this, running the application on the target it shall show the output in the Eclipse Console View:

eclipse-console-view


Segger SWO Viewer

Segger has a special SWO Viewer (both command line and GUI version).

In the GUI version, I specify the device used, and it can sense the trace clock:

segger-gui-swo-viewer


In the viewer, I can turn on/off ports and see the data received:

segger-j-link-swo-viewer


Telnet: Putty

But there is no fancy viewer or Eclipse needed to see the SWO data. Segger uses port 2332 by default:

segger-swo-port


I can configure any telnet client (e.g. PuTTY) to open a session on port 2332:

putty-telnet-session-settings


And the I get the output in PuTTY:

swo-output-in-putty

Summary

The ARM SWO trace pin allows you to send trace messages to the host. One common usage is to send debugging or other messages. SWO only needs a single pin, works only with SWD (not JTAG), and requires little code and ressources on the target. Unfortunately, many boards do not have the SWO trace pin routed to the debug header, so if you are making your own design, routing SWO to the debug header should be at least considered.

While SWO trace output is great, it is limited to the higher end Cortex-M. I did not find it in the Cortex-M0(+), and it is output only, and requires a debug probe/interface supporting it. At least with Eclipse and the GNU ARM Eclipse plugins, in combination with Segger J-Link probes, SWO output has worked great for me.

On the other side, the Segger RTT is much more versatile — and very fast, too. It works on all ARM Cortexes, and best of all, it does not need an extra pin. However, it requires a little more overhead and RAM on the target system. Plus, it allows you to both send and receive data. So, for the serial debug message printing, the Segger RTT sounds a better solution to me.

Happy SWOing.

Arm (geography) Eclipse Debug (command) application Command-line interface

Published at DZone with permission of Erich Styger, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • How to Debug the Spring Boot Application in Eclipse? [Video]
  • 10 Most Popular Tools to Monitor and Debug Serverless Applications
  • Building a Serverless Application on AWS With AWS SAM
  • An Introduction to BentoML: A Unified AI Application Framework

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: