On this page

Debug and Programming Interfaces

JTAG/SWD are the interfaces for taking over the CPU from the outside (breakpoints, single-stepping, flashing, boundary scan), while DFU and UART bootloaders are the chip’s built-in flashing channels. Use SWD for development, flash the bootloader first for mass production followed by batch DFU, and use OTA for field upgrades—different stages use different interfaces.

Overview

The "interfaces" around an MCU actually serve three different purposes: debugging (pausing the CPU, breakpoints, single-stepping, reading/writing memory), flashing (writing firmware into Flash), and production testing (verifying soldering without running firmware). To understand each interface, first determine which category it belongs to and what prerequisites it depends on:

InterfacePinsCapabilitiesPrerequisites
JTAG4~5Debug + Flash + Boundary ScanExternal Debugger
SWD2Debug + Flash (ARM Cortex)External Debugger
UART Bootloader2Flash onlyBuilt into Chip Boot ROM
USB DFU1 USB cableFlash onlyBuilt into Chip Boot ROM
ISP/ICSP6 pinFlash (AVR family)Programmer

Key distinction: JTAG/SWD take over the CPU from the outside—the chip can be debugged and recovered even if it's bricked; DFU/UART bootloaders cooperate with the chip for flashing—no dedicated hardware is needed, but if the firmware misconfigures the boot pins, you won't be able to enter the bootloader.

JTAG (IEEE 1149.1)

Born in the 1980s for testing PCB soldering (Joint Test Action Group), it later became a debugging standard as well.

PinFull NameFunction
TMSTest Mode SelectDrives the internal state machine
TCKTest ClockClock signal
TDITest Data InData input
TDOTest Data OutData output
TRSTTest ResetOptional reset

Multiple chips can be daisy-chained (TDI → TDO → next chip's TDI), allowing one debugger to control the entire board. Voltage must match the target (1.8V~5V), with typical speeds of 1~50MHz.

Among its three uses, boundary scan best reflects its origins: JTAG can directly control/read the voltage levels of every pin on a chip, verifying whether traces between two chips on a PCB are properly soldered without running any firmware—this is the foundation of production line testing. Debugging (pausing CPU, breakpoints, reading/writing memory/Flash) and flashing were capabilities added later.

SWD (Serial Wire Debug)

A streamlined alternative designed by ARM for Cortex: compressing JTAG's 4~5 lines down to 2 lines—SWDIO (bidirectional data) + SWCLK (clock), plus the necessary GND. Debugging capabilities are not compromised: breakpoints/single-stepping/register access, Flash programming, and multi-core debugging via the DP/AP mechanism, with speeds reaching 50MHz+ (CoreSight).

JTAGSWD
Pins4~52
FeaturesFull + Boundary Scan + Daisy ChainDebug + Flash, sufficient for most needs
CoverageAlmost all chips (including FPGA/DSP)ARM Cortex series
PCB FootprintLargeSmall, easy to route two lines

The selection logic is straightforward: always use SWD for Cortex-M development; for non-ARM, complex SoCs, or when boundary scan is needed → use JTAG; if unsure, leave the full JTAG port available (JTAG pins can be multiplexed to output SWD).

Debugger Hardware and OpenOCD

DebuggerInterfacePricePositioning
ST-Link V2SWD$2~10 (clone)First choice for learning STM32
DAP-Link (CMSIS-DAP)SWD+JTAG$5~15Open-source, universal ARM
J-Link (SEGGER)SWD+JTAG$20~1000Professional: fast speed, RTT, unlimited breakpoints
FT2232HJTAG$10~20Versatile companion for OpenOCD
Raspberry Pi PicoSWD$4Becomes a debugger after flashing picoprobe

The hub on the software side is OpenOCD—it translates between third-party tools:

flowchart LR
    GDB["gdb-multiarch<br>(breakpoints/single-stepping/variables)"] <-->|"GDB remote protocol<br>:3333"| O["OpenOCD"]
    O <-->|USB| P["Debugger<br>ST-Link / J-Link / DAP"]
    P <-->|SWD / JTAG| T["Target Chip"]
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg   # Start GDB server
gdb-multiarch firmware.elf
(gdb) target remote :3333

The interface side supports ST-Link/J-Link/DAP-Link/FTDI, etc., and the target side covers almost all ARM + RISC-V + MIPS—it is the de facto standard in the open-source ecosystem.

Built-in Chip Flashing Channels

USB DFU

The chip's Boot ROM (factory-fused, cannot be erased) detects specific conditions and makes the chip enumerate as a USB device, allowing the Host to send firmware directly via USB:

  • STM32: Pull BOOT0 high on power-on → System Memory bootloader
  • nRF52: Specific register values + reset
  • RP2040: Hold BOOTSEL while powering on → appears directly as a USB drive; drag and drop firmware to flash (best DFU experience)

The advantage is zero additional hardware—users only need a USB cable to flash; the disadvantage is that it can only flash, not debug.

UART Bootloader

Also a Boot ROM behavior, but the medium is changed to serial (XMODEM/YMODEM/custom protocol):

  • STM32: System bootloader listens on USART1
  • ESP32: ROM bootloader, esptool enters automatically (or pull GPIO0 low)
  • AVR: Not present at factory; must first flash one using ISP (Arduino bootloader is this)
  • MSP430: BSL

As long as there is a serial port, you can flash, but the cost is speed—115200bps is about 10KB/s, so a few hundred KB of firmware takes tens of seconds.

Three Channels in the Product Lifecycle

flowchart LR
    DEV["Development Phase<br>SWD/JTAG<br>Debug + Flash anytime"] --> FAC["Production Line<br>First flash bootloader via SWD<br>Then batch flash via DFU"]
    FAC --> FIELD["Field<br>APP built-in DFU/OTA<br>User self-service upgrade"]

Logic Analyzer: Bus-Level Debugging

Debuggers solve "where the code is wrong," while logic analyzers solve "what exactly is happening on the lines"—when firmware looks correct but peripherals ignore you, use this to settle the matter. Saleae / DSLogic / PulseView all have built-in protocol decoders: I2C (auto-decode address+data+ACK), SPI (frame-by-frame display), UART (convert to ASCII by baud rate), CAN/LIN, 1-Wire; they also support protocol-level triggering (e.g., "start capturing when address 0x68 appears on I2C").

Typical troubleshooting (using an unresponsive I2C sensor as an example):

flowchart TD
    S["I2C Sensor Not Working"] --> C["Capture SDA/SCL Waveforms"]
    C --> Q{"ACK after Address?"}
    Q -->|No ACK| A["Wrong Address / Wiring Error / Chip Not Powered"]
    Q -->|Has ACK| B{"Register Read/Write Values Correct?"}
    B -->|Incorrect| D["Check Register Timing in Datasheet"]
    B -->|Correct| E["Problem Not on Bus → Return to Firmware Logic"]

SPI Flash instability is similar: capture CS timing, CLK frequency, and data integrity to rule out physical layer issues first. Details of bus protocols can be found in Serial Bus.

Quick Selection Guide

Chip/ScenarioRecommendation
STM32 DevelopmentSWD (ST-Link)
nRF52 DevelopmentSWD (J-Link / DAP-Link)
ESP32 DevelopmentSerial (Built-in bootloader, esptool)
RP2040 DevelopmentSWD or USB Drag-and-Drop
AVR (Arduino)ISP (6-pin)
ARM Linux Kernel DebugJTAG (OpenOCD + GDB)
FPGAJTAG (Vivado/Quartus Built-in)
Field Firmware UpgradeDFU / OTA
Sensor/Peripheral UnresponsiveLogic Analyzer Capture Bus
Production Line TestingJTAG Boundary Scan

References

  • JTAG: IEEE 1149.1 · ARM Debug Interface (ADIv5) Manual
  • OpenOCD: openocd.org/doc
  • SEGGER: wiki.segger.com (RTT/J-Link documentation quality is extremely high)
  • Sigrok/PulseView: sigrok.org (Open-source logic analysis)

Keywords: JTAG, SWD, SWDIO, SWCLK, OpenOCD, DFU, Boot ROM, bootloader, ST-Link, J-Link, DAP-Link, Boundary Scan, Logic Analyzer