From a5d8ada052f13b8298941b032a68bec39ade2a2b Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Tue, 22 Jul 2025 12:21:38 +0100 Subject: [PATCH 01/10] Remove vid/pid filter when using forced commands The vid/pid will typically change when switching to BOOTSEL mode, so remove those filters and just filter on serial number if present Fixes #261 --- main.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/main.cpp b/main.cpp index 063d3c6..8da6225 100644 --- a/main.cpp +++ b/main.cpp @@ -8841,6 +8841,11 @@ int main(int argc, char **argv) { // again is to assume it has the same serial number. settings.address = -1; settings.bus = -1; + // also skip vid/pid filtering, as that will typically change in BOOTSEL mode + settings.pid = -1; + // still filter for rpi vid/pid if we don't have a serial number, as that is an RP2040 running a no_flash binary, so will + // have a standard rpi vid/pid in BOOTSEL mode + settings.vid = settings.ser.empty() ? -1 : 0; // 0 means skip vid/pid filtering entirely, -1 means filter for rpi vid/pid continue; } } From 1b6272d0e3ceb57c236bfb844f354422e08c4eae Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Wed, 6 Aug 2025 10:41:58 +0100 Subject: [PATCH 02/10] Improve handling of RP2040 devices after reboot Calling GET_INFO when not available sometimes causes issues with forced commands Also improve libusb error messages when debugging --- main.cpp | 2 +- picoboot_connection/picoboot_connection.c | 36 +++++++++++++---------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/main.cpp b/main.cpp index 8da6225..603ec0c 100644 --- a/main.cpp +++ b/main.cpp @@ -8841,7 +8841,7 @@ int main(int argc, char **argv) { // again is to assume it has the same serial number. settings.address = -1; settings.bus = -1; - // also skip vid/pid filtering, as that will typically change in BOOTSEL mode + // also skip vid/pid filtering, as that will typically change in BOOTSEL mode, and could be white-labelled on RP2350 settings.pid = -1; // still filter for rpi vid/pid if we don't have a serial number, as that is an RP2040 running a no_flash binary, so will // have a standard rpi vid/pid in BOOTSEL mode diff --git a/picoboot_connection/picoboot_connection.c b/picoboot_connection/picoboot_connection.c index 9ee797e..c83673c 100644 --- a/picoboot_connection/picoboot_connection.c +++ b/picoboot_connection/picoboot_connection.c @@ -69,7 +69,7 @@ enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_d int ret = libusb_get_device_descriptor(device, &desc); enum picoboot_device_result res = dr_vidpid_unknown; if (ret && verbose) { - output("Failed to read device descriptor\n"); + output("Failed to read device descriptor %s\n", libusb_error_name(ret)); } if (!ret) { if (pid >= 0) { @@ -107,14 +107,14 @@ enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_d } ret = libusb_get_active_config_descriptor(device, &config); if (ret && verbose) { - output("Failed to read config descriptor\n"); + output("Failed to read config descriptor %s\n", libusb_error_name(ret)); } } if (!ret) { ret = libusb_open(device, dev_handle); if (ret && verbose) { - output("Failed to open device %d\n", ret); + output("Failed to open device %s\n", libusb_error_name(ret)); } if (ret) { if (vid == 0 || strlen(ser) != 0) { @@ -169,7 +169,7 @@ enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_d if (verbose) output("Found PICOBOOT interface\n"); ret = libusb_claim_interface(*dev_handle, interface); if (ret) { - if (verbose) output("Failed to claim interface\n"); + if (verbose) output("Failed to claim interface %s\n", libusb_error_name(ret)); return dr_vidpid_bootrom_no_interface; } } else { @@ -180,16 +180,22 @@ enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_d if (!ret) { if (*chip == unknown) { - struct picoboot_get_info_cmd info_cmd; - info_cmd.bType = PICOBOOT_GET_INFO_SYS, - info_cmd.dParams[0] = (uint32_t) (SYS_INFO_CHIP_INFO); - uint32_t word_buf[64]; - // RP2040 doesn't have this function, so returns non-zero - int info_ret = picoboot_get_info(*dev_handle, &info_cmd, (uint8_t*)word_buf, sizeof(word_buf)); - if (info_ret) { + if (desc.idVendor == VENDOR_ID_RASPBERRY_PI && desc.idProduct == PRODUCT_ID_RP2040_USBBOOT) { + // Set model based on bootrom vid/pid for RP2040, as it cannot be white-labelled *chip = rp2040; } else { - *chip = rp2350; + // Otherwise check the chip info + struct picoboot_get_info_cmd info_cmd; + info_cmd.bType = PICOBOOT_GET_INFO_SYS, + info_cmd.dParams[0] = (uint32_t) (SYS_INFO_CHIP_INFO); + uint32_t word_buf[64]; + // RP2040 doesn't have this function, so returns non-zero + int info_ret = picoboot_get_info(*dev_handle, &info_cmd, (uint8_t*)word_buf, sizeof(word_buf)); + if (info_ret) { + *chip = rp2040; + } else { + *chip = rp2350; + } } } if (strlen(ser) != 0) { @@ -301,7 +307,7 @@ int picoboot_cmd(libusb_device_handle *usb_device, struct picoboot_cmd *cmd, uin ret = libusb_bulk_transfer(usb_device, out_ep, (uint8_t *) cmd, sizeof(struct picoboot_cmd), &sent, 3000); if (ret != 0 || sent != sizeof(struct picoboot_cmd)) { - output(" ...failed to send command %d\n", ret); + output(" ...failed to send command %s\n", libusb_error_name(ret)); return ret; } @@ -321,7 +327,7 @@ int picoboot_cmd(libusb_device_handle *usb_device, struct picoboot_cmd *cmd, uin int received = 0; ret = libusb_bulk_transfer(usb_device, in_ep, buffer, cmd->dTransferLength, &received, timeout); if (ret != 0 || received != (int) cmd->dTransferLength) { - output(" ...failed to receive data %d %d/%d\n", ret, received, cmd->dTransferLength); + output(" ...failed to receive data %s %d/%d\n", libusb_error_name(ret), received, cmd->dTransferLength); if (!ret) ret = 1; return ret; } @@ -329,7 +335,7 @@ int picoboot_cmd(libusb_device_handle *usb_device, struct picoboot_cmd *cmd, uin if (verbose) output(" send %d...\n", cmd->dTransferLength); ret = libusb_bulk_transfer(usb_device, out_ep, buffer, cmd->dTransferLength, &sent, timeout); if (ret != 0 || sent != (int) cmd->dTransferLength) { - output(" ...failed to send data %d %d/%d\n", ret, sent, cmd->dTransferLength); + output(" ...failed to send data %s %d/%d\n", libusb_error_name(ret), sent, cmd->dTransferLength); if (!ret) ret = 1; picoboot_cmd_status_verbose(usb_device, NULL, true); return ret; From 9ffb9d2d4c5e072a2bcca17c0712484af0e58762 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Wed, 6 Aug 2025 12:08:00 +0100 Subject: [PATCH 03/10] Add rp2040 workaround to allow forced reboots, and improve behaviour with no vid/pid filtering --- main.cpp | 29 ++++++++++++++++------- picoboot_connection/picoboot_connection.c | 6 ++--- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/main.cpp b/main.cpp index 603ec0c..ce23a2f 100644 --- a/main.cpp +++ b/main.cpp @@ -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; @@ -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 workarounds on Windows when using custom vid/pid (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"); @@ -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(); @@ -8797,13 +8806,13 @@ 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 } } #endif @@ -8820,7 +8829,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"; @@ -8841,11 +8850,13 @@ int main(int argc, char **argv) { // again is to assume it has the same serial number. settings.address = -1; settings.bus = -1; - // also skip vid/pid filtering, as that will typically change in BOOTSEL mode, and could be white-labelled on RP2350 - settings.pid = -1; - // still filter for rpi vid/pid if we don't have a serial number, as that is an RP2040 running a no_flash binary, so will - // have a standard rpi vid/pid in BOOTSEL mode - settings.vid = settings.ser.empty() ? -1 : 0; // 0 means skip vid/pid filtering entirely, -1 means filter for rpi vid/pid + if (settings.pid != -1 || settings.vid != -1) { + // also skip vid/pid filtering, as that should change in BOOTSEL mode, and could be white-labelled on RP2350 + settings.pid = -1; + // still filter for rpi vid/pid if we don't have a serial number, as that is an RP2040 running a no_flash binary, so will + // have a standard rpi vid/pid in BOOTSEL mode + settings.vid = settings.ser.empty() ? -1 : 0; // 0 means skip vid/pid filtering entirely, -1 means filter for rpi vid/pid + } continue; } } diff --git a/picoboot_connection/picoboot_connection.c b/picoboot_connection/picoboot_connection.c index c83673c..8f3bf01 100644 --- a/picoboot_connection/picoboot_connection.c +++ b/picoboot_connection/picoboot_connection.c @@ -184,15 +184,15 @@ enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_d // Set model based on bootrom vid/pid for RP2040, as it cannot be white-labelled *chip = rp2040; } else { - // Otherwise check the chip info + // Otherwise check the chip info command exists struct picoboot_get_info_cmd info_cmd; info_cmd.bType = PICOBOOT_GET_INFO_SYS, info_cmd.dParams[0] = (uint32_t) (SYS_INFO_CHIP_INFO); uint32_t word_buf[64]; - // RP2040 doesn't have this function, so returns non-zero + // Other devices don't have this function, so will return errors int info_ret = picoboot_get_info(*dev_handle, &info_cmd, (uint8_t*)word_buf, sizeof(word_buf)); if (info_ret) { - *chip = rp2040; + return dr_vidpid_unknown; } else { *chip = rp2350; } From 783f75dc026a6298dac5602e72d2967a9bdd551c Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Wed, 6 Aug 2025 12:10:40 +0100 Subject: [PATCH 04/10] Readme update for --rp2040 option --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/README.md b/README.md index 572586c..7ff9cb4 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,8 @@ TARGET SELECTION: Filter by product id --ser Filter by serial number + --rp2040 + Use RP2040 workarounds on Windows when using custom vid/pid (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 @@ -221,6 +223,8 @@ TARGET SELECTION: Filter by product id --ser Filter by serial number + --rp2040 + Use RP2040 workarounds on Windows when using custom vid/pid (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 @@ -322,6 +326,8 @@ OPTIONS: Filter by product id --ser Filter by serial number + --rp2040 + Use RP2040 workarounds on Windows when using custom vid/pid (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 @@ -388,6 +394,8 @@ OPTIONS: Filter by product id --ser Filter by serial number + --rp2040 + Use RP2040 workarounds on Windows when using custom vid/pid (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 @@ -462,6 +470,8 @@ OPTIONS: Filter by product id --ser Filter by serial number + --rp2040 + Use RP2040 workarounds on Windows when using custom vid/pid (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 @@ -511,6 +521,8 @@ OPTIONS: Filter by product id --ser Filter by serial number + --rp2040 + Use RP2040 workarounds on Windows when using custom vid/pid (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 @@ -724,6 +736,8 @@ OPTIONS: Filter by product id --ser Filter by serial number + --rp2040 + Use RP2040 workarounds on Windows when using custom vid/pid (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 @@ -881,6 +895,8 @@ OPTIONS: Filter by product id --ser Filter by serial number + --rp2040 + Use RP2040 workarounds on Windows when using custom vid/pid (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 @@ -980,6 +996,8 @@ TARGET SELECTION: Filter by product id --ser Filter by serial number + --rp2040 + Use RP2040 workarounds on Windows when using custom vid/pid (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 @@ -1040,6 +1058,8 @@ TARGET SELECTION: Filter by product id --ser Filter by serial number + --rp2040 + Use RP2040 workarounds on Windows when using custom vid/pid (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 @@ -1087,6 +1107,8 @@ OPTIONS: Filter by product id --ser Filter by serial number + --rp2040 + Use RP2040 workarounds on Windows when using custom vid/pid (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 @@ -1131,6 +1153,8 @@ OPTIONS: Filter by product id --ser Filter by serial number + --rp2040 + Use RP2040 workarounds on Windows when using custom vid/pid (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 @@ -1216,6 +1240,8 @@ OPTIONS: Filter by product id --ser Filter by serial number + --rp2040 + Use RP2040 workarounds on Windows when using custom vid/pid (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 @@ -1281,6 +1307,8 @@ TARGET SELECTION: Filter by product id --ser Filter by serial number + --rp2040 + Use RP2040 workarounds on Windows when using custom vid/pid (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 From 06f43e7fe0c4337b8f08369dd2e8e85d6ca7a09c Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Wed, 6 Aug 2025 12:26:15 +0100 Subject: [PATCH 05/10] Add Zadig message to failed RP2040 forced reboots Also encourage -f/F on Windows, rather than a separate reboot --- main.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/main.cpp b/main.cpp index ce23a2f..cfbe85b 100644 --- a/main.cpp +++ b/main.cpp @@ -8729,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 \"Getting started with Raspberry Pi Pico\" 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 } @@ -8760,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, @@ -8813,6 +8813,7 @@ int main(int argc, char **argv) { libusb_get_device_descriptor(to_reboot, &desc); 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 From c1cf36217c89e60e4cb9da7927efe8feeed661d7 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Thu, 14 Aug 2025 11:41:55 +0100 Subject: [PATCH 06/10] Tidy up comments around vid/pid filter disable --- main.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/main.cpp b/main.cpp index cfbe85b..30da650 100644 --- a/main.cpp +++ b/main.cpp @@ -8852,11 +8852,16 @@ int main(int argc, char **argv) { settings.address = -1; settings.bus = -1; if (settings.pid != -1 || settings.vid != -1) { - // also skip vid/pid filtering, as that should change in BOOTSEL mode, and could be white-labelled on RP2350 - settings.pid = -1; - // still filter for rpi vid/pid if we don't have a serial number, as that is an RP2040 running a no_flash binary, so will - // have a standard rpi vid/pid in BOOTSEL mode - settings.vid = settings.ser.empty() ? -1 : 0; // 0 means skip vid/pid filtering entirely, -1 means filter for rpi vid/pid + // 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; } From bd1eff61c922eb9301b005c26978b90f300467a6 Mon Sep 17 00:00:00 2001 From: will-v-pi <108662275+will-v-pi@users.noreply.github.com> Date: Thu, 14 Aug 2025 11:43:16 +0100 Subject: [PATCH 07/10] Tweak help text Co-authored-by: Andrew Scheller --- main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.cpp b/main.cpp index 30da650..c05f21b 100644 --- a/main.cpp +++ b/main.cpp @@ -611,7 +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 workarounds on Windows when using custom vid/pid (ignored on other platforms)" + + 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"); From b696d1a035141ae0bb933f74f5d33087cf3c7da4 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Thu, 14 Aug 2025 11:46:03 +0100 Subject: [PATCH 08/10] Update readme with help text --- README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 7ff9cb4..9e2cb34 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ TARGET SELECTION: --ser Filter by serial number --rp2040 - Use RP2040 workarounds on Windows when using custom vid/pid (ignored on other platforms) + 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 @@ -224,7 +224,7 @@ TARGET SELECTION: --ser Filter by serial number --rp2040 - Use RP2040 workarounds on Windows when using custom vid/pid (ignored on other platforms) + 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 @@ -327,7 +327,7 @@ OPTIONS: --ser Filter by serial number --rp2040 - Use RP2040 workarounds on Windows when using custom vid/pid (ignored on other platforms) + 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 @@ -395,7 +395,7 @@ OPTIONS: --ser Filter by serial number --rp2040 - Use RP2040 workarounds on Windows when using custom vid/pid (ignored on other platforms) + 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 @@ -471,7 +471,7 @@ OPTIONS: --ser Filter by serial number --rp2040 - Use RP2040 workarounds on Windows when using custom vid/pid (ignored on other platforms) + 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 @@ -522,7 +522,7 @@ OPTIONS: --ser Filter by serial number --rp2040 - Use RP2040 workarounds on Windows when using custom vid/pid (ignored on other platforms) + 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 @@ -737,7 +737,7 @@ OPTIONS: --ser Filter by serial number --rp2040 - Use RP2040 workarounds on Windows when using custom vid/pid (ignored on other platforms) + 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 @@ -896,7 +896,7 @@ OPTIONS: --ser Filter by serial number --rp2040 - Use RP2040 workarounds on Windows when using custom vid/pid (ignored on other platforms) + 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 @@ -997,7 +997,7 @@ TARGET SELECTION: --ser Filter by serial number --rp2040 - Use RP2040 workarounds on Windows when using custom vid/pid (ignored on other platforms) + 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 @@ -1059,7 +1059,7 @@ TARGET SELECTION: --ser Filter by serial number --rp2040 - Use RP2040 workarounds on Windows when using custom vid/pid (ignored on other platforms) + 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 @@ -1108,7 +1108,7 @@ OPTIONS: --ser Filter by serial number --rp2040 - Use RP2040 workarounds on Windows when using custom vid/pid (ignored on other platforms) + 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 @@ -1154,7 +1154,7 @@ OPTIONS: --ser Filter by serial number --rp2040 - Use RP2040 workarounds on Windows when using custom vid/pid (ignored on other platforms) + 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 @@ -1241,7 +1241,7 @@ OPTIONS: --ser Filter by serial number --rp2040 - Use RP2040 workarounds on Windows when using custom vid/pid (ignored on other platforms) + 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 @@ -1308,7 +1308,7 @@ TARGET SELECTION: --ser Filter by serial number --rp2040 - Use RP2040 workarounds on Windows when using custom vid/pid (ignored on other platforms) + 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 From ef4fb7fd147f27a5d9ae496df55cf0b11d15475d Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Thu, 14 Aug 2025 12:00:47 +0100 Subject: [PATCH 09/10] Add Zadig note to the readme This is cleaner than directing to a document name that must then be searched for the word Zadig --- README.md | 5 +++++ main.cpp | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9e2cb34..64b3b4c 100644 --- a/README.md +++ b/README.md @@ -1658,3 +1658,8 @@ 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. diff --git a/main.cpp b/main.cpp index c05f21b..6806ade 100644 --- a/main.cpp +++ b/main.cpp @@ -8731,7 +8731,7 @@ int main(int argc, char **argv) { if (tries) { #if defined(_WIN32) if (settings.force_rp2040) { - fos << " You may need to install a driver via Zadig. See \"Getting started with Raspberry Pi Pico\" for more information."; + 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"; @@ -8756,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 From d0f16a1c4c621f19f37903a5dbaa5a3ed3627df3 Mon Sep 17 00:00:00 2001 From: will-v-pi <108662275+will-v-pi@users.noreply.github.com> Date: Thu, 14 Aug 2025 13:18:47 +0100 Subject: [PATCH 10/10] Update README.md Co-authored-by: Andrew Scheller --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 64b3b4c..626bad7 100644 --- a/README.md +++ b/README.md @@ -1660,6 +1660,7 @@ to unlock our lockout of USB MSD writes (we have turned them off so the user doe `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.