SWO: An ARM Printf under another name

I will admit. Although printf-There is a bad representation of style debugging, I see myself turning to it. Of course, printf It is expensive and comes with a lot of code, but if you have the space and time to use it when debugging, you can always remove it before it’s too late. However, what if you do not have an output device or you use it for something else? If you use most modern ARM chips, you have another option – a dedicated output channel that is used for a variety of things, including debugging output. I decided that what I really needed to do was try embedding BlackPill running, and found that it wasn’t as easy as you think. But it is possible, and when you finish reading, you will be able to do it too.

I am writing this using STM32-specific ST-LINK hardware. If you use other JTAG devices like the BlackMagic Probe, this is probably already set up for you.

Did you get

I will start back with the final result, then talk about the software, so that you will be well and inspired by the time you get the hardware requirements. Spoiler alert: You may need a quick hack for your existing hardware to work, although you can buy something off the shelf if you prefer.

Here is a very simple test program:



SWO_Channel debugport;  // requires #include "SWO.h"
int main() 
  {
  unsigned count=0;
  debugport.printf("\r\nHello World from SWO\r\n");
  debugport.printf("CPU SystemCoreClock is %d Hz\r\n", SystemCoreClock);

  while (1) 
    {
    led = !led; // flip LED if output is true
    ThisThread::sleep_for(rate); // sleepy time
    if (count % 10) debugport.putc('*'); else debugport.printf("%d\r\n",count); 
    count++;
    }
}


There is nothing difficult to imagine here. You can use putc Or printf Write to the debugging output. As you can see in the picture, you get a nice window that shows all the output. There are actually 32 channels of output, but channel 0 is reserved for debugging output. In this case, I picked it all up because that’s the only thing coming out of the device.

What do you want

ST’s STM32CubeProgrammer can display SWO data.

First, you need a compatible ARM chip. Not all ARM chips support ITM – Integrated Trace Macrosell – but this is what you need. The device marked SWO will have a PIN (and possibly other things as well). Since I’m using BlackPill with an STM32F411CE, we know it will work and the output pin will be PB3.

You also need an ST-Link dongle to have a SWO pin Unfortunately, the cheap ones you usually get that look like a USB memory device don’t have a SWO PIN. But you can easily hack them. The PIN has been introduced in the “complete” ST-Link V2, but is usually much more expensive. However, if you shop in a typical Chinese store, you can usually find one at a reasonable price. I paid less than 10.

Of course, you also need some kind of tool to read the output. A typical terminal will not do this, but ST’s STM32CubeProgrammer can read data easily. Of course, there are other options. Many IDEs and debuggers can read SWO output. There are also some open source tools, but the Ubuntu packages are very old and the release packages did not work. It worked from scratch, though.

Software setup

Since I’m using embed, the first thing I did was go find a library. I was not disappointed. The library is a thin wrap around ITM functions in CMSIS, so if you don’t use Mbed, just look at those functions and you’ll be able to figure it out. If you like STM32Duino, check it out for something similar.

Once I added it to the project, I had to fix a small thing. This probably didn’t matter, but there is an example where an array is assigned to a file name and then mistakenly deleted. Make a note delete In the following code:



bool SWO_Channel::claim (FILE *stream) {
  if ( FileBase::getName() == NULL) {
  error("claim requires a name to be given in the instantiator of the SWO instance!\r\n");
  }

//Add '/' before name:
  char *path = new char[strlen(FileBase::getName()) + 2];
  sprintf(path, "/%s", FileBase::getName());

  if (freopen(path, "w", stream) == NULL) {
// Failed, should not happen
  return false;
}

  delete [] path;   //  fixed

//No buffering
  setvbuf(stream, NULL, _IONBF, 32);
  return true;
}


Once it’s done, you’re good to go. You just need some hardware.

Hardware setup

If you have a “normal” ST dongle like the white one in the picture below, then the setup is a simple setup. Connect the power, ground and two debugging pins to the connector on the back of the BlackPill and then run a cable from SWO to B4 pin on the device.

If you have one of the cheapest clones next to the white device, you will need to do some surgery to get an extra pin out.

Load a program that produces some simple SWO output and then fires everything. You may need to upgrade ST-Link’s firmware – the STM32CubeProgrammer software can do the same.

While connecting the programmer to the hardware, I noticed that the white dongle did not connect reliably at 4000 kHz, so I had to select 1800 kHz. It could just be that device or my random cable. You can see the connection information I am using in the adjacent screenshot. Press Connect to get started.

When you select the SWV item, you need to set a clock of 96 MHz for this setup. Most likely, if you are running on a different frequency, you will know the exact value for your setup. When you press Start, you will see the output from the program.

The only thing to remember is that your software will fight the dongle unless it works in “shared” mode. In my case, embed studio doesn’t seem to care about that setting so if you want to reprogram the chip you have to disconnect. Of course, you can use programmers to do everything. It will all depend on your equipment and setup.

Of course, once you turn it on, it’s pretty easy to replicate for future projects. Your program has only one extra cable and two additional files.

Going forward

You can go further, though. First, there is the color output. If your debug string contains #RED #, #GRN #, or #ORG #, the rest of the characters will be in that color (red, green or orange) for the rest of the line. Guess, of course, the viewer understands it and you turn it on. It’s easy to be able to show important messages in red, for example.

However, it is a waste that there are so many additional channels that we are not using. For example, why does Channel 0 not have progress messages and Channel 1 does not have detailed debugging information? You may have a dump on what is coming from an external device in Channel 5. Of course, you can write a prefix on the line and pull the data that way, but it’s more fun.

I rewrote a very small bit of the existing SWO class and thanks to the optional argument, it still works the same. The only difference is that you can add a channel number to the constructor to create multiple debug streams:



SWO_Channel debugport;
SWO_Channel dbg2("second",1);


There are very few changes to the code, but I will leave the whole project on GitHub.

If you can’t tell, I enjoy working with STM32 and Mbed. Of course, you can get better performance by bypassing the embed, but the good thing is you can. Oddly enough, pushing data across multiple channels on one port is something I’ve done before in a completely different way.

Leave a Reply

Your email address will not be published.