Skip to content

Debug Interfaces: UART, JTAG & Trace

Advanced11 min read
Assumes: 10.1 Debug Bench
TL;DR

Three hardware interfaces give you visibility below the OS: UART (serial console — passive, always-on log stream at 115200n8), JTAG/SWD (CPU debug — halt, step, inspect registers and memory), and CoreSight Trace (non-invasive execution recording via ETM/ETF/ETR). Each has different intrusiveness, bandwidth, and mode availability. UART is your daily tool. JTAG is for hard crashes. CoreSight is for performance analysis. Debug policy fuses on production boards can disable JTAG and restrict trace — always know your board’s fuse state before planning a debug session.

Every software debug technique in this curriculum — QFIL over EDL, <GlossaryTooltip client:load id="adb">adb logcat</GlossaryTooltip>, QNX slog2info, crashdump collection, TRACE32 post-mortem — ultimately rides on one of three physical interfaces. On SA8155P/SA8295P cockpit platforms running QNX + AAOS under QHEE, you cannot assume all three are available on every board. This page explains what each interface does, how to wire it, when to reach for it, and what fuse policy can take away. When software debug tools lie to you (and they will), hardware interfaces tell the truth.

The serial console is the most important debug interface on an automotive bench. Always connect UART first. It requires no special probe, works from the first PBL instruction, and costs less than a lunch.

Qualcomm automotive standard: 115200n8 (115200 baud, 8 data bits, no parity, 1 stop bit, no flow control) at 3.3V TTL — not RS-232 ±12V. Connect a USB-to-UART adapter (FTDI FT232RL preferred; CP2102/CH340 work) to the board debug UART header. Pin order on ADP boards: TX, RX, GND (check schematic — carriers may label from DUT perspective).

Wiring rule: Connect GND first, then TX/RX. UART TX on the adapter connects to RX on the board, and vice versa (crossover). If you see nothing, swap TX/RX once before chasing software.

On QHEE hypervisor ADP boards, QNX and AAOS share the same physical UART. Output is interleaved on one stream. Learn to read the prefixes:

Source Prefix / Format Example
PBL / XBL / ABL Stage-specific banners, no Linux timestamp B - 12345678 PBL...
QNX Plain text, no timestamp prefix Starting QNX Neutrino...
AAOS (Linux) [seconds.microseconds] kernel timestamp [ 3.452891] init: ...
Firehose (EDL) XML command/response over UART (secondary to USB) <?xml version="1.0"?>

When debugging a multi-VM boot hang, scroll the UART capture and mark which stage last printed. That tells you whether the failure is in XBL, QHEE guest load, QNX IFS, or AAOS kernel init — without guessing from USB enumeration alone.

Terminal window
# Linux — picocom (Ctrl-A Ctrl-X to exit), minicom, or screen
picocom -b 115200 /dev/ttyUSB0
minicom -D /dev/ttyUSB0 -b 115200
screen /dev/ttyUSB0 115200
# macOS — device usually at /dev/cu.usbserial-*
picocom -b 115200 /dev/cu.usbserial-XXXX
screen /dev/cu.usbserial-XXXX 115200
# Always tee to a timestamped log (Linux)
picocom -b 115200 /dev/ttyUSB0 | tee -a uart_$(date +%Y%m%d_%H%M%S).log
# macOS without picocom
script -q uart_$(date +%Y%m%d_%H%M%S).log screen /dev/cu.usbserial-XXXX 115200

The BSP device tree controls whether UART is enabled and which port is the boot console. Page 5.6 covers the full DTS hierarchy; the debug-relevant nodes are:

/ {
chosen {
stdout-path = "serial0:115200n8";
};
};
&serial0 {
status = "okay";
compatible = "qcom,geni-debug-uart";
};
Symptom DTS Check
UART silent after flashing production BSP status = "disabled" on debug UART node
Garbage at 115200 Wrong stdout-path baud suffix or wrong QUP instance
Works on ADP, not carrier OEM overlay disabled debug UART for production

UART works in all boot modes, including EDL. Firehose primarily uses USB (QDLoader 9008), but XML programmer commands can also traverse UART on some platforms — useful when USB routing is broken but serial is alive.

Think About It

You need to debug a boot failure that happens before UART output starts. What interface can help?

Reveal Answer

JTAG (or SWD if exposed) through the DAP is your only option below UART — power off, attach TRACE32 or OpenOCD, then halt at reset and inspect PC/register state before any printk runs. Also scope VDD_CX and the 19.2 MHz reference crystal — silent UART often means PMIC sequencing or clock failure, not a missing BSP. Confirm fuse-open status first; JTAG_DISABLE blocks this path permanently on production units.

When UART shows nothing useful — boot hangs before any print, CPU exception before OS init, or SDI with cores halted — you need CPU-level debug. JTAG and SWD connect to the SoC’s DAP (Debug Access Port), the gateway into ARM debug logic.

JTAG (Joint Test Action Group) uses five signals:

Signal Direction Purpose
TDI Host → Target Test Data In — serial data into the scan chain
TDO Target → Host Test Data Out — serial data out of the scan chain
TMS Host → Target Test Mode Select — state machine control
TCK Host → Target Test Clock — synchronizes all JTAG operations
TRST Host → Target Test Reset (optional) — async reset of debug logic

Through the DAP, a debugger can:

  • Halt and resume CPU cores
  • Single-step instructions
  • Read and write general-purpose registers
  • Read and write memory (including device registers)
  • Set hardware breakpoints and watchpoints
  • Inspect cache and TLB state (debugger-dependent)

SWD (Serial Wire Debug) replaces the four data/clock JTAG wires with two:

Signal Purpose
SWDIO Bidirectional data
SWCLK Clock

SWD provides the same DAP capabilities as JTAG with fewer pins. Not all Qualcomm automotive boards expose SWD — check your ADP schematic. Many automotive reference boards use the standard 20-pin ARM JTAG header instead.

On SA8155P/SA8295P, the JTAG scan chain includes multiple cores and subsystems. The debugger must select the correct TAP (Test Access Port) in the chain before halt/step operations take effect on the intended core.

flowchart LR
    PROBE["Debug Probe\n(TRACE32 / OpenOCD)"]
    DAP["DAP\n(Debug Access Port)"]
    C0["Kryo Core 0"]
    C1["Kryo Core 1"]
    C2["Kryo Core 2"]
    C3["Kryo Core 3"]
    C4["Kryo Core 4"]
    C5["Kryo Core 5"]
    C6["Kryo Core 6"]
    C7["Kryo Core 7"]
    DSP["Hexagon DSP\n(if accessible)"]
    CS["CoreSight\n(ETM, ETF, funnel)"]

    PROBE --> DAP
    DAP --> C0 --> C1 --> C2 --> C3 --> C4 --> C5 --> C6 --> C7 --> DSP --> CS

Practical implication: Attaching TRACE32 and halting “the CPU” may halt core 0 while your QNX driver runs on core 3. Always verify which core owns the code under investigation. Qualcomm T32 scripts for SA8155P/SA8295P pre-configure core selection for common automotive bring-up tasks.

Tool Type Automotive Use
Lauterbach TRACE32 Commercial (industry standard) Full JTAG + trace, Qualcomm scripts, SDI post-crash
ARM DSTREAM Commercial JTAG/SWD + CoreSight trace
OpenOCD Open source Basic halt/step/memory — limited Qualcomm script support
Qualcomm T32 scripts Vendor automation Pre-built SA8155P/SA8295P core maps, TZ-aware attach sequences

Use JTAG when UART fails you: boot hang before first character (ROM/XBL stuck), CPU exception before OS init (need faulting PC), SDI with halted cores, or register-level MMIO debug the driver never logs.

Never connect or disconnect JTAG with the board powered on. Hot-plugging can damage the DAP and permanently disable debug access on that SoC. Power off the board, attach the probe, power on, then connect from the host debugger. Reverse the sequence on teardown.

JTAG stops the CPU to inspect state. CoreSight trace records execution without halting — a flight recorder at full speed. This is how you answer “where did those 16 milliseconds go?” or “what was the exact instruction sequence before the race?”

Component Abbreviation Role
Embedded Trace Macrocell ETM One per CPU core — records instruction flow (branch addresses, exceptions)
Embedded Trace FIFO ETF On-chip SRAM buffer — holds trace data when external bandwidth is limited
Embedded Trace Router ETR Routes trace data to system memory (DDR) or external trace port
Trace Funnel — Merges multiple ETM streams into one downstream path
TPIU — Trace Port Interface Unit — drives off-chip trace pins to external probe
flowchart TB
    subgraph cores ["CPU Cores"]
        C0["Kryo Core 0"]
        C1["Kryo Core 1"]
        C2["Kryo Core 2"]
        C3["Kryo Core 3"]
    end

    subgraph etm ["ETM (one per core)"]
        ETM0["ETM0"]
        ETM1["ETM1"]
        ETM2["ETM2"]
        ETM3["ETM3"]
    end

    FUNNEL["Trace Funnel"]
    ETF["ETF\n(on-chip buffer)"]
    ETR["ETR\n(router)"]
    DDR["DDR Trace Buffer\n(system memory)"]
    TPIU["TPIU\n(external port)"]
    PROBE["Trace Probe\n(PowerTrace / DSTREAM)"]

    C0 --> ETM0
    C1 --> ETM1
    C2 --> ETM2
    C3 --> ETM3

    ETM0 --> FUNNEL
    ETM1 --> FUNNEL
    ETM2 --> FUNNEL
    ETM3 --> FUNNEL

    FUNNEL --> ETF
    FUNNEL --> ETR
    ETR --> DDR
    ETR --> TPIU
    TPIU --> PROBE
    ETF --> PROBE

Repeat the ETM-per-core pattern for all eight Kryo cores on SA8155P/SA8295P. Hexagon DSP trace is a separate path — availability depends on fuse policy and BSP configuration.

Problem Trace Approach
Performance profiling Record ETM for 10 seconds during lag — decode to see hot functions
Race condition Capture instruction sequence on both cores around the shared variable access
Interrupt latency Measure cycles from IRQ assert to handler entry via timestamped trace
Scheduler jitter Compare QNX thread switches against AAOS vCPU scheduling on adjacent cores
Requirement Notes
Trace-capable probe Lauterbach PowerTrace, ARM DSTREAM — standard JTAG probes often lack trace bandwidth
Trace port on board Not all ADP boards expose TPIU pins; check schematic for MIPI STP or parallel trace header
Trace decode license ETM raw packets need instruction decode against your exact binary — symbols required
BSP trace enable Some production BSPs disable ETM at boot via debug policy

On the AAOS side, CoreSight integrates with the Linux perf subsystem:

Terminal window
# List CoreSight devices
ls /sys/bus/coresight/devices/
# perf with CoreSight (platform and kernel config dependent)
perf record -e cs_etm/@tmc_etf0/ -- sleep 5
perf report

QNX-side trace typically goes through vendor tools (Momentics + JTAG) rather than sysfs. For hypervisor debugging, decide which guest’s binary you need symbols for before starting capture — mixing QNX and AAOS trace decode in one session requires separate symbol files.

Interface Bandwidth Intrusiveness Works in Crashdump? Needs Special HW? Setup Time Typical Use
UART Low (~11.5 KB/s) None (passive) Yes USB-UART adapter (~$5) 1 minute Boot logs, OS console, daily debug
JTAG Medium Halting (stops CPU) Yes (with SDI) Lauterbach/DSTREAM ($$$) 15 minutes Register inspect, hard crash debug
SWD Medium Halting Yes (with SDI) Debug probe 10 minutes Same as JTAG, fewer pins
CoreSight Trace High (GB/s internal) None (non-invasive) No Trace probe ($$$$) 30 minutes Performance profiling, race conditions

Selection heuristic: Start UART. Escalate to JTAG when UART is silent or SDI is active. Add trace only when you need timing or instruction-level history without stopping execution.

Mental Model

UART is a security camera — watches passively, records everything it sees, never changes what happens. JTAG is a freeze-frame button — stops time, lets you examine every detail, but nothing moves while you look. CoreSight trace is a flight recorder — captures everything at full speed; you analyze the recording later.

UART = conversation (text logs). JTAG = brain surgery (CPU halt/step). Trace = surveillance camera (non-intrusive recording).

Memorization trick: UART = Universal, always there. JTAG = Just halted everything. Trace = Total capture, zero halt.

Hardware debug is not a software toggle on production automotive boards. Qualcomm eFuses permanently configure debug policy at manufacturing time.

Fuse / Policy Effect When Blown (Closed)
JTAG_DISABLE DAP locked — no JTAG/SWD attach
ALL_DEBUG_DISABLE Broad debug lockdown — JTAG, some trace, debug auth paths
DEBUG_POLICY_OVERRIDE Enables temporary re-enable via signed debug certificate (OEM-controlled)

Open fuse (development ADP): UART + JTAG + trace enabled (BSP permitting). Closed fuse (production): UART usually retained; JTAG disabled; trace restricted.

Some OEM programs issue a signed debug certificate that temporarily re-enables JTAG via DEBUG_POLICY_OVERRIDE — requires fuse support, OEM cert matched to SOC ID, and TRACE32 with Qualcomm pack. Without all three, a fuse-closed board stays closed.

Fuse State UART JTAG / SWD CoreSight Trace Crashdump
Open (dev ADP) Yes Yes Yes (if exposed) Yes (policy permitting)
Closed (production) Usually yes No Restricted / No Policy-dependent
Closed + debug cert Yes Yes (temporary) Policy-dependent Yes
flowchart TD
    START["Can I use JTAG?"]
    FUSE{"Check fuse state"}
    OPEN["Open (dev fuse)\n→ Yes, JTAG available"]
    CLOSED{"Closed (production fuse)"}
    OVERRIDE{"Debug policy override\nenabled?"}
    CERT{"Have signed debug\ncertificate?"}
    YES["Yes — load cert in TRACE32\n→ JTAG temporarily enabled"]
    NO["No — JTAG permanently disabled\nUse UART + crashdump instead"]

    START --> FUSE
    FUSE -->|"Open"| OPEN
    FUSE -->|"Closed"| CLOSED
    CLOSED --> OVERRIDE
    OVERRIDE -->|"No"| NO
    OVERRIDE -->|"Yes"| CERT
    CERT -->|"Yes"| YES
    CERT -->|"No"| NO

Software can also restrict debug without fuses — a production BSP may disable debug UART in device tree or set debug_policy=0 in boot config. Always check both fuse state and BSP variant (debug vs production).

Where You'll See This

UART setup checklist — run this at the start of every bench session:

  1. Power off board before connecting UART cable.
  2. Connect GND first, then TX/RX (crossover: adapter TX → board RX).
  3. Identify serial device:
    • Linux: ls /dev/ttyUSB* or dmesg | tail after plug-in
    • macOS: ls /dev/cu.usb*
  4. Open terminal at 115200 8N1, no flow control.
  5. Start log capture immediately:
    Terminal window
    picocom -b 115200 /dev/ttyUSB0 | tee -a uart_$(date +%Y%m%d_%H%M%S).log
  6. Power on board — confirm PBL banner within 2 seconds.
  7. Mark timestamps in your notes when changing boot mode (EDL entry, fastboot flash, OTA trigger).

Rule: Always tee UART to a timestamped log file. The one time you don’t is when the intermittent crash reproduces.

Common Gotcha

Beginner thinks JTAG is just for programming flash chips. Reality: it’s a full CPU debug interface — halt/step execution, inspect registers and memory, set hardware breakpoints, and capture CoreSight trace. Programming is one use case; post-mortem crash analysis and live debugging are the daily ones.

If JTAG stops connecting on a board that used to work, check three things in order:

  1. Is the board powered on? JTAG needs target power — the probe does not power the SoC.
  2. Did someone flash a production BSP? Software debug disable in device tree or boot policy blocks DAP even on fuse-open boards.
  3. Were fuses blown? Permanent disable — no software workaround without a debug policy override certificate.

Number 3 is irreversible on that unit. If fuse-closed, stop trying JTAG and pivot to UART + crashdump analysis.

Deep Dive

ARM debug architecture versions define what the DAP, breakpoints, and trace macrocells can do. Qualcomm implements these across the Kryo clusters on SA8155P and SA8295P with different CoreSight generations.

Generation SA8155P SA8295P Key Differences
CoreSight v2 architecture v3 architecture v3 adds improved funnel routing, larger ETF buffers, better multi-core synchronization
Debug (ARMv8-A) v8-A Debug architecture v8-A Debug architecture Self-hosted debug, OS-aware breakpoints, reduced invasive debug in secure world
ETM version ETMv4.x class ETMv4.x class (expanded) More trace bandwidth, better timestamp correlation across cores

What changed from CoreSight v2 (SA8155P) to v3 (SA8295P):

  • Larger on-chip trace buffers (ETF) — longer capture windows before overflow, critical for intermittent automotive bugs.
  • Improved cross-triggering — one core’s breakpoint can trigger trace on another core (essential for QNX/AAOS inter-VM race debugging).
  • Better integration with system memory trace (ETR → DDR) — store more trace in DDR when TPIU is not wired, at the cost of memory bandwidth.
  • Stricter secure-world gating — TrustZone can lock ETM for secure cores independently; automotive programs often restrict trace in production fused builds.

Practical impact: Scripts and trace decode profiles built for SA8155P do not always transfer cleanly to SA8295P. Update TRACE32/QTI packs when moving between generations. For day-to-day work, the user-visible difference is trace buffer depth and multi-core correlation — not the basic JTAG halt/step workflow, which remains the same DAP model.

Connect the Dots

Page 5.6 (BSP) configures UART and JTAG enablement in device tree — stdout-path, qcom,geni-debug-uart, and debug policy nodes. Page 8.4 (secure boot) explains fuse blowing and why production boards restrict JTAG. Page 10.1 (debug bench) maps physical connector pinouts to these interfaces. Page 10.2 (boot modes) lists which interfaces work in EDL, normal HLOS, crashdump, and SDI. Page 10.4 (software debug tools) covers TRACE32, OpenOCD, perf, and QNX Momentics — the host-side tools that speak these hardware protocols.

Check Your Understanding

1. What is the role of the ETM (Embedded Trace Macrocell) in CoreSight?

Recall

2. SWD provides the same DAP capabilities as JTAG but uses how many primary data/clock wires?

Recall

3. UART shows garbage characters after a BSP flash. What should you try first?

Applied

4. Boot hangs with zero UART output after power-on. PBL never prints. Which debug interface should you use next?

Applied

5. A production-fused SA8295P board has JTAG_DISABLE blown. Your team has no OEM debug certificate. Which statement is true?

Synthesis

Connects to: Module 8 — Secure Boot

6. You need non-invasive instruction-level history on two Kryo cores during a QNX/AAOS race condition. Trace Funnel and TPIU are wired on the ADP. Which CoreSight path and host tool fit?

Synthesis

Connects to: Module 6 — Kernel Internals

Further Reading