Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to reset pico #88

Closed
LandryNorris opened this issue Nov 13, 2023 · 22 comments
Closed

Unable to reset pico #88

LandryNorris opened this issue Nov 13, 2023 · 22 comments
Assignees
Milestone

Comments

@LandryNorris
Copy link

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
Copy link
Author

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.

@Reneg973
Copy link

Reneg973 commented Jan 3, 2024

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"

@lurch
Copy link
Contributor

lurch commented Jan 3, 2024

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?

@Reneg973
Copy link

Reneg973 commented Jan 3, 2024

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.

@lurch
Copy link
Contributor

lurch commented Jan 3, 2024

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

@Reneg973
Copy link

Reneg973 commented Jan 3, 2024

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.

@lurch
Copy link
Contributor

lurch commented Jan 3, 2024

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!)

@Reneg973
Copy link

Reneg973 commented Jan 4, 2024

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.

@lurch
Copy link
Contributor

lurch commented Jan 4, 2024

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.

@dmo9
Copy link

dmo9 commented Jan 9, 2024

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.

@lurch
Copy link
Contributor

lurch commented Jan 9, 2024

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

@dmo9
Copy link

dmo9 commented Jan 9, 2024

@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?

@lurch
Copy link
Contributor

lurch commented Jan 9, 2024

If you want to do a slightly deeper dive, you should probably take a look at raspberrypi/pico-sdk#197 and #23

@dmo9
Copy link

dmo9 commented Jan 10, 2024

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)

@tempelmann
Copy link

tempelmann commented Jul 26, 2024

#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.

@dmo9
Copy link

dmo9 commented Jul 26, 2024

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.

@will-v-pi
Copy link

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)

@tempelmann
Copy link

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.

@will-v-pi
Copy link

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 will-v-pi added this to the 1.6.2 milestone Jul 26, 2024
@dmo9
Copy link

dmo9 commented Jul 26, 2024

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.

@lurch
Copy link
Contributor

lurch commented Jul 29, 2024

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.

@will-v-pi
Copy link

Added to the readme

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants