picotool icon indicating copy to clipboard operation
picotool copied to clipboard

Unable to reset pico

Open LandryNorris opened this issue 2 years ago • 14 comments

When I run picotool.exe reboot -f -u, I get the following error: ERROR: Unable to locate reset interface on the device, despite the fact that running the info command indicates Device at bus 1, address 30 appears to be a RP2040 device with a USB serial connection, not in BOOTSEL mode. You can force reboot into BOOTSEL mode via 'picotool reboot -f -u' first.. Running a load command does work, however, if I manually enter BOOTSEL via the button.

I am using picotool 1.1.2 and libusb 1.0.26 on Windows 11.

I have tried using both the Win32 driver and the libusb-win32 driver from Zadig.

LandryNorris avatar Nov 13 '23 18:11 LandryNorris

By adding some logging to the source for the 1.1.2 release, I can determine that picotool can find two interfaces with altsettings: one with class/subclass of 2/2, and one with class/subclass of 10/0. Neither of these matches the defined class/subclass for reset.

LandryNorris avatar Nov 13 '23 18:11 LandryNorris

Having the same issue. When using PlatformIO (which uses the tool too), it works without problems. Checking the log (macOS) shows the following: Forcing reset using 1200bps open/close on port /dev/cu.usbmodem11301

Using picotool shows: "No accessible RP2040 devices in BOOTSEL mode were found.

but:

Device at bus 1, address 4 appears to be a RP2040 device with a USB serial connection, so consider -f to force the reboot."

Now using the proposed command line shows: "ERROR: Unable to locate reset interface on the device"

Reneg973 avatar Jan 03 '24 10:01 Reneg973

You need to ensure that PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE is enabled, which adds the reset interface. See Appendix B in https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-c-sdk.pdf

Forcing reset using 1200bps open/close on port /dev/cu.usbmodem11301

I guess that indicates that PICO_STDIO_USB_ENABLE_RESET_VIA_BAUD_RATE is enabled. Maybe that implies that PlatformIO has disabled PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE for some reason?

lurch avatar Jan 03 '24 11:01 lurch

You need to ensure that PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE is enabled, which adds the reset interface. See Appendix B in https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-c-sdk.pdf

Forcing reset using 1200bps open/close on port /dev/cu.usbmodem11301

I guess that indicates that PICO_STDIO_USB_ENABLE_RESET_VIA_BAUD_RATE is enabled. Maybe that implies that PlatformIO has disabled PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE for some reason?

What I mean is PlatformIO (with Arduino) uses picotool (or I'm wrong?) to reset the Pico into BOOTSEL for uploading the uf2. So uploading via VSCode with PlatformIO does everything automatically. But when building my app with pico-sdk (No platformIO nor Arduino), I first have to reconnect Pico while pressing BOOTSEL. I would like to prevent this.

Reneg973 avatar Jan 03 '24 12:01 Reneg973

What I mean is PlatformIO (with Arduino) uses picotool (or I'm wrong?) to reset the Pico into BOOTSEL for uploading the uf2.

Your log message indicates that PlatformIO is rebooting the Pico by changing the baud rate of the USB-serial device, which isn't something that picotool does itself.

But when building my app with pico-sdk (No platformIO nor Arduino), I first have to reconnect Pico while pressing BOOTSEL. I would like to prevent this.

Have you got stdio_usb enabled in your CMakeLists.txt ? See Chapter 4 in https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf

lurch avatar Jan 03 '24 12:01 lurch

Your log message indicates that PlatformIO is rebooting the Pico by changing the baud rate of the USB-serial device, which isn't something that picotool does itself.

Ok understood. I thought the message "use -f to force the reboot" would tell me it does that.

Reneg973 avatar Jan 03 '24 14:01 Reneg973

I thought the message "use -f to force the reboot" would tell me it does that.

Copied from the README.md for this project:

        -f, --force
            Force a device not in BOOTSEL mode but running compatible code to reset so the command can be executed. After executing
            the command (unless the command itself is a 'reboot') the device will be rebooted back to application mode
        -F, --force-no-reboot
            Force a device not in BOOTSEL mode but running compatible code to reset so the command can be executed. After executing
            the command (unless the command itself is a 'reboot') the device will be left connected and accessible to picotool, but
            without the RPI-RP2 drive mounted

i.e. if your Pico is already in BOOTSEL mode then the -f flag isn't necessary; but if your Pico is currently running user-code (and if you have both stdio_usb and the custom reset interface enabled), then you need to use the -f flag, and picotool will then use the custom reset-interface to reboot your Pico into BOOTSEL mode, before doing whatever else it is that you asked picotool to do. (I hope that all makes sense!)

lurch avatar Jan 03 '24 19:01 lurch

Yes, but you already mentioned the point I was talking about:

(and if you have both stdio_usb and the custom reset interface enabled)

If PlatformIO is able to reboot the Pico, even if it is not in BOOTSEL mode nor has these interfaces enabled, I would expect Picotool to be able to handle this too.

Reneg973 avatar Jan 04 '24 21:01 Reneg973

As already mentioned, it appears that PlatformIO (which I've not used myself) is using the PICO_STDIO_USB_ENABLE_RESET_VIA_BAUD_RATE feature (whereby it changes the baud-rate of the stdio_usb connection to PICO_STDIO_USB_RESET_MAGIC_BAUD_RATE). If you want picotool to be able to do this baud-rate twiddling too, you should probably open a separate issue for that.

lurch avatar Jan 04 '24 21:01 lurch

Also getting the same issues with picotool where the f flag is not working on linux:

image

I have confirmed that PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE is set as per the SDK default.

dmo9 avatar Jan 09 '24 04:01 dmo9

@dmo9 Have you tried using sudo? (or whatever the ArchLinux equivalent is)

lurch avatar Jan 09 '24 08:01 lurch

@dmo9 Have you tried using sudo? (or whatever the ArchLinux equivalent is)

No difference with sudo. Per the picotool documentation, it states the flag should work with "compatible" code, but there is no definition of what compatible code is. My code does call stdio_init_all() and enables the USB port via pico_enable_stdio_usb(nasa 1) in CMakeLists.txt

Interestingly, when flashing with picoprobe, which works fine, I get the following message: Warn : could not read product string for device 0x2e8a:0x000a: Operation timed out

After a really light dive into picotool's source code, I noticed that picotool's error message probably from the following function on line 1584 of main.cpp: string missing_device_string(bool wasRetry)

Could this be the root cause of the issue?

dmo9 avatar Jan 09 '24 19:01 dmo9

If you want to do a slightly deeper dive, you should probably take a look at https://github.com/raspberrypi/pico-sdk/pull/197 and https://github.com/raspberrypi/picotool/pull/23

lurch avatar Jan 09 '24 20:01 lurch

Ok, I figured out the problem: incompatible code. My code was exiting before picotool could send it commands. I suggest that the definition of compatible code is added to this repo's documentation.

main.c:

#include "pico/stdio_usb"
int main()
{
    stdio_usb_init();
    while(true)
    {
        // your code here
    }
}

CMakeLists.txt:

pico_enable_stdio_usb(<yourProjectName> 1)

dmo9 avatar Jan 10 '24 21:01 dmo9

#include "pico/stdio_usb"

I had to change it to (probably because I'm using C, not C++):

#include "pico/stdio_usb.h"

With these changes, I was indeed able to get the picow_blink.uf2 example from "pico-examples" to reset with picotool reboot -u -f (but not with a more complex project, i.e. tcp_client from the examples, but that's probably not a topic for this thread).

And I guess that this is only needed if stdio is not used. So, any project using printf() probably automatically includes the usb stuff and therefore won't need any changes. But when stdlib is not use, then this also has to be added to CMakeLists.txt, probably:

target_link_libraries(${NAME}
    pico_stdio_usb	# for making reset via picotool work
    …

I would ask that you add some instructions somewhere that explain which changes to make to the CMakeLists.txt and the source code in order to make this work with any Pico project, so that this resolution won't stay quite hidden in this long thread of the issues tracker.

Huh, after some more testing, it seems that if the main() function returns, then the reset via picotool fails. If I keep the code looping instead of returning from main, the reset works. That's an odd behavior but important information. Ideally, the Pico should reboot into BOOTSEL mode automatically when main() returns, even. I wonder how I can accomplish that - googling for this is difficult because all the results turn up how to reset the Pico with the button press.

tempelmann avatar Jul 26 '24 11:07 tempelmann

Good call on the import. I don't remember what libraries I had linked but I agree that it should be included in the documentation. I agree that main cannot return; that's why my code was within an infinite loop.

dmo9 avatar Jul 26 '24 15:07 dmo9

Ideally, the Pico should reboot into BOOTSEL mode automatically when main() returns, even. I wonder how I can accomplish that - googling for this is difficult because all the results turn up how to reset the Pico with the button press.

You can set PICO_ENTER_USB_BOOT_ON_EXIT to do this (eg with target_compile_definitions(my_target PRIVATE PICO_ENTER_USB_BOOT_ON_EXIT=1 in your CMakeLists.txt)

We can add a definition of compatible code to the readme - the definition being simply code that

  • Uses stdio_usb
  • Is running (ie hasn't returned)

will-v-pi avatar Jul 26 '24 15:07 will-v-pi

You can set PICO_ENTER_USB_BOOT_ON_EXIT to do this (eg with target_compile_definitions(my_target PRIVATE PICO_ENTER_USB_BOOT_ON_EXIT=1 in your CMakeLists.txt)

Good to know. I wish these things were mentioned in the "Getting started" docs on the Raspi website, because I think they're essential for using the SDK. But those pages don't even have a feedback link.

We can add a definition of compatible code to the readme - the definition being simply code that

  • Uses stdio_usb
  • Is running (ie hasn't returned)

Thank you.

Please consider making this easier for newbies like me and mention that the lib to include in the MakeLists is then call "pico_stdio_usb", and that one needs to activate either that or the stdio lib so that this works, e.g. by showing examples like @dmo9 did here, along with my notes.

tempelmann avatar Jul 26 '24 15:07 tempelmann

You don't need pico_stdio_usb in your CMakeLists.txt file - you just need pico_stdlib and then to add pico_enable_stdio_usb(<yourTargetName> 1) to that file and call stdio_init_all() from your binary (see the hello_usb example)

I'll make that clear in the readme

will-v-pi avatar Jul 26 '24 16:07 will-v-pi

A bit of clarification to the newer people for why I was including pico_stdio_usb and stdio_usb_init() rather than pico_stdlib:

stdio_usb_init() is a wrapper function that initializes all standard IO(uart & USB) but since my application only uses usb, that’s all I initialized.

dmo9 avatar Jul 26 '24 16:07 dmo9

Huh, after some more testing, it seems that if the main() function returns, then the reset via picotool fails. If I keep the code looping instead of returning from main, the reset works. That's an odd behavior but important information.

This is because if your main() exits / returns, then the USB-code (TinyUSB) on the RP2040 is no longer running, and so your device "disappears" from the list of USB-devices visible to your main computer.

lurch avatar Jul 29 '24 10:07 lurch

Added to the readme

will-v-pi avatar Aug 09 '24 15:08 will-v-pi

Hello , whenever you get that error message of picotool , next time try to do this:

In your c file , import the stidio_usb.h library and write stidio_init_all() in the main function

In the CMakeLists.txt : add this following line : pico__enable_stdio_usb(project name 1)

By doing this , you would be able to flash any uf2 file into the pico without any issues,

And by the way , I made a pico sdk project that can let you reset your pico into storage mode

Good luck

heyitsmeyo avatar Nov 27 '24 10:11 heyitsmeyo

After some headbanging I found the reason for this error in my case on Arduino IDE:

If last time, the pico was flashed using UF2 mode, then picotool fails to reset.

solution for this is to manually enter BOOTSEL mode for the first time you use picotool. For any subsequent flashes after that reset works correctly.

frak0d avatar Jun 07 '25 07:06 frak0d