Library 46- Debug STM32F4 device with SWO feature

All Cortex-M4 devices have feature to output different data for debugging. This can be used instead of one USART available in STM32F4 to display data to user when something is going wrong and you want use debug.

STM32F4 has SWD (Serial Wire Debug) option for programming/debugging. All STM32 boards, which have ST-Link on board, uses this option. For programming, only clock and data lines are required. Full SWD also enables you to output something from MCU which debugging. This is called SWV (Serial Wire Viewer) using SWO (Serial Wire Output) output.

ST-Link on STM32 boards has this input, if SWO from MCU is connected to ST-Link by default, check schematics. Some boards (like F429-Discovery) needs solder bridge if you want to enable connection.

If you are using external programmer/debugger (Keil ULINK2, Keil ULINK Pro, Segger J-Link, etc), then you should check if they have SWO option, but every serious debugger should have this!

This feature is enabled only when MCU is in debug mode. In production (non debug) mode, SWV will not work.

To get this to work, you have to make sure for some things. First is that you need to specify real CPU clock so trace will be synchronous (like baudrate in USART).

In Keil uVision this can be simple set:

  • Open “Options for Target” -> “Debug” tab
  • Select your debugger, if you are working with STM32F4-Discovery, select ST-Link
  • Click on “Settings”, new window will open
  • In “Trace” tab make sure you have settings the same as on picture below
    • Set CPU clock to match your clock
  • Go to application, compile it and press “Start/Stop Debug Session” (Red button)
    • Make sure, you have enabled option “Debug information” under “Options for Target” -> “Output”
  • To start program in real time, press F5. Program will be in real time speed and you will watch your data on SWO pin in Keil uVision
Debugger settings for trave view in Keil uVision

Debugger settings for trave view in Keil uVision

If you don’t have Keil uVision, you can still use SWO feature. In ST-Link Utility, open “ST-LINK” -> “Printf via SWO Viewer”, set your frequency and hit “Start”. MCU will be reset, in debug mode and SWO will work if it is enabled.

This can be also used if your IDE does not feature debugging mode!

I’ve tested this feature on some boards:

  • STM32F429-Discovery: worked without any problem, SB9 solder bridge required before to be soldered
  • STM32F4-Discovery: worked without any problem
  • STM32-Nucleo:
    • F401: didn’t worked, I always got error that memory cannot be read, but physical connection is there by default
    • F411: didn’t worked, I always got error that memory cannot be read, but physical connection is there by default



  • Enables SWO functionality on STM32F4
  • Printf like output style
  • Can be completely disabled when not using debug mode


    • STM32F4xx
  • TM
    • TM STDIO
    • defines.h
    • attributes.h
  • stdio.h

STM32F4 programming/debugging pins

SWD STM32F4 Description
SWCLK PA14 Clock for programming, necessary if you want to program/debug MCU
SWDIO PA13 Data input and output, necessary if you want to program/debug MCU
SWO PB3 Data pin from MCU for trace view (Serial Wire Viewer), optional and recommended

On initialize, SWO peripheral is enabled on pin PB3. When you are in debug mode and want to display some data, you can do with print function in my library. But then, you want to completely disable this debugging mode. One option will be to everywhere in your project delete lines when you display something to SWO.

Second option, is to set one define I’ve made in library. If you enable this define and set debug to 0, then all functions becomes defines with empty content and compiler will just throw them out. They will be in your code, but will not affect to size/speed of your code.

If you want disable debug mode (when in completely production mode), you can do it with define in defines.h file:

You can also leave debug active, it still won’t work if you are not in debug mode, but functions will be there, compiled and will take some time when it will try to print something.

If you don’t need debug mode (project done and in production) then you should use define above, or delete all function calls for SWO you have in your project.

Functions and enumerations


  • Every 500ms, new time is displayed to SWO output in your debug console.
  • If you have any problems and you are not sure if this is working or not, then you ST-Link Utility and it’s Printf via SWO feature to see if communication is even working

Project is available on Github, download library below.



Owner of this site. Also electronic enthusiasts, web developer, 3D printer fan, handball player and more. Big fan of STM32F4 devices. In anticipation of the new Discovery board for STM32F7 lines.

You may also like...

Read before commenting!

Before you make a new comment, make sure you agree with things listed below:

  • - Read post to make sure if it is already posted what you are asking for,
  • - Make sure you have the latest version of libraries used in your project,
  • - Make a clean and grammatically correct written message,
  • - Report as many details as possible, including what have you done so far,
  • - Do NOT post any code here. Use Pastebin,
  • - Do NOT post any error codes here. Use Pastebin,
  • - Specify STM32Fxxx family and used Discovery/EVAL/Nucleo or custom made board,
  • - Make sure your clock is set correct for PLL,
  • - If you are using my HAL drivers, please check this post how to start.
Comment will be deleted on breaking these rules without notification!
  • sunphoenixt

    My Nucleo-F401RE can’t use swv at first,but after read the discussion on ST support
    I find out that it’s the mcu clock setting didn’t match the swd trace clock.

    so maybe you should change”PLLx” pars. in “system_stm32f4xx.c” file,make sure that the mcu running on the 84Mhz or whatever you want.

    • Sorry man, but I know that.
      Clock is just fine and trace too..

      Works for both discovery, should here too.

  • Syrer

    Hello Majerle,

    I’m working on the F405xx (custom board, unfortunately!) and I need the redirecting of the printf to work on Keil in order to debug code and develop something useful. The problem is, that it doesn’t really work, after 3 days of trying and drawing and surfing I decided to post my question here.
    I am using the STM32 ST-Link for programming, it works so far for programming, not for debugging. Connections are:
    TCK PA14
    TDI PA15
    TDO PB3
    TRST PB4
    TMS PA13

    I’ve tried it with the Keil debugger session and with the ST-link utility, and many configuration for the ITM Stimulus ports, nothing worked. Got any tips? 🙂

    • You dobt use jtag, ok. If you send too many bytes of data over itm, it will blow and stop working in keil. Try to test in stlink utility if it works.

      Settings here looks ok, is clock of your f405 really 168mhz?

      • Syrer

        I send a welcome message and a string of 6 bytes every 200ms, that should be OK 🙂

        well I am thinking right now about the problem source #1, the frequency: Is it really 168 MHz? The answer is theoretically yes, but to be honest I didn’t check it.
        F405 has the HSI (16 MHz) and the board has a HSE (8 MHz), now I’m somehow confused because I’m not sure anymore how do I tell the controller which CLK source should it use, HSI, HSE or PLL? :s

        • System boot will first try to grab clock fron hse. If it does not exists, then hsi will be used. In your case, 8mhz hse is used 🙂 set pll_m to 8 and hse_value to 8000000 🙂

          • Syrer

            I already did, i wrote another replay to attach a picture, i cant attach a picture when if I just want to edit. So, the Good news is that the system core clock is really 168 MHz. I could verify it in the debug session (Watch 1 window). The bad news is that the debug messages are not displayed in the debug viewer 🙁

          • This is your SystemCoreClock variable? This is not calculated from “real values”. You pass this value.

            Make PWM, assume that your clock is 168MHz, set 1k PWM frequency, put to oscilloscope and see if it is really 1k. then clock is really correct 😉

          • Syrer

            You are right. I programmed a PWM-Signal with 1kHz, it was actually 1KHz => SystemCoreClock = 168 MHz. Still not working :/

          • Hum, then I think I’m out of my choices. You can try to verify if your pin PB3 is really connected to SWO.

          • Syrer

            Well i made a mistake while programming the PWM Signal. It outputs a 500Hz pwm when I program the 1kHz one. In this case the SystemCoreClock should be the half as supposed, i.e. 84 MHz instead of 168 MHz (Why, I don’t really know). I changed it and it helped nothing. I still get nothing as debug info.
            The PB3 is the JTDO/TRACESWO Pin of the F405 and is connected to the JTDO Pin of the ST-Link programmer as requested in the ST-LINKV2 User Manual. I have no idea why this is still not working :'(

          • go here.

            Select your board.
            Open folder, download .hex file, using “Save as” method.

            Upload to your board and test. If it does not work, you have hardware problems. This is working fine on my boards. Upload via ST-Link Utility and use it’s “Printf SWO” option inside program. Frequencies in project are set to max allowed in device.

          • Syrer

            Thanx for your reply. The used target is none of the targets you are using, its the STM32F405RGT6.

          • Then use F4-Discovery target. It’s the same speed.

          • Syrer

            I’m afraid its not working either. With the

            ST-Link utility and a frequency of 168MHz or 84MHz. Thanx for your support, I will let you know if it runs somehow or somewhere 🙂

          • Syrer

            There’s something strange:
            Nucleo F411 Board: Comparing the Clock tree and the configurations in the file system_stm32f4xx.c for the clock settings lead to a reasonable values for the peripherals: 100 MHz for the AHB, APB1 timers, APB2 clocks and timers, and 50MHz for APB1 clocks.
            STMF405 Board: Doing the same comparison leads to some contradiction. The Reference manual ( on page 213 states that the max. SYSCLK is only 120MHz, which contradicts the configurations on the system_stm32f4xx.c (SYSCLK is said to be set to 168MHz). Do you have any clarification for that?

          • This is mistake.
            F405 can go up to 168MHz for sure 🙂

          • Syrer

            I managed to run it, but only if I power the board first, then the ST-Link programmer, not the programmer first and then the board! That’s funny, and I have no Idea why. It maybe lose the synchronicity if I power the programmer first. I mean its a matter of displaying the messages only, the board prints out the messages on the PB3 (SWO-pin) in both cases.
            Thanx for your patience and all the best, till I face a new problem 😉
            Just as a notice for the readers: I used timer3 for the PWM and its clocked by the APB1 timer clock, which is divided by 4 and then multiplied by 2 which gives 84 MHz. The Board runs indeed with the maximum frequency of 168MHz. Sorry for this mistake, but i assumed the APBx timer clocks have a prescaler of 1, as in the Nucleo F411.

          • Sounds strange.
            Well, F401 and F411 have ABP1 prescaler set to 2 and APB2 set to 1 🙂

          • Syrer

            ya, in the case of F405: APB1 prescaler is 4 and APB2 prescaler is 2

          • True, APB1 can go up to 50MHz and APB2 up to 100, no matter which device you use 🙂

          • Syrer

            Yup, i heard that some when during the theoretical part before getting into the programming 🙂
            the multiplier for the timer clocks only (after the APBx divider) doubles back the divided frequency for the timers.

      • Syrer

        In case of the HSI: PLL_M=16, PLL_N=336, PLL_P=2 and the resulting system core clock should be 168 MHz.
        Due the schematics of the board (see below), it has an external quartz (8 MHz): PLL_M=8, PLL_N=336, PLL_P=2 and the resulting system core clock should be also 168 MHz.
        But Im still confused how does the µC knows which source to use.

  • Pingback: All STM32F4 libraries - STM32F4 Discovery()

  • Saurabh Gupta

    Hello Majerle,

    I’m working on the F407VG. I’m running into problems while trying to debug with keil uVision 5. The core clock is initialized to 16 MHz in the initialization file. I have attached an image to confirm that. Also, the 16 MHz setting works in uVision 4. However, for some reason it does not work in uVision 5 even with the exact same settings in the trace tab. I have also tried a lot of other configurations such as 168,160,64,53.76,32. However, none works with uVision 5. Kindly help

    • F407 clock should be 168MHz not 16!

      • Saurabh Gupta

        It is initialized to 16 in the startup file. Are you saying that it wont work unless i change it to 168?

        • cluckcluck

          I changed to 16 MHz and it worked. thanks, I was trying to figure out what was wrong for days… I am going through the apnt_230 examples. Were you able to fix it back to 168? Could it just be a PLL settings issue?

          • I’m not sure I understand you correct here.
            What are apnt_230 examples?

          • cluckcluck

            They are a set of examples provided by Keil, they go through the IDE using SWV among other features. I am using these along with your tutorials.

  • seliman virginia

    Hi! Do u have any idea if this swo feature can used also for the stm32f411(so also a M4 proccesor)? Thanks in advance!

    • It can. This is in datasheet specified. Check there.

      • seliman virginia

        in the data sheet it says about serial wire debug and Embedded Trace Macrocell. So I wasnt sure if SWO as well is working. Does it?:D Thanks

  • seliman virginia

    Hello Majerle! I have problems in compiling this swo library due to the FILE structure in stdio. Am I wrong with something? I just want to compile the module in openstm with gcc… Sorry for bothering

    • It is very hard to say what could be wrong from your info.

      • seliman virginia

        from what I can tell this FILE struct that u use having 2 pointer members is a redefinition of the classic FILE struct, so I dont exactly know this input/output fct pointer is designed. So the error I.m getting when I compile your code is :../Src/tm_stm32f4_stdio.c: In function ‘TM_STDIO_SetInputFunction’:
        ../Src/tm_stm32f4_stdio.c:59:3: error: ‘FILE {aka struct __sFILE}’ has no member named ‘inputFuncPointer’
        f->inputFuncPointer = inputFuncPointer;

        • On GCC, it is a little different. An example provided by ST is in STM32Cube package. If you take a look at example in relative path inside cube package F4 below, you will be able to find define called “PUTCHAR_PROTOTYPE”. Check how it is implemented and used.


          Instead of UART, use SWO output function to send data.
          Then, your printf will work as expected.

          • seliman virginia

            Thanks a lot!

  • seliman virginia

    Hi Majerle, can u quick check this comment of mine related to compiling issue?
    – from what I can tell this FILE struct that u use having 2 pointer members is a redefinition of the classic FILE struct, so I dont exactly know this input/output fct pointer is designed. So the error I.m getting when I compile your code is Thanks in advance

  • Артем Тихонович

    Hi! You wrote: “This feature is enabled only when MCU is in debug mode. In production (non debug) mode, SWV will not work.” does it possible to switch mcu in debug mode? I try to run swo on stm32f407 & stm32f207 unfortunatelly (no sync in keil) but on stm32f100 swo work well!

    • You can put device to debug mode with debugger.

      • Артем Тихонович

        swo does not work in keil debug mode or true st-link utility..i spent a lot of time to discover the problem. You wrote – STM32-Nucleo:
        F401: didn’t worked, I always got error that memory cannot be read, but physical connection is there by default
        F411: didn’t worked, I always got error that memory cannot be read, but physical connection is there by default

        do you have some ideas – why?

      • Артем Тихонович

        i have resolve my problem-)))) i removed pb3 gpio initialization-)