T
02 October 2026 · 1 views

How to Debug the RP2350 with SWD and GDB

How to Debug the RP2350 with SWD and GDB

Serial logs work until firmware crashes before logging starts, deadlocks inside an interrupt, resets continuously, or corrupts the USB stack. At that point, the RP2350’s hardware debug interface provides a direct path into the target.

The RP2350 powers the Raspberry Pi Pico 2 and related boards. Its development workflow supports hardware-assisted debugging through a debug probe, a debug server, and a debugger such as GDB. This workflow lets you halt and resume execution, set breakpoints, inspect memory and registers, trace call stacks, and recover firmware that no longer communicates through USB.

This guide covers a practical workflow:

  1. Connect an SWD-compatible debug probe.
  2. Build firmware with debug symbols.
  3. Start a compatible debug server.
  4. Attach GDB or an integrated development environment.
  5. Halt, inspect, and recover the target.

Exact wiring and command syntax depend on the board, probe, processor architecture, and software versions. Verify the board pinout and tool configuration against current Raspberry Pi documentation.

Understand the RP2350 Debug Interface

What Debug Mode Does

RP2350 debugging uses a hardware interface rather than the application’s communication channels. The probe can communicate with the processor even when firmware has crashed, entered an infinite loop, disabled USB, or failed during startup.

A debug session can provide:

  • CPU halt and resume control
  • Source-level breakpoints
  • Hardware watchpoints
  • Single-step execution
  • Register inspection
  • Memory reads and writes
  • Call-stack inspection
  • Fault analysis
  • Debug flashing and reset control

This differs from USB bootloader mode. The bootloader accepts firmware through the board’s normal recovery mechanism. A debugger controls the processor and can often access the target when application firmware prevents normal USB operation.

Serial logging remains useful for event histories and timing observations. It generally cannot stop execution at an instruction, inspect a stack pointer, or examine fault registers after a crash. Hardware debugging provides those capabilities.

SWD and the RP2350

Serial Wire Debug, or SWD, is a low-pin-count debug interface commonly used with microcontrollers. A typical connection includes:

  • SWDIO: Bidirectional debug data
  • SWCLK: Debug clock
  • GND: Shared electrical reference
  • RESET: Optional target reset control
  • VTREF: Optional target-voltage reference for probe detection

The RP2350 datasheet and board documentation define the available debug connections. Do not assume that every RP2350 board uses the same connector or pin order. The Raspberry Pi Pico 2, custom RP2350 boards, and third-party development boards may route debug signals differently.

SWDIO and SWCLK are signal connections, not power supplies. The probe and target must use compatible voltage levels, and both devices must share ground. A voltage reference may allow the probe to detect the target’s logic level, but it does not make incompatible voltage systems safe.

See the Raspberry Pi Pico 2 documentation for official debug connection guidance.

RP2350 Processor Cores and Debugging

The RP2350 supports Arm and RISC-V processor options. The firmware build determines which architecture runs the application. The debugger must attach to the core and architecture selected by the project.

This affects:

  • The compiler and linker
  • The GDB executable
  • The target configuration
  • Debug-server support
  • Register names and architecture-specific behavior
  • Fault and exception analysis

Confirm the project’s processor choice before configuring GDB. A firmware image compiled for one architecture cannot be debugged correctly using another architecture’s assumptions, symbols, or register model.

The ELF file is especially important because it records the architecture, symbols, source locations, and memory layout used by the build.

Connect a Debug Probe

Required Hardware

A basic RP2350 debug setup requires:

  • An RP2350 development board
  • A compatible debug probe
  • A USB cable for the probe
  • Jumper wires or a suitable debug cable
  • A stable power source for the target board

The Raspberry Pi Debug Probe is one supported option. A second microcontroller configured as a debug probe may also work, as may another adapter that supports the target’s debug interface and architecture. Confirm compatibility before relying on a third-party adapter.

The target can often be powered separately from the probe. Use one controlled power source unless the board documentation explicitly permits power sharing. Connecting two active supplies can create unwanted current paths or damage hardware.

Connect the Probe Safely

Use the target board’s documented connector or pinout. A generic signal map looks like this:

Probe signalRP2350 target connectionPurpose
SWDIOSWDIOBidirectional debug data
SWCLKSWCLKDebug clock
GNDGNDShared electrical reference
RESET, if availableTarget resetHardware reset control
VTREF, if supportedTarget reference voltageVoltage detection

The table describes signal roles, not a universal physical connector layout.

Before powering the system, check that:

  • SWDIO connects to SWDIO.
  • SWCLK connects to SWCLK.
  • Ground connects to ground.
  • The probe supports the target voltage.
  • RESET is connected only when the board and probe support it.
  • VTREF is connected according to the probe documentation.
  • No peripheral is driving the debug lines.
  • Jumper wires are short and secure.

Reversed SWDIO and SWCLK connections commonly appear as a completely undetected target. Long wires and breadboards can also degrade the debug-clock signal. Lower the debug clock when the target is detected intermittently or fails during attachment.

Do not connect the probe’s power output to the target unless the probe documentation and board design allow it. Confirm the target voltage before enabling shared power.

Prepare the Software Environment

Install the Development Tools

Install the Raspberry Pi Pico SDK and the build tools required by the project. Confirm that the SDK version supports the RP2350 and the selected processor architecture.

A typical environment includes:

  • CMake
  • Ninja or Make
  • An architecture-compatible compiler
  • OpenOCD or the debug server supplied with the probe
  • GDB matching the firmware architecture
  • USB drivers and permissions required by the probe

OpenOCD configuration varies between releases and probes. Some probe packages provide their own server or scripts. Use the configuration files shipped with the installed tools instead of copying a command from an unrelated board.

Verify these items before debugging:

  1. The probe appears as a USB device.
  2. The selected interface configuration matches the probe.
  3. The target configuration matches the RP2350 and project architecture.
  4. The server reports a listening GDB port.

Build Firmware with Debug Symbols

Source-level debugging requires debug information. Build a diagnostic configuration with symbols enabled and optimization reduced or disabled where practical.

A useful debug build normally includes:

  • Debug symbols
  • Low compiler optimization during initial investigation
  • Assertions where they provide useful failure information
  • Logging that does not alter the timing under investigation

Lower optimization improves variable visibility and keeps source lines closer to generated instructions. Higher optimization better reflects production behavior but can cause variables to disappear, merge, move, or become unavailable to GDB.

Use both configurations. First reproduce the issue in a low-optimization debug build. Then validate the fix with production-like optimization, linker settings, and timing.

Do not add volatile to every variable that GDB cannot display. Use it where the C or C++ memory model and hardware access require it, especially for appropriate memory-mapped registers or shared state with a defined access strategy. Indiscriminate use can reduce performance and conceal synchronization errors.

Keep the Exact ELF File

The .elf file maps machine instructions to source files, line numbers, function names, symbols, variables, sections, and addresses.

A UF2 or raw binary file alone does not provide the information required for full source-level debugging. Keep the ELF file generated from the exact build flashed to the target.

A common failure occurs when a developer flashes a new image but continues debugging with an older ELF file. Breakpoints then appear at incorrect locations, variables show misleading values, and the call stack may not match the running code.

Record the firmware commit, SDK version, compiler version, board revision, and build configuration with each diagnostic image.

Enter RP2350 Debug Mode

Start the Debug Server

The debug server bridges the probe and GDB. It detects the USB probe, connects to the target, and exposes a GDB remote-debugging endpoint.

The command depends on the probe and installation. Do not use a generic OpenOCD command without checking the installed interface and target scripts. Confirm:

  • The interface configuration
  • The target configuration
  • The probe’s USB identity
  • The selected target architecture
  • The server’s GDB port
  • The reset method

A successful startup should indicate that the probe was detected, the target was identified, debug access was established, and a GDB server is listening. If target detection fails, resolve hardware and configuration issues before troubleshooting GDB.

Attach with GDB

The general sequence is:

  1. Launch GDB with the matching ELF file.
  2. Connect to the local debug server.
  3. Reset and halt the target.
  4. Load firmware only when intentionally replacing the target image.
  5. Set a breakpoint.
  6. Continue execution.

Representative commands are:

gdb-multiarch path/to/firmware.elf
target remote localhost:<gdb-port>
monitor reset halt
break main
continue

target remote connects GDB to the server. monitor reset halt sends a server-specific reset-and-halt command. break main creates a source breakpoint. continue resumes execution.

Command names and reset behavior vary between GDB servers. Some environments use an architecture-specific GDB executable instead of gdb-multiarch. Some servers use a different monitor command or port. Adapt the executable name, ELF path, port, and target configuration to the installed tools.

Use load only when you intend to program the target. Attaching for inspection should not unexpectedly overwrite firmware.

Use an Integrated Development Environment

An integrated development environment can combine build and flash operations, source-level breakpoints, register and memory views, call-stack navigation, watch expressions, debug-server startup, and reset control.

The configuration normally requires:

  • Firmware ELF path
  • GDB executable
  • Debug-server command
  • Target architecture
  • Reset strategy
  • Optional flash and erase commands

An IDE does not correct incorrect wiring, target selection, voltage problems, or an ELF mismatch. Validate the command-line workflow first when diagnosing a new board or probe. Then move the known-working settings into the IDE.

Debug RP2350 Firmware Effectively

Set Useful Breakpoints

Start with stable locations:

  • main
  • Board initialization
  • Peripheral setup
  • Interrupt handlers
  • Error handlers
  • Assertion handlers
  • State-machine transitions

Conditional breakpoints help when a failure occurs only after a particular event, counter value, or identifier. They reduce manual stepping but can still affect timing.

Frequent breakpoints distort real-time behavior. A processor stopped by the debugger can cause communication timeouts, watchdog resets, missed interrupts, and altered race conditions. Use hardware breakpoints when debugging flash-resident code and when the target or server does not safely support software breakpoints.

Inspect Variables and Registers

Inspect variables related to initialization state, pointer validity, buffer lengths, error codes, queue indexes, peripheral configuration, and interrupt state.

Registers become important when source code appears correct but the hardware behaves incorrectly. Inspect the program counter, stack pointer, link register, status registers, peripheral registers, and fault-status registers as appropriate.

An optimized-out variable may require a lower optimization level or a rebuild with symbols. A variable can also be unavailable because the compiler proved that its value was unnecessary, stored it in a register, or removed the corresponding code.

Trace Crashes and Hard Faults

When execution stops after a fault, capture diagnostic state before resetting:

  • Program counter
  • Link register
  • Stack pointer
  • Processor status
  • Fault-status registers
  • Call stack
  • Relevant memory near the stack and faulting address

Common causes include invalid pointer access, stack overflow, buffer overruns, misaligned access, incorrect interrupt handling, peripheral access before initialization, corrupted return addresses, and races involving shared state.

The ELF file maps the faulting program-counter address to a function and source line. The source line identifies where execution stopped, but the underlying bug may have corrupted memory earlier. Inspect the stack, callers, pointers, and recent buffer operations.

Diagnose Timing and Race Conditions

Breakpoints change timing, so they can make a race disappear or create a different failure. Use less intrusive methods when timing matters:

  • Watchpoints
  • GPIO timing markers
  • Nonblocking logging
  • Event counters
  • Circular trace buffers
  • Captured state at failure
  • Assertions that record context before reset

Shared data between interrupt handlers and main code requires a deliberate synchronization strategy. A debugger can reveal inconsistent values, but it does not replace correct atomicity, ordering, and ownership rules.

Flash, Reset, and Recovery Workflows

Debug Flashing versus USB Bootloader Flashing

USB bootloader flashing depends on boot ROM entry and USB communication. Debug flashing uses the hardware debug interface and can remain available when the application crashes during startup, USB initialization fails, firmware repeatedly resets, normal communication is disabled, or the target never reaches its USB code.

The exact flashing process depends on the board, probe, debug server, and toolchain. Preserve the ELF file and diagnostic state before erasing or replacing firmware.

Reset Strategies

Common strategies include:

  • Reset and halt: Start from reset and stop before application execution. Use this for startup debugging.
  • Reset and run: Reset the target and immediately resume execution.
  • Attach without reset: Preserve current runtime state. Use this when resetting would destroy evidence.
  • Hardware reset: Drive the target reset connection through the probe when supported.

Reset methods may not affect every peripheral identically. A processor reset, system reset, watchdog reset, and external reset can produce different peripheral and clock states. Select the method that matches the failure being investigated.

Recover from a Firmware Lockup

Follow this sequence:

  1. Disconnect application peripherals that may interfere with boot or debug pins.
  2. Hold or trigger target reset.
  3. Start the debug server.
  4. Connect with GDB.
  5. Halt the processor.
  6. Capture registers, the program counter, the stack, and useful memory.
  7. Erase or replace firmware only after preserving diagnostic evidence.
  8. Reflash a known-good debug build.
  9. Reconnect peripherals one at a time.

Erasing firmware is irreversible for the current diagnostic state. Confirm that evidence is no longer needed before erasing. Keep a minimal recovery image for future testing.

Troubleshoot Common RP2350 Debug Problems

The Probe Cannot Detect the Target

Check common ground, SWDIO and SWCLK orientation, target power, voltage reference, probe drivers, USB permissions, interface configuration, target configuration, and peripheral conflicts on debug pins.

Lower the debug clock, shorten the wires, disconnect external peripherals, and try hardware reset during connection.

GDB Connects but Cannot Halt the Core

Confirm that the architecture and target configuration match the firmware. Try reset-and-halt instead of attach-only. Check for rapid resets, watchdog activity, and unsupported core configurations. Test with a minimal known-good firmware image.

Breakpoints Do Not Work

Confirm that:

  • The ELF matches the flashed image.
  • The build contains debug symbols.
  • The breakpoint is in executable code.
  • Optimization has not removed or moved the function.
  • The debugger has available hardware breakpoints when required.

Avoid placing breakpoints in timing-sensitive paths.

The Program Stops in Unexpected Code

Inspect the program counter and call stack. Check for stack corruption, invalid return addresses, interrupt-vector errors, memory overwrites, incorrect linker configuration, startup-code errors, and fault-status indications.

Reduce the firmware to a minimal application and add peripherals or tasks incrementally.

Production-Ready Debugging Practices

Separate Debug and Release Configurations

Maintain explicit build profiles. Keep debug symbols for release binaries in a controlled archive without placing them in the device image.

Record the SDK version, toolchain version, board revision, firmware commit, compiler flags, linker settings, target architecture, and debug configuration.

Use production-like settings when confirming that a fix survives optimization and real timing.

Protect the Debug Interface

Physical debug access is privileged. An exposed interface can permit firmware extraction, memory inspection, or device modification.

Define production requirements for debug-port access, device ownership, firmware extraction, secure deployment, and authorized service recovery.

Restrict or disable debug access when the product threat model requires it. Document the authorized recovery process before deployment.

Use a Repeatable Debug Checklist

  • Confirm target power.
  • Confirm SWD wiring.
  • Confirm probe detection.
  • Confirm target detection.
  • Confirm architecture selection.
  • Confirm that the ELF and firmware match.
  • Start with reset and halt.
  • Capture fault registers before resetting.
  • Reproduce with a minimal test case.
  • Validate the fix in debug and release-like builds.

Conclusion

RP2350 debug mode provides control that serial logs cannot. A compatible probe can halt a failing processor, inspect its registers and memory, identify a faulting address, and reflash firmware when USB communication has failed.

The reliable workflow is straightforward:

  1. Connect the probe using the board’s documented SWD wiring.
  2. Verify power, ground, signal direction, and voltage compatibility.
  3. Build with debug symbols.
  4. Keep the exact ELF file.
  5. Start the correct debug server.
  6. Attach GDB or an IDE.
  7. Reset and halt the target.
  8. Set a breakpoint, inspect state, and reproduce the failure.

Begin with a known-good RP2350 example. Confirm that a breakpoint at main works, then apply the same setup to the failing application.

Frequently Asked Questions

What is RP2350 debug mode?

RP2350 debug mode is a hardware-assisted development workflow that lets a probe halt, resume, inspect, and control the processor. It supports breakpoints, watchpoints, register inspection, memory access, stepping, and fault analysis.

Do I need a Raspberry Pi Debug Probe?

No. The Raspberry Pi Debug Probe is one option. A compatible debug adapter or properly configured second microcontroller may also work if it supports the required interface, voltage, board connection, and processor architecture.

Can I debug the RP2350 without SWD?

SWD is the standard hardware-debug path for many RP2350 development workflows. USB and serial logging can diagnose application behavior, but they do not provide the same halt, register, breakpoint, and recovery capabilities.

Why does GDB connect but show no source code?

The ELF file may be wrong, the firmware may lack debug symbols, or optimization may have removed or rearranged source-level information. Rebuild with symbols and use the ELF file generated from the exact firmware flashed to the target.

Can debugging recover a bricked RP2350 board?

Often, yes. A hardware debug connection can reach the target when application firmware crashes or USB communication fails. Recovery still requires correct wiring, target power, supported tooling, and an accessible debug interface.

Should I leave the debug interface enabled in production?

That depends on the device’s security and service requirements. Unrestricted debug access can expose firmware and device state. Define an authorized recovery process, then restrict or disable debug access when the product’s threat model requires it.

1 views