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.
-
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
-
-
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
-
Raspberry Pi Pico and Pico W
If you have to choose between a Pico and a Pico W, I’ld recommend the simple Pico, because Pico W does not add any benefits
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.
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.
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 | Linux | Windows (10) | Example command line |
---|---|---|---|
OpenOCD 0.11 & 0.12 |
yes |
yes |
|
pyOCD 0.34 & 0.35 |
yes |
yes |
|
cp / copy |
yes |
yes |
|
Note
|
For best RP2040 support, OpenOCD bundled with PlatformIO is recommended. See PlatformIO |
YAPicoprobe tries to identify the connecting tool and sets some internal parameters for best performance. Those settings are:
Tool | Parameter |
---|---|
pyOCD / CMSIS-DAPv2 |
DAP_PACKET_COUNT=1 |
OpenOCD / CMSIS-DAPv2 |
DAP_PACKET_COUNT=2 |
unknown / CMSIS-DAPv2 |
DAP_PACKET_COUNT=1 |
CMSIS-DAPv1 HID |
DAP_PACKET_COUNT=1 |
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. |
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. |
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
|
|
Because CMSIS-DAP access should be generic, flashing of other SWD compatible devices is tool dependant (OpenOCD/pyOCD).
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
|
|
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.
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…) |
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 |
The Pico Debug Probe has four additional LEDs. Assignment is as follows:
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
|
|
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 address192.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 withpwd:<your-pwd>
-
r_start
/r_end
- RAM start/end for generic target to override default 0x20000000..0x20040000.
-
-
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
|
|
Under Linux one wants to use the following udev rules for convenience.
# 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"
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.
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.
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 shows192.168.14.2
for an Ethernet adapter, the procedure has most likely succeeded and SystemView is ready for operation
PlatformIO configuration in platformio.ini
is pretty straight forward:
[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:
[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
.
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");
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
git clone https://github.com/rgrr/yapicoprobe.git
cd yapicoprobe
git submodule update --init --recursive
# 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
make clean-build
make cmake-create-debug PICO_BOARD=pico_debug_probe
make all
make create-images
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.
the original |
|
another probe which gave ideas for PIO code |
|
original RP2040 based sigrok logic analyzer / oscilloscope |
|
The SWD probe software for a lot of targets and boards |
if the link does not work, try this |
|
-
more hardware information and some ideas concerning a probe hardware
-
some optimizations
-
some benchmarks
-
adventures with lwIP, Ethernet over USB and operating system compatibility