Skip to content

Repository files navigation

pico-remote-probe

A network-attached SWD debug probe on a Raspberry Pi Pico 2 (RP2350). It speaks pyOCD's remote-probe protocol over a software 10BASE-T Ethernet link, so a remote pyocd — and therefore GDB — can debug an RP2040/RP2350 target's SWD as if the probe were plugged into the dev machine over USB. Everything runs on one Pico 2; nothing at the remote site but the probe, power, and an Ethernet drop.

  dev machine                                    remote site
  ───────────                                    ───────────
  GDB ⇄ pyocd  ──(line-delimited JSON / TCP)──▶  Pico 2 probe
   │              over software 10BASE-T            ├─ smoltcp TCP servers
   └─ gdb-multiarch ──(GDB RSP / TCP :3333)──────▶  │   :5555 pyOCD · :3333 GDB
      (no host tool)                                │   :5556 console · :5557 OpenOCD
  nc / RTT viewer ──(raw RTT / TCP :5558)─────────▶ │   :5558 RTT (host-free)
      (no host tool)                                └─ SWD engine (PIO)  ──▶ target SWCLK/SWDIO

It also runs a native GDB stub on-probe (:3333): point a bare gdb-multiarch straight at it — no pyOCD, no host gdbserver — and debug both RP2350 cores, set hardware breakpoints + watchpoints, single-step, flash firmware (load), and reset/run, all over the network. That's the Black Magic Probe model: the probe itself speaks GDB's protocol. See Build & use and DESIGN.md §12.

There's also a native on-probe RTT viewer (:5558): the probe finds the target's SEGGER RTT control block in RAM and streams up-channel 0 to the socket, so nc <probe-ip> 5558 tails a running target's RTT log with nothing on the host — no J-Link, no pyOCD, no OpenOCD. RTT is non-intrusive (it polls the ring buffers via background memory reads while the core runs; it never halts). See DESIGN.md §13.

By default: no Wi-Fi, no USB-Ethernet dongle, no host at the remote end — just bit-banged 10BASE-T (PIO + DMA + an RS-485 transceiver + magnetics) bridged to smoltcp, with a PIO SWD engine on the side. Pure Rust, no_std, on the RP2350's Hazard3 RISC-V cores.

On a Pico 2 W there's also an optional Wi-Fi transport (--features wifi) that replaces the 10BASE-T link with the onboard CYW43439 (station mode, DHCP) — same pyOCD/GDB-over-the-network experience, no Ethernet drop required. The SWD engine and all five TCP servers are transport-agnostic, so only the link changes. See Build & use.

Status

Working and hardware-validated against a real RP2350 target: pyOCD connects over the network, does SWD multidrop selection, halts the dual Cortex-M33 cores, reads/writes registers and memory, flashes firmware, and runs a full interactive GDB session (breakpoints, stepping, memory). The probe can even self-rescue a gated RP2350.

The on-probe GDB stub (:3333) is complete and hardware-validated too: a bare gdb-multiarch does the whole debug+flash cycle with no host tool — dual-core threads, hardware breakpoints, DWT data watchpoints, single-step, load to flash (via the RP2350 bootrom), and reset/run. Also reachable: pyOCD/OpenOCD/probe-rs and a serial console, all concurrently.

The native on-probe RTT viewer (:5558) is hardware-validated too: nc the port and a running target's RTT log streams out, host-free (the probe scans RAM for the control block and bridges up-channel 0). RTT also works host-driven through the existing pyOCD/probe-rs paths on :5555 (pyocd rtt, or probe-rs-net --rtt).

The RP2350's RISC-V side is covered too: an OpenOCD remote_bitbang server (:5557) lets OpenOCD debug the Hazard3 cores through the same probe — both cores examine, halt, and read registers (connect ~10–15 s with the bundled read-batching patch; see host/README.md). And a target serial console (:5556) bridges the target's UART to TCP, running concurrently with any debug session. The four SWD-using front ends (pyOCD, GDB, OpenOCD, RTT) share the wire one-owner-at-a-time; the console is independent.

Performance is modest by design — it's a software PHY: ~3 ms round-trip, ~100 KB/s block memory reads (~10–15 KB/s writes), ~0.4 kB/s flash programming. Great for a low-rate remote debug box, not a fast bench flasher.

⚠️ An open debug port is remote code execution on the target. Keep it on an isolated segment or VPN.

Hardware

A Pico 2 (RP2350) + an ISL3177E transceiver + HR911105A RJ45 magnetics (the pico-10base-t-rs board), plus SWD wiring to the target: SWCLK→GP2, SWDIO→GP3, shared GND. Ethernet on GP13/GP14. Force the peer NIC to 10 Mbit half-duplex.

Optional extras: GP6→target nRESET (driven open-drain, active-low) for reset control, and GP0/GP1↔target UART (115200 8N1) for the serial console on :5556.

Build & use

The 10BASE-T transport comes from pico-10base-t-rs as a Cargo path dependency, so clone the two repos side by side. Flashing uses picotool over USB BOOTSEL.

git clone https://github.com/mattdeeds/pico-10base-t-rs
git clone https://github.com/mattdeeds/pico-remote-probe
cd pico-remote-probe
rustup target add riscv32imac-unknown-none-elf   # the firmware runs on the Hazard3 cores

cargo run --release          # build + flash via picotool over USB BOOTSEL

# Or, on a Pico 2 W, the Wi-Fi build (replaces the 10BASE-T link; 2.4 GHz only).
# Credentials are baked in at build time (nothing stored in the repo):
WIFI_SSID='YourSSID' WIFI_PASSWORD='YourPass' cargo run --release --features wifi
# The probe joins the AP + DHCPs; its USB-CDC heartbeat prints the acquired IP.

Then, from a host on the probe's network — either drive it through pyOCD:

pyocd gdbserver -t rp2350 -u remote:<probe-ip>:5555   # plain pyOCD; cores auto-discover

…or attach GDB directly to the on-probe stub, no host tool in between:

gdb-multiarch -ex 'set architecture armv8-m.main' \
              -ex 'target extended-remote <probe-ip>:3333' your.elf
# then: load · break/watch · stepi · continue · monitor reset · run

…or tail the target's RTT log straight from the probe, no host tool:

nc <probe-ip> 5558           # streams SEGGER RTT up-channel 0 (probe scans RAM for it)

…or the target's serial console (nc <probe-ip> 5556), or OpenOCD against the RISC-V side (openocd -f host/rbb-rp2350-riscv.cfg), or probe-rs via the host/probe-rs-net network driver.

See DESIGN.md for the architecture and milestones, host/README.md for the pyOCD/GDB/OpenOCD recipes (incl. the RP2350 rescue + flash gotchas and the OpenOCD speed patch), and docs/swd-port-notes.md for the SWD engine + protocol reference.

Credits & license

Builds on pico-10base-t-rs (the software 10BASE-T NIC, itself a port of kingyoPiyo's Pico-10BASE-T) for transport, and Raspberry Pi's debugprobe for the SWD engine. Speaks pyOCD's remote-probe protocol.

Licensed under either of MIT or Apache-2.0 at your option.

About

Network-attached SWD debug probe on a Pico 2 (RP2350): pyOCD remote-probe protocol over software 10BASE-T Ethernet

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages