SWO plotting on STM32: interrupt timing and fast signals over one pin
SWO (Serial Wire Output) is a single debug pin that streams data from the ITM peripheral of an Arm Cortex-M core. One register write in your code marks the start or end of an interrupt, or sends a sample of a fast signal - MCUViewer timestamps the data and plots it. No logic analyzer, no spare GPIO and next to no overhead.
What you need
- A Cortex-M core with SWO, for example STM32F1, F4, G4, H5 or H7. Cortex-M0 and M0+ have no SWO.
- An ST-Link or J-Link with the SWO line - many low-cost ST-Link V2 clones don't have it.
- The
SWDIO,SWCLK,SWOandGNDlines connected between the probe and your target. - The core clock frequency of your target.
- MCUViewer for Windows, Linux or macOS - free download.
-
1Enable the SWO pin
The SWO pin has to be configured as a trace output. In STM32CubeMX set
DebugtoTrace Asynchronous Sw- it's underTrace and Debug → DEBUGon newer series such as STM32H5, orSystem Core → SYSon older ones - and regenerate the code. Then check that SWO is wired to the probe - on most STM32 parts it'sPB3. -
2Mark the code you want to measure
Write an enter tag before the code and an exit tag after it. Each tag is a single write to an ITM stimulus port, and the port number is the channel number in MCUViewer. For example, to see how long a timer interrupt takes:
void TIM2_IRQHandler(void) { ITM->PORT[0].u8 = 0xaa; // enter tag - channel 0 goes high HAL_TIM_IRQHandler(&htim2); ITM->PORT[0].u8 = 0xbb; // exit tag - channel 0 goes low } -
3Flash the firmware and select the trace probe
Flash the firmware, switch MCUViewer to the
Trace Viewertab and openOptions → Acquisition. ChooseSTLINKorJLINKas the trace probe, pick its serial number and close the window. -
4Set the core frequency and the prescaler
Enter the core frequency in kHz - for example
250000for 250 MHz - and start with a relatively high trace prescaler, around 15-20. The resulting SWO clock is shown below it. After the first start MCUViewer also shows the maximum SWO clock of your probe and turns the field red if you're above it. -
5Enable channel 0 and start
Enable only channel 0 for the first run and press the large
STOPPEDbutton. Every interrupt now shows up as a pulse: its width is the execution time and the spacing between pulses is the period. Stop the acquisition to measure it with cursors or open the statistics window. -
6Plot fast signals too
Channels can carry values as well. Write the sample to the port, then set the channel's domain to
analogand its type to match what you send:float a = sinf(10.0f * t); ITM->PORT[4].u32 = *(uint32_t*)&a; // float on channel 4 uint16_t adc = getAdcSample(); ITM->PORT[5].u16 = adc; // uint16_t on channel 5
Troubleshooting
I see no data and get a timeout error
Check that SWO is really active - put a logic analyzer or an oscilloscope on the pin and see if it starts toggling after you press start. Usually the pin isn't configured as a trace output or isn't wired to the probe.
I get a lot of error frames (red markers)
The probe can't keep up with the SWO clock. Increase the prescaler and double-check the core frequency - with a wrong value the SWO clock is wrong too.
I get a lot of delayed frames (yellow markers)
You're close to the bandwidth limit of the probe. Disable the channels you don't need, or lower the prescaler as long as no error frames show up.