Skip to main content
PHolt.1
Senior
September 30, 2025
Question

32F417: How to use SWV ITM SWO debug output, without Cube IDE or even a debugger?

  • September 30, 2025
  • 13 replies
  • 1271 views

I have overall found this feature to be very unreliable, for reasons unknown. The data comes out OK from PB3 and goes all the way to the STLINK V3, at the expected speed, 1MHz, but Cube IDE displays nothing. I have this across a number of development units. Sometimes it works and then stops...

Anyway, digging into this, it looks like the entire trace macrocell is configured via the debugger when (or before) reset is released from the target. That is why none of the STM example code sets up any of this stuff. I also managed, years ago, to get SWV working not with Cube IDE but with the STM32 STLINK Utility, which presumably does the same via-debugger config tricks.

Also just because you see 1MHz stuff on the scope doesn't mean that it is in the right format for Cube IDE to decode it.

So I went looking for how to get this stuff configured in software in the target. Obviously any such config will override the Cube/debugger config so you will have to make sure Cube IDE's config matches exactly if you still want that to work. And after a lot of work I found the following, and wonder whether it is complete:

1) Set up PB3 to be an output, probably fast mode, and enable portb clock.

2) Set up the macrocell. I found this on this ST forum

/*
	Initialize the SWO trace port for debug message printing
	portMask : Stimulus bit mask to be configured
	cpuCoreFreqHz : CPU core clock frequency in Hz
	baudrate : SWO frequency in Hz
*/
 
void swoInit (uint32_t portMask, uint32_t cpuCoreFreqHz, uint32_t baudrate)
{
	uint32_t SWOPrescaler = (cpuCoreFreqHz / baudrate) - 1u ; // baudrate in Hz, note that cpuCoreFreqHz is expected to match the CPU core clock
 
	CoreDebug->DEMCR = CoreDebug_DEMCR_TRCENA_Msk; 		// Debug Exception and Monitor Control Register (DEMCR): enable trace in core debug
	DBGMCU->CR	= 0x00000027u ;							// DBGMCU_CR : TRACE_IOEN DBG_STANDBY DBG_STOP 	DBG_SLEEP
	TPI->SPPR	= 0x00000002u ;							// Selected PIN Protocol Register: Select which protocol to use for trace output (2: SWO)
	TPI->ACPR	= SWOPrescaler ;						// Async Clock Prescaler Register: Scale the baud rate of the asynchronous output
	ITM->LAR	= 0xC5ACCE55u ;							// ITM Lock Access Register: C5ACCE55 enables more write access to Control Register 0xE00 :: 0xFFC
	ITM->TCR	= 0x0001000Du ;							// ITM Trace Control Register
	ITM->TPR	= ITM_TPR_PRIVMASK_Msk ;				// ITM Trace Privilege Register: All stimulus ports
	ITM->TER	= portMask ;							// ITM Trace Enable Register: Enabled tracing on stimulus ports. One bit per stimulus port.
	DWT->CTRL	= 0x400003FEu ;							// Data Watchpoint and Trace Register
	TPI->FFCR	= 0x00000100u ;							// Formatter and Flush Control Register
 
	// ITM/SWO works only if enabled from debugger.
	// If ITM stimulus 0 is not free, don't try to send data to SWO
	if (ITM->PORT [0].u8 == 1)
	{
		bItmAvailable = 1 ;
	}
}

 What I don't get however is the comment "ITM/SWO works only if enabled from debugger.". What is this about? There may not be a debugger!

The actual output function is the usual ST one:

// Copy of the one in core_cm4.h
static inline void ITM_SendChar (uint32_t ch)
{
 if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */
 ((ITM->TER & 1UL ) != 0UL) ) /* ITM Port #0 enabled */
 {
 while (ITM->PORT[0U].u32 == 0UL)
 {
 __NOP();
 }
 ITM->PORT[0U].u8 = (uint8_t)ch;
 }
 return;
}

 

13 replies

PHolt.1
PHolt.1Author
Senior
October 2, 2025

I posted an update here

https://www.eevblog.com/forum/microcontrollers/stlink-debugger-configures-some-32f4-target-registers-e-g-swo-trace-macrocell/msg6055277/#msg6055277

Basically the problem seems to be that frequent reading of the CYCCNT counter breaks the profiling.

Not at all sure how this is possible.

But I can work around that one. The bigger problem is that Cube IDE stops logging at approx 4095 packets. One needs way more... I've tried upping the buffer up to 200MB but it makes no difference. Is there a config for this value somewhere? It does look like there is a 4096 limit.

EDIT: seeing you using OpenOCD, I tried that, and it seems to work for both profiling and SWO debug. What a waste of time this has been. And I am still using STLINK V3.

PHolt.1
PHolt.1Author
Senior
October 2, 2025

A final update on this dead horse flogging project:

OpenOCD did indeed make both profiling and SWV ITM debug working, with PC Sampling (obviously) enabled, concurrently.

But it then stopped and I could never get it back.

It looks like the debugger needs a power cycle, or maybe the PC needs a reboot, after any debug related config change. 100% definitely Cube IDE needs a restart after any change in the Project Properties / Debugger menu.

So I went back to STLINK GDB Server mode, just to get SWV ITM debug working.

One funny thing I noticed during when the profiling worked: some 30% of the time was spent in a function whose name was not recognised by Cube, whose base address was 0x1. This is nonsense; the code starts at 0x8000000 or some such. I would expect that much time to be spent in the RTOS Idle thread, as was found previously.

Pavel A.
Super User
October 3, 2025

Again - are you using the ST own branch of OpenOCD? If you do, you could request support from ST. Of course a small, reproducible project for a well known board and clear description will be helpful.

 

 

PHolt.1
PHolt.1Author
Senior
October 3, 2025

"Again - are you using the ST own branch of OpenOCD? "

Yes.

It works a lot better than the GDB Server mode, although the latter has worked fine for normal program upload and breakpoint debugging.