The steps below explain how to load programs and do interactive debugging by connecting the Debug pins of the Raspberry Pi Pico.
This is helpful because holding the BOOTSEL button and connecting the USB cable is tedious during debugging sessions.
Instead, applications can be loaded using the debug pins. The debug interface consists of 3 pins on the Raspberry Pi Pico which implement Serial Wire Debug (SWD). SWD is a standard interface on Cortex-M microcontrollers.
This section covers how to:
The easiest way to connect the debug pins is by using the GPIO pins of a Raspberry Pi 3/4/400.
To use the Raspberry Pi 3/4/400 GPIO pins use jumper wires to connect the pins in the table below.
Raspberry Pi 3/4/400 | Raspberry Pi Pico |
---|---|
GND (Pin 20) | SWD GND |
GPIO24 (Pin 18) | SWDIO |
GPIO25 (Pin 22) | SWCLK |
If a Raspberry Pi 3/4/400 is not available, the debug interface can be connected to another Raspberry Pi Pico which serves as a debug probe.
The second Pico bridges the development computer to the Pico running the program to be debugged. The Pico serving as the debug probe runs a software application called Picoprobe. More information about using two Pico boards is available in Getting Started with Raspberry Pi Pico , search for Picoprobe.
After making the connections attach the micro USB cable between the Raspberry Pi 3/4/400 and the Pico.
When using the debug interface, the application .elf file is used instead of the .uf2 file. It is located in the build directory along with the other files generated by the build process.
Program loading is done using openocd. Two configuration files are passed to openocd which describe the hardware. These are provided by the Raspberry Pi Pico SDK. After the configuration files, a series of commands are passed to openocd to load the application and run it.
Run the same hello world application used in a
previous step
. If build/hello.elf
is not present, rebuild the application.
openocd -f $PICO_SDK_PATH/../openocd/tcl/interface/raspberrypi-swd.cfg -f $PICO_SDK_PATH/../openocd/tcl/target/rp2040.cfg -c "program build/hello.elf verify reset exit"
Openocd copies the .elf file to the Pico. This replaces copying the .uf2 to the USB storage.
The program output is the same as before. Use minicom to see the print statements from USB serial.
sudo minicom -b 115200 -o -D /dev/ttyACM0
Interactive debugging with gdb can be done with a slight modification to the openocd commands.
Make sure the application was compiled for debugging. This is done by setting the Debug build type.
cd build
cmake -DCMAKE_BUILD_TYPE=Debug ..
make
cd ..
Removing the command string causes openocd to wait for a debugger connection from gdb.
openocd -f $PICO_SDK_PATH/../openocd/tcl/interface/raspberrypi-swd.cfg -f $PICO_SDK_PATH/../openocd/tcl/target/rp2040.cfg
In another terminal, start gdb.
gdb-multiarch build/hello.elf
Once gdb starts, a complete debugging session is shown below, the (gdb) prompt is shown, enter only the commands after the (gdb) prompt.
(gdb) target remote localhost:3333
Remote debugging using localhost:3333
warning: multi-threaded target stopped without sending a thread-id, using first non-exited thread
time_reached (t=...)
at /home/jasand01/pico/pico-sdk/src/rp2_common/hardware_timer/include/hardware/timer.h:116
116 uint32_t hi_target = (uint32_t)(target >> 32u);
(gdb) load
Loading section .boot2, size 0x100 lma 0x10000000
Loading section .text, size 0x7188 lma 0x10000100
Loading section .rodata, size 0x1718 lma 0x10007288
Loading section .binary_info, size 0x20 lma 0x100089a0
Loading section .data, size 0x440 lma 0x100089c0
Start address 0x100001e8, load size 36352
Transfer rate: 33 KB/sec, 6058 bytes/write.
(gdb) monitor reset init
target halted due to debug-request, current mode: Thread
xPSR: 0xf1000000 pc: 0x000000ee msp: 0x20041f00
target halted due to debug-request, current mode: Thread
xPSR: 0xf1000000 pc: 0x000000ee msp: 0x20041f00
(gdb) b main
Breakpoint 1 at 0x1000035c: file /home/jasand01/hello.c, line 5.
Note: automatically using hardware breakpoints for read-only addresses.
(gdb) continue
Continuing.
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x0000012a msp: 0x20041f00
Thread 1 hit Breakpoint 1, main () at /home/jasand01/hello.c:5
5 {
(gdb) list
1 #include <stdio.h>
2 #include "pico/stdlib.h"
3
4 int main()
5 {
6 const uint LED_PIN = PICO_DEFAULT_LED_PIN;
7
8 gpio_init(LED_PIN);
9 gpio_set_dir(LED_PIN, GPIO_OUT);
10
(gdb) info reg
r0 0x200002bd 536871613
r1 0x1000035d 268436317
r2 0x26 38
r3 0x20000500 536872192
r4 0x10000264 268436068
r5 0x20041f01 537140993
r6 0x18000000 402653184
r7 0x0 0
r8 0xffffffff -1
r9 0xffffffff -1
r10 0xffffffff -1
r11 0xffffffff -1
r12 0x4001801c 1073840156
sp 0x20042000 0x20042000
lr 0x10000223 268436003
pc 0x1000035c 0x1000035c <main>
All gdb commands are available to single step, inspect memory, display registers, disassemble, and print variables. Feel free to search for gdb tutorials to learn more about using gdb.
The Raspberry Pi Pico debug interface can be used to load programs and debug them with gdb. There is need to hold the BOOTSEL button and copy the .uf2 file to USB storage every time the program is changed.