Raspberry Pi Pico H: Spec Sheet & Board Variant Comparison
The Raspberry Pi Pico H (part number SC0916) is the header-equipped, non-wireless variant of the original RP2040 development board. Unlike the standard Pico which ships with bare castellated pads, the Pico H comes with pre-soldered 0.1" pin headers and a dedicated 3-pin JTAG debug connector on the right edge. This makes it the definitive choice for breadboard prototyping and hardware-level debugging without requiring a soldering iron or delicate flying-lead connections.
Difficulty Rating: Intermediate (Hardware wiring is beginner-friendly; JTAG setup and I2C bus recovery code require intermediate debugging concepts).
Choosing the right Pico variant prevents mid-project hardware swaps. Here is how the Pico H stacks up against the rest of the current RP2040 lineup:
| Board Variant | Pre-Soldered Headers | JTAG Debug Connector | Wireless (WiFi/BT) | Flash Memory | Typical Price (USD) |
|---|---|---|---|---|---|
| Pico (Standard) | No (Castellated pads) | No (Test pads only) | No | 2MB | $4.00 |
| Pico H | Yes (0.1" male) | Yes (3-pin JTAG) | No | 2MB | $5.00 |
| Pico W | No (Castellated pads) | No | Yes (CYW43439) | 2MB | $6.00 |
| Pico WH | Yes (0.1" male) | Yes (3-pin JTAG) | Yes (CYW43439) | 2MB | $7.00 |
| Pico 2 (Standard) | No (Castellated pads) | No | No (RP2350) | 4MB | $5.00 |
Source: Raspberry Pi Pico Datasheet
Parts List & Pin Mapping for I2C Debug Build
To demonstrate the Pico H's hardware advantages, we are building an environmental monitor using a BME280 sensor, while simultaneously hooking up the JTAG header to catch I2C bus lockups at the silicon level.
Required Components
- Microcontroller: Raspberry Pi Pico H (SC0916)
- Sensor: Adafruit BME280 I2C/SPI Breakout (Product ID: 2652) or equivalent 3.3V BME280 module
- Debug Probe: Official Raspberry Pi Debug Probe (SC1148) or a second Pico running Picoprobe firmware
- Wiring: 22 AWG solid-core jumper wires, standard 830-point breadboard
- Software: Thonny IDE (v4.1+) configured for MicroPython
Pin Mapping Table
| Pico H Pin / Label | GPIO Number | Target Component | Target Pin | Function |
|---|---|---|---|---|
| 3V3(OUT) | N/A (Power) | BME280 Breakout | VIN / VCC | 3.3V Power Rail |
| GND | N/A (Ground) | BME280 Breakout | GND | Common Ground |
| GP4 (I2C0 SDA) | GPIO 4 | BME280 Breakout | SDA | I2C Data Line |
| GP5 (I2C0 SCL) | GPIO 5 | BME280 Breakout | SCL | I2C Clock Line |
| JTAG SWCLK | N/A (Debug) | Debug Probe | SWCLK | Serial Wire Clock |
| JTAG GND | N/A (Debug) | Debug Probe | GND | Debug Ground |
| JTAG SWDIO | N/A (Debug) | Debug Probe | SWDIO | Serial Wire Data I/O |
Step-by-Step Wiring & JTAG Setup
- Seat the Pico H: Press the Pico H into the breadboard. The pre-soldered headers should slide in with moderate pressure. Ensure the micro-USB port hangs off the edge of the board to avoid stressing the breadboard tabs.
- Wire the I2C Bus: Connect GP4 to the BME280 SDA pin, and GP5 to the BME280 SCL pin. Route 3V3(OUT) and GND to the sensor's power rails. Bench tip: The Adafruit breakout includes onboard 10kΩ pull-up resistors. If using a bare-bones generic BME280 module, verify it has pull-ups, or the RP2040 I2C peripheral will read floating noise.
- Connect the JTAG Header: Locate the 3-pin JTAG header on the right edge of the Pico H (near the reset button). Using female-to-female jumper wires, connect SWCLK, GND, and SWDIO to the corresponding pins on the Raspberry Pi Debug Probe's 3-pin JTAG cable.
- Verify Probe Enumeration: Plug the Debug Probe into your PC via its dedicated USB-C port. Open your terminal and run
lsusb(Linux/Mac) or check Device Manager (Windows). You should see 'Raspberry Pi Debug Probe (CMSIS-DAP)' listed.
Complete MicroPython Firmware with I2C Bus Recovery
The RP2040's I2C peripheral is notorious for locking up if a transaction is interrupted mid-byte, leaving the SDA line held low by the slave device. This code implements a software bus-recovery routine that toggles the SCL line to force the slave to release SDA, preventing hard reboots.
import machine
import time
import sys
# --- PIN DEFINITIONS ---
I2C0_SDA_PIN = 4
I2C0_SCL_PIN = 5
I2C_FREQ = 400_000 # 400kHz Fast Mode
BME280_ADDR = 0x77 # Default Adafruit address (0x76 for some generic modules)
# --- I2C INITIALIZATION ---
i2c = machine.I2C(0, sda=machine.Pin(I2C0_SDA_PIN), scl=machine.Pin(I2C0_SCL_PIN), freq=I2C_FREQ)
def recover_i2c_bus():
"""Toggles SCL to force a stuck slave to release the SDA line."""
print('[WARN] Attempting I2C bus recovery...')
scl_pin = machine.Pin(I2C0_SCL_PIN, machine.Pin.OUT)
for _ in range(9):
scl_pin.value(1)
time.sleep_us(5)
scl_pin.value(0)
time.sleep_us(5)
# Re-initialize the I2C peripheral after manual toggling
global i2c
i2c = machine.I2C(0, sda=machine.Pin(I2C0_SDA_PIN), scl=machine.Pin(I2C0_SCL_PIN), freq=I2C_FREQ)
print('[INFO] I2C bus re-initialized.')
def read_sensor_safe():
"""Reads BME280 chip ID with robust error handling."""
try:
# Read 1 byte from register 0xD0 (Chip ID)
chip_id = i2c.readfrom_mem(BME280_ADDR, 0xD0, 1)
return chip_id[0]
except OSError as e:
# Catch specific I2C hardware errors
print(f'[ERROR] I2C Transaction Failed: {e}')
recover_i2c_bus()
return None
def main():
print('Starting Raspberry Pi Pico H Environmental Monitor...')
# Initial bus scan
devices = i2c.scan()
if BME280_ADDR not in devices:
print(f'[FATAL] BME280 not found at 0x{BME280_ADDR:02X}. Devices found: {[hex(d) for d in devices]}')
sys.exit()
while True:
cid = read_sensor_safe()
if cid == 0x60:
print(f'[OK] BME280 responding. Chip ID: 0x{cid:02X}')
elif cid is not None:
print(f'[WARN] Unexpected Chip ID: 0x{cid:02X} (Expected 0x60)')
else:
print('[FAIL] Sensor read failed even after bus recovery.')
time.sleep(2)
if __name__ == '__main__':
main()
Reference: MicroPython RP2 Quick Reference
Debugging I2C Lockups: The First Three Things to Check
When working with the RP2040's I2C blocks, you will inevitably encounter bus lockups, especially when hot-swapping sensors or dealing with long wire runs. If your Thonny REPL throws the exact error string OSError: [Errno 110] ETIMEDOUT or OSError: [Errno 5] EIO, do not immediately reach for the reset button. Check these three items in order:
- Missing or Insufficient Pull-Up Resistors (Most Common): The I2C specification requires pull-up resistors on both SDA and SCL. The RP2040's internal pull-ups (accessible via
machine.Pin.PULL_UP) are roughly 50kΩ to 80kΩ—far too weak for 400kHz Fast Mode I2C. Fix: Ensure your breakout board has 4.7kΩ or 10kΩ external pull-ups enabled. If wiring multiple devices, the parallel resistance drops; you may need to disable pull-ups on all but one board to keep the total bus pull-up between 2kΩ and 10kΩ. - SDA and SCL Swapped: Unlike UART, I2C is not forgiving of swapped lines. The RP2040 will not throw a 'wrong pin' error; it will simply time out waiting for an ACK bit that never arrives, resulting in
ETIMEDOUT. Fix: Verify GP4 is strictly SDA and GP5 is strictly SCL for I2C0. Use thei2c.scan()function to verify enumeration before attempting memory reads. - Clock Stretching Timeout: Some sensors (like the SHT31 or certain BME280 modes) hold the SCL line low to 'stretch' the clock while they perform internal ADC conversions. If the RP2040's I2C peripheral times out before the sensor releases the line, the bus locks. Fix: Lower the I2C frequency from 400kHz to 100kHz (
freq=100_000) in your initialization, or switch the sensor to a non-stretching polling mode via its configuration registers.
Extending and Simplifying the Build
The beauty of the Pico H's pre-soldered headers is that you can pivot your project requirements without desoldering a single joint.
How to Simplify (Drop the JTAG)
If you are moving from prototyping to a simple desktop deployment and don't need hardware-level fault tracing, you can safely ignore the 3-pin JTAG header. Rely entirely on the Micro-USB connection for both power and the Thonny REPL serial console. To simplify the code further, strip out the recover_i2c_bus() function and replace it with a simple machine.reset() inside the except OSError block. While a full reboot is less elegant than a software bus toggle, it is perfectly acceptable for low-duty-cycle environmental logging where a 2-second boot delay is unnoticeable.
How to Extend (Add an OLED and Secondary I2C Bus)
The RP2040 features two independent I2C peripherals (I2C0 and I2C1). If you want to add a 128x64 SSD1306 OLED display to visually log the BME280 data, do not put it on the same bus as the sensor. Long display updates can block the bus and delay sensor polling. Instead, map the display to I2C1 using GPIO 26 (SDA1) and GPIO 27 (SCL1). This allows you to initialize a second machine.I2C(1) object, keeping your sensor polling and display rendering completely asynchronous and immune to cross-device lockups.






