rgrr / yapicoprobe

Yet Another Picoprobe
120 stars 12 forks source link
cmsis-dap daplink msc nrf52 nrf52832 nrf52840 pico picoprobe probe-rs rp2040 rtt systemview yapicoprobe

:imagesdir: doc/png :source-highlighter: rouge :toc: :toclevels: 5

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 https://github.com/raspberrypi/picoprobe[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

Details

Known Devices

Supported Probe Hardware

Other RP2040 hardware will work as well, e.g. https://mcuoneclipse.com/2023/04/08/open-source-picolink-raspberry-pi-rp2040-cmsis-dap-debug-probe/[picoLink] is happy with the firmware image for the Pico.

Firmware images can be downloaded from https://github.com/rgrr/yapicoprobe/releases[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.

[.text-center] image::board_schematic_bb.png[Wiring, 60%]

More information about setup can be found in the https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf[Pico Getting Started Guide]. See "Appendix A: Using Picoprobe".

For information about cabling between Pico Debug Probe and target refer to the corresponding https://www.raspberrypi.com/documentation/microcontrollers/debug-probe.html[documentation].

For details about probe pin assignments see the link:doc/hardware.adoc[hardware section]. Ochamodev wrote a nice https://github.com/ochamodev/raspberry_pico_setup_guide[setup guide], containing the steps from installation until debugging in VSCode.

Tool Compatibility

.Tool Compatibility [%autowidth] [%header] |=== |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 <>

Parameter Optimization

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

.Parameter Optimization [%autowidth] [%header] |=== |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]

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

RTT - Real Time Transfer

https://www.segger.com/products/debug-probes/j-link/technology/about-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]

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 https://www.segger.com/products/development-tools/systemview/[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

.LED Indications [%autowidth] [%header] |=== | 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:

.Pico Debug Probe Additional LEDs [%autowidth] [%header] |=== | 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]

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:

[NOTE]

udev rules

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

./etc/udev/rules.d/90-picoprobes.rules [source]

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:

[source]

allow-hotplug enxfe iface enxfe 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:

Win11

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

PlatformIO [[platformio]]

https://platformio.org/[PlatformIO] configuration in platformio.ini is pretty straight forward:

.PlatformIO configuration [source,yaml]

[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 [source,yaml]

[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:

Internals

Building from Source [[how-to-build]]

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 https://github.com/raspberrypi/pico-sdk[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:

.Clone yapicoprobe including submodules [source,bash]

git clone https://github.com/rgrr/yapicoprobe.git cd yapicoprobe git submodule update --init --recursive

.General build sequence [source,bash]

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] [source,bash]

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 [source,bash]

make create-images

.Bare call of cmake [source,bash]

mkdir _build; cd _build cmake .. -D

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

[%autowidth] [%header] ===

| https://github.com/raspberrypi/picoprobe[Picoprobe] | the original

| https://github.com/essele/pico_debug[pico_debug] | another probe which gave ideas for PIO code

| https://github.com/pico-coder/sigrok-pico[sigrok-pico] | original RP2040 based sigrok logic analyzer / oscilloscope

| https://github.com/ARMmbed/DAPLink[DAPLink] | The SWD probe software for a lot of targets and boards

|===

Some Links

[%autowidth] [%header] ===

| https://documentation-service.arm.com/static/5f900b1af86e16515cdc0642[Debug Interface v5.2 Architecture Specification] | if the link does not work, try https://developer.arm.com/documentation/ihi0031/latest/[this]

https://github.com/ARM-software/abi-aa/blob/main/semihosting/semihosting.rst[Semihosting Information]
https://github.com/raspberrypi/pico-sdk[Raspberry Pi Pico SDK]
https://github.com/pyocd/pyOCD[pyOCD on github]

| https://github.com/openocd-org/openocd[OpenOCD on github] | https://openocd.org/[Official Homepage]

https://github.com/probe-rs/probe-rs[probe-rs on github]
https://wiki.segger.com/Use_SystemView_without_RTOS[Use SystemView without RTOS]
https://www.usb.org/document-library/network-control-model-devices-specification-v10-and-errata-and-adopters-agreement[NCM Specification]

|===

Notes

More Text