Skip to content

rgrr/yapicoprobe

 
 

Repository files navigation

Yet Another Picoprobe

Overview

YAPicoprobe allows a Pico / RP2040 to be used as USB → SWD and UART bridge. This means it can be used as a debugger and serial console for another Pico or any other SWD compatible controller.

YAPicoprobe is a fork of the original Picoprobe and was created due to my lazyness to follow the PR discussions and delays with unknown outcome.

Another reason for this fork is that I wanted to play around with SWD, RTT, PIO etc pp, so the established development process was a little bit hindering.

Finally there is Yet Another Picoprobe around, the YAPicoprobe.

Note
Pico2 / RP2350 can also be used as probe hardware. This is an experimental feature.
Warning
Pico2 / RP2350 targets are currently not supported.
Warning
Pico2 target is only working at ⇐ 300kHz reliably.
time /home/hardy/.pico-sdk/openocd/0.12.0 dev/openocd.exe -c "gdb_port 50000" -c "tcl_port 50001" -c "telnet_port 50002" -s /home/hardy/.pico-sdk/openocd/0.12.0 dev/scripts -f /home/hardy/.vscode/extensions/marus25.cortex-debug-1.12.1/support/openocd-helpers.tcl -f interface/cmsis-dap.cfg -f target/rp2350.cfg -c "adapter speed 349" -c "program {pio_blink.elf} verify reset; shutdown;"

Features

  • FAST, at least faster than most other picoprobes, see benchmarks

  • standard debug tool connectivity

    • CMSIS-DAPv2 WinUSB (driver-less vendor-specific bulk) - CMSIS compliant debug channel

    • CMSIS-DAPv1 HID - CMSIS compliant debug channel as a fallback

  • MSC - drag-n-drop support of UF2 firmware image à la DAPLink for RP2040 Pico / PicoW and nRF52832/833/840 targets

  • CDC - virtual com port for bidirectional communication with target

    • UART connection between target and probe is redirected

    • RTT terminal channel is automatically redirected into this CDC (if there is no CMSIS-DAPv2/MSC connection)

  • SystemView support over TCP/IP (NCM/ECM/RNDIS)

  • CDC - virtual com port for (debug) logging of the probe

  • optional CDC sigrok probe - data collection on eight digital and three analog channels (logic analyzer and oscilloscope) with auto-trigger capability. See here for more information

  • LED for state indication

  • Other Benefits

    • on Windows no more Zadig fiddling because the underlying protocols of CMSIS-DAPv1 and v2 are driver-less

    • easy drag-n-drop (or copy) upload of a firmware image to the target via the probe

    • no more reset push button (or disconnect/connect cycle) to put the target into BOOTSEL mode

    • auto detection of RP2040/nRF52/Generic targets

Details

Known Devices

  • RP2040 (and its flash "win w25q16jv"), size of the targets flash is automatically detected

  • nRF52832/833/840

  • other SWD compatible (Arm) devices with limitations in MSC access

Supported Probe Hardware

Other RP2040 hardware will work as well, e.g. picoLink is happy with the firmware image for the Pico.

Firmware images can be downloaded from github.

Probe / Target Wiring

Wires between Pico probe and target board are shown below. At least three wires (plus supply) are required: SWCLK, SWDIO and Gnd. The Reset line is optional. If target UART RX/TX are used, additional two wires are needed. Sigrok inputs go extra.

Wiring

More information about setup can be found in the Pico Getting Started Guide. See "Appendix A: Using Picoprobe".

For information about cabling between Pico Debug Probe and target refer to the corresponding documentation.

For details about probe pin assignments see the hardware section. Ochamodev wrote a nice setup guide, containing the steps from installation until debugging in VSCode.

Tool Compatibility

Table 1. Tool Compatibility
Tool Linux Windows (10) Example command line

OpenOCD 0.11 & 0.12

yes

yes

openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c "adapter speed 25000" -c "program {firmware.elf} verify reset; shutdown;"

pyOCD 0.34 .. 0.36

yes

yes

pyocd flash -f 400000 -t nrf52840 firmware.elf

probe-rs 0.23 ..

yes

?

probe-rs benchmark --protocol swd --address 0x20000000 --chip RP2040

cp / copy

yes

yes

cp firmware.uf2 /media/picoprobe

Note
For best RP2040 support, OpenOCD bundled with PlatformIO is recommended. See PlatformIO

Parameter Optimization

YAPicoprobe tries to identify the connecting tool and sets some internal parameters for best performance. Those settings are:

Table 2. Parameter Optimization
Tool Parameter

pyOCD / CMSIS-DAPv2

DAP_PACKET_COUNT=1
DAP_PACKET_SIZE=512

OpenOCD / CMSIS-DAPv2

DAP_PACKET_COUNT=1
DAP_PACKET_SIZE=512

probe-rs / CMSIS-DAPv2

DAP_PACKET_COUNT=8
DAP_PACKET_SIZE=512

unknown / CMSIS-DAPv2

DAP_PACKET_COUNT=1
DAP_PACKET_SIZE=64

CMSIS-DAPv1 HID

DAP_PACKET_COUNT=1
DAP_PACKET_SIZE=64

SWD Adapter Speed

The tools above allow specification of the adapter speed. This is the clock frequency between probe and target device. Unfortunately DAP converts internally the frequency into delays which are always even multiples of clock cycles. That means that actual clock speeds are 125MHz / (2*n), n>=3 → 20833kHz, 12500kHz, 10417kHz, …​

Normally the requested frequency is rounded down according to the possible values from above. But if the specified frequency is completely out of range, the allowed maximum target SWD frequency is used, e.g. for the RP2040 24MHz.

Actually usable frequency depends on cabling and the DAP speed. If the DAP cannot access memory with speed determined by the host, it responds with WAIT and the host needs to retry.

Effects of cabling should be clear: the longer the cables plus some more effects, the worse the signals. Which effectively means slowing down clock frequency is required to get the data transported.

Tip

SWCLK speed for MSC and RTT (below) is set according to the latest used tool setup. E.g. pyocd reset -f 5000000 -t rp2040 sets SWCLK to 5MHz.

Note

SWD clock frequency is also limited by the target controller. For nRF52 targets default clock is set to 6MHz, for unknown SWD targets 2MHz are used.

MSC - Mass Storage Device Class

Via MSC the so called "drag-n-drop" supported is implemented. Actually this also helps in copying a UF2 image directly into the target via command line.

MSC write access, i.e. flashing of the target, is device dependent and thus works only for a few selected devices which are in my range of interest. Those devices are the RP2040 (and its flash "win w25q16jv") and the Nordic nRF52 family (namely nRF52832/833/840).
For the RP2040 some special flash routines has been implemented. For nRF52 flashing regular DAPLink modules have been taken. Which also implies, that extending the probes capabilities shouln’t be too hard.

Note
  • RP2040: flash erase takes place on a 64KByte base: on the first write to a 64 KByte page, the corresponding page is erased. That means, that multiple UF2 images can be flashed into the target as long as there is no overlapping within 64 KByte boundaries

  • nRF52: whole chip is erased on first write operation of an UF2 image which means that only one UF2 image can be flashed

Because CMSIS-DAP access should be generic, flashing of other SWD compatible devices is tool dependant (OpenOCD/pyOCD).

RTT - Real Time Transfer

RTT allows transfer from the target to the host in "realtime" via the SWD interface.

The RTT control block on the target is automatically detected. Currently channels 0 and 1 are supported.

To get the RTT channels running, code on the target has to be either instrumented or adopted.

Note
  • only the devices RAM is scanned for an RTT control block, for unknown devices RAM the range 0x20000000-0x2003ffff is assumed

  • don’t be too overwhelmed about Seggers numbers in the above mentioned document. The data must still be transferred which is not taken into account in the diagram (of course the target processor has finished after writing the data)

  • only one of CMSIS-DAP / MSC / RTT can access the target at the same time. RTT is disconnected in case CMSIS-DAP or MSC are claiming access

  • the probe tries hard to find an active RTT control block. Worst case scenario are multiple inactive RTT control blocks in the targets memory (this might happen if the targets RAM is not cleared completely)

Terminal I/O

RTT channel 0 is used for bidirectional console communication. This channel is directed into the UART CDC of the target device.

Communication is birectional, but don’t expect high transfer rates from host to target.

SystemView

RTT channel 1 is used for communication with Seggers SystemView. YAPicoprobe provides the data over TCP at port 19111 which is the default for SystemView communication. Default IP address of the probe (if not configured otherwise) is 192.168.14.1.

Note

SystemView communication via TCP/IP had been chosen to spare you from another CDC port and also because SystemView over COM port works on my Linux device just until v3.30 (Segger promises a fix for > 3.50a, nevertheless TCP/IP is used…​)

LED Indications

Table 3. LED Indications
State Indication

no target found

5Hz blinking

DAPv1 connected

LED on, off for 100ms once per second

DAPv2 connected

LED on, off for 100ms twice per second

MSC active

LED on, off for 100ms thrice per second

UART data from target

slow flashing: 300ms on, 700ms off

target found

LED off, flashes once per second for 20ms

RTT control block found

LED off, flashes twice per second for 20ms

RTT data received

LED off, flashes thrice per second for 20ms

sigrok running

10Hz flashing

sigrok waiting for auto trigger

10Hz negative flashing (flicker)

Note

pyOCD does not disconnect correctly at an end of a gdb debug session so the LED still shows a connection. To get out of this situation issue pyocd reset -t rp2040 or similar.

Pico Debug Probe

The Pico Debug Probe has four additional LEDs. Assignment is as follows:

Table 4. Pico Debug Probe Additional LEDs
LED Color Indication

UART_TX

yellow

5ms flash, if target sends data

UART_RX

green

20ms flash, if target gets data

DAP_TARGET_RUNNING

yellow

set by host tool

DAP_CONNECTED

green

set by host tool

Note
  • currently OpenOCD sets both DAP_* LEDs on CMSIS-DAP connection

  • pyOCD currently does not set the DAP_* LEDs at all

Configuration

Runtime Configuration of Probe Parameters

Several parameters can be configured via the Debug CDC of the probe. These parameters include the network selection and CPU/SWCLK frequencies.

Because configuration of the probe is seen as once in a life time, the interface is kept very simple.

Following procedure applies:

  • connect with a terminal program to the Debug CDC of the probe

  • unlock configuration thru hitting <enter>, this works as long there is no pwd

  • commands: <cmd>

    • lock - lock the configuration parameters

    • killall - kill all current configuration parameters

    • reset - restart the probe

    • show - shows the current configuration (initially empty)

  • variables: <variable>=<value>

    • f_cpu - set CPU frequency in MHz

    • f_swd - set SWD frequency in kHz

    • net - set the net of the probes IP address 192.168.<net>.1

    • nick - set nickname of the probe. Use this with care because it also changes the USB serial number (which might be intended)

    • pwd - set a password for locking the configuration. Unlocking is done subsequently with pwd:<your-pwd>

    • r_start / r_end - RAM start/end for generic target to override default 0x20000000..0x20040000.

    • rtt - enable/disable RTT access, default is RTT enabled (0: disable, 1:enable).

  • special characters:

    • CR/LF - end the line

    • BS - backspace one character

  • unknown commands / variables are ignored

  • if configuration is locked, all commands are ignored (except pwd:<your-pwd>)

Note
  • the interface is far from perfect

  • after every configuration change, the probe must restart

udev rules

Under Linux one wants to use the following udev rules for convenience.

/etc/udev/rules.d/90-picoprobes.rules
# set mode to allow access for regular user
SUBSYSTEM=="usb", ATTR{idVendor}=="2e8a", ATTR{idProduct}=="000c", MODE:="0666"

# create COM port for target CDC
ACTION=="add", SUBSYSTEMS=="usb", KERNEL=="ttyACM[0-9]*", ATTRS{interface}=="YAPicoprobe CDC-UART",    MODE:="0666", SYMLINK ="ttyPicoTarget"
ACTION=="add", SUBSYSTEMS=="usb", KERNEL=="ttyACM[0-9]*", ATTRS{interface}=="YAPicoprobe CDC-DEBUG",   MODE:="0666", SYMLINK ="ttyPicoProbe"
ACTION=="add", SUBSYSTEMS=="usb", KERNEL=="ttyACM[0-9]*", ATTRS{interface}=="YAPicoprobe CDC-SIGROK",  MODE:="0666", SYMLINK ="ttyPicoSigRok
ACTION=="add", SUBSYSTEMS=="usb", KERNEL=="ttyACM[0-9]*", ATTRS{interface}=="YAPicoprobe CDC-SysView", MODE:="0666", SYMLINK ="ttyPicoSysView"

# mount Picoprobe to /media/picoprobe
ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", ENV{ID_FS_USAGE}=="filesystem", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="000c", RUN ="/usr/bin/logger --tag picoprobe-mount Mounting what seems to be a Raspberry Pi Picoprobe", RUN ="/usr/bin/systemd-mount --no-block --collect --fsck=0 -o uid=hardy,gid=hardy,flush $devnode /media/picoprobe"
ACTION=="remove", SUBSYSTEMS=="usb", SUBSYSTEM=="block", ENV{ID_FS_USAGE}=="filesystem", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="000c", RUN ="/usr/bin/logger --tag picoprobe-mount Unmounting what seems to be a Raspberry Pi Picoprobe", RUN ="/usr/bin/systemd-umount /media/picoprobe"

# mount RPi bootloader to /media/pico
ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", ENV{ID_FS_USAGE}=="filesystem", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0003", RUN ="/usr/bin/logger --tag rpi-pico-mount Mounting what seems to be a Raspberry Pi Pico", RUN ="/usr/bin/systemd-mount --no-block --collect --fsck=0 -o uid=hardy,gid=hardy,flush $devnode /media/pico"
ACTION=="remove", SUBSYSTEMS=="usb", SUBSYSTEM=="block", ENV{ID_FS_USAGE}=="filesystem", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0003", RUN ="/usr/bin/logger --tag rpi-pico-mount Unmounting what seems to be a Raspberry Pi Pico", RUN ="/usr/bin/systemd-umount /media/pico"

Network Configuration

SystemView connectivity over TCP/IP is on most systems not configuration free.

If everything is configured fine, the probe has the default address 192.168.14.1 and the host computer gets 192.168.14.2.

Debian

On Debian the configuration is as follows:

  • after connecting the probe with the host, ip a shows its network interface, e.g. enxfe<your-probe>. If the network interface already shows an IP address everything is fine and you are ready

  • if not, then you can get the IP address with sudo dhclient enxfe<your-probe>

  • to make this permanent add the following lines to /etc/network/interfaces:

allow-hotplug enxfe<your-probe>
iface enxfe<your-probe> inet dhcp

On my system this unfortunately leads to error messages (which are harmless) if the probe is not connected.

Win10

A certain version of Win10 is required for USB-NCM connectivity. Exact version is unknown.

The driver needs to be installed manually. Procedure is roughly as follows:

  • in "Device Manager" search for YaPicoprobe NCM with an exclamation mark

  • "Update Driver"

  • "Browse my computer for drivers"

  • "Let me pick…​"

  • "Network adapters"

  • "Microsoft"

  • "UsbNcm Host Device" - if this is not available, then the version of Win10 is not ready for USB-NCM

  • confirm any dialog boxes

  • if ipconfig on a command line shows 192.168.14.2 for an Ethernet adapter, the procedure has most likely succeeded and SystemView is ready for operation

Win11

It is said, that USB-NCM is working out of the box. This has not been tested.

PlatformIO

PlatformIO configuration in platformio.ini is pretty straight forward:

PlatformIO configuration
[env:pico]
framework = arduino
platform = https://github.com/maxgerhardt/platform-raspberrypi
board = rpipicow
board_build.core = earlephilhower
upload_protocol = cmsis-dap
debug_tool = cmsis-dap
monitor_speed = 115200
monitor_port  = /dev/ttyPicoTarget

The firmware image can alternativly copied directly (and faster) via MSC with custom upload:

PlatformIO copy configuration
[env:pico_cp]
...
upload_protocol = custom
upload_command = cp .pio/build/pico_cp/firmware.uf2 /media/picoprobe
...

I’m sure there are smarter ways to specify the image path.

Optional: there is also a special PlatformIO handling in the probe: it ignores the defensive 1MHz clock setting which is used by the above contained OpenOCD. Standard clock is thus 15MHz. If this is too fast, set the frequency with pyocd reset -f 1100000 -t rp2040 or similar. If this is too slow, use pyocd reset -f 50000000 -t rp2040.

RTT

To use RTT for debug/console output the following has to be done:

  • in platformio.ini:

[env:pico]
...
lib_deps =
    ...
    koendv/RTT Stream
  • in main.cpp:

...
#include <RTTStream.h>
...
RTTStream rtt;
...
rtt.println("main module");
  • in other modules:

...
#include <RTTStream.h>
...
extern RTTStream rtt;
...
rtt.println("sub module");

Internals

Building from Source

Building from source is done with the help of a stub Makefile which eases integration into Eclipse (but can be used from command line as well). The Makefile creates via cmake a build.ninja which is responsible for the actual build process.

To build the project, there must be somewhere a recent Pico SDK and the environment variable PICO_SDK_PATH must point to it.

Note
I’m most of the time on the master branch of TinyUSB which is part of the Pico SDK. Originally TinyUSB 0.15.0 is being used by Pico SDK 1.5.1.
So if you experience unexpected behaviour, I recommend to update TinyUSB and retry.

If you want to adopt YAPicoprobe options to your needs, check CMakeLists.txt and invoke cmake accordingly.

Requirements:

  • arm-none-eabi-gcc

  • make, cmake, ninja

  • Pico SDK

Clone yapicoprobe including submodules
git clone https://github.com/rgrr/yapicoprobe.git
cd yapicoprobe
git submodule update --init --recursive
General build sequence
# create _build/ninja.build for a debug target
make cmake-create-debug

# build yapicoprobe, output in _build/picoprobe.uf2
make all

# clean build files
make clean
Build sequence for a specific board [pico|pico_w|pico_debug_probe]
make clean-build
make cmake-create-debug PICO_BOARD=pico_debug_probe
make all
Build firmware images for supported boards, images can be found in images/yapicoprobe*.uf2
make create-images
Bare call of cmake
mkdir _build; cd _build
cmake .. -D<option>=<value> -DPICO_BOARD=pico_w
cmake --build .
# output in picoprobe.elf/uf2/hex/bin

If you want to know the several options use the one liner in the build directory: cmake -LH . | sed -n -e '/OPT_/{x;1!p;g;$!N;p;D;}' -e h.
Or use simply make show-options in the projects root.

Code Inherited

Picoprobe

the original

pico_debug

another probe which gave ideas for PIO code

sigrok-pico

original RP2040 based sigrok logic analyzer / oscilloscope

DAPLink

The SWD probe software for a lot of targets and boards

Notes

  • Frequencies

    • the CPU is overclocked to 168MHz (=7*24MHz)

    • SWD frequency limits

      • RP2040: 25MHz, actually allowed are 24MHz; default is 15MHz

      • nRF52xxx: 10MHz, actually allowed are 8MHz; default is 6MHz

  • sigrok

    • PIO is running 7x faster in auto trigger mode than the specified sample rate

More Text