Skip to content

Improve forced commands for RP2040 and custom vid/pid #263

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

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ TARGET SELECTION:
Filter by product id
--ser <ser>
Filter by serial number
--rp2040
Use RP2040-specific workarounds when using a custom vid/pid on Windows (ignored on other platforms)
-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
Expand Down Expand Up @@ -221,6 +223,8 @@ TARGET SELECTION:
Filter by product id
--ser <ser>
Filter by serial number
--rp2040
Use RP2040-specific workarounds when using a custom vid/pid on Windows (ignored on other platforms)
-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
Expand Down Expand Up @@ -322,6 +326,8 @@ OPTIONS:
Filter by product id
--ser <ser>
Filter by serial number
--rp2040
Use RP2040-specific workarounds when using a custom vid/pid on Windows (ignored on other platforms)
-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
Expand Down Expand Up @@ -388,6 +394,8 @@ OPTIONS:
Filter by product id
--ser <ser>
Filter by serial number
--rp2040
Use RP2040-specific workarounds when using a custom vid/pid on Windows (ignored on other platforms)
-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
Expand Down Expand Up @@ -462,6 +470,8 @@ OPTIONS:
Filter by product id
--ser <ser>
Filter by serial number
--rp2040
Use RP2040-specific workarounds when using a custom vid/pid on Windows (ignored on other platforms)
-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
Expand Down Expand Up @@ -511,6 +521,8 @@ OPTIONS:
Filter by product id
--ser <ser>
Filter by serial number
--rp2040
Use RP2040-specific workarounds when using a custom vid/pid on Windows (ignored on other platforms)
-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
Expand Down Expand Up @@ -724,6 +736,8 @@ OPTIONS:
Filter by product id
--ser <ser>
Filter by serial number
--rp2040
Use RP2040-specific workarounds when using a custom vid/pid on Windows (ignored on other platforms)
-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
Expand Down Expand Up @@ -881,6 +895,8 @@ OPTIONS:
Filter by product id
--ser <ser>
Filter by serial number
--rp2040
Use RP2040-specific workarounds when using a custom vid/pid on Windows (ignored on other platforms)
-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
Expand Down Expand Up @@ -980,6 +996,8 @@ TARGET SELECTION:
Filter by product id
--ser <ser>
Filter by serial number
--rp2040
Use RP2040-specific workarounds when using a custom vid/pid on Windows (ignored on other platforms)
-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
Expand Down Expand Up @@ -1040,6 +1058,8 @@ TARGET SELECTION:
Filter by product id
--ser <ser>
Filter by serial number
--rp2040
Use RP2040-specific workarounds when using a custom vid/pid on Windows (ignored on other platforms)
-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
Expand Down Expand Up @@ -1087,6 +1107,8 @@ OPTIONS:
Filter by product id
--ser <ser>
Filter by serial number
--rp2040
Use RP2040-specific workarounds when using a custom vid/pid on Windows (ignored on other platforms)
-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
Expand Down Expand Up @@ -1131,6 +1153,8 @@ OPTIONS:
Filter by product id
--ser <ser>
Filter by serial number
--rp2040
Use RP2040-specific workarounds when using a custom vid/pid on Windows (ignored on other platforms)
-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
Expand Down Expand Up @@ -1216,6 +1240,8 @@ OPTIONS:
Filter by product id
--ser <ser>
Filter by serial number
--rp2040
Use RP2040-specific workarounds when using a custom vid/pid on Windows (ignored on other platforms)
-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
Expand Down Expand Up @@ -1281,6 +1307,8 @@ TARGET SELECTION:
Filter by product id
--ser <ser>
Filter by serial number
--rp2040
Use RP2040-specific workarounds when using a custom vid/pid on Windows (ignored on other platforms)
-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
Expand Down Expand Up @@ -1630,3 +1658,9 @@ this requirement (see the [hello_usb](https://github.com/raspberrypi/pico-exampl
If you ctrl+c out of the middle of a long operation, then libusb seems to get a bit confused, which means we aren't able
to unlock our lockout of USB MSD writes (we have turned them off so the user doesn't step on their own toes). Simply running
`picotool info` again will unlock it properly the next time (or you can reboot the device).

### Zadig

To communicate with RP2040 in BOOTSEL mode on Windows, you will need to install a driver. To do this, download and run [Zadig](http://zadig.akeo.ie), select `RP2 Boot (Interface 1)` from the dropdown box and select `WinUSB` as the driver, and click on the "Install Driver" button. Wait for the installation to complete - this may take a few minutes.

This is only required for RP2040.
42 changes: 32 additions & 10 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@ struct _settings {
int vid=-1;
int pid=-1;
string ser;
bool force_rp2040 = false;
uint32_t offset = 0;
uint32_t from = 0;
uint32_t to = 0;
Expand Down Expand Up @@ -610,6 +611,7 @@ auto device_selection =
(option("--vid") & integer("vid").set(settings.vid).if_missing([] { return "missing vid"; })) % "Filter by vendor id" +
(option("--pid") & integer("pid").set(settings.pid)) % "Filter by product id" +
(option("--ser") & value("ser").set(settings.ser)) % "Filter by serial number"
+ option("--rp2040").set(settings.force_rp2040) % "Use RP2040-specific workarounds when using a custom vid/pid on Windows (ignored on other platforms)"
+ option('f', "--force").set(settings.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" +
option('F', "--force-no-reboot").set(settings.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 USB drive mounted"
).min(0).doc_non_optional(true).collapse_synopsys("device-selection");
Expand Down Expand Up @@ -8703,6 +8705,13 @@ int main(int argc, char **argv) {
if (result != dr_error) {
devices[result].emplace_back(std::make_tuple(chip, *dev, handle));
}

if (settings.vid == 0 && !settings.ser.empty() && !devices[dr_vidpid_bootrom_ok].empty()) {
// Searching with no vid/pid filtering (ie opening all devices) can cause issues, so stop
// searching when we have a serial number, as we know we have the correct device
DEBUG_LOG("Found bootrom device with serial number, so stopping search");
break;
}
}
}
auto supported = selected_cmd->get_device_support();
Expand All @@ -8720,6 +8729,11 @@ int main(int argc, char **argv) {
bool had_note = false;
fos << missing_device_string(tries>0, selected_cmd->requires_rp2350());
if (tries) {
#if defined(_WIN32)
if (settings.force_rp2040) {
fos << " You may need to install a driver via Zadig. See Zadig in the README (https://github.com/raspberrypi/picotool#zadig) for more information.";
}
#endif
fos << " It is possible the device is not responding, and will have to be manually entered into BOOTSEL mode.\n";
had_note = true; // suppress "but:" in this case
}
Expand All @@ -8742,7 +8756,7 @@ int main(int argc, char **argv) {
" appears to have a USB serial connection, but picotool was unable to connect. Maybe try 'sudo' or check your permissions.");
#else
printer(dr_vidpid_bootrom_cant_connect,
" appears to be in BOOTSEL mode, but picotool was unable to connect. You may need to install a driver via Zadig. See \"Getting started with Raspberry Pi Pico\" for more information");
" appears to be in BOOTSEL mode, but picotool was unable to connect. You may need to install a driver via Zadig. See Zadig in the README (https://github.com/raspberrypi/picotool#zadig) for more information");
printer(dr_vidpid_stdio_usb_cant_connect,
" appears to have a USB serial connection, but picotool was unable to connect.");
#endif
Expand All @@ -8751,13 +8765,8 @@ int main(int argc, char **argv) {
printer(dr_vidpid_micropython,
" appears to be an RP-series MicroPython device not in BOOTSEL mode.");
if (selected_cmd->force_requires_pre_reboot()) {
#if defined(_WIN32)
printer(dr_vidpid_stdio_usb,
" appears to have a USB serial connection, not in BOOTSEL mode. You can force reboot into BOOTSEL mode via 'picotool reboot -f -u' first.");
#else
printer(dr_vidpid_stdio_usb,
" appears to have a USB serial connection, so consider -f (or -F) to force reboot in order to run the command.");
#endif
} else {
// special case message for what is actually just reboot (the only command that doesn't require reboot first)
printer(dr_vidpid_stdio_usb,
Expand Down Expand Up @@ -8797,13 +8806,14 @@ int main(int argc, char **argv) {
// we reboot into BOOTSEL mode and disable MSC interface (the 1 here)
auto &to_reboot = std::get<1>(devices[dr_vidpid_stdio_usb][0]);
auto &to_reboot_handle = std::get<2>(devices[dr_vidpid_stdio_usb][0]);
unsigned int disable_mask = 1; // disable MSC interface
#if defined(_WIN32)
{
struct libusb_device_descriptor desc;
libusb_get_device_descriptor(to_reboot, &desc);
if (desc.idProduct == PRODUCT_ID_RP2040_STDIO_USB) {
fail(ERROR_NOT_POSSIBLE,
"Forced commands do not work with RP2040 on Windows - you can force reboot into BOOTSEL mode via 'picotool reboot -f -u' instead.");
if (desc.idProduct == PRODUCT_ID_RP2040_STDIO_USB || settings.force_rp2040) {
disable_mask = 0; // enable MSC interface so Zadig works correctly
settings.force_rp2040 = true;
}
}
#endif
Expand All @@ -8820,7 +8830,7 @@ int main(int argc, char **argv) {
}
}

reboot_device(to_reboot, to_reboot_handle, true, 1);
reboot_device(to_reboot, to_reboot_handle, true, disable_mask);
fos << "The device was asked to reboot into BOOTSEL mode so the command can be executed.";
} else if (tries == 1) {
fos << "\nWaiting for device to reboot";
Expand All @@ -8841,6 +8851,18 @@ int main(int argc, char **argv) {
// again is to assume it has the same serial number.
settings.address = -1;
settings.bus = -1;
if (settings.pid != -1 || settings.vid != -1) {
// vid/pid filtering was enabled, but should change in BOOTSEL mode, so needs to be disabled
if (settings.ser.empty()) {
// this is an RP2040 running a no_flash binary, so will have a standard RP2040 vid/pid in BOOTSEL mode
settings.vid = -1; // -1 means filter for standard vid/pid
settings.pid = -1;
} else {
// skip vid/pid filtering, as it can be white-labelled on RP2350, and we know the serial number
settings.vid = 0; // 0 means skip vid/pid filtering entirely
settings.pid = -1;
}
}
continue;
}
}
Expand Down
Loading
Loading