---
title: Hardware Setup
description: Wiring debug probes, choosing SWD vs JTAG, and OpenOCD configuration
sidebar:
  order: 1
---

This guide covers the physical and configuration setup needed before mcjtag can talk
to your target. It assumes you already have a debug probe and a target board — if you
are looking for a recommendation, the [DAP-Link + Blue Pill kit](https://www.amazon.com/dp/B0D93ZFVPY)
is what mcjtag is developed against.

## SWD vs JTAG

Both are debug transport protocols supported by ARM cores. The choice depends on
your hardware and what you need to do.

| Feature | SWD | JTAG |
|---|---|---|
| Signal count | 2 (SWDIO + SWCLK) | 4+ (TDI, TDO, TMS, TCK) |
| Pin budget | Lower — fits on small boards | Higher — needs a header or adapter |
| Chain scanning | Single target only | Multiple devices on one chain |
| Speed | Generally equal | Generally equal |
| Chip support | ARM Cortex-M/A/R only | ARM, RISC-V, FPGA, any JTAG device |
| Recommendation | Use for most Cortex-M work | Use when you need chain scanning or non-ARM targets |

If your target is an ARM Cortex-M and you only have one chip to debug, SWD is
simpler. If you have multiple devices on a chain, or your target is RISC-V or
an FPGA, use JTAG.

## Wiring

See [Connector Standards](/reference/connectors/) for pinout diagrams, part numbers, and probe-to-connector compatibility.

### SWD (minimum connections)

| Probe Pin | Target Pin | Notes |
|---|---|---|
| SWDIO | SWDIO | Bidirectional data line |
| SWCLK | SWCLK | Clock, driven by the probe |
| GND | GND | **Required** — the most common wiring mistake is a missing ground |
| 3.3V | VCC | Only if the target needs power from the probe. Many boards have their own supply. |

### JTAG (minimum connections)

| Probe Pin | Target Pin | Notes |
|---|---|---|
| TDI | TDI | Test Data In — serial data from probe to target |
| TDO | TDO | Test Data Out — serial data from target to probe |
| TMS | TMS | Test Mode Select — controls the TAP state machine |
| TCK | TCK | Test Clock — driven by the probe |
| GND | GND | **Required** |
| nRST | RESET | Optional but recommended. Allows the probe to reset the target. |

### Common wiring mistakes

- **Missing GND** — The debug interface will not work without a shared ground reference.
  If you see "no JTAG TAPs found" or "target not examined yet", check ground first.
- **Swapped TDI/TDO** — These are named from the perspective of the *target*. TDI goes
  into the target, TDO comes out. Some probe boards label them from their own perspective,
  which reverses the sense.
- **nRST floating** — If the target has a reset pin that is not connected to the probe,
  `reset_halt` and `reset_run` may not work reliably. Use a pull-up if you cannot wire it.

## Common debug probes

### DAP-Link (CMSIS-DAP)

Budget-friendly open-source probe. Many USB dongles and dev boards include a DAP-Link
interface. mcjtag ships with example configs for this probe.

```tcl
source [find interface/cmsis-dap.cfg]
transport select swd
adapter speed 1000
source [find target/stm32f1x.cfg]
```

Supports both SWD and JTAG depending on the firmware variant.

### ST-Link

Built into STMicroelectronics Nucleo and Discovery boards. Also available as a
standalone USB dongle (ST-Link/V2, ST-Link/V3).

```tcl
source [find interface/stlink.cfg]
transport select hla_swd
adapter speed 1000
source [find target/stm32f4x.cfg]
```

Note: ST-Link uses a proprietary protocol (`hla_swd` or `hla_jtag`), which has
some limitations compared to CMSIS-DAP. For example, you cannot do raw JTAG
shift operations through `jtag_shift()`.

### J-Link

Professional probe from Segger. Fast, reliable, and well-supported. Requires
the J-Link software package to be installed alongside OpenOCD.

```tcl
source [find interface/jlink.cfg]
transport select swd
adapter speed 4000
source [find target/nrf52.cfg]
```

### FTDI-based adapters

Various low-cost adapters based on FTDI chips (FT2232H, FT232H). Configuration
depends on the specific board layout.

```tcl
source [find interface/ftdi/olimex-arm-usb-ocd-h.cfg]
transport select jtag
adapter speed 2000
source [find target/stm32f1x.cfg]
```

## OpenOCD configuration

An OpenOCD config file has four logical sections. The order matters.

```tcl
# 1. Interface — what debug probe are you using?
source [find interface/cmsis-dap.cfg]

# 2. Transport — SWD or JTAG?
transport select swd

# 3. Speed — adapter clock in kHz. Start low and increase if stable.
adapter speed 1000

# 4. Target — what chip is being debugged?
source [find target/stm32f1x.cfg]
```

### Finding the right target config

OpenOCD ships with configs for hundreds of chips. Common ones:

| Chip Family | Config File |
|---|---|
| STM32F1 (Blue Pill, etc.) | `target/stm32f1x.cfg` |
| STM32F4 (Nucleo-F4, etc.) | `target/stm32f4x.cfg` |
| STM32H7 | `target/stm32h7x.cfg` |
| nRF52 (Nordic) | `target/nrf52.cfg` |
| RP2040 (Raspberry Pi Pico) | `target/rp2040.cfg` |
| ESP32 | `target/esp32.cfg` |
| GD32F1 (GigaDevice) | `target/stm32f1x.cfg` (compatible) |
| Generic Cortex-M | `target/cortex_m.cfg` |

If you are unsure which config to use, `target/cortex_m.cfg` works for any
ARM Cortex-M device. You lose chip-specific flash programming support, but
all register and memory operations work.

To find configs on your system:

```bash
find /usr/share/openocd/scripts/target -name "*.cfg" | sort
```

### Adapter speed

Start at `1000` kHz (1 MHz). If you get reliable connections, you can increase to
`4000` or higher. If you see errors or intermittent failures, drop to `100`.

Long wires, breadboard connections, and noisy environments all degrade signal
integrity and may require lower speeds.

### Using mcjtag's auto-spawn

Instead of starting OpenOCD manually, set `OPENOCD_CONFIG` and mcjtag handles it:

```bash
# Pass the config file path
OPENOCD_CONFIG=/path/to/my-board.cfg uvx mcjtag
```

mcjtag will start OpenOCD as a subprocess, connect to it, and stop it when the
session ends. The config file should be a complete OpenOCD config (interface +
transport + speed + target).

You can also pass host and port for an existing OpenOCD instance:

```bash
OPENOCD_HOST=192.168.1.100 OPENOCD_PORT=6666 uvx mcjtag
```

### Verifying the setup manually

Before involving mcjtag, confirm OpenOCD works on its own:

```bash
openocd -f /path/to/your/config.cfg
```

Healthy output looks like:

```
Info : CMSIS-DAP: SWD supported
Info : CMSIS-DAP: FW Version = 0254
Info : clock speed 1000 kHz
Info : SWD DPIDR 0x1ba01477
Info : stm32f1x.cpu: Cortex-M3 r1p1 processor detected
Info : stm32f1x.cpu: target has 6 breakpoints, 4 watchpoints
```

If OpenOCD fails here, mcjtag will also fail. Fix the OpenOCD setup first.
