Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.

16x2 I2C LCD with Raspberry Pi Pico W — level-shifted wiring and MicroPython

Drive a 16x2 I2C LCD (PCF8574 backpack) from a Pico W: 5 V from VBUS, SDA/SCL through a level shifter to GP4/GP5, and a small MicroPython driver.

MicroPythonVerified — micropython (mpy-cross v1.29.0), 3 Nov 2026Compile-only

Community draft — report a mistake

A 16x2 LCD with an I2C backpack needs only four wires, but on a Pico W two of them need care: the backpack runs on 5 V and pulls the I2C lines up to 5 V. This guide powers it from VBUS and puts a BSS138 level shifter between the backpack and GP4/GP5.

MicroPython has no LCD driver built in, so the sketch includes a small one. The script prints “Hello, Pico W!”, then shows an uptime clock.

Wiring

Raspberry Pi Pico WOnly the pins used are shown · 3.3 V logic16×2 LCD + I2C backpackLV⇄HVLV⇄HVGNDGP4GP5VBUSGNDVCCSDASCL
Also needed: 4-channel BSS138 I2C level shifter.
Every connection
Raspberry Pi Pico W16×2 LCD + I2C backpackWireNotes
GNDGNDblack
VBUSVCCredVBUS (pin 40) is USB 5 V. At 3.3 V most of these LCDs show almost no contrast.
GP4SDAblueVia level shifter — GP4 (pin 6) → shifter LV1 ↔ HV1 → SDA. Shifter LV = 3V3, HV = VBUS, GND = GND.
GP5SCLyellowVia level shifter — GP5 (pin 7) → shifter LV2 ↔ HV2 → SCL.

5 V (3.3 V versions exist) part, 3.3 V board. Most of these LCDs need 5 V for good contrast, and the backpack pulls SDA/SCL up to its own VCC. On ESP32 or Pico, put a BSS138 level shifter between the board and the backpack instead of wiring SDA/SCL directly.

Board quirks

  • The backpack pulls SDA and SCL up to 5 V. Wired straight to a Pico, that 5 V sits on GP4/GP5 all the time — the BSS138 shifter keeps the Pico side at 3.3 V.
  • Copy lcd_i2c.py (a 60-line driver written for FlashReady, MIT) to the board next to main.py. The same driver handles a 20x4 LCD: LcdI2c(i2c, addr, 20, 4).
  • The script scans the bus and picks 0x27 (PCF8574T) or 0x3F (PCF8574AT) automatically.
  • Blank screen with the backlight on? Turn the blue contrast pot on the backpack before suspecting the code.

Code

main.pyMicroPython
# 16x2 I2C LCD (PCF8574 backpack) on a Raspberry Pi Pico W (MicroPython).
# The backpack runs on 5 V and pulls SDA/SCL up to 5 V, so they go through a BSS138 level shifter:
#   LCD VCC -> VBUS (pin 40, USB 5 V), LCD GND -> GND
#   LCD SDA -> shifter HV1 / LV1 -> GP4 (pin 6), LCD SCL -> shifter HV2 / LV2 -> GP5 (pin 7)
#   Shifter LV -> 3V3 (pin 36), HV -> VBUS, GND -> GND.
# Copy lcd_i2c.py to the board too.
from machine import Pin, I2C
import time
from lcd_i2c import LcdI2c

i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=100_000)
found = i2c.scan()
print("I2C devices:", [hex(a) for a in found])
addr = 0x27 if 0x27 in found else (0x3F if 0x3F in found else None)
if addr is None:
    raise SystemExit("No LCD backpack at 0x27/0x3F - check the level shifter and 5 V supply")

lcd = LcdI2c(i2c, addr, 16, 2)
lcd.line(0, "Hello, Pico W!")
lcd.line(1, "FlashReady.in")
print("LCD at", hex(addr))
time.sleep(2)

start = time.ticks_ms()
while True:
    up = time.ticks_diff(time.ticks_ms(), start) // 1000
    lcd.line(0, "Uptime")
    lcd.line(1, "{:02d}:{:02d}:{:02d}".format(up // 3600, up // 60 % 60, up % 60))
    print("Uptime", up, "s")
    time.sleep(1)

Expected serial output

REPL / Thonny shellOutput
I2C devices: ['0x27']
LCD at 0x27
Uptime 0 s
Uptime 1 s
Uptime 2 s

Common errors

No LCD backpack at 0x27/0x3F

Check the shifter: LV to 3V3, HV to VBUS, both grounds connected, and SDA/SCL on matching channels. Run on USB — VBUS is dead on battery.

Row of solid blocks, no text

The LCD has power but missed the initialise sequence. Press Ctrl-D in Thonny to soft-reset so LcdI2c() runs again.

ImportError: no module named 'lcd_i2c'

Save lcd_i2c.py to the Pico (Thonny: File → Save copy → Raspberry Pi Pico).

↑↓ to move · Enter to open