If you have ever wanted your Raspberry Pi Pico project to actually show something instead of blinking an LED or printing endless lines in a serial console, an SSD1306 OLED display is one of the easiest and most satisfying upgrades you can make. It’s cheap, it uses only two signal wires, and once it’s running, you can throw text, sensor readings, graphics, and even simple animations onto a crisp little screen.
In this guide, we’ll walk through the entire process step by step — from wiring the display to writing and understanding the MicroPython code — so that even if this is your first time working with an OLED, you’ll have it up and running with confidence.
Table of Contents
Overview
The SSD1306 is a driver chip built into small monochrome OLED display modules, most commonly found in the 128×64 pixel, 0.96-inch size (though 128×32 versions exist too). Unlike LCDs, OLED pixels emit their own light, so there’s no backlight to power. That means deep blacks, sharp contrast, and lower power draw — pixels that are “off” literally use no energy.
These displays are typically sold as a small 4-pin breakout board with the following pins:
- VCC – power input
- GND – ground
- SCL – serial clock line (I2C clock)
- SDA – serial data line (I2C data)
That 4-pin layout means the module talks over I2C, a two-wire communication protocol that lets a single microcontroller control multiple devices using just SDA and SCL. Some SSD1306 modules also support SPI (usually with more pins), but the I2C version is by far the most popular for hobby projects because of its simplicity — and it’s what this tutorial focuses on.
The Raspberry Pi Pico, built around the RP2040 microcontroller, is a perfect match for this display. It has multiple hardware I2C-capable GPIO pin pairs, runs MicroPython comfortably, and there’s a mature, well-tested ssd1306.py driver library available for it — meaning you don’t need to write any low-level display commands yourself.
By the end of this tutorial, you’ll be able to:
- Wire the SSD1306 to your Pico correctly
- Install the driver library
- Display text, shapes, and a bitmap logo
- Understand exactly what each line of the code does
- Troubleshoot the most common connection errors
Required Components
You don’t need much for this project. Here’s the full parts list:
| Component | Notes |
|---|---|
| Raspberry Pi Pico or Pico W | Either works fine; Pico W just adds Wi-Fi, which isn’t needed here |
| SSD1306 OLED display (I2C, 128×64) | 4-pin version (VCC, GND, SCL, SDA) |
| Micro-USB cable | For power and programming |
| Breadboard | Optional but makes wiring cleaner |
| 4 male-to-male jumper wires | To connect the OLED to the Pico |
| Computer with Thonny IDE installed | Used to flash MicroPython and upload code |
That’s it — no resistors or extra components are required for most modules, since the breakout boards usually include the necessary pull-up resistors on the SDA/SCL lines already.
Before starting, make sure your Pico is flashed with the latest MicroPython UF2 firmware. If you haven’t done this yet, hold the BOOTSEL button while plugging the Pico into your computer, then drag and drop the MicroPython .uf2 file onto the drive that appears.
For 16X2 LED display please check: Interfacing 16X2 LCD Module with Raspberry pi Pico with and without I2C
Connections
Wiring the SSD1306 to the Pico is refreshingly simple since it only needs four wires. In this tutorial, we’ll use the Pico’s I2C0 peripheral on GP0 (SDA) and GP1 (SCL) — a common and convenient choice since these pins sit right next to the Pico’s power and ground pins. Note that the Pico has a second I2C bus (I2C1) as well, and you’re free to use a different pin pair; just make sure your code matches whatever pins you physically wire.

| SSD1306 OLED Pin | Raspberry Pi Pico Pin | Description |
|---|---|---|
| VCC | 3V3 (OUT) – physical pin 36 | Power supply (3.3V) |
| GND | GND – physical pin 38 (or any GND pin) | Ground reference |
| SCL | GP1 – physical pin 2 | I2C clock line |
| SDA | GP0 – physical pin 1 | I2C data line |
A few practical notes before you power things on:
- Double-check VCC. Most SSD1306 modules are fine on 3.3V, which is what the Pico’s 3V3 pin outputs. Avoid connecting VCC to the Pico’s 5V VBUS pin unless your specific module is explicitly rated for 5V and you’ve confirmed this works — the safer default is always 3.3V.
- Loose wires are the #1 cause of problems. A shaky breadboard connection on SDA or SCL is responsible for the majority of “display not detected” issues, so push jumper wires in firmly.
- Note your display’s I2C address. The vast majority of SSD1306 modules default to address
0x3C. A few (or modules with a solderable address jumper) use0x3Dinstead. If you’re not sure, the code below includes a quick I2C scan that will print the address for you.
Program Code
With the wiring done, it’s time to write the software. There are two files involved:
ssd1306.py– the driver library that handles all the low-level SSD1306 commandsmain.py(or any script name) – your actual program that uses the driver
Step 1: Install the SSD1306 driver
The easiest way is through Thonny’s built-in package manager:
- Open Thonny IDE with your Pico plugged in.
- Go to Tools > Manage Packages.
- Search for
ssd1306and install micropython-ssd1306.
This automatically uploads the ssd1306.py driver file to your Pico. If you’d rather do it manually, you can find the official driver source on the MicroPython GitHub repository and save it onto your Pico’s filesystem as ssd1306.py using Thonny’s “Save as > Raspberry Pi Pico” option.
Step 2: Write your main script
Here’s a complete working example that initializes the display, scans for its I2C address, and prints some text and shapes to the screen:

Download the code: oled_pipico.py
Save this as main.py on the Pico (so it runs automatically on boot), or run it directly from Thonny by clicking the green Run button.
Code Explanation
Let’s break down what’s actually happening, line by line:
Imports
from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
machine is MicroPython’s built-in module for interacting with the Pico’s hardware — GPIO pins, I2C, SPI, ADC, and so on. SSD1306_I2C is the display class provided by the driver you just installed; it does all the heavy lifting of formatting your commands into the byte sequences the SSD1306 chip expects.
Setting up I2C
i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=400000)
This line creates an I2C object using the Pico’s hardware I2C0 peripheral, tells it which pins are acting as clock (scl) and data (sda), and sets the communication speed to 400kHz (a standard “fast mode” I2C speed that the SSD1306 handles comfortably). If you wired to a different pin pair or the second I2C bus, just adjust the bus number and pin assignments accordingly.
Scanning for the display
devices = i2c.scan()
This is a genuinely useful debugging step — i2c.scan() returns a list of every I2C device address currently detected on the bus. If your wiring is correct, you’ll see a single address show up, almost always 0x3C (60 in decimal). If the list comes back empty, that’s your first sign to recheck connections before touching the code further.
Initializing the display object
oled = SSD1306_I2C(WIDTH, HEIGHT, i2c)
This creates the display object itself, telling the driver the screen’s resolution (128×64) and which I2C bus to talk over. Behind the scenes, this line sends the full SSD1306 initialization sequence — turning on the internal charge pump, setting the multiplex ratio, contrast, and memory addressing mode — all the fiddly low-level setup that the driver abstracts away from you.
Clearing the buffer
oled.fill(0)
The SSD1306 driver works by writing to an in-memory buffer first, then pushing that whole buffer to the screen at once. fill(0) sets every pixel in the buffer to off (black). Using fill(1) would set every pixel to on (white/lit), which is handy for inverted displays or testing.
Drawing text and shapes
oled.text("Hello, World!", 0, 0)
oled.rect(0, 40, 40, 20, 1)
oled.line(50, 40, 120, 60, 1)
Because the driver is built on top of MicroPython’s framebuf module, you get a set of simple drawing primitives for free:
text(string, x, y)draws text starting at pixel coordinate (x, y)rect(x, y, width, height, color)draws a rectangle outlinefill_rect(...)draws a filled rectangleline(x0, y0, x1, y1, color)draws a line between two pointspixel(x, y, color)sets an individual pixel
All of these write into the buffer — nothing appears on the physical screen yet.
Updating the screen
oled.show()
This is the command that actually flushes the buffer to the SSD1306’s internal display RAM over I2C, making everything you’ve drawn visible on the screen. Forgetting this line is one of the most common beginner mistakes — you can call text() and rect() all day, but nothing will show up until show() is called.
A Few Practical Examples
Once the basics are working, here are a few small variations worth trying:
Example 1: Displaying a live sensor/ADC reading

This turns the OLED into a simple live voltmeter — great for potentiometers, light sensors, or any analog input.
For ADC please check: How to use ADC on Raspberry Pi Pico in detail with MicroPython example
Example 2: Scrolling a countdown timer

A nice way to test timing and screen refresh responsiveness.
Example 3: Handling a different I2C address
If your scan reveals address 0x3D instead of the default, simply pass it explicitly:
oled = SSD1306_I2C(128, 64, i2c, addr=0x3D)
Related Project:
DIY Smartphone Oscilloscope using Raspberry Pi Pico in 5$
Conclusion
Interfacing the SSD1306 OLED display with the Raspberry Pi Pico is one of those projects that looks intimidating at first glance but turns out to be genuinely approachable once you break it into pieces: four wires, one driver file, a handful of drawing commands, and you’re displaying live text and graphics. The combination of the Pico’s low cost, MicroPython’s readability, and the SSD1306’s plug-and-play I2C interface makes this a great foundation for bigger builds — weather stations, sensor dashboards, mini games, or status displays for other electronics projects.
From here, a natural next step is experimenting with custom bitmap logos, multiple I2C devices sharing the same bus, or combining the display with sensors like the DHT22 or BMP280 to build a real-time data readout. The core skills you’ve practiced here — wiring I2C correctly, understanding the buffer-then-show pattern, and reading driver documentation — will carry over directly to almost any other I2C display or module you pick up next.
