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
Wire: Ensure the board’s SWO/TRACESWO pin is connected to the debugger (ST-Link on Nucleo/Discovery already is).
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).
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).
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;
}
Now normal printf prints to the SWV ITM Data Console:
printf("adc=%lu, temp=%.2f\n", adcVal, tempC); // appears in SWV console
Tips
- Disable buffering so text appears immediately:
setvbuf(stdout, NULL, _IONBF, 0);
- 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.
Add SEGGER_RTT.c/.h to your project (from SEGGER’s RTT package).
In code:
#include "SEGGER_RTT.h"
SEGGER_RTT_WriteString(0, "Hello RTT!\n");
SEGGER_RTT_printf(0, "count=%lu\n", count);
- 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);
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)