RP2040 Pi Pico: buggy J-Link/Ozone, yet OpenOCD works - Page 1
Forum section: electronics / general

author: mblinov
author_rank: Contributor
timestamp: February 12, 2023, 12:44:18 am
content: Hi all, I'm facing a really frustrating issue: I am trying to run under debug one of thepico-examplesprojects, specifically thehello_uart.cexample.Now, I've got two debug probes in front of me:A Pi Pico that is flashed with the latestpicoprobe binary, using the latest freshly-builtopenocdthat is specific for the picoprobeA J-Link Edu miniThe Picoprobe works without a hitch: The J-Link does not. The J-Link can load the binary, single step for a bit, but it very quickly throws a HardFault exception, which I'm having real trouble debugging.The point at which the HardFault is thrown appears to not be consistent.Judging from the internet (and SEGGER's own website) this should work without a hitch, so I'm fairly confident I'm doing something wrong - the only trouble is, as far as I can tell, I'm doing everything by the book - would love if someone more experienced with debug probes would suggest something.The (working) Picoprobe OpenOCD flowNow, as the title says, the OpenOCD -> picoprobe flow works perfectly. The flow works like this:1). Open terminal A (MSYS2), and invokeCode:$ openocd-install/bin/openocd.exe \-f openocd-install/share/openocd/scripts/interface/cmsis-dap.cfg \-f openocd-install/share/openocd/scripts/interface/picoprobe.cfg -f openocd-install/share/openocd/scripts/target/rp2040.cfgThe server then duly responds:Code:Open On-Chip Debugger 0.11.0-g8e3c38f78 (2023-02-11-21:45)Licensed under GNU GPL v2For bug reports, readhttp://openocd.org/doc/doxygen/bugs.htmlWarn : Interface already configured, ignoringadapter speed: 5000 kHzInfo : auto-selecting first available session transport "swd". To override use 'transport select <transport>'.Info : Hardware thread awareness createdInfo : Hardware thread awareness createdInfo : RP2040 Flash Bank CommandInfo : Listening on port 6666 for tcl connectionsInfo : Listening on port 4444 for telnet connectionsInfo : Using CMSIS-DAPv2 interface with VID:PID=0x2e8a:0x000c, serial=E66118604B1F5E21Info : CMSIS-DAP: SWD SupportedInfo : CMSIS-DAP: FW Version = 2.0.0Info : CMSIS-DAP: Interface Initialised (SWD)Info : SWCLK/TCK = 0 SWDIO/TMS = 0 TDI = 0 TDO = 0 nTRST = 0 nRESET = 0Info : CMSIS-DAP: Interface readyInfo : clock speed 5000 kHzInfo : SWD DPIDR 0x0bc12477Info : SWD DLPIDR 0x00000001Info : SWD DPIDR 0x0bc12477Info : SWD DLPIDR 0x10000001Info : rp2040.core0: hardware has 4 breakpoints, 2 watchpointsInfo : rp2040.core1: hardware has 4 breakpoints, 2 watchpointsInfo : starting gdb server for rp2040.core0 on 3333Info : Listening on port 3333 for gdb connections2). Open terminal B (cmd.exe), and open GDB:Code:C:\Users\Maxim\prj\pi-pico-blah>arm-none-eabi-gdb.exe pico-examples-build-debug\uart\hello_uart\hello_uart.elfConnect to the OpenOCD GDB server interface on port 3333:Code:(gdb) tar extended-remote :3333Load the binary:Code:(gdb) loadLoading section .boot2, size 0x100 lma 0x10000000Loading section .text, size 0x4200 lma 0x10000100Loading section .rodata, size 0xfa0 lma 0x10004300Loading section .binary_info, size 0x20 lma 0x100052a0Loading section .data, size 0x22c lma 0x100052c0Start address 0x100001e8, load size 21740Transfer rate: 4 KB/sec, 3623 bytes/write.(gdb)Now, I can run the program to completionCode:(gdb) cContinuing.target halted due to debug-request, current mode: ThreadxPSR: 0x01000000 pc: 0x00000138 msp: 0x20041f00Thread 1 received signal SIGTRAP, Trace/breakpoint trap._exit (status=0)at C:/Users/Maxim/prj/pi-pico-blah/pico-sdk/src/rp2_common/pico_runtime/runtime.c:186186 __breakpoint();(gdb)(It is expected for us to end up in_exit, since themain()function in this case returns after printing some text.)The (non-working) J-Link flowThe J-Link tools however are constantly throwing HardFaults all over the place. I've tried using two tools:J-Link GDB serverOzoneI'm using the latest J-Link as of writing (version 7.84f DLLs, and version 3.28c for Ozone.)Here is what a typical J-Link GDB server session looks like:First, setup the server:After launching:This time ofcourse I don't have to open a separate OpenOCD terminal. In cmd.exe, I open the GDB client exactly the same way, exactly the same binary:Code:C:\Users\Maxim\prj\pi-pico-blah>arm-none-eabi-gdb.exe pico-examples-build-debug\uart\hello_uart\hello_uart.elfAnd attach to the port as specified by the J-Link GDB server (port 2331):Code:(gdb) tar extended-remote :2331Remote debugging using :2331__breakpoint ()at C:/Users/Maxim/prj/pi-pico-blah/pico-sdk/src/rp2_common/pico_platform/include/pico/platform.h:269269 __asm__("bkpt #0");(gdb)Ok, fine. I should specify at this point: I have not powered off the Pi Pico under debug: I've literally hot-swapped the SWD connectors from the Picoprobe over to the J-Link. Nothing has been power cycled. (Actually, reading this back: it *is* weird that it reports a different source line...)So now I load the binary:Code:(gdb) loadLoading section .boot2, size 0x100 lma 0x10000000Loading section .text, size 0x4200 lma 0x10000100Loading section .rodata, size 0xfa0 lma 0x10004300Loading section .binary_info, size 0x20 lma 0x100052a0Loading section .data, size 0x22c lma 0x100052c0Start address 0x100001e8, load size 21740Transfer rate: 732 KB/sec, 3623 bytes/write.All the numbers exactly the same, fine. Now I just continue:Code:(gdb) cContinuing.Program received signal SIGTRAP, Trace/breakpoint trap.0xfffffffe in ?? ()And there it is. We don't end up in_exitas last time, but in a reset vector of some kind? (showing my ignorance here.)Listing the backtrace givesCode:(gdb) bt#0 0xfffffffe in ?? ()#1 <signal handler called>#2 0x60000200 in ?? ()#3 0x10000264 in hold_non_core0_in_bootrom ()at C:/Users/Maxim/prj/pi-pico-blah/pico-sdk/src/rp2_common/pico_standard_link\crt0.S:322Backtrace stopped: previous frame identical to this frame (corrupt stack?)My own observationsReally interesting aside: The entry point symbol is called_entry_point. If I put a breakpoint atmain, and print the program counter with(gdb) p /x $sp, the value is different depending on whether the GDB server is OpenOCD or J-Link:For the OpenOCD, upon entry tomainthe stack pointer was0x20042000:Code:(gdb) loadLoading section .boot2, size 0x100 lma 0x10000000Loading section .text, size 0x4200 lma 0x10000100Loading section .rodata, size 0xfa0 lma 0x10004300Loading section .binary_info, size 0x20 lma 0x100052a0Loading section .data, size 0x22c lma 0x100052c0Start address 0x100001e8, load size 21740Transfer rate: 4 KB/sec, 3623 bytes/write.(gdb) i bNo breakpoints or watchpoints.(gdb) b mainBreakpoint 1 at 0x10000364: file C:/Users/Maxim/prj/pi-pico-blah/pico-examples/uart/hello_uart/hello_uart.c, line 22.Note: automatically using hardware breakpoints for read-only addresses.(gdb) cContinuing.target halted due to debug-request, current mode: ThreadxPSR: 0x01000000 pc: 0x00000138 msp: 0x20041f00Thread 1 hit Breakpoint 1, main ()at C:/Users/Maxim/prj/pi-pico-blah/pico-examples/uart/hello_uart/hello_uart.c:2222 int main() {(gdb) p /x $sp$1 = 0x20042000And for the J-Link, upon entry tomainthe stack pointer was0x20041ff0:Code:(gdb) loadLoading section .boot2, size 0x100 lma 0x10000000Loading section .text, size 0x4200 lma 0x10000100Loading section .rodata, size 0xfa0 lma 0x10004300Loading section .binary_info, size 0x20 lma 0x100052a0Loading section .data, size 0x22c lma 0x100052c0Start address 0x100001e8, load size 21740Transfer rate: 758 KB/sec, 3623 bytes/write.(gdb) cContinuing.Thread 2 hit Breakpoint 1, main ()at C:/Users/Maxim/prj/pi-pico-blah/pico-examples/uart/hello_uart/hello_uart.c:2222 int main() {(gdb) p /x $sp$3 = 0x20041ff0(That is, assuming that I can get tomainbefore it throws an exception.)

author: mblinov
author_rank: Contributor
timestamp: February 12, 2023, 12:51:48 am
content: P.S. if someone could *please* tell me what the difference betweenRP2040_M0_0andRP2040_M0_1in the J-Link MCU selector is, I will be forever indebted:

author: Foxxz
author_rank: Regular Contributor
timestamp: February 12, 2023, 02:27:58 am
content: Is that maybe which CPU core you want to debug?

author: mwb1100
author_rank: Frequent Contributor
timestamp: February 12, 2023, 06:41:12 am
content: Quote from: mblinov on February 12, 2023, 12:51:48 amJust a guess, but each entry might be for one of the 2 cores on the RP2040

author: mwb1100
author_rank: Frequent Contributor
timestamp: February 12, 2023, 07:24:09 am
content: Have you read Segger's wiki article on the RP2040 -https://wiki.segger.com/Raspberry_Pi_RP2040QuoteMaybe the OpenOCD .cfg files are taking care of this somehow and it's not being done for the J-Link?One of the things that the second stage bootloader does is set up the execute in place (XIP) environment for the flash that's on the board. I imagine that if that's not set up correctly, the kind of crash you're seeing might be the result.Also, I see that in the OpenOCD example when it gets to the breakpoint at main, it's on "Thread 1". But for the J-Link it's on "Thread 2". Don't know what that means, but it seems fishy.Of course, I've only spent about 10 minutes reading the Segger article an some of the PR2040 datasheet. So I could be spouting non-sense. But if you don't know how the 2nd stage BTL is working, it might be a place to start looking.

author: mino-fm
author_rank: Regular Contributor
timestamp: February 12, 2023, 11:40:38 am
content: Quote from: mwb1100 on February 12, 2023, 07:24:09 amAs far as I can remember 2. stage bootloader is included in Segger's examples.I tried Segger's IDE and Ozone but put it away very soon. I don't know anything about OpenOCD.@mblinovDid you connect /reset-pin of J-Link to run-pin of RP2040?Do you like to test another IDE I'm working with? It is EWARM from IAR. I'm using J-Link edu-mini too and could give you some demo examples. Debugging works very fine.Sometimes debugging is critical because of RP2040's bootloader, which is always running before reaching main(). It seems to me, programm is starting without stop at main() so hard faults could happen before the degugger could tell you anything.Without PowerOn there is no reset of GPIO, UART, ... so you have to do it by your own. Sometimes this can be very nasty.

author: bson
author_rank: Unknown
timestamp: February 12, 2023, 06:34:24 pm
content: Quote from: mblinov on February 12, 2023, 12:44:18 amIt's in _exit. The problem is the gdb server in this case doesn't properly cross exceptions on the call stack. If you do a stack backtrace ('bt') in gdb one will show the exception boundary, the other will just display nonsense.It's also be plausible that even if their own debugger uses the gdb debug server, it might not rely on it to walk the stack frame chain so they don't really use this server functionality themselves and don't see a problem. Then when a real gdb doesn't work right they assume it's just gdb.

author: enz
author_rank: Regular Contributor
timestamp: April 03, 2025, 02:47:09 pm
content: Did you ever solve the problem?I am asking because i ran into the exact same issue today and found the solution in the Segger Wiki after some digging around.