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.

Target Board Variant: The firmware and wiring in this guide specifically target the Raspberry Pi Pico H (RP2040, no WiFi/BT) running MicroPython v1.22 or newer.
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

  1. 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.
  2. 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.
  3. 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.
  4. 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:

  1. 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Ω.
  2. 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 the i2c.scan() function to verify enumeration before attempting memory reads.
  3. 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.