DEV Community

Junaid
Junaid

Posted on

USB HID in RPI PICO W Solved!

WAIT! Before proceeding—if you don't know how to set up CircuitPython, check out: What is RPI PICO W and how to SETUP it?


Index


Why Rubber Ducky, PICO Ducky, etc. Don't Work on RPI PICO W?

The answer is simple: Everyone tries to add a fail-safe or trigger to enable/disable storage in boot.py.

But according to CircuitPython documentation, the storage state can only be triggered once.

boot.py – This runs only once before the main code executes.


Investigation and Explanation

Here, I’m using boot.py to manipulate the USB protocol and declare the device as a USB HID to the OS.

boot.py – USB HID Init

import usb_hid, storage storage.disable_usb_drive() usb_hid.enable(usb_hid.Devices.KEYBOARD) 
Enter fullscreen mode Exit fullscreen mode

code.py – The main keystroke or ducky script

import time import usb_hid from adafruit_hid.keyboard import Keyboard from adafruit_hid.keycode import Keycode from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS # Setup keyboard kyb = Keyboard(usb_hid.devices) layout = KeyboardLayoutUS(kyb) # Open Notepad (Windows: Win + R → type 'notepad' → Enter) kyb.press(Keycode.WINDOWS) kyb.send(Keycode.R) kyb.release_all() time.sleep(0.5) layout.write("notepad") kyb.send(Keycode.ENTER) time.sleep(1) for i in range(10): layout.write("Hello World From Pico HID\n") 
Enter fullscreen mode Exit fullscreen mode

OLAA! Your own ducky script.


WAIT WAIT!

Like everyone else, you may think:
"I can just add a trigger to switch between HID and USB Mass Storage!"

But here's the twist, my friend!

boot.py doesn't wait (or delay) for GPIO-related tasks.
Even if you add a delay, it skips it.
If anything goes wrong in boot.py, it automatically falls back to USB Mass Storage mode by default.


How to Fix It?

There are two ways to fix this:


Internal Communication (RECOMMENDED)

Here you have more reliable options to communicate between boot.py and code.py.
I recommend using microcontroller.nvm which helps toggle state between the two scripts.

microcontroller.nvm – Persistent Non-Volatile Memory.

Example:

boot.py

import microcontroller microcontroller.nvm[0] = 1 # Use 1 or 0 depending on mode 
Enter fullscreen mode Exit fullscreen mode

code.py

import microcontroller if microcontroller.nvm[0] == 1: print("USB drive was enabled") else: print("USB drive was disabled") 
Enter fullscreen mode Exit fullscreen mode

External Communication

You can also use a simple state.txt file to read/write the current state.
This allows both scripts to enable or disable USB Mass Storage based on that value.

Example:

Get state from file

def getState(): with open("state", "r") as f: return f.read().replace("\n", "") 
Enter fullscreen mode Exit fullscreen mode

Set state to file

def setState(bool_val): with open("state", "w") as f: f.write(str(bool_val)) 
Enter fullscreen mode Exit fullscreen mode

What is RPI PICO W and How to SETUP it?

Hello Beginners!

  • RPI – Raspberry Pi

There are two ways to use Python on your RPI PICO W:

  1. CircuitPython – Easy, stable, and beginner-friendly.
  2. MicroPython – Gives full control. A bit tricky at first but easy once understood.

In simple terms:

  • CircuitPython is like Ubuntu for RPI-based microcontrollers.
  • MicroPython is like Arch Linux for RPI-based microcontrollers.

🚀 Speedrun: Setup Process

  1. Download the CircuitPython .uf2 file from the CircuitPython website.
  2. Download nuke.uf2 from CircuitPython or the Raspberry Pi website.
  3. Download the latest CircuitPython RPI PICO W bundle and unzip it.
  4. While plugging in your PICO to your PC, hold the BOOTSEL button until RPI-RP2 shows up in File Explorer.
  5. Copy nuke.uf2 to the RPI-RP2 drive.
  6. WAIT 2 seconds. It will eject and reconnect automatically.
  7. Now, copy the CircuitPython .uf2 file to RPI-RP2.
  8. WAIT again—this time it will show as CIRCUITPY.
  9. From the CircuitPython bundle, find the usb_hid folder and copy it to your PICO.
  10. Copy your code.py and boot.py into the CIRCUITPY drive.
  11. OLAA! DONE!

NOTE: I'm still exploring better solutions to improve this further.
If you have any suggestions or ideas, please comment down below!


Author: Junaid

Sources:

Top comments (0)