The 1.3-inch OLED is the bigger sibling of the 0.96″ SSD1306 — and it almost always uses a different controller, the SH1106. MicroPython doesn’t ship a driver for it, so this sketch includes a short one built on framebuf.
Wire it to 3V3 and I2C0 (GP4/GP5). The script draws a border, a counter, an uptime clock and a moving bar.
Wiring
| Raspberry Pi Pico W | SH1106 OLED 1.3″ (128×64, I2C) | Wire | Notes |
|---|---|---|---|
| 3V3 | VDD | red | 3V3 is pin 36. Check the silkscreen — many 1.3″ boards put VDD first and GND second. |
| GND | GND | black | |
| GP5 | SCK | yellow | GP5 is physical pin 7 (I2C0 SCL). Printed SCK or SCL depending on the seller. |
| GP4 | SDA | blue | GP4 is physical pin 6 (I2C0 SDA). |
3.3–5 V (on-board regulator) part, 3.3 V board. Most modules have a regulator and pull-ups to VDD. On ESP32 and Pico power the OLED from 3.3 V so SDA/SCK stay at 3.3 V; on Uno 5 V is fine.
Board quirks
- The 1.3″ OLED usually carries an SH1106, not an SSD1306. The SSD1306 driver “almost” works but shows a two-pixel shift and a stripe of noise at the edge.
- Copy
sh1106.py(written for FlashReady, MIT) to the board. It subclassesframebuf.FrameBuffer, sotext(),rect(),line()work exactly as with the SSD1306. - The SH1106 has no horizontal addressing mode, so
show()sends the screen one 128-byte page at a time, starting at column 2. - Power it from 3V3: the module’s pull-ups go to VDD, so 3.3 V keeps SDA/SCK at a Pico-safe level.
Code
# 1.3-inch SH1106 OLED (128x64, I2C) on a Raspberry Pi Pico W (MicroPython).
# Wiring: VDD -> 3V3 (pin 36), GND -> GND, SCK -> GP5 (pin 7), SDA -> GP4 (pin 6). I2C0.
# Check your module's pin order - many 1.3" boards print VDD first and GND second.
# Copy sh1106.py to the board too.
from machine import Pin, I2C
import time
from sh1106 import SH1106
i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=400_000)
found = i2c.scan()
print("I2C devices:", [hex(a) for a in found])
addr = 0x3C if 0x3C in found else (0x3D if 0x3D in found else None)
if addr is None:
raise SystemExit("No OLED at 0x3C/0x3D - check VDD/GND order and SDA/SCK")
oled = SH1106(i2c, addr)
start = time.ticks_ms()
n = 0
while True:
up = time.ticks_diff(time.ticks_ms(), start) // 1000
oled.fill(0)
oled.rect(0, 0, 128, 64, 1)
oled.text("Pico W + SH1106", 4, 4)
oled.hline(0, 15, 128, 1)
oled.text("Count: {}".format(n), 4, 24)
oled.text("Up {:02d}:{:02d}".format(up // 60, up % 60), 4, 38)
oled.fill_rect(4, 52, (n % 31) * 4, 8, 1) # moving bar shows it is alive
oled.show()
print("Count:", n)
n += 1
time.sleep_ms(500)# 1.3-inch SH1106 OLED (128x64, I2C) on a Raspberry Pi Pico W (MicroPython).
# Wiring: VDD -> 3V3 (pin 36), GND -> GND, SCK -> GP5 (pin 7), SDA -> GP4 (pin 6). I2C0.
# Check your module's pin order - many 1.3" boards print VDD first and GND second.
# Copy sh1106.py to the board too.
from machine import Pin, I2C
import time
from sh1106 import SH1106
i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=400_000)
found = i2c.scan()
print("I2C devices:", [hex(a) for a in found])
addr = 0x3C if 0x3C in found else (0x3D if 0x3D in found else None)
if addr is None:
raise SystemExit("No OLED at 0x3C/0x3D - check VDD/GND order and SDA/SCK")
oled = SH1106(i2c, addr)
start = time.ticks_ms()
n = 0
while True:
up = time.ticks_diff(time.ticks_ms(), start) // 1000
oled.fill(0)
oled.rect(0, 0, 128, 64, 1)
oled.text("Pico W + SH1106", 4, 4)
oled.hline(0, 15, 128, 1)
oled.text("Count: {}".format(n), 4, 24)
oled.text("Up {:02d}:{:02d}".format(up // 60, up % 60), 4, 38)
oled.fill_rect(4, 52, (n % 31) * 4, 8, 1) # moving bar shows it is alive
oled.show()
print("Count:", n)
n += 1
time.sleep_ms(500)Expected serial output
I2C devices: ['0x3c']
Count: 0
Count: 1
Count: 2I2C devices: ['0x3c'] Count: 0 Count: 1 Count: 2
Common errors
Picture shifted by two pixels with a noisy column at one edge
You are using an SSD1306 driver. Use the included sh1106.py.
No OLED at 0x3C/0x3D
VDD and GND swapped (very common on 1.3″ boards), or SDA/SCK on the wrong pins. GP4 is pin 6, GP5 is pin 7.
Image upside down
Change 0xA1 to 0xA0 and 0xC8 to 0xC0 in sh1106.py’s init list.