pico-sdk icon indicating copy to clipboard operation
pico-sdk copied to clipboard

Pico board gets stuck in pre-main when using PICO_CXX_ENABLE_EXCEPTIONS.

Open MarioPL98 opened this issue 1 year ago • 11 comments

Hi. I have a weird issue. My setup is as follows:

  1. Windows pc with vscode and official extension.
  2. Pi Zero with openocd server installed.
  3. Pi Pico connected to Pi Zero over SWD. The board is non-stock, some purple version with additional SPI memory, a little bit different layout https://content.invisioncic.com/r322239/monthly_2023_08/image.png.e0bc5e9365fc0aa30308e0e641d12499.png

I am able to build, upload, debug, etc all programs as long as the CMakeLists parameter PICO_CXX_ENABLE_EXCEPTIONS is set to 0. When I enable it (set to 1), the board gets stuck in pre-main in:

while (!time_reached(t_before)) {   
    uint32_t save = spin_lock_blocking(sleep_notifier.spin_lock);  
    lock_internal_spin_unlock_with_wait(&sleep_notifier, save);  
}   

(https://github.com/raspberrypi/pico-sdk/blob/master/src/common/pico_time/time.c)

I also get this warning in vscode:

warning: multi-threaded target stopped without sending a thread-id, using first non-exited thread  
sleep_until (t=<optimized out>) at C:/Users/Mario/.pico-sdk/sdk/2.0.0/src/common/pico_time/time.c:401  
401                 uint32_t save = spin_lock_blocking(sleep_notifier.spin_lock); 

And this in openocd (Pi Zero's SSH), but I don't think it's related:

Warn : Function FUNC_BOOTROM_STATE_RESET not found in RP2xxx ROM. (probably an RP2040 or an RP2350 A0)  
Warn : Function FUNC_FLASH_RESET_ADDRESS_TRANS not found in RP2xxx ROM. (probably an RP2040 or an RP2350 A0) 

Also, sample code that doesn't even reach main() with PICO_CXX_ENABLE_EXCEPTIONS enabled:

#include <stdio.h>
#include "pico/stdlib.h"

int main()
{
    stdio_init_all();

    while (true) {
        sleep_ms(1000);
    }
}

And CMakeLists.txt:

# Generated Cmake Pico project file

cmake_minimum_required(VERSION 3.13)

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# Initialise pico_sdk from installed location
# (note this can come from environment, CMake cache etc)

# == DO NEVER EDIT THE NEXT LINES for Raspberry Pi Pico VS Code Extension to work ==
if(WIN32)
    set(USERHOME $ENV{USERPROFILE})
else()
    set(USERHOME $ENV{HOME})
endif()
set(sdkVersion 2.0.0)
set(toolchainVersion 13_3_Rel1)
set(picotoolVersion 2.0.0)
set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake)
if (EXISTS ${picoVscode})
    include(${picoVscode})
endif()
# ====================================================================================
set(PICO_BOARD pico CACHE STRING "Board type")

# Pull in Raspberry Pi Pico SDK (must be before project)
include(pico_sdk_import.cmake)

project(hello_world C CXX ASM)

set(PICO_CXX_ENABLE_EXCEPTIONS 1)

set(PICO_CXX_ENABLE_RTTI 1)

# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()

# Add executable. Default name is the project name, version 0.1

add_executable(hello_world hello_world.cpp )

pico_set_program_name(hello_world "hello_world")
pico_set_program_version(hello_world "0.1")

# Modify the below lines to enable/disable output over UART/USB
pico_enable_stdio_uart(hello_world 0)
pico_enable_stdio_usb(hello_world 0)

# Add the standard library to the build
target_link_libraries(hello_world
        pico_stdlib)

# Add the standard include files to the build
target_include_directories(hello_world PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts or any other standard includes, if required
)

pico_add_extra_outputs(hello_world)

Part of launch.json that sends and debugs the program on remote openocd:

        {
            "name": "Pico Debug (Cortex-Debug with external OpenOCD)",
            "cwd": "${workspaceRoot}",
            "executable": "${command:raspberry-pi-pico.launchTargetPath}",
            "request": "launch",
            "type": "cortex-debug",
            "servertype": "external",
            "gdbTarget": "192.168.1.36:3333",
            "gdbPath": "${command:raspberry-pi-pico.getGDBPath}",
            "device": "${command:raspberry-pi-pico.getChipUppercase}",
            "svdFile": "${userHome}/.pico-sdk/sdk/2.0.0/src/${command:raspberry-pi-pico.getChip}/hardware_regs/${command:raspberry-pi-pico.getChipUppercase}.svd",
            "runToEntryPoint": "main",
            // Give restart the same functionality as runToEntryPoint - main
            "postRestartCommands": [
                "break main",
                "continue"
            ]
        },

Any ideas what might be going on? If someone wants to investigate it, we can talk over discord or mumble. I'm out of ideas. Also asked on pico forums: https://forums.raspberrypi.com/viewtopic.php?t=377061 And reddit: https://www.reddit.com/r/raspberrypipico/comments/1fo1wo3/pico_board_gets_stuck_in_premain_when_using_pico/

MarioPL98 avatar Sep 25 '24 13:09 MarioPL98

Can you test a real pico?

peterharperuk avatar Sep 25 '24 15:09 peterharperuk

I just tested with stock board with RPI-B1 stepping. It has the exact same behavior, identical.

MarioPL98 avatar Sep 25 '24 15:09 MarioPL98

image Maybe this will help.

MarioPL98 avatar Sep 25 '24 15:09 MarioPL98

I just noticed that, according to the call stack, it's in main() however breakpoints in main() don't work.

MarioPL98 avatar Sep 25 '24 15:09 MarioPL98

I noticed one more thing. With set(PICO_CXX_ENABLE_EXCEPTIONS 1) the binary doesn't even seem to upload properly. I changed blink time to 1000 ms set PICO_CXX_ENABLE_EXCEPTIONS to 0, ran, debugged program (all working correctly). Then I changed it to 100 ms, did the same and reset the board. For some reason the 100ms binary didn't upload and the board still blinks with 1000ms intervals.

MarioPL98 avatar Sep 25 '24 16:09 MarioPL98

With some help on Discord I discovered that:

  1. Just sending uf2 file via usb (boot while pressing button) works fine and the code is properly sent.
  2. Someone tested on local openocd and it also seems to work fine.
  3. The issue seems to be only when using remote openocd with the parameter PICO_CXX_ENABLE_EXCEPTIONS set to 1. Binary is not updated and thus debug is freaking out and not stopping at breakpoints.

MarioPL98 avatar Sep 25 '24 16:09 MarioPL98

I decided to bloat the .uf2 by adding hardcoded 150KB int array to test if it's the .uf2 size issue. https://pastebin.com/raw/mxySbqV8 With PICO_CXX_ENABLE_EXCEPTIONS set to 0 it still works properly. With it set to 1, it won't upload and thus won't debug properly.

MarioPL98 avatar Sep 25 '24 16:09 MarioPL98

Could you try replacing

"postRestartCommands": [
    "break main",
    "continue"
]

with

"overrideLaunchCommands": [
    "monitor reset init",
    "load \"${{command:raspberry-pi-pico.launchTargetPath}}\""
],

in your launch.json configuration and see if that works any better?

In the VS Code extension we noticed some issues with the default monitor reset halt used, so use this alternative sequence for the "Pico Debug (Cortex-Debug)" configuration, but haven't updated the "Pico Debug (Cortex-Debug with external OpenOCD)" configuration yet

will-v-pi avatar Sep 27 '24 15:09 will-v-pi

It gave an error:

${{command:raspberry-pi-pico.launchTargetPath}}: No such file or directory.
Failed to launch GDB: ${{command:raspberry-pi-pico.launchTargetPath}}: No such file or directory. (from interpreter-exec console "load \"${{command:raspberry-pi-pico.launchTargetPath}}\"")

So I replaced with instead:

            "overrideLaunchCommands": [
                "monitor reset init",
                "load \"${command:raspberry-pi-pico.launchTargetPath}\""
            ],

But it doesn't fix the main problem. The behavior is the same as before; works with "PICO_CXX_ENABLE_EXCEPTIONS 0" but doesnt with "PICO_CXX_ENABLE_EXCEPTIONS 1"

MarioPL98 avatar Sep 27 '24 15:09 MarioPL98

Has this issue been fixed? I'm running into a debugger issue where it doesn't stop at main. I have a working project, and I'm comparing the differences in the .vscode and changing the .vscode on the nonworking project does not seem to help. I'm not quite sure what is causing this issue. I have been trying to use the picoboard_blinky project and it seems to load the firmware since it blinks on the board, but I cannot for the life of me get it to stop at the main function.

shinta4ever avatar Oct 09 '24 18:10 shinta4ever

So, I installed brought my vs code extension Raspberry Pi Pico to 12.2.2 and now it stops at main! I'm not sure if this will solve your issue but it fixed mine. I created the blinky project from the "New Project From Examples" and now it stops at main. Something must have broken in the new vs code extension on the later versions.

UPDATE: The 13.1 version works, but anything above it has issues creating "New Project From Examples."

shinta4ever avatar Oct 09 '24 19:10 shinta4ever

Closing this as it has been fixed in the extension, by using the alternative launch commands

will-v-pi avatar Nov 12 '24 11:11 will-v-pi

I'm having this exact issue using the SDK 2.1.0 and Raspberrry Pi Pico VSCode Extension V 0.17.3 (both latest versions)

When PICO_CXX_ENABLE_EXCEPTIONS is set to 1, and I select debug, the program is not uploaded to the pico, and I can't get any breakpoints to work.

@will-v-pi , what do you mean about using the alternative launch commands?

tomdude126 avatar Jan 23 '25 12:01 tomdude126

and I select debug

What button are you clicking to debug - is it definitely one provided by the VS Code Extension (see the getting started guide for details)?

the program is note uploaded to the pico

What error do you get when it fails to upload the program?

will-v-pi avatar Jan 23 '25 13:01 will-v-pi

@will-v-pi , what do you mean about using the alternative launch commands?

The extension now uses updated launch commands which fix the issue - you don't need to change any of your launch commands

will-v-pi avatar Jan 23 '25 13:01 will-v-pi

Here's my output from DEBUG CONSOLE when I have set(PICO_CXX_ENABLE_EXCEPTIONS 1) in my cmakelists.txt

Cortex-Debug: VSCode debugger extension version 1.12.1 git(652d042). Usage info: https://github.com/Marus/cortex-debug#usage
Reading symbols from c:/users/dude/.pico-sdk/toolchain/13_3_rel1/bin/arm-none-eabi-objdump --syms -C -h -w c:/Users/Dude/Google Drive/RAYKEYZ/Program/KEEZI/KEEZI/build/KEEZI.elf
Reading symbols from c:/users/dude/.pico-sdk/toolchain/13_3_rel1/bin/arm-none-eabi-nm --defined-only -S -l -C -p c:/Users/Dude/Google Drive/RAYKEYZ/Program/KEEZI/KEEZI/build/KEEZI.elf
Launching GDB: "C:\\Users\\Dude\\.pico-sdk\\toolchain\\13_3_Rel1\\bin\\arm-none-eabi-gdb" -q --interpreter=mi2
    IMPORTANT: Set "showDevDebugOutput": "raw" in "launch.json" to see verbose GDB transactions here. Very helpful to debug issues or report problems
Launching gdb-server: "C:\\Users\\Dude/.pico-sdk/openocd/0.12.0+dev/openocd.exe" -c "gdb_port 50000" -c "tcl_port 50001" -c "telnet_port 50002" -s "C:\\Users\\Dude/.pico-sdk/openocd/0.12.0+dev/scripts" -f "c:/Users/Dude/.vscode/extensions/marus25.cortex-debug-1.12.1/support/openocd-helpers.tcl" -f interface/cmsis-dap.cfg -f target/rp2350.cfg -c "adapter speed 5000"
    Please check TERMINAL tab (gdb-server) for output from C:\Users\Dude/.pico-sdk/openocd/0.12.0+dev/openocd.exe
Finished reading symbols from objdump: Time: 74 ms
Finished reading symbols from nm: Time: 91 ms
Output radix now set to decimal 10, hex a, octal 12.
Input radix now set to decimal 10, hex a, octal 12.
`c:\Users\Dude\Google Drive\RAYKEYZ\Program\KEEZI\KEEZI\build\KEEZI.elf' has changed; re-reading symbols.
warning: multi-threaded target stopped without sending a thread-id, using first non-exited thread
main () at C:/Users/Dude/Google Drive/RAYKEYZ/Program/KEEZI/KEEZI/KEEZI.cpp:10
warning: Source file is more recent than executable.
10	        printf("Hello, world!\n");
Program stopped, probably due to a reset and/or halt issued by debugger
[rp2350.dap.core1] VECTRESET is not supported on this Cortex-M core, using SYSRESETREQ instead.
[rp2350.dap.core1] Set 'cortex_m reset_config sysresetreq'.
[rp2350.dap.core0] halted due to breakpoint, current mode: Thread
xPSR: 0xf9000000 pc: 0x00000088 msp: 0xf0000000
[rp2350.dap.core1] halted due to debug-request, current mode: Thread
xPSR: 0xf9000000 pc: 0x00000088 msp: 0xf0000000
[rp2350.dap.core1] VECTRESET is not supported on this Cortex-M core, using SYSRESETREQ instead.
[rp2350.dap.core1] Set 'cortex_m reset_config sysresetreq'.
[rp2350.dap.core0] halted due to breakpoint, current mode: Thread
xPSR: 0xf9000000 pc: 0x00000088 msp: 0xf0000000
[rp2350.dap.core1] halted due to debug-request, current mode: Thread
xPSR: 0xf9000000 pc: 0x00000088 msp: 0xf0000000
warning: could not convert 'main' from the host encoding (CP1252) to UTF-32.
This normally should not happen, please file a bug report.

And here is my DEBUG CONSOLE when I remove set(PICO_CXX_ENABLE_EXCEPTIONS 1) from cmakelists.txt

Cortex-Debug: VSCode debugger extension version 1.12.1 git(652d042). Usage info: https://github.com/Marus/cortex-debug#usage
Reading symbols from c:/users/dude/.pico-sdk/toolchain/13_3_rel1/bin/arm-none-eabi-objdump --syms -C -h -w c:/Users/Dude/Google Drive/RAYKEYZ/Program/KEEZI/KEEZI/build/KEEZI.elf
Reading symbols from c:/users/dude/.pico-sdk/toolchain/13_3_rel1/bin/arm-none-eabi-nm --defined-only -S -l -C -p c:/Users/Dude/Google Drive/RAYKEYZ/Program/KEEZI/KEEZI/build/KEEZI.elf
Launching GDB: "C:\\Users\\Dude\\.pico-sdk\\toolchain\\13_3_Rel1\\bin\\arm-none-eabi-gdb" -q --interpreter=mi2
    IMPORTANT: Set "showDevDebugOutput": "raw" in "launch.json" to see verbose GDB transactions here. Very helpful to debug issues or report problems
Launching gdb-server: "C:\\Users\\Dude/.pico-sdk/openocd/0.12.0+dev/openocd.exe" -c "gdb_port 50000" -c "tcl_port 50001" -c "telnet_port 50002" -s "C:\\Users\\Dude/.pico-sdk/openocd/0.12.0+dev/scripts" -f "c:/Users/Dude/.vscode/extensions/marus25.cortex-debug-1.12.1/support/openocd-helpers.tcl" -f interface/cmsis-dap.cfg -f target/rp2350.cfg -c "adapter speed 5000"
    Please check TERMINAL tab (gdb-server) for output from C:\Users\Dude/.pico-sdk/openocd/0.12.0+dev/openocd.exe
Finished reading symbols from objdump: Time: 67 ms
Finished reading symbols from nm: Time: 82 ms
Output radix now set to decimal 10, hex a, octal 12.
Input radix now set to decimal 10, hex a, octal 12.
`c:\Users\Dude\Google Drive\RAYKEYZ\Program\KEEZI\KEEZI\build\KEEZI.elf' has changed; re-reading symbols.
warning: multi-threaded target stopped without sending a thread-id, using first non-exited thread
0x10000cd0 in timer_time_reached (t=<optimized out>, timer=0x400b0000) at C:/Users/Dude/.pico-sdk/sdk/2.1.0/src/rp2_common/hardware_timer/include/hardware/timer.h:324
324	    return (hi >= hi_target && (timer->timerawl >= (uint32_t) target || hi != hi_target));
Program stopped, probably due to a reset and/or halt issued by debugger
[rp2350.dap.core1] VECTRESET is not supported on this Cortex-M core, using SYSRESETREQ instead.
[rp2350.dap.core1] Set 'cortex_m reset_config sysresetreq'.
[rp2350.dap.core0] halted due to breakpoint, current mode: Thread
xPSR: 0xf9000000 pc: 0x00000088 msp: 0xf0000000
[rp2350.dap.core1] halted due to debug-request, current mode: Thread
xPSR: 0xf9000000 pc: 0x00000088 msp: 0xf0000000
[rp2350.dap.core1] VECTRESET is not supported on this Cortex-M core, using SYSRESETREQ instead.
[rp2350.dap.core1] Set 'cortex_m reset_config sysresetreq'.
[rp2350.dap.core0] halted due to breakpoint, current mode: Thread
xPSR: 0xf9000000 pc: 0x00000088 msp: 0xf0000000
[rp2350.dap.core1] halted due to debug-request, current mode: Thread
xPSR: 0xf9000000 pc: 0x00000088 msp: 0xf0000000
Note: automatically using hardware breakpoints for read-only addresses.
warning: could not convert 'main' from the host encoding (CP1252) to UTF-32.
This normally should not happen, please file a bug report.


Thread 1 "rp2350.dap.core0" hit Temporary breakpoint 2, main () at C:/Users/Dude/Google Drive/RAYKEYZ/Program/KEEZI/KEEZI/KEEZI.cpp:7
warning: Source file is more recent than executable.
7	    stdio_init_all();

I don't any warnings per se

And yes I'm hitting "Debug Project" from the Raspberry Pico Extension Sidebar:

Image

Here's my full cmakelists.txt if needed (with set(PICO_CXX_ENABLE_EXCEPTIONS 1) commented out):

# Generated Cmake Pico project file

cmake_minimum_required(VERSION 3.13)

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# Initialise pico_sdk from installed location
# (note this can come from environment, CMake cache etc)

# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work ==
if(WIN32)
    set(USERHOME $ENV{USERPROFILE})
else()
    set(USERHOME $ENV{HOME})
endif()
set(sdkVersion 2.1.0)
set(toolchainVersion 13_3_Rel1)
set(picotoolVersion 2.1.0)
set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake)
if (EXISTS ${picoVscode})
    include(${picoVscode})
endif()
# ====================================================================================

# Manually control DEBUG_MODE. Used to remove printf statements from the main .cpp binary
set(ENABLE_DEBUG_MODE ON) # Set to OFF to disable debug mode

if(ENABLE_DEBUG_MODE)
    add_compile_definitions(DEBUG_MODE) # This defines DEBUG_MODE for the compiler
    message("DEBUG_MODE is enabled")
else()
    message("DEBUG_MODE is disabled")
endif()
#======================================================================================

#Only Set one of the board types below. Will also need to restart VS Code after changing
#set(PICO_BOARD pico CACHE STRING "Board type")
set(PICO_BOARD pico2 CACHE STRING "Board type")

# Pull in Pico SDK (must be before project)
include(pico_sdk_import.cmake)

project(KEEZI C CXX ASM)

#set(PICO_CXX_ENABLE_EXCEPTIONS 1)
set(PICO_CXX_ENABLE_RTTI 1)

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")

# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()


# Add the executable. Default name is the project name, version 0.1
add_executable(KEEZI KEEZI.cpp Bitmap.cpp)

# Set the program name and version
#pico_set_program_name(KEEZI "KEEZI")
#pico_set_program_version(KEEZI "0.1")

# Enable stdio over UART and USB
pico_enable_stdio_uart(KEEZI 1)
pico_enable_stdio_usb(KEEZI 1)

# Link necessary libraries
target_link_libraries(KEEZI 
    tinyusb_host 
    tinyusb_board 
    pico_stdlib 

)

#sign binary with private key and create otp.json file to load into bookey0 otp rows with picotool
#pico_sign_binary(KEEZI ${CMAKE_CURRENT_SOURCE_DIR}/ec_private_key.pem)
#pico_set_otp_key_output_file(KEEZI ${CMAKE_CURRENT_LIST_DIR}/otp.json)
# Create map/bin/hex/uf2 files
pico_add_extra_outputs(KEEZI)

tomdude126 avatar Jan 23 '25 13:01 tomdude126

Ok, I can reproduce this, but it only occurs with SDK 2.1.0 (whereas the original issue was with SDK 2.0.0).

A fix that is working for me is to delete the build folder, click "Configure CMake" to recreate it, and then when I click "Debug Project" it works. Obviously that's not ideal, but could you check if that fix works for you too?

Also, for me this line only appears when it doesn't work - when it works there is no line like this

`c:\Users\Dude\Google Drive\RAYKEYZ\Program\KEEZI\KEEZI\build\KEEZI.elf' has changed; re-reading symbols.

will-v-pi avatar Jan 23 '25 14:01 will-v-pi

That method works some of the time. I'm getting really inconsistent results. I seem to have better luck using the Run and Debug start debug button than the Debug button from the pico extension. I can't really figure out anything that works 100% of the time yet. The "Flash Project (SWD)" button works consistently to load the program atleast but obviously debugging will be a bit more annoying until there's a real fix.

It also seems that if I'm in a debug session, then stop the debug, then immediately start debug again, it almost never works. If I don't make a change to my program it's less likely to work 2 times in a row. Sorry for the non concrete information but I'm gonna take a break from testing for now.

tomdude126 avatar Jan 23 '25 16:01 tomdude126

Please Reopen this...

For me, the PICO_CXX_ENABLE_EXCEPTIONS doesn't seem to make much of a difference..

I can, most of the time, debug fine if I delete the build-folder beforehand

ONCE

SDK 2.1.1

If I don't delete the build folder beforehand, the code isn't even uploaded at all...

I've also tried changing my launch commands to something like this

            "overrideLaunchCommands": [
                "monitor reset init",
                "file \"${command:raspberry-pi-pico.launchTargetPath}\"",
                "load",
            ],

Update

I can get somewhat reliable debugging when both

  • Not having enabled CXX_Exceptions
  • using "monitor reset halt" instead of "monitor reset init"

Alia5 avatar Mar 29 '25 19:03 Alia5

I couldn't get my debug session to start. (PicoProbe + Pico2W)

Thanks to this thread, changed launch.json to

using "monitor reset halt" instead of "monitor reset init"

It now launches

BryanCrotazGivEnergy avatar Jul 04 '25 13:07 BryanCrotazGivEnergy

same problem debugging freertos apps, Sometimes deleting build folder and restarting vs code helps, sometimes not... :(

krzysztofkuczek avatar Aug 24 '25 11:08 krzysztofkuczek

A simple example seems to work out of the box repeatedly, but my actual project with USB (tinyusb usbtmc) I think runs into interrupt troubles during startup. Same project used to work flawlessly a year ago

tvallaitis avatar Aug 29 '25 15:08 tvallaitis

but my actual project with USB (tinyusb usbtmc) I think runs into interrupt troubles during startup. Same project used to work flawlessly a year ago

Downgrading to an older release of pico-sdk that still works correctly with your project is always an option.

But if you want us to investigate your problem, you'll be better off creating a new issue, and providing as much info as possible.

lurch avatar Sep 01 '25 13:09 lurch

This should still be a live issue, debug is a nightmare. Keeps loosing sync and failing to upload new builds to pico. Fed up with having to reset and rebuild to get around this

GuySMowbray avatar Sep 26 '25 19:09 GuySMowbray