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:

  • Connect the debug pins
  • Load and run a program from the command line without configuring the Pico as a USB storage device
  • Use gdb for interactive debugging

How do I connect the debug wires to the Raspberry Pi Pico?

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/400Raspberry 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.

How do I run a Raspberry Pi Pico application from the command line?

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
        
    

How do I use gdb for interactive debugging?

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.

Summary

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.

Back
Next