VARIANTS
| MODEL | CHIP | FLASH | RAM | WIFI/BT | USB | NOTES |
|---|---|---|---|---|---|---|
| Pico | RP2040 | 2MB | 264KB SRAM | None | USB 1.1 FS | Original — castellated edges |
| Pico H | RP2040 | 2MB | 264KB SRAM | None | USB 1.1 FS | Pre-soldered headers + debug connector |
| Pico W | RP2040 | 2MB | 264KB SRAM | WiFi 802.11n · BT 5.2 | USB 1.1 FS | CYW43439 radio |
| Pico WH | RP2040 | 2MB | 264KB SRAM | WiFi · BT | USB 1.1 FS | Pico W with headers |
| Pico 2 | RP2350A | 4MB | 520KB SRAM | None | USB 1.1 FS | Dual Cortex-M33 + RISC-V, 2× faster |
| Pico 2 W | RP2350A | 4MB | 520KB SRAM | WiFi · BT 5.2 | USB 1.1 FS | Latest — 2024 |
PINOUT — RP2040 / RP2350 (40-pin)
GP0 · UART0 TX · SPI0 RX · I2C0 SDA · PWM0A
GP1 · UART0 RX · SPI0 CSn · I2C0 SCL · PWM0B
GND
GP2 · SPI0 SCK · I2C1 SDA · PWM1A
GP3 · SPI0 TX · I2C1 SCL · PWM1B
GP4 · UART1 TX · SPI0 RX · I2C0 SDA · PWM2A
GP5 · UART1 RX · SPI0 CSn · I2C0 SCL · PWM2B
GND
GP6 · SPI0 SCK · I2C1 SDA · PWM3A
GP7 · SPI0 TX · I2C1 SCL · PWM3B
GP8 · UART1 TX · SPI1 RX · I2C0 SDA · PWM4A
GP9 · UART1 RX · SPI1 CSn · I2C0 SCL · PWM4B
GND
GP10 · SPI1 SCK · I2C1 SDA · PWM5A
GP11 · SPI1 TX · I2C1 SCL · PWM5B
GP12 · UART0 TX · SPI1 RX · I2C0 SDA · PWM6A
GP13 · UART0 RX · SPI1 CSn · I2C0 SCL · PWM6B
GND
GP14 · SPI1 SCK · I2C1 SDA · PWM7A
GP15 · SPI1 TX · I2C1 SCL · PWM7B
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
VBUS (5V from USB)
VSYS (2-5V supply)
GND
3V3_EN (pull low to disable 3.3V)
3V3 OUT (300mA max)
ADC_VREF (ADC reference voltage)
GP26 · ADC0 · I2C1 SDA
GND (AGND)
GP27 · ADC1 · I2C1 SCL
GP28 · ADC2 · SPI1 RX
RUN / RESET (pull low to reset)
GP22 · PWM3A
GND
GP21 · I2C0 SCL · PWM2B
GP20 · I2C0 SDA · PWM2A · UART1 TX
GP19 · SPI0 TX · I2C1 SCL · PWM1B
GP18 · SPI0 SCK · I2C1 SDA · PWM1A
GND
GP17 · SPI0 CSn · I2C0 SCL · PWM0B
GP16 · SPI0 RX · I2C0 SDA · PWM0A · UART0 TX
■ GPIO (digital I/O + alternate funcs)
■ ADC (12-bit, 0–3.3V)
■ 3.3V power
■ VSYS/VBUS
■ GND
■ System pins
FLASHING — .UF2 METHOD (easiest)
BOOTSEL / DFU MODE
Enters mass storage mode — no driver needed
- Hold the BOOTSEL button
- Connect USB to PC (or plug in while holding)
- Release BOOTSEL — drive appears as RPI-RP2 (or RP2350)
- Drag and drop the .uf2 file onto the drive
- Drive disappears — board reboots into new firmware automatically
Works on Windows, Linux, macOS, Android with OTG cable. No esptool, no drivers, no serial config required.
PICOTOOL (advanced)
CLI tool for flash, info, reboot
# Install (requires libusb)
pip install picotool
# or build from source: github.com/raspberrypi/picotool
# Flash while in BOOTSEL mode:
picotool load firmware.uf2
picotool reboot
# Info about connected Pico:
picotool info
# Reboot into BOOTSEL from running firmware
# (if firmware supports USB_RESET_TO_BOOTLOADER)
picotool reboot -f -u
CIRCUITPYTHON ON PICO
Download from circuitpython.org/board/raspberry_pi_pico
- Download adafruit-circuitpython-raspberry_pi_pico-*.uf2
- Enter BOOTSEL mode
- Drop .uf2 onto RPI-RP2 drive
- Board reboots as CIRCUITPY USB drive
- Edit code.py directly in any text editor
Also install Mu editor or use Thonny for REPL access.
MICROPYTHON ON PICO
Download from micropython.org/download/RPI_PICO
- Download rp2-pico-*.uf2 (or rp2-pico-w for Pico W)
- Enter BOOTSEL mode
- Drop .uf2 onto RPI-RP2 drive
- Connect Thonny or any terminal at 115200 baud
- REPL prompt >>> appears
# Thonny: Tools > Options > Interpreter > MicroPython (Pico)
# Or raw terminal:
screen /dev/ttyACM0 115200 # Linux
putty COM? 115200 # Windows
BADUSB / HID PAYLOADS
PICO-DUCKY (DuckyScript)
github.com/dbisu/pico-ducky
- Flash CircuitPython onto Pico
- Download pico-ducky release zip
- Copy duckyinpython.py → code.py on CIRCUITPY
- Install adafruit_hid library to lib/
- Write payload to payload.dd in DuckyScript format
- Reconnect — payload runs automatically
Hold GP0 to ground on boot to disable payload (safe mode). GP0 is the default — configurable in code.
WIFI DUCK (Pico W)
github.com/SpacehuhnTech/WiFiDuck
- Download WiFi Duck Pico W .uf2
- Flash via BOOTSEL method
- Pico W creates WiFi AP: WiFiDuck (pw: wifiduck)
- Connect phone/laptop to AP
- Open 192.168.4.1 in browser
- Write and run DuckyScript payloads via web UI
Pico W acts as USB HID to target while also serving web UI over WiFi. No USB connection to attacker device needed during execution.
CIRCUITPYTHON HID (custom)
Full control via Python
# code.py example
import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keycode import Keycode
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
import time
kbd = Keyboard(usb_hid.devices)
layout = KeyboardLayoutUS(kbd)
time.sleep(2) # wait for host
kbd.send(Keycode.GUI, Keycode.R)
time.sleep(0.5)
layout.write("cmd\n")
time.sleep(1)
layout.write("whoami\n")
KEYBOARD LAYOUTS
Critical — match target OS keyboard setting
| LAYOUT LIB | TARGET |
|---|---|
| keyboard_layout_us | US QWERTY (default) |
| keyboard_layout_win_uk | Windows UK |
| keyboard_layout_de | German QWERTZ |
| keyboard_layout_fr | French AZERTY |
UK layout shifts @ and " — use keyboard_layout_win_uk or payloads will mistype on UK targets.
MICROPYTHON QUICK REFERENCE
GPIO
from machine import Pin
led = Pin(25, Pin.OUT) # onboard LED
led.on()
led.toggle()
btn = Pin(15, Pin.IN, Pin.PULL_UP)
print(btn.value()) # 0 when pressed
UART
from machine import UART
uart = UART(0, baudrate=115200,
tx=Pin(0), rx=Pin(1))
uart.write(b'hello\r\n')
if uart.any():
print(uart.read())
ADC
from machine import ADC
adc = ADC(26) # GP26 = ADC0
# 16-bit value 0–65535
val = adc.read_u16()
volts = val * 3.3 / 65535
I2C
from machine import I2C, Pin
i2c = I2C(0, sda=Pin(4), scl=Pin(5))
devices = i2c.scan() # list addresses
i2c.writeto(0x68, bytes([0x6B, 0]))
data = i2c.readfrom(0x68, 6)
SPI
from machine import SPI, Pin
spi = SPI(0, baudrate=1_000_000,
sck=Pin(2), mosi=Pin(3), miso=Pin(4))
cs = Pin(5, Pin.OUT)
cs.low()
spi.write(b'\x00\x01')
cs.high()
PICO W WIFI
import network, time
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect('SSID', 'password')
while not wlan.isconnected():
time.sleep(0.5)
print(wlan.ifconfig())
DEBUGGING
SWD / PICOPROBE DEBUG
Hardware debugging with a second Pico
Flash a second Pico with picoprobe.uf2 (download from raspberrypi.com). Wire SWCLK, SWDIO, GND to target Pico debug pins. Use with OpenOCD + GDB or the VS Code Raspberry Pi Pico extension.
| PROBE PIN | TARGET PIN |
|---|---|
| GP2 (SWCLK) | SWCLK (pin 24) |
| GP3 (SWDIO) | SWDIO (pin 25) |
| GND | GND |
| GP4 (UART TX) | GP1 (UART0 RX) |
| GP5 (UART RX) | GP0 (UART0 TX) |
COMMON ISSUES
| PROBLEM | FIX |
|---|---|
| RPI-RP2 not appearing | Hold BOOTSEL before connecting USB — not after |
| Drive appears but .uf2 copy fails | Use File > Copy, not drag-drop, on some Windows |
| CIRCUITPY not showing | Wait 10s after flash — first boot is slow |
| Thonny can't connect | Close other serial terminals first — only one app can own COM port |
| HID not working | Check boot.py — HID must be enabled, usb_cdc may conflict |
| Payload mistypes | Wrong keyboard layout — match target OS/locale |