Using Serial Wire Trace with CubeIDE (aka a new level of debugging)

I’ve been developing for STM32’s for a couple of years now, and I did a lot of different projects – from large powersupplies to small headlamps – but on 95 % of them, I used two connectors:

  • SWD (Serial Wire Debug), used to program and debug the chip
  • UART, used to get back some telemetry from the running firmware

The reason for having UART is simple – while SWD does allow debugging, it is relatively limited to basically either stepping the program or stopping the processsor and examining memory (variables, registers, etc.). This is fine, but often you need the debugging to be more dynamic – print a variable every second, print a statement when something happens etc. Sometimes you also want to chart a variable, or see how long does the execution of a certain function take.

There is an alternative to UART-debugging, called Serial Wire Output. With a small modification to the cheap ST-LINK v2 clone, we can get all the functionality of a UART and a lot more. So what can Serial Wire Output do?

  • display messages in a console (using printf)
  • display value of a variable (memory address) including a list of reads/writes to that location
  • chart the above variable
  • trace exceptions and interrupts (when they occured and how long it took to process them)
  • make statistics on the usage of the MCU (how much does every function use the MCU)

Note: simply speaking, Serial Wire Viewer is the part of the IDE which will allow you to view the data; Serial Wire Output is the connection between the debugger and the MCU. And ITM – Instrumentation Trace Macrocell – is the part of MCU which manages reading, preparing and sending the data.

Hardware

Contrary to popular opinion, you can use SWO even on those cheap ST-link dongles from Ebay – I use them for all of my projects and they’re great, especially given the cost. Truth be told, I think they are more reliable than most of the AVR programming tools.

The only problem with the ST-link is that for some reason, the SWO pin is not available on the IDC 10P connector. The firmware, however, supports this functionality, so we’ll just repurpose one of the existing 5 V pins (why would you need two of those anyways?).

Using a screwdriver, pry the plastic part around the USB apart from the aluminium case. Once it is free, remove the case as well and you should have this:

Then it is simply a case of cutting the 5 V trace, soldering a 22 ohm resistor (actually, it’s there just for safety – the value doesn’t matter at all, you could also do without it). Then, solder some wire to the other end of the resistor and to the small pad near the IC. And that’s all.

Firmware

There is no setup required for SWV to work – you don’t even have to setup the PB3 pin to alternate function. To send the data to the console, you could use the function ITM_SendChar(), but that allows you to send just single chars.

Warning: at least in STM32CubeIDE, the console window will update only after receiving the \n (LF) character!

A much more convenient way to debug is to reroute the output of the well-known printf function from the library stdio.h. The output of printf normally calls the _write function, which, in a normal x86 console application, would then put chars into the console.

In the STM32CubeIDE, this _write function is already implemented in the file syscalls.c, which is generated with every project by default. It however has the weak attribute, meaning if we define a function with the same name elsewhere, our function will get linked into the final bin.

So just put the following anywhere in your project:

int _write(int file, char *ptr, int len)
{ 
    for (int DataIdx = 0; DataIdx < len; DataIdx++)       
        ITM_SendChar(*ptr++); 
    
    return len; 
}

Warning: if you put this function into a .cpp file, you’ll need to put it into a extern "C" {...} section – linkers for C and C++ work differently.

Note: you could also simply redirect your printf output to UART with this, just replace the ITM_SendChar() with a function to send a single chart via UART.

Using SWV in STM32CubeIDE

Firstly you must enable SWV – this is done by clicking on the small arrow next to the Debug button and selecting Debug Configurations. In the window that pops up, switch to the Debugger tab and select “enable” in the SVW area:

Before hitting debug, you’ll also need to provide the actual value of system clock. Then, with your device in debugging mode, open the required view (using Window -> Show View -> SWV):

  • SWV Trace Log – all the packets transmitted via SWO should be visible here, including a lot of sync packets (which are generated automatically once you enable SWV).
  • SWV ITM Data Consoleprintf traffic will be redirected here.
  • SWV Data Trace – this allows you to track up to 4 different variables/memory addresses, including each read/write from/to that address. Graphing those variables is available with the SWV Data Trace Timeline Graph view.
  • SWV Exception Trace Log – this allows you to track all your interrupts and exceptions (and also possible graph them); for this to work, you must enable the EXC and EXETRC.
  • SWV Statistical Profiling – allows you to see how much time CPU spends in each function; for this to work, you must enable the PC sampling option. This works by sampling the MCU’s status each x cycles, so it has limited accuracy.

With the desired view opened, you’ll need to do one last configuration. Click on the small wrench icon (“configure trace”) in the bottom right corner and the following window should pop up:

For your printf to work, you must enable port 0 (that’s the default for ITM_SendChar). Then, for tracing variables, you must enable one of the four comparators (I still don’t get why are they called like that). And the last step is to enable SWO recording by pressing the big red button right next to the Configure trace button.

Warning: SWO has a definite bandwidth, so if you call the prinf too often, it can jam up. You’ll then get the “device not responding error”. This can also easily happen with the PC sampling and a too low prescaler.

Conclusion

I see two major advantages over UART:

  • extra functionality you just wouldn’t get with UART for a very little extra CPU load
  • no extra USB dongles needed, no extra windows open on your desktop and just 1 more wire required

And two small disadvantages:

  • works only in debug mode
  • you need to modify your ST-LINK clones

But the advantages are enormous in my opinion, so I’d recommend anybody interested in serious development for STM32’s to learn to work with this technology.

2 Replies to “Using Serial Wire Trace with CubeIDE (aka a new level of debugging)”

Leave a Reply

Your email address will not be published.