# Raspberry Pi Picoprobe Debug Setup/Tips & Tricks This document details useful information on how to use a Raspberry Pi Pico as a SWD probe for another Pico using the Picoprobe software. This information assumes you have followed all of the steps in Appendix A of the [Getting Started with Raspberry Pi Pico Guide](https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf) and that you are doing development on a Linux system. ## Essential Setup 1. Add the below files to your system to enable non-root access to the devices **/etc/udev/rules.d/99-openocd.rules:** ``` # Raspberry Pi Picoprobe ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0004", MODE="0666" ``` **/etc/udev/rules.d/95-pi-pico-udev.rules:** ``` # Raspberry Pi Pico ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0003", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" ``` 2. Then run the following command: ``sudo udevadm control --reload-rules && sudo udevadm trigger`` ## Typical Debug Workflow 1. Use terminal multiplexer of some sort (e.g. `screen` or `tmux`) or just two windows to spawn two shells, one to build your code and another with GDB to step through your code. **NOTE:** This setup unfortunately has not worked with semihosting output for me. 2. In the GDB shell, run `gdb-multiarch` with your desired ELF executable. See section [GDB Init File](#gdb-init-file) for example invocation and usage of init files. 4. Still in GDB, run `load` followed by whatever breakpoints and other things you'd like to set before running the program. 5. Finally, still in GDB, run `continue` or `c` to run the program on the chip. ## Notes on Output via Direct USB and Semihosting The following assumes that you have followed [Essential Setup](#essential-setup) to enable user-land usage of the Raspberry Pi Pico both as Picoprobe and other programs and have followed the debug probe setup in Appendix A of the [Getting Started with Raspberry Pi Pico Guide](https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf) (or have setup similar otherwise). ### USB Output When simply flashing and running a program on the Pico when attached directly to the development machine via USB (i.e. no middleman debug probe), output from the Pico can be viewed in terminal by installing `minicom` and running it via: `minicom -b 115200 -D /dev/ttyACMn`, where `n` is some number like 0, 1, 2, etc. If you have more than one Pico or similar device plugged in to your development machine via USB, there will be more than one `ttyACM` file. ### Semihosting Output To get program output while using a debug probe, enable Semihosting, your *very* slow partner in debugging crime, do the following (assuming you're using Pico-SDK's stdio): **NOTE:** You must run OpenOCD separately to get output from the device. See [GDB Init File](#gdb-init-file) for details. 1. In your project's CMake file add the following: `pico_enable_stdio_semihosting( 1)` 2. Re-run both `cmake` and your build system (probably Make, possibly Ninja). 3. Assuming OpenOCD is running, start GDB with the commands in [GDB Init File](#gdb-init-file) in addition to: The second command disables logging to ensure semihosting output is not hidden by log output. ``` monitor arm semihosting enable monitor debug_level -2 ``` 4. Finally, flash the device and run your program via GDB at which point you should get output from the device **in the OpenOCD shell**, albeit *very* slowly. ## GDB Init File To simplify debugging setup, run GDB with the `--init-command` flag before you enter interactive GDB session to run desired commands. Example usage is as follows: ### Not Using Semihosting (will SIGTRAP when program using semihosting) ``gdb-multiarch --init-command=/path/to/gdbinit/file /path/to/exec.elf`` GDB Init File: (first line spawns OpenOCD from GDB and pipes output to GDB) ``` tar ext | openocd -c "gdb_port pipe" -f interface/picoprobe.cfg -f target/rp2040.cfg -s tcl monitor reset halt ``` ### Using Semihosting (make sure you built target w/ semihosting enabled) Leave running in one shell: `openocd -f interface/picoprobe.cfg -f target/rp2040.cfg -s tcl` Next, in another shell: `gdb-multiarch --init-command=/path/to/gdbinit/file /path/to/exec.elf` GDB Init File: (first line connects to OpenOCD TCP server) ``` tar ext :3333 monitor arm semihosting enable monitor debug_level -2 monitor reset halt ``` ## Shell Functions to Flash via UF2 Functions to check for existence of `/media/RPI-RP2` and copy UF2 file to Raspberry Pi Pico for flashing via UF2 bootloader. Remove `sudo` in commands if the user you're logged in as has proper permissions. Example usage: `rpi-check && rpi-copy /path/to/exec.uf2` `rpi-copy --mount-from /path/to/device/dir /path/to/exec.uf2` Functions (tested in zsh): ``` RPI_STANDARD_DIR=/media/alex/RPI-RP2 rpi-copy() { # Copy executable to RaspberryPi Pico # Verify args if [ "$#" -ne 1 ] && [ "$#" -ne 3 ]; then echo "usage: rpi-copy [--mount-from MOUNT] EXECUTABLE" >&2 return 1 fi if [ "$#" -eq 1 ]; then # Standard copy executable # # $1: Executable sudo cp $1 $RPI_STANDARD_DIR else # Mount and then copy # Sometimes RPI shows up in weird places # # $1: --mount # $2: Mount source # $3: Executable RPI_MOUNT=/mnt/rpi sudo mkdir $RPI_MOUNT sudo mount $2 $RPI_MOUNT sudo cp $3 $RPI_MOUNT sudo umount $RPI_MOUNT fi return 0 } rpi-check-dir() { if [ -d $RPI_STANDARD_DIR ]; then echo "device mounted to standard directory \"$RPI_STANDARD_DIR\"" return 0; else echo "rpi-check-dir: device not mounted to standard directory "\ "\"$RPI_STANDARD_DIR\"" >&2 return 1; fi } ``` ## Useful References: - [Getting Started with Raspberry Pi Pico Guide](https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf), specifically Chapter 6 and Appendix A. - [Develop and Debug Raspberry Pi Pico on macOS Big Sur](https://andrejacobs.org/electronics/develop-and-debug-raspberry-pi-pico-on-macos-big-sur/) - [GDB and OpenOCD (OpenOCD User's Guide](https://openocd.org/doc/html/GDB-and-OpenOCD.html) - [How do I print debug messages to gdb console with STM32 discovery board using GDB, OpenOCD and arm-none-eabi-gcc?](https://electronics.stackexchange.com/questions/149387/how-do-i-print-debug-messages-to-gdb-console-with-stm32-discovery-board-using-gd)