Debugging ARM and RISC-V
This all started when I wanted to understand how the RP2350 behaves when reading memory at 0x00000000 on both the ARM and RISC-V cores. Instead of a simple answer, I fell into a rabbit hole of breakpoints being ignored, GDB refusing to launch, and inconsistent core detection.
These experiments eventually led to three practical insights that made multi-core debugging on the Pico 2W much more predictable.
Environment
Just before getting into this post, here is some information about the setup I used.
I have been using a Raspberry Pi Pico 2W and the following software and their respective versions:
- Visual Studio Code 1.106.3
- Raspberry Pi Pico extension 0.19.0
- OpenOCD version 0.12.0+
- Raspberry Pi Debug Probe firmware 2.2.3 [1]
Well, the Raspberry Pi Debug Probe firmware version actually gets me to my first point…
Flashing the Raspberry Pi Debug Probe to its latest release
During the exploration of the possible issues, I was quickly informed, through some of the debug output, that my Raspberry Pi Debug Probe was running outdated firmware. Nothing extraordinary here. I opened my Debug Probe, pressed the BOOTSEL button, powered on the device and flashed the latest debug probe release v2.2.3 [1].

RISC-V or ARM, make sure the cores are configured correctly
One of the most confusing issues I ran into was GDB simply refusing to launch. This happened whenever I previously ran a program for a different architecture than the one I was trying to debug next.

From RISC-V to ARM debugging
When you’ve run a RISC-V program before debugging an ARM program, this is what you typically see in the gdb-server output:
...
Info : SWD DPIDR 0x4c013477
Info : [rp2350.cm0] become unavailable
Info : [rp2350.cm1] become unavailable
Info : [rp2350.cm0] starting gdb server on 50000
Info : Listening on port 50000 for gdb connections
Info : accepting 'gdb' connection on tcp/50000
Error: Target not examined yet
Error: [rp2350.cm0] Execution of event gdb-attach failed:
Error: Target not examined yet
Error: SYSINFO CHIP_ID read failed
Error: auto_probe failed
Error: Connect failed. Consider setting up a gdb-attach event for the target to prepare target for GDB connect, or use 'gdb_memory_map disable'.
Error: attempted 'gdb' connection rejected
...
Now, when you flash the same program onto the Pico 2W and only then, you start debugging the code, your program will correctly halt immediately at main() and your gdb-server output will show the following:
...
Info : SWD DPIDR 0x4c013477
Info : [rp2350.cm0] Cortex-M33 r1p0 processor detected
Info : [rp2350.cm0] target has 8 breakpoints, 4 watchpoints
Info : [rp2350.cm0] Examination succeed
Info : [rp2350.cm1] Cortex-M33 r1p0 processor detected
Info : [rp2350.cm1] target has 8 breakpoints, 4 watchpoints
Info : [rp2350.cm1] Examination succeed
Info : [rp2350.cm0] starting gdb server on 50000
Info : Listening on port 50000 for gdb connections
Info : accepting 'gdb' connection on tcp/50000
[rp2350.cm0] halted due to breakpoint, current mode: Thread
xPSR: 0xa1000000 pc: 0x20010418 msp: 0x20081fd8
...
Happy to see this time the gdb connection got accepted!
From ARM to RISC-V debugging
The other way around, when the previous program was running on the ARM core and then you immediately try to debug in RISC-V, you get to see the following errors in the gdb-server output:
...
Info : SWD DPIDR 0x4c013477
Info : [rp2350.rv0] datacount=1 progbufsize=2
Info : [rp2350.rv0] unavailable.
Error: [rp2350.rv0] Examination failed
Warn : target rp2350.rv0 examination failed
Info : [rp2350.rv1] datacount=1 progbufsize=2
Info : [rp2350.rv1] unavailable.
Error: [rp2350.rv1] Examination failed
Warn : target rp2350.rv1 examination failed
Info : [rp2350.rv0] starting gdb server on 50000
Info : Listening on port 50000 for gdb connections
Info : accepting 'gdb' connection on tcp/50000
Error: Target not examined yet
Error: [rp2350.rv0] Execution of event gdb-attach failed:
Error: Target not examined yet
Error: SYSINFO CHIP_ID read failed
Error: auto_probe failed
Error: Connect failed. Consider setting up a gdb-attach event for the target to prepare target for GDB connect, or use 'gdb_memory_map disable'.
Error: attempted 'gdb' connection rejected
...
Just make sure you flash your Pico 2W in BOOTSEL mode with a RISC-V program and you won’t have a problem anymore to debug this program in RISC-V.
RISC-V or ARM? Mind the number of breakpoints!
Once the above issues were clarified, ARM was easy to debug: the debugger always stopped at my breakpoints. However, for RISC-V, this was not the case. The debugger in my RISC-V program always ended up in some j reenter_bootrom statement.

and the gdb-server output is equivalent to:
...
Info : [rp2350.rv1] XLEN=32, misa=0x40901105
Info : [rp2350.rv1] Examination succeed
Info : [rp2350.rv0] starting gdb server on 50000
Info : Listening on port 50000 for gdb connections
Info : accepting 'gdb' connection on tcp/50000
rp2350.rv0 halted due to debug-request.
rp2350.rv1 halted due to debug-request.
Info : RP2350 rev 2, QSPI Flash win w25q32fv/jv id = 0x1640ef size = 4096 KiB in 1024 sectors
Info : New GDB Connection: 1, Target rp2350.rv0, state: halted
Warn : [rp2350.rv0] Failed to read memory via program buffer.
Warn : [rp2350.rv0] Failed to read memory via system bus.
Warn : [rp2350.rv0] Failed to read memory via abstract access.
Error: [rp2350.rv0] Failed to read memory (addr=0xbdf0)
Error: [rp2350.rv0] progbuf=failed, sysbus=failed, abstract=failed
Error: [rp2350.rv0] Failed to read memory (addr=0xbdf0)
Error: [rp2350.rv0] progbuf=failed, sysbus=failed, abstract=failed
Info : RP2xxx ROM API function FC @ 7d6a
Info : RP2xxx ROM API function FC @ 7d6a
Info : Padding image section 0 at 0x1000a13c with 196 bytes (bank write end alignment)
Info : [rp2350.rv0] Found 4 triggers
Info : [rp2350.rv1] Found 4 triggers
Error: [rp2350.rv0] can't add breakpoint: resource not available
Error: [rp2350.rv0] can't add breakpoint: resource not available
...
What you clearly see is the error “can’t add breakpoint: resource not available”. As it turns out, in RISC-V, we are limited to a certain number of breakpoints, whereas for ARM we seem to be able to add a lot more. I’ve noticed that when you start with 4 breakpoints in your RISC-V source code before launching the debugger, the above errors are typically what you’ll get. Now, if you had 3 breakpoints in source code before launching the debugger, you’ll be able to debug. Nevertheless, whenever you go beyond 4 breakpoints in source code during program execution, you’ll get the following type of exception.

The gdb-server output is the following:
...
Info : [rp2350.rv1] Found 4 triggers
rp2350.rv1 halted due to debug-request.
rp2350.rv1 halted due to debug-request.
rp2350.rv1 halted due to debug-request.
Error: [rp2350.rv0] can't add breakpoint: resource not available
This is probably tightly linked to the implementation of the RISC-V Debug Module of the RP2350. The RP2350 datasheet mentions that the Hazard3 supports an instruction address trigger unit with 4 hardware breakpoints [2].
Final tip
Several sources hinted that I should check whether the launch.json was referencing the correct chip or architecture. But this isn’t always straightforward when this config file contains variables like
"target/${command:raspberry-pi-pico.getTarget}.cfg"
Now, it is relatively easy to add
"showDevDebugOutput": "raw"
to the launch.json configuration file. Whenever you do this, the actual configuration from the launch.json file being used is then immediately visible in the Debug Console whenever you launch the debugger. The example above has become:
"target/rp2350-riscv.cfg"
References
- [1]: Raspberry Pi Debug Probe firmware v2.2.3
- [2]: RP2350 Datasheet, chapter 3.8.5 Debug mentions the RISC-V debug features implemented on the Hazard3.
Debugging got a lot easier
Debugging got a lot easier once I understood these behaviours, and I hope these findings save you some time as well.
If you’ve run into other ARM/RISC-V quirks on the Pico 2W, or if you disagree with any of these conclusions, feel free to share your experience in the comments!
comments powered by Disqus