DEV Community

Hedy
Hedy

Posted on

How to output a variable to console in STM32 debugger?

You’ve got a few clean ways to print variables to a “console” while debugging STM32. The two most convenient are SWV/ITM (via SWO pin) and SEGGER RTT (no pin). Here’s how to set each up (plus UART and semihosting options).

Option A — SWV/ITM (Serial Wire Viewer) via SWO

Best when you’re using STM32CubeIDE or Keil/IAR with an ST-Link/J-Link and your MCU exposes the TRACESWO pin (often PB3).

STM32CubeIDE steps

  1. Wire: Ensure the board’s SWO/TRACESWO pin is connected to the debugger (ST-Link on Nucleo/Discovery already is).

  2. Debug config: Run → Debug Configurations… → your launch config → Debugger tab:

  • Interface: SWD
  • Check Serial Wire Viewer (SWV) / Trace Asynchronous SW
  • Set Core clock (HCLK) correctly (e.g., 80 MHz).
  • Set SWO clock (e.g., 2 MHz–4 MHz; must be ≤ HCLK/2 and supported by probe).
  1. Open console: Window → Show View → SWV ITM Data Console. Click the settings (wrench), enable Stimulus Port 0, then click Start Trace (red/green dot icon).

  2. Code: Either call ITM_SendChar() directly or retarget printf to ITM.

Minimal ITM “printf” retarget

Add this function (e.g., retarget.c), include and CMSIS core headers:

#include "stm32fxxx.h"
#include <stdio.h>

int _write(int file, char *ptr, int len) {
  (void)file;
  for (int i = 0; i < len; i++) {
    // Wait for STIM0 ready then write
    while ((ITM->TCR & ITM_TCR_ITMENA_Msk) == 0 || (ITM->TER & 1) == 0);
    while (ITM->PORT[0].u32 == 0); // optional: avoid if using ITM_SendChar
    ITM_SendChar((uint32_t)*ptr++);
  }
  return len;
}
Enter fullscreen mode Exit fullscreen mode

Now normal printf prints to the SWV ITM Data Console:

printf("adc=%lu, temp=%.2f\n", adcVal, tempC);  // appears in SWV console
Enter fullscreen mode Exit fullscreen mode

Tips

  • Disable buffering so text appears immediately:
setvbuf(stdout, NULL, _IONBF, 0);
Enter fullscreen mode Exit fullscreen mode
  • Float printf needs: linker option -u _printf_float (newlib-nano).
  • Don’t call heavy printf inside ISRs; use brief formatting or ITM_SendChar in ISRs.

Option B — SEGGER RTT (no SWO pin required)

Great when SWO isn’t routed or you want zero-pin, high-speed logs. Works with J-Link; also usable with ST-Link + OpenOCD plugins in some setups.

  1. Add SEGGER_RTT.c/.h to your project (from SEGGER’s RTT package).

  2. In code:

#include "SEGGER_RTT.h"
SEGGER_RTT_WriteString(0, "Hello RTT!\n");
SEGGER_RTT_printf(0, "count=%lu\n", count);
Enter fullscreen mode Exit fullscreen mode
  1. View output:
  • J-Link RTT Viewer app, or
  • In CubeIDE/VS Code with appropriate RTT console plugin, or
  • JLinkRTTClient (CLI).

Pros: fast, non-blocking, no pin. Cons: best with J-Link tooling.

Option C — UART printf (portable & simple)

Route logs to a serial terminal.

int _write(int file, char *ptr, int len) {
  HAL_UART_Transmit(&huart2, (uint8_t*)ptr, len, HAL_MAX_DELAY);
  return len;
}
// Then:
printf("x=%d\n", x);
Enter fullscreen mode Exit fullscreen mode

Open a terminal on the board’s UART (Nucleo: ST-Link VCP). This doesn’t depend on the debugger, just the COM port.

Option D — Semihosting (works but slow)

Enable semihosting in your debugger config and link with semihosting stubs; then printf goes to the debugger console. It’s blocking & slow (halts the CPU on each write), so it’s better for quick demos than realtime systems.

Quick troubleshooting checklist

  • Nothing appears? Ensure SWV is started and stimulus port 0 is enabled; HCLK and SWO frequencies set correctly.
  • No SWO pin on your board? Use RTT or UART.
  • Garbled text? Lower SWO speed; confirm actual HCLK.
  • “Header not found” for ITM: include the CMSIS core header (core_cm4.h, core_cm7.h, etc.) that matches your MCU.
  • Performance: prefer RTT/ITM for speed; avoid printf with floats in tight loops.

Top comments (0)