majbthrd / pico-debug

virtual debug pod for RP2040 "Raspberry Pi Pico" with no added hardware
372 stars 51 forks source link

Add basic usage instructions #1

Closed cesarvandevelde closed 3 years ago

cesarvandevelde commented 3 years ago

First off, this is really cool!

I gave it a go yesterday, but I could not quite get it to work. The UF2 file works as expected, but I could not figure out which OpenOCD branch / which initialization settings to use. I've tried the rp2040_cmsisdap and the rp2040_singlecore branches.

The rp2040_cmsisdap branch was launched with the following command:

./src/openocd -s tcl -f interface/cmsis-dap.cfg -c "cmsis_dap_vid_pid 0x1209 0x2488" -c "transport select swd" -c "adapter speed 4000" -f target/rp2040.cfg

This gave me the following output:

Open On-Chip Debugger 0.10.0+dev-g7e5ea1861-dirty (2021-02-06-12:25)
Licensed under GNU GPL v2
For bug reports, read
    http://openocd.org/doc/doxygen/bugs.html
swd
adapter speed: 4000 kHz

Info : Hardware thread awareness created
Info : Hardware thread awareness created
Info : RP2040 Flash Bank Command
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : CMSIS-DAP: SWD  Supported
Info : CMSIS-DAP: FW Version = 2.0.0
Info : CMSIS-DAP: Interface Initialised (SWD)
Info : SWCLK/TCK = 0 SWDIO/TMS = 0 TDI = 0 TDO = 0 nTRST = 0 nRESET = 0
Info : CMSIS-DAP: Interface ready
Info : clock speed 4000 kHz
Error: Sequence 4 not supported
Info : DAP init failed

Error: Sequence 3 not supported
Error: Sequence 4 not supported

For the rp2040_singlecore branch (this was before 5e8624d):

./src/openocd -s tcl -f interface/cmsis-dap.cfg -c "cmsis_dap_vid_pid 0x1209 0x2488" -c "transport select swd" -c "adapter speed 4000" -f target/rp2040-core1.cfg

The OpenOCD server started without problem, but when I issue a load command from GDB, the OpenOCD server hangs:

Open On-Chip Debugger 0.10.0+dev-g937c0aa1d-dirty (2021-02-06-12:45)
Licensed under GNU GPL v2
For bug reports, read
    http://openocd.org/doc/doxygen/bugs.html
swd
adapter speed: 4000 kHz

Info : Hardware thread awareness created
Info : RP2040 Flash Bank Command
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : CMSIS-DAP: SWD  Supported
Info : CMSIS-DAP: FW Version = 2.0.0
Info : CMSIS-DAP: Interface Initialised (SWD)
Info : SWCLK/TCK = 0 SWDIO/TMS = 0 TDI = 0 TDO = 0 nTRST = 0 nRESET = 0
Info : CMSIS-DAP: Interface ready
Info : clock speed 4000 kHz
Error: Sequence 4 not supported
Info : SWD DPIDR 0x0bc12477
Info : SWD DLPIDR 0x10000001
Info : rp2040.core1: hardware has 4 breakpoints, 2 watchpoints
Info : starting gdb server for rp2040.core1 on 3333
Info : Listening on port 3333 for gdb connections
Info : accepting 'gdb' connection on tcp/3333
Warn : target was in unknown state when halt was requested
Info : RP2040 B0 Flash Probe: 2097152 bytes @10000000, in 512 sectors

Warn : target not halted
target halted due to debug-request, current mode: Thread
xPSR: 0xf1000000 pc: 0x000000ee msp: 0x20041f00
Info : Writing 24500 bytes starting at 0x0
Error: error writing data: hid_error is not implemented yet
Error: CMSIS-DAP command CMD_DISCONNECT failed.
Error: error writing data: hid_error is not implemented yet
Error: CMSIS-DAP command CMD_CONNECT failed.
Error: error writing data: hid_error is not implemented yet
Error: CMSIS-DAP command CMD_DISCONNECT failed.
Error: error writing data: hid_error is not implemented yet
Error: CMSIS-DAP command CMD_CONNECT failed.
Error: error writing data: hid_error is not implemented yet
^CError: error writing data: hid_error is not implemented yet
Error: CMSIS-DAP command CMD_DISCONNECT failed.
Error: error writing data: hid_error is not implemented yet
Error: CMSIS-DAP command CMD_CONNECT failed.
/bin/bash: line 1:  7445 Killed: 9               ./src/openocd -s tcl -f interface/cmsis-dap.cfg -c "cmsis_dap_vid_pid 0x1209 0x2488" -c "transport select swd" -c "adapter speed 4000" -f target/rp2040-core1.cfg

Could you add some basic usage instructions to the readme? Thanks!

majbthrd commented 3 years ago

Thanks @cesarvandevelde. I'm trying to get a feel for how people might be using this, and such helpful feedback is appreciated.

When both of last week's PRs (rp2040_cmsisdap and rp2040_singlecore) are finally adopted... given pico_debug v10.01+, OpenOCD usage would be like this:

./src/openocd -s tcl -f interface/cmsis-dap.cfg -c "transport select swd" -c "adapter speed 4000" -f target/rp2040-core0.cfg

Until both PRs get adopted, taking the rp2040_cmsisdap branch and adding in the ./tcl/target/rp2040-core0.cfg from rp2040_singlecore would be a workaround.

Alternatively, for users of Rowley Crossworks for ARM, code like the following just works without any special additions:

https://github.com/majbthrd/pico-cachedetector

However, that might not appeal to everyone.

Going back to OpenOCD, if Chapter 5 of Getting started with Raspberry Pi Pico proves to be the guide that most people are reading...

pico-debug-gimmecache.uf2 is the better pico-debug choice for existing Raspberry examples.

I would have suggested "blink" as a more universal example project rather than "hello_world".

Section 5.2 "Installing OpenOCD" mixes Raspberry Pi cabling with OpenOCD, and the Raspberry Pi cabling can be ignored.

For Section 5.4, their openocd command line is replaced with the openocd at the top of this post.

At the moment, the problem is that Raspberry Pi suggests "monitor reset init" as a gdb command. This is a problem because pico-sdk, in particular, pulls the rug out from under pico-debug multiple times by doing the very two things that the pico-debug README.md asks users to not do:

1) it resets the USB peripheral 2) it re-initializes the clock going to the USB peripheral

I think yet another PR to pico-sdk to stop unnecessary jostling the USB peripheral is needed to try to address this. Until that happens, pico-debug is not a replacement for Raspberry Pi's more expensive offerings.

Note that I'm been super happy with pico-debug for debugging RAM-only programs... however, the problem is that pico-sdk has ABSOLUTELY NOTHING existing for this, and even with a new linker script, pico-sdk still presently pulls the rug out from under pico-debug.

Another alternative that I've been contemplating is to make Dapper Mime a replacement to both Chapter 5's Raspberry Pi and Appendix A's picoprobe. It doesn't do that currently, but I could get that done by this evening, I think.

In that case, one would only need the OpenOCD rp2040_cmsisdap branch and TWO rp2040s, and usage would be:

./src/openocd -s tcl -f interface/cmsis-dap.cfg -c "transport select swd" -c "adapter speed 4000" -f target/rp2040.cfg

and the instructions would be largely the same (same SWCLK and SWDIO wiring as Figure 34, and OpenOCD would be basically the same except the call immediately above).

Thoughts?

majbthrd commented 3 years ago

It has been suggested by someone else that pico-debug could be compiled into the user application. That way, no matter what pico-sdk does during initialization, pico-debug could start after that but before main() got called. I'm not as keen on this.

A fourth option that just occurred to me would be to submit a PR to pico-sdk that looked in RAM for a signature indicating that the user had just loaded pico-debug. In that case, it would call pico-debug prior to calling main(). In the normal scenario of the rp2040 booting, that signature would not be present and the user code would be started normally.

cesarvandevelde commented 3 years ago

Thanks for the detailed response! I'll have another go at it tomorrow. Just a thought: how about going the black magic probe route, i.e. expose a GDB-server over USB serial, and do away with OpenOCD entirely. Would probably take up more code space, but you'd have total control over monitor commands...

majbthrd commented 3 years ago

OpenOCD isn't the problem; pico-sdk is. Even with a black magic probe approach, pico-sdk would still disrupt USB. That's the tradeoff with using two CPUs on the same chip. The significant upside, though, is the prospect of a single chip being able to debug itself. Anyway, these should be solvable problems, but will require some pico-sdk modifications to be more hospitable (towards users that are using pico-sdk project examples).

For those that have two RP2040, I've modified Dapper Mime to be a raspberrypi_swd.cfg and picoprobe alternative. The rp2040_cmsisdap branch is needed prior to the PR being accepted.

majbthrd commented 3 years ago

@cesarvandevelde, please give the following a try; it is a set of basic usage instructions:

https://github.com/majbthrd/pico-demos

cesarvandevelde commented 3 years ago

Thanks for the detailed write-up! I did spend some more time on this yesterday, and got the basics to work with the Pico SDK.

The SDK lets you selectively disable certain libraries by setting a SKIP_xxx variable before including pico_sdk_init.cmake. You can then provide your own implementation in order to overwrite undesired behavior. In this case, the problematic libraries are pico_runtime and pico_standard_link. I hacked together a replacement pico_runtime that does not reset the USB periperhal. I have not done anything about pico_standard_link yet. I figured it was unlikely that my blinky sketch would interfere with the upper 6K of RAM, but for proper debugging, a custom linker script should be used.

Here's the CMakeLists I used:

cmake_minimum_required(VERSION 3.12)

set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")

if (NOT PICO_SDK_PATH)
    message(FATAL_ERROR "SDK location was not specified. Please set PICO_SDK_PATH.")
endif()

set(SKIP_PICO_RUNTIME 1)

# Pull in SDK (must be before project)
include(${PICO_SDK_PATH}/pico_sdk_init.cmake)

project(pico_testy C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

pico_sdk_init()

add_subdirectory(pico_runtime_hack)

add_executable(blink
    "src/main.cpp"
)

# Pull in our pico_stdlib which pulls in commonly used features
target_link_libraries(blink
    pico_stdlib
    hardware_pwm
)

# Create map/bin/hex file etc.
pico_add_extra_outputs(blink)

The modified pico_runtime is almost exactly the same as the one included in the SDK, save for 2 lines:

@@ -67,7 +67,8 @@
             RESETS_RESET_IO_QSPI_BITS |
             RESETS_RESET_PADS_QSPI_BITS |
             RESETS_RESET_PLL_USB_BITS |
-            RESETS_RESET_PLL_SYS_BITS
+            RESETS_RESET_PLL_SYS_BITS |
+            RESETS_RESET_USBCTRL_BITS
     ));

     // Remove reset from peripherals which are clocked only by clk_sys and
@@ -78,8 +79,8 @@
             RESETS_RESET_SPI0_BITS |
             RESETS_RESET_SPI1_BITS |
             RESETS_RESET_UART0_BITS |
-            RESETS_RESET_UART1_BITS |
-            RESETS_RESET_USBCTRL_BITS
+            RESETS_RESET_UART1_BITS //|
+            // RESETS_RESET_USBCTRL_BITS
     ));

     // pre-init runs really early since we need it even for memcpy and divide!

Seems that it should be possible to create a small CMake library to beat the Pico SDK into submission, but that will take some more work...

majbthrd commented 3 years ago

Thank so much for deciphering the cryptic CMakeList. I think we're making real progress.

I'm hoping that you will be able to duplicate the same successes that I'm seeing locally. There is a new v10.02 pico-debug release, and with that and the following pico-sdk diff, I can use pico-debug with gdb (and other IDEs) with pico-example code.

diff --git a/src/rp2_common/hardware_clocks/clocks.c b/src/rp2_common/hardware_clocks/clocks.c
index 6195dcd..125edc6 100644
--- a/src/rp2_common/hardware_clocks/clocks.c
+++ b/src/rp2_common/hardware_clocks/clocks.c
@@ -148,12 +148,16 @@ void clocks_init(void) {
     // PLL USB: 12 / 1 = 12MHz * 40  = 480 MHz / 5 / 2 =  48MHz
     /// \end::pll_settings[]

-    reset_block(RESETS_RESET_PLL_SYS_BITS | RESETS_RESET_PLL_USB_BITS);
-    unreset_block_wait(RESETS_RESET_PLL_SYS_BITS | RESETS_RESET_PLL_USB_BITS);
+    /* check if we have a roommate (other core has initialized PLL_USB) */
+    bool roommate = pll_usb_hw->cs & PLL_CS_LOCK_BITS;
+
+    uint32_t pll_resets = RESETS_RESET_PLL_SYS_BITS | ((roommate) ? 0 : RESETS_RESET_PLL_USB_BITS);
+    reset_block(pll_resets);
+    unreset_block_wait(pll_resets);

     /// \tag::pll_init[]
     pll_init(pll_sys, 1, 1500 * MHZ, 6, 2);
-    pll_init(pll_usb, 1, 480 * MHZ, 5, 2);
+    if (!roommate) pll_init(pll_usb, 1, 480 * MHZ, 5, 2);
     /// \end::pll_init[]

     // Configure clocks
diff --git a/src/rp2_common/pico_runtime/runtime.c b/src/rp2_common/pico_runtime/runtime.c
index dba0d3c..b9d400f 100644
--- a/src/rp2_common/pico_runtime/runtime.c
+++ b/src/rp2_common/pico_runtime/runtime.c
@@ -67,6 +67,8 @@ void runtime_init(void) {
             RESETS_RESET_IO_QSPI_BITS |
             RESETS_RESET_PADS_QSPI_BITS |
             RESETS_RESET_PLL_USB_BITS |
+            RESETS_RESET_USBCTRL_BITS |
+            RESETS_RESET_SYSCFG_BITS |
             RESETS_RESET_PLL_SYS_BITS
     ));

The executive summary on the changes is:

There are two PLLs on the RP2040: PLL_SYS and PLL_USB

pico-sdk uses both, and pico-bootrom uses just PLL_SYS. For v10.01 and earlier, I adopted the code from pico-bootrom because it is 1/10th the code size of pico-sdk's equivalent routine. v10.02 uses a mix of pico-sdk and optimized routines to keep code size in check.

Since pico-sdk is going to mess with the PLLs, using just one (PLL_USB) makes it easier to avoid its wrath.

The diff avoids the reset that you discovered (as well as SYSCFG, as this is used by one core debugging the other), and if it sees PLL_USB is already in use, it doesn't try to reinitialize it.

cesarvandevelde commented 3 years ago

Great! I'll give it a go later this week. I'll see if I can put together an example repo with CMake overrides for clocks.c, runtime.c and a custom linker script...

majbthrd commented 3 years ago

FYI: the latest commit now includes complete instructions on obtaining a patched pico-sdk and openocd, building examples from pico-examples, and debugging them with pico-debug! :)

About the only remaining issue is the linker script. Ideally, it would be desirable to not have to modify every example. Given that the current linker script uses the "SCRATCH" memory (0x2004_0000+) for stacks and starts from the bottom of SRAM for everything else, the memory region pico-debug is using is as far away from the user code as it can be.

dcelectr commented 3 years ago

@majbthrd Thank you for directing me to this repository.

Thanks @cesarvandevelde. I'm trying to get a feel for how people might be using this, and such helpful feedback is appreciated.

I have been able to run successfully opneocd with a second RP Pico board, configured as a picoprobe. I was thinking to design a dev board with two RP2040 chips, one as the main chip and the other as the EDBG chip (similar to Arduino Zero). When I heard that the EDBG functionality can be implemented in a single chip, I was excited. I understand that there are limitations with the USB using both cores of a single RP2040 chip. People have been using the USB serial port as a poor man's debugger; thus, using the USB as an SWD probe is a better trade off. An instance where this can be an issue is when the RP2040 is used as a Human Interface Device (HID such as: keyboard, mouse, etc). With this message, I wanted to give you a feel on how I intend to use this application. EDIT: I tried the pico-debug-gimmecache.uf2 and built the openocd with --enable-cmsis-dap flag. I successfully loaded the blink.elf from the pico-examples the as well as I2C OLED example. After the

(gdb) target remote localhost:3333
(gdb) load
(gdb) monitor reset init
(gdb) continue

the gdb connection breaks, but the uploaded .elf file runs. program_stopped I understand this is WIP, unless I am doing something wrong.

majbthrd commented 3 years ago

@DCelectronics, sorry for the delay. I have been without electricity for the past 30 hours. :(

I appreciate your interest in the project, and I'm excited about the potential. I honestly think we should be past the Work In Progress point.

I hate to ask, but did you follow the steps into the howto subdirectory, including downloading the alternate pico-sdk, setting the PICO_SDK_PATH, and running cmake in a newly created build directory? The behavior that you are showing looks exactly like you've used the standard pico-sdk. The standard pico-sdk re-configures the PLL_USB used by pico-debug (even when the user's pico application doesn't have USB functionality... GRRRR), so that's why the alternate pico-sdk is needed (until the main pico-sdk is fixed/improved).

dcelectr commented 3 years ago

@majbthrd sorry to hear about the power outages you experience. Thank you for asking if I followed the steps into the howto subdirectory. I admit that I skipped the step for downloading the alternate pico-sdk because I erroneously thought I have met that requirement (I didn't realize that it was different. Oops).

majbthrd commented 3 years ago

I'm closing this because basic usage instructions have since been added. What would really help would be if people who have used pico-debug to post about their success and star the project.