picotool
picotool copied to clipboard
Unable to reset pico
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.
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.
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"
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?
You need to ensure that
PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACEis enabled, which adds the reset interface. See Appendix B in https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-c-sdk.pdfForcing reset using 1200bps open/close on port /dev/cu.usbmodem11301
I guess that indicates that
PICO_STDIO_USB_ENABLE_RESET_VIA_BAUD_RATEis enabled. Maybe that implies that PlatformIO has disabledPICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACEfor 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.
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
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.
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!)
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.
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.
Also getting the same issues with picotool where the f flag is not working on linux:
I have confirmed that PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE is set as per the SDK default.
@dmo9 Have you tried using sudo? (or whatever the ArchLinux equivalent is)
@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?
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
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)
#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.
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.
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)
You can set
PICO_ENTER_USB_BOOT_ON_EXITto do this (eg withtarget_compile_definitions(my_target PRIVATE PICO_ENTER_USB_BOOT_ON_EXIT=1in 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.
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
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.
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.
Added to the readme
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
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.