Skip to content

Enable Serial Wire Output (SWO) for debug tracing #41

Open

Description

@emrainey

Summary

SWO (Serial Wire Output) provides a low-cost, single-pin trace channel for debug output via the ITM/TPIU. The hardware infrastructure exists in the codebase but is incomplete — the core trace peripherals are defined and the cortex::swo::emit() API works, but no initialization code connects them to the physical pin.

This issue covers enabling SWO on both the STM32H7 and STM32F4 families used in this project.

Current State

The following already exists (family-independent):

  • modules/cortex/include/cortex/swo.hpp — Public API (cortex::swo::emit() for ports 0–1)
  • modules/cortex/source/swo.cpp — Implementation (blocks on FIFO ready, writes ITM stimulus port)
  • modules/cortex/include/cortex/peripherals/InstructionTraceMacrocell.hpp — Full register maps for ITM, DWT, and TPIU, with extern instances linked in peripherals.cpp
  • modules/cortex/include/cortex/peripherals/DebugSystem.hpp — DEMCR register definition with enable_trace bit (TRCENA)

What's Missing

1. Family-specific DBGMCU register headers

No STM32 DBGMCU register header exists for either family. The key registers and fields differ:

STM32H7 (DBGMCU_CR at 0x5C001004):

Bit Field Purpose
20 TRACECLKEN Enable trace port clock
21 D1DBGCKEN Enable D1 debug clock (trace runs in D1 domain)
28 TRGOEN External trigger output (optional)

Currently reads 0x00000007 — only debug-sleep/stop/standby bits are set.

STM32F4 (DBGMCU_CR at 0xE0042004):

Bit Field Purpose
5 TRACE_IOEN Enable trace port I/Os
6:7 TRACE_MODE 0b00=async, 0b01=async SWO/NRZ, 0b10=async SWO/Manchester, 0b11=parallel
20 TRACECLKEN Enable trace clock (some F4 variants)

Both are defined in their respective SVD files under modules/stm32/scripts/.

2. SWO pin configuration

The SWO pin is the same on both families:

  • Pin: PB3, Alternate Function AF0 (TRACESWO)
  • Mode: Alternate Function
  • Output Type: Push-Pull
  • Speed: Very High
  • Pull: None

On the Nucleo-H753ZI, PB3 is also used as SPI1_SCL on the Arduino header (solder-bridge SB63/SB64 isolates it). On some STM32F4 packages PB3 may also serve as JTDO — board-specific handling may be needed.

3. System-level trace initialization sequence

A new cortex::initialize::trace() function that performs:

  1. Core: Set DEMCR.TRCENA via DebugSystem::ExceptionMonitorControl.enable_trace
  2. Family-specific DBGMCU:
    • H7: DBGMCU_CR.TRACECLKEN = 1, D1DBGCKEN = 1
    • F4: DBGMCU_CR.TRACE_IOEN = 1, TRACE_MODE = 0b01 (async NRZ)
  3. GPIO: Configure PB3 as AF0 push-pull very high speed
  4. TPIU:
    • TPIU_ACPR.SWOSCALER = (trace_ref_clock / desired_baud) - 1
    • TPIU_SPPR.Protocol = AsyncNRZ (preferred over Manchester)
  5. DWT:
    • DWT_CTRL.CYCCNTENA = 1 (cycle counter)
    • DWT_CTRL.PCSAMPLENA = 1 (periodic PC sampling)
  6. ITM:
    • ITM_TCR.ITMENA = 1, SWOENA = 1, DWTENA = 1, TSENA = 1
    • ITM_TER = enable stimulus ports 0 and 1
    • Unlock via ITM_LAR = 0xC5ACCE55

4. Clock frequency plumbing

The TPIU SWO baud prescaler formula is the same for both:

SWOSCALER = (trace_ref_clock / desired_baud) - 1
Family Trace ref clock Typical 2 MHz SWO prescaler
H7 rcc_hclk6 200 MHz 99
F4 HCLK 168 MHz 83

The clock tree must be initialized before trace init, since the prescaler depends on the measured frequency.

Measured Live Register Values (from J-Link on H753)

Register Value Key bits
DBGMCU_CR (H7) 0x00000007 TRACECLKEN=0, TRGOEN=0
DBGMCU_CR (F4) TBD TBD
ITM_TCR 0x00000001 ITMENA=1, SWOENA=0, DWTENA=0, TSENA=0
ITM_TER 0x00000003 ports 0,1 enabled — but no output path
TPIU_ACPR 0x00000000 prescaler=0 — not configured
TPIU_SPPR 0x00000000 protocol=Manchester — fallback
DEMCR 0x01000000 TRCENA=1 — core-level trace enabled
DWT_CTRL 0x400003FF CYCCNTENA=1, cycle counter running
DWT_CYCCNT 15742475 free-running

The ITM and DWT are partially initialized (likely by debugger or reset defaults), but the system-level path to the pin is gated off.

Acceptance Criteria

  • Common cortex::initialize::trace() function handles both H7 and F4
  • Family-specific DBGMCU register headers under modules/stm32/include/stm32/
  • SWO stimulus port 0 emits characters visible via J-Link SWO viewer on both platforms
  • SWO baud rate is configurable (default 2 MHz)
  • DWT cycle counter and PC sampling packets appear on SWO
  • Works after cortex::system::main() in normal startup
  • No interference with existing PB3 functionality when SWO is not enabled

Activity

  1. emrainey commented on Jul 27, 2026

    @emrainey
    OwnerAuthor

    The issue as written covers the STM32H7 family only. The STM32F4 family differs in several ways and is not yet tracked:

    F4 vs H7 differences:

    • DBGMCU_CR address: 0xE0042004 (F4) vs 0x5C001004 (H7)
    • Trace enable: TRACE_IOEN (bit 5) + TRACE_MODE (bits 6:7) on F4, vs TRACECLKEN (bit 20) on H7
    • TRACE_MODE=0b01 selects async SWO on F4 (SWO on PB3, AF0, same pin)
    • Trace reference clock: HCLK (~168 MHz) on F4 vs HCLK6 (~200 MHz) on H7
    • The DBGMCU peripheral is in the STM32F405/F407 SVDs under modules/stm32/scripts/ — the CR register has TRACE_IOEN and TRACE_MODE fields
    • SWO pin PB3 may conflict with JTDO on some F4 packages; needs board-specific handling

    F4 boards in the project: stm32_f4ve_v2 and netduinoplus2

  2. self-assigned this
    on Aug 12, 2026
  3. emrainey commented on Aug 13, 2026

    @emrainey
    OwnerAuthor

    Implemented in PR #56 (branch issue-41).

    The ST SWO/SWTF path is now programmed from the vendor clocks():

    • DBGMCU TRACECLKEN/D1DBGCKEN/D3DBGCKEN
    • SWO block: AsyncNRZ + CODR=43 (100 MHz TRACECK / 2.24 MBaud)
    • SWTF funnel: ENSO enabled
    • PB3 configured as TRACESWO (AF0)

    Verified on the Nucleo-H753ZI via single-session breakpoint dump at main entry: DBGMCU_CR=0x00700007, SWO_CODR=0x2b, SWO_SPPR=2, SWTF_CTRL=0x301.

    Note: a J-Link reconnect clobbers DBGMCU_CR to 0x07 (unclocking the D3 debug domain), so SWO reads must be done within one session.

    Deferred:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions