PlatformIO Community

Viewing SWO output within PIO?

After hearing about SWO I’ve modified my ST Link and made the necessary code changes for it to transmit printf’s via SWO, when testing it with the ST Link Utility I successfully am presented the messages I log, however I cannot figure out how to view these from within vscode / PIO itself. Judging by how sparse information about this is its probably straight forward and I just dont see it. Help would be much appreciated, thanks in advance :slight_smile:

Partially discussed in Using SWO trace output from Atmel-ICE and STM32, libopencm3 and SWV/SWO but I’ve not yet seen information about it with PIO. The serial monitor is designed to connect to serial devices (/dev/ttyX / COMX devices). OpenOCD seems to be able to write it into a logfile (ref)… Do you know of a cross-platform tool for viewing SWO output?

I have seen those posts however those seem to be doing much more than I seemed to need to make it work. To have it work all I needed to do is switch my Debug mode to Trace Asynchronous Sw and add the couple lines of code and thats it. My ST Link has not introduced a new com port to the system nor is there anything on the mentioned port 2332 that you can find here and there.

As far as a cross platform tool goes, i dont know one no. I’m on windows so I’ve used the ST Link Utility and that works for me, unfortunately I obviously need to disconnect the debugger in vscode before i can connect with that to view the output, hence its not really a viable solution.

I’m assuming that the STM32CubeIDE might be able to view the output but I dont really know as I dont use that.

Actually, as little update, seems like OpenOCD, which Platformio uses anyways, does support SWO tracing. PIO just doesnt make use of it.

We have a feature request for this and plan to implement soon

1 Like

As a workaround I used to configure openocd (that ships with pio) like this (platformio.ini):

debug_server = $PLATFORMIO_CORE_DIR/packages/tool-openocd/bin/openocd
  -f $PLATFORMIO_CORE_DIR/packages/tool-openocd/scripts/board/st_nucleo_l4.cfg
  -f $PLATFORMIO_CORE_DIR/packages/tool-openocd/scripts/interface/stlink-v2-1.cfg
  -c "tpiu config internal - uart off 80000000"
  -c "itm ports on"
  -c "tcl_port 6666"

What is does, it turns all itm ports on and reopen tcl server that is disabled by default. You have of course to change the interface and board cfg to the one of your board. Also change 80000000 to the clock of your microcontroller.

Use this python script to listen on tcl server (port 6666):

You can open this script inside of vscode, so it is as near as having it “builtin” to vscode.

With this setup you can debug your program with pio debugger and simultaniously listen to itm packages. Of course you can overwrite _io_putchar to use printf:

extern "C"
{
int __io_putchar(int ch){
	//HAL_UART_Transmit(&huart2,(uint8_t *)&ch, 1, 10);
	ITM_SendChar(ch);
	return ch;
}
}
3 Likes

Good to know that its already a planned feature, thanks a lot! I will definitely check out your workaround. For now I’ve been using the ST-Link utility but being unable to use SWO and SWD at the same time is kind of annoying some times.

I did everything as you said, but after compilation I see an error

Not SWO, but a good alternative is the Segger RTT. It’s fast transfer through the J-link without additional hw or pins, and you can use the built-in PIO monitor as Printf() target. It’s possible (and legal) to flash the Nucleo board’s STLink adapter to JLink. Or there is the inexpensive J-Link Edu mini.

Perhaps a bit late for this discussion, but here’s how I got SWO going (on MacOS, it should also work on Linux). I have this in the ./.gdbinit file:

tar ext | openocd -f board/stm32f7discovery.cfg \
                -c "gdb_port pipe" -c "itm port 0 on"
mon halt
mon tpiu config internal :6464 uart false 200000000 115200
file .pio/build/disco-f750/firmware.elf
load
run

The 200,000,000 is the µC’s clock rate, and 115,200 is how fast it will be transferred (I think).

Once launched, netcat can be used to pick up the data, i.e. “nc 127.0.0.1 6464”. The data will contain a '\x01' byte every other byte, which is harmless when viewed on the console. It can easily be filtered out. Higher baud rates appear to lose data - not sure why (maybe the on-board ST-Link V2.1 is the bottleneck?).

1 Like

That’s interesting, because one could then instruct miniterm.py and hence PlatformIO to listen to the socket data, with like

monitor_port = socket://127.0.0.1:6464

in the platformio.ini.

Ah, nice. I needed both a serial console and SWO (to debug a DMA-based console driver), so for this particular case it wouldn’t work, but yes, good idea.

BTW, I have to follow up on the above script: -c "itm port 0 on". It doesn’t really work as expected. The proper way seems to be -c "gdb...; itm..." (i.e. one combined arg). But more importantly, I still have to briefly connect via telnet 127.0.0.1 4444 and enter the itm command there. I suspect that it’s sent too early, before the board is attached.

Nevertheless, once set up, it works nicely. I can now keep both the serial console and the ITM output windows open, and use a small script to upload via the running openocd process:

$ cat ocdload.py
#!/usr/bin/env python3

import socket, sys

cmd = "program %s verify reset" % sys.argv[1]

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("127.0.0.1", 6666))

sock.send(cmd.encode() + b'\x1A')

data = b''
while data [-1:] != b'\x1A':
    data += sock.recv(4096)

reply = data[:-1].decode()
if reply:
    print(reply)
$

In combination with these settings in platformio.ini:

upload_protocol = custom
upload_command = ./ocdload.py $PROG_PATH

Note that there’s no gdb involved in this workflow.

This is with an STM Discovery board, i.e. through the standard on-board ST-Link V2.1, and should therefore also work with Nucleo boards (except Nucleo-32, which doesn’t use SWO).

It’s convenient, but I’m always looking for ways to make the edit / upload / run cycle faster …