Retargeting printf: use Serial Wire Output (SWO) with printf

In this guide, we shall retargeting printf which part of stdio library to debug you code. For example, interrupt handler, variable to be displayed etc.

In this guide, we shall cover the following:

  • Serial Wire Output.
  • Implementing header file.
  • Implementing source code for keil uVision.
  • Implementing source code of STM32CubeIDE.
  • Setup Serial Wire Viewer in Keil uVison.
  • Setup Serial Wire Viewer in STM32CubeIDE.
  • Demo.

1. Serial Wire Output:

Serial Wire Output (SWO) alongside Serial Wire Debug (SWD) allows for the CPU to emit real-time trace data. In particular, when used with an Instrumentation Trace Macrocell (ITM), it can be used to form a Serial Wire Viewer (SWV). The ITM ports are provided by the ARM controller. The SWV typically implements a form of printf style debugging for embedded systems.

2. Implementing header file:

After we created a new header file with name of swo.h, we can implementing the functions such as:

  • log_error
  • log_info
  • log_debug
  • log_debug_array
#ifndef __SWO__h
#define __SWO__h
#include <stdio.h>
#include "stm32f4xx.h"                  // Device header

void log_error(char *p);
void log_info(char *p);
void log_debug(char *p);
void log_debug_array(char const * const label, void const *array, uint16_t const len);
#endif

3. Implementing source code for keil uVision:

In Keil uVision, the printf function can be retargeted as following:

struct __FILE {int handle;/* Add whatever you need here */};

FILE __stdout;
FILE __stdin;

int fputc(int ch, FILE *f)
{
  ITM_SendChar(ch);
  return(ch);
}

For the other functions:

void log_error(char *p)
{

	printf("log Error: ");

		printf((char*)p);
printf("\r\n");


}

void log_info(char *p)
{

	printf("log info: ");

		printf((char*)p);
printf("\r\n");


}

void log_debug(char *p)
{

	printf("log debug: ");

		printf((char*)p);
printf("\r\n");


}

void log_debug_array(char const * const label, void const *array, uint16_t const len)
{
  	printf("log debug array: ");
       
    for (uint16_t i = 0; i < len; i++)
    {
    	uint8_t val = *((uint8_t *)(array + i));
    	printf("0x%02X", val);
    	
    	// Add ", " after all elements except the last one.
    	if (i < len - 1)
    	{
    	    printf(", ");
    	}
    }
	printf("}\n");
}

4. Implementing source code for STM32CubeIDE:

In STM32CubeIDE, the printf functionality can be retargeted as following:

int __io_putchar(int ch)
	{
	 ITM_SendChar(ch);
	return ch;
	}

5. Setup Serial Wire Viewer in Keil uVison:

After you compile the code and enter a debug session:

6. Setup for STM32CubeIDE:

Please check the video from here:

7. Results:

Happy coding 🙂

12 Comments

  • Neil Posted March 10, 2022 5:24 am

    Is there a reason that when I come to this page I get an automatic download of file “Screen-Recording-2022-03-04-at-7.28.51-AM.mov” ?

    • Husamuldeen Posted March 10, 2022 5:29 am

      Hi,
      This is for the video we attached with topic for configuring SWV for CubeIDE.
      It is very long to do it in pictures, hence we opt the option to use video instead.
      Feel free to add our website to not download automatically specially videos.

    • Husamuldeen Posted March 22, 2022 4:12 am

      Hi,
      From now and on, the videos shall be uploaded to youtube for the convenience of the site visitors.

  • Simon Morrison Posted March 15, 2022 2:28 pm

    I can’t see the section “Setup Serial Wire Viewer in STM32CubeIDE”

    • Husamuldeen Posted March 15, 2022 3:07 pm

      It shall be reuploaded soon.
      The older version was triggering auto-download and it was troublesome for visitors.
      Keep your eyes on the post and shall be updated soon.

    • Husamuldeen Posted March 22, 2022 4:11 am

      Hi,
      I wanted to let you know that STM32CubeIDE setup section has been added.

  • Wagner Posted March 15, 2022 2:35 pm

    Hi thanks for this code. I’m trying it but on uVision I’m getting the error message below. Any ideia how to solve it ?

    ..\source\src\swo.c(89): error: #852: expression must be a pointer to a complete object type
    uint8_t val = *((uint8_t *)(array + i));
    ..\source\src\swo.c: 0 warnings, 1 error

    One more thing. At the first line of the C code, there is missing a “S” letter right at the beginning:

    truct __FILE {int handle;/* Add whatever you need here */};

    Thanks !

    • Husamuldeen Posted March 15, 2022 3:08 pm

      Regarding struct, fixed.
      Regarding the issue, try ARM compiler v6.

  • Bill Rogers Posted March 15, 2022 3:30 pm

    The printf works already in the latest version of stm32

  • Impulse Posted June 15, 2022 11:20 pm

    struct __FILE {int handle/* Add whatever you need here */};
    in KEIL I get error redefinition of ‘ __FILE ‘
    How I can improve it?
    Thanks for your posts I came across to this site and this is amazing

    • Husamuldeen Posted June 16, 2022 3:34 am

      Hi,
      change the compiler from v6 to v5 or remove __ from __FILE and all the other functions.

      • Impulse Imp Posted June 16, 2022 11:11 am

        I can’t thank you enough. Thanks a lot it helped. The other problem was I tried to debug it through a serial monitor not through Debug printf Viewer. And sorry for off topic in other topics I had an error uploading my massage from the phone and didn’t see it posted. Btw I’m glad I discovered your site you’re a life saver. Hat off to you man

Add Comment

Your email address will not be published. Required fields are marked *