Back

ITM

Loading views...

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

  1. Printf debug without UART
  2. RTOS event logging (SEGGER SystemView, Tracealyzer)
  3. Cycle-accurate performance measurement
  4. CI/CD firmware test assertions
  5. 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