Using OpenOCD with LLDB for Raspberry Pi Pico W on macOS
This guide provides detailed instructions for setting up and using OpenOCD and LLDB to debug a Raspberry Pi Pico W on macOS. While these instructions are specific to the Pico W, they should work for any board supported by OpenOCD with minimal modifications.
Prerequisites
- Raspberry Pi Pico W
- Raspberry Pi Debug Probe (or any other SWD-compatible debugger)
- macOS system with OpenOCD and LLDB installed
- Your compiled ELF file
Make sure you are compiling your program in DEBUG mode.
Starting OpenOCD
Open a terminal and start the OpenOCD server with the following command:
$ sudo openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c "adapter speed 5000"
You should see output similar to this:
$ sudo openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c "adapter speed 5000"
Password:
Open On-Chip Debugger 0.12.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
adapter speed: 5000 kHz
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Warn : could not read product string for device 0x2e8a:0x000a: Operation timed out
Info : Using CMSIS-DAPv2 interface with VID:PID=0x2e8a:0x000c, serial=E6614103E7728F24
Info : CMSIS-DAP: SWD supported
Info : CMSIS-DAP: Atomic commands supported
Info : CMSIS-DAP: Test domain timer supported
Info : CMSIS-DAP: FW Version = 2.0.0
Info : CMSIS-DAP: Interface Initialised (SWD)
Info : SWCLK/TCK = 0 SWDIO/TMS = 0 TDI = 0 TDO = 0 nTRST = 0 nRESET = 0
Info : CMSIS-DAP: Interface ready
Info : clock speed 5000 kHz
Info : SWD DPIDR 0x0bc12477, DLPIDR 0x00000001
Info : SWD DPIDR 0x0bc12477, DLPIDR 0x10000001
Info : [rp2040.core0] Cortex-M0+ r0p1 processor detected
Info : [rp2040.core0] target has 4 breakpoints, 2 watchpoints
Info : [rp2040.core1] Cortex-M0+ r0p1 processor detected
Info : [rp2040.core1] target has 4 breakpoints, 2 watchpoints
Info : starting gdb server for rp2040.core0 on 3333
Info : Listening on port 3333 for gdb connections
Info : starting gdb server for rp2040.core1 on 3334
Info : Listening on port 3334 for gdb connections
Info : accepting 'gdb' connection on tcp/3333
Info : Found flash device 'win w25q16jv' (ID 0x001540ef)
Info : RP2040 B0 Flash Probe: 2097152 bytes @0x10000000, in 32 sectors
Leave this terminal window open.
Using LLDB
Open a new terminal tab or window.
Start LLDB and load your ELF file:
$ lldb path/to/your/project.elf
(lldb) target create "path/to/your/project.elf"
Current executable set to '/path/to/your/project.elf' (arm).
- Select the remote GDB server platform:
(lldb) platform select remote-gdb-server
Platform: remote-gdb-server
Connected: no
- Connect to the OpenOCD server:
(lldb) process connect connect://localhost:3333
You should see output indicating that the process has stopped, usually at a memory address.
Debugging with LLDB
Now that you're connected, you can use standard LLDB commands to debug your program. Here are some key points and useful commands:
- Setting breakpoints: Use hardware breakpoints to avoid issues with software breakpoints. To set a hardware breakpoint, use the following command:
(lldb) breakpoint set --hardware --name function_name
- Continuing execution:
(lldb) continue
- Stepping through code:
(lldb) step # Step in
(lldb) next # Step over
(lldb) finish # Step out
- Inspecting variables:
(lldb) frame variable
(lldb) print variable_name
- Restarting the program:
To restart the program, use the
process plugin packet
command:
(lldb) process plugin packet monitor reset run
This sends the reset run
command to OpenOCD, which resets the device and starts program execution.
Advanced LLDB Commands
- Backtrace: View the call stack:
(lldb) bt
- Disassemble: View the assembly code:
(lldb) disassemble
- Memory examination: View memory contents:
(lldb) memory read --size 4 --format x --count 10 0x10000000
- Register inspection: View register contents:
(lldb) register read
Tips and Tricks
- Create an LLDB init file:
You can create a
.lldbinit
file in your home directory with commonly used commands. For example:
platform select remote-gdb-server
process connect connect://localhost:3333
- Use LLDB aliases: Create aliases for frequently used commands:
(lldb) command alias bh breakpoint set --hardware --name
Now you can set a hardware breakpoint with:
(lldb) bh function_name
Debugging multiple cores: The RP2040 has two cores. OpenOCD provides separate GDB servers for each core (ports 3333 and 3334). To debug the second core, connect to port 3334 instead.
Flash memory operations: OpenOCD can perform flash operations. For example, to erase the flash:
(lldb) process plugin packet monitor flash erase_sector 0 last
I still haven't figured out how to load the elf file through lldb, and for now am using Telnet to load the elf file.
$ telnet localhost 4444
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> program build/pico-swift-display.elf verify
[rp2040.core0] halted due to debug-request, current mode: Thread
xPSR: 0xf1000000 pc: 0x000000ea msp: 0x20041f00
[rp2040.core1] halted due to debug-request, current mode: Thread
xPSR: 0xf1000000 pc: 0x000000ea msp: 0x20041f00
** Programming Started **
Padding image section 1 at 0x1008ae78 with 136 bytes (bank write end alignment)
Adding extra erase range, 0x1008af00 .. 0x1008ffff
keep_alive() was not invoked in the 1000 ms timelimit. GDB alive packet not sent! (8905 ms). Workaround: increase "set remotetimeout" in GDB
** Programming Finished **
** Verify Started **
** Verified OK **