ITM
ITM
Category: Debug/Programming
Overview
ITM (Instrumentation Trace Macrocell) provides non-invasive software-generated trace via the SWO pin on ARM Cortex-M3/M4/M7/M33. It enables printf-style debug output, RTOS event logging, and performance measurement without a UART — just the standard debug connector.
1. Theory & Fundamentals
- Available on all ARM Cortex-M3/M4/M7/M33
- 32 software stimulus ports (ITM_STIM0–31)
- Output: SWO pin (multiplexed with ETM and DWT)
- SWO speed: 2–4 Mbps typical; up to 64 Mbps
- Encoding: Manchester or NRZ
- Non-blocking: Writes silently ignored if no debugger connected
- Used by: SEGGER SystemView, Percepio Tracealyzer, ARM MDK
2. Frame / Packet Structure
ITM Packet over SWO:
Source Packet Header:
SS(2b): 01=1B, 10=2B, 11=4B payload
Addr(5b): Stimulus port 0–31
Bit0=1: Instrumentation packet
Example: Write 'A' (0x41) to port 0:
Header: 0x03 (port 0, 1 byte)
Payload: 0x41
Timestamp packet: 0b0111_DDDD where D=delta
Sync packet: 0x00×5 then 0x80
3. Protocol Mechanics
- Write to ITM_STIM[n]: If ITM enabled and port enabled → SWO output
- Non-invasive check: Test TER bit; skip silently if debugger absent
- Overflow: Emit overflow packet when TPIU FIFO full; data lost
- Multiple ports: Port 0 = text/printf; 1-31 = structured binary data
- Atomic: 4-byte write to PORT[n].u32 is atomic timestamp-safe
4. Hardware Implementation
- SWO pin: Available on standard 10-pin Cortex Debug or 20-pin connector
- Debug probes: J-Link (SWO Viewer), ST-Link V2+, CMSIS-DAP with SWO
- No extra hardware vs ETM — same debug connector
- Oscilloscope: Verify SWO signal at configured NRZ/Manchester rate
- J-Link RTT: Alternative via shared memory (any probe, no SWO needed)
5. Register-Level / Configuration
void ITM_Init(uint32_t swo_hz) {
// Configure TPI (Trace Port Interface)
TPI->ACPR = SystemCoreClock / swo_hz - 1;
TPI->SPPR = 2; // NRZ encoding
TPI->FFCR = 0x100; // Enable formatter
// Unlock and enable ITM
ITM->LAR = 0xC5ACCE55;
ITM->TCR = ITM_TCR_ITMENA_Msk
| (1UL << ITM_TCR_TRACEID_Pos);
ITM->TER = 0xFFFFFFFF; // All ports enabled
ITM->TPR = 0; // All ports privileged
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
}
void ITM_PutChar(uint8_t ch) {
if(ITM->TCR & ITM_TCR_ITMENA_Msk)
if(ITM->TER & 1)
while(!ITM->PORT[0].u32);
ITM->PORT[0].u8 = ch;
}
6. Driver / Software Development
// Retarget printf to ITM (GCC)
int _write(int fd, char *ptr, int len) {
for(int i=0;i<len;i++) ITM_PutChar(ptr[i]);
return len;
}
// Structured binary on port 1
void ITM_LogU32(uint32_t val) {
while(!ITM->PORT[1].u32);
ITM->PORT[1].u32 = val; // Atomic 4-byte write
}
// Cycle timing on port 2
uint32_t t0 = DWT->CYCCNT;
do_work();
ITM->PORT[2].u32 = DWT->CYCCNT - t0;
7. Debugging & Testing
- J-Link SWO Viewer: Simple text display via port 0
- SEGGER Ozone: Full ITM decode with timestamps
- STM32CubeIDE SWV Trace: Built-in ITM console
- Common issues: SWO baud mismatch; TPI not configured before ITM; printf blocks if full
- Check SWO pin not used as GPIO
8. Real-World Applications
- Printf debug without UART
- RTOS event logging (SEGGER SystemView, Tracealyzer)
- Cycle-accurate performance measurement
- CI/CD firmware test assertions
- Production field diagnostics (safe read-only)
9. Advanced Topics & Edge Cases
- SEGGER RTT: Shared memory alternative; works without SWO; any J-Link probe
- ITM vs UART: ITM silent when no debugger; UART always transmits
- ITM overflow: If written too fast, data lost; add busy-wait or drop non-critical
- RTOS tracing: SystemView uses ITM ports for task events, ISR logging
- Production: ITM reads are zero-cost if debugger absent
10. Standards & Variants
| Method | Probe | Works standalone | Speed |
|---|---|---|---|
| ITM/SWO | SWO-capable | No (silent) | ~4 Mbps |
| SEGGER RTT | Any J-Link | Yes | Very fast |
| UART | USB-UART | Yes | 3 Mbps |
| Semihosting | Any JTAG/SWD | No (halts!) | Slow |
💡 Practical Examples
Ex 1: ITMInit(2000000) then printf("Hello ITM!\n") via retargeted write().
Ex 2: RTOS trace — In traceTASKSWITCHEDIN: ITM->PORT[1].u32 = (uint32_t)pxCurrentTCB;
Ex 3: Timing: DWT->CYCCNT=0; fn(); ITM->PORT[2].u32=DWT->CYCCNT;
🧪 Practice Questions
Beginner: 1) SWO pin? 2) How many ports? 3) Works without debugger? 4) ITM vs UART? 5) View with what tool?
Intermediate: 1) ITM_Init() registers. 2) Retarget printf GCC. 3) Non-blocking write. 4) ITM vs RTT. 5) Binary logging port 1.
Advanced: 1) Custom ITM packet decoder. 2) ITM + DWT profiling. 3) SystemView-compatible RTOS logging. 4) Minimal overhead comparison. 5) Safe production ITM.
Checklist
- [ ] Configure ITM and TPI registers
- [ ] Retarget printf to ITM
- [ ] View output in J-Link SWO Viewer
- [ ] Send structured data on port 1
- [ ] Use DWT with ITM for timing
- [ ] Set up SEGGER SystemView RTOS tracing
- [ ] Handle port busy correctly
- [ ] Compare ITM vs RTT
- [ ] Decode ITM packets manually
- [ ] Implement safe production-mode ITM