Raspberry Pi Pico · SSD1306 OLED

Raspberry Pi Pico SSD1306 OLED Simulator: Wiring, Code and a Live Circuit

This is a 0.96 inch SSD1306 OLED, 128 by 64 pixels, wired to a Raspberry Pi Pico over I2C and running live: the board writes two lines of text, draws a box and counts the seconds in it. It uses the Adafruit SSD1306 and GFX libraries, exactly as a tutorial would.

Four wires: power, ground, SDA to GP4 (physical pin 6) and SCL to GP5 (physical pin 7). The Raspberry Pi Pico is a 3.3 V board, so the display runs from 3V3.

  • 3.3 V logic
  • Library: Adafruit_SSD1306.h
  • I2C address 0x3C
  • SDA 4, SCL 5
Raspberry Pi Pico · SSD1306 OLEDlive0.000 s 0.00x
Click to open it in the editor
The circuit itself, running on the simulator with the sketch below. Press what can be pressed; click anything else to open it in the editor.

Wiring the SSD1306 OLED to the Raspberry Pi Pico

Every connection in the circuit above, with the board’s own pin names.

SSD1306 OLED pinRaspberry Pi Pico pinWhy
VCC3V3(OUT)The usual blue module runs from 3.3 V, and its I2C pull-ups then pull to 3.3 V too.
GNDGNDCommon ground.
SDAGP4 (physical pin 6)Raspberry Pi Pico’s I2C data line, where Wire.begin() puts it.
SCLGP5 (physical pin 7)Raspberry Pi Pico’s I2C clock line.

On the Pico, Wire.begin() puts SDA on GP4 and SCL on GP5, physical pins 6 and 7. The display answers at address 0x3C, the address almost every 0.96 inch module ships with.

Pins to leave alone on the Raspberry Pi Pico

The numbers in the code are GP numbers, not the physical pin numbers printed beside the header: GP15 is pin 20. GP23 to GP25 are used on the board itself, and GP25 is the LED.

On a real bench

Solder headers on the Pico and press it into the breadboard across the center channel; the SSD1306 OLED goes in beside it. GND pins sit every fifth pin down both sides (pins 3, 8, 13, 18 and so on), so there is always one close. The first upload needs BOOTSEL held while plugging in.

The code

The sketch the circuit above runs. Open it in the editor, change a line and press Run: it compiles in your browser.

SSD1306 on Raspberry Pi Pico I2C
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// 128 x 64 pixels, on the I2C bus: SDA GP4 (physical pin 6), SCL GP5 (physical pin 7)
Adafruit_SSD1306 display(128, 64, &Wire, -1);

void setup() {
  Serial.begin(115200);
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("No SSD1306 at 0x3C");
    for (;;) {}
  }
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(2);
  display.setCursor(0, 0);
  display.println("HELLO");
  display.setTextSize(1);
  display.println("SSD1306 OLED");
  display.drawRect(0, 40, 128, 24, SSD1306_WHITE);
  display.display();
  Serial.println("OLED ready");
}

void loop() {
  // A counter in the box, redrawn twice a second.
  display.fillRect(2, 42, 124, 20, SSD1306_BLACK);
  display.setCursor(8, 48);
  display.print("Up for ");
  display.print(millis() / 1000);
  display.print(" s");
  display.display();
  delay(500);
}

Adafruit_SSD1306 display(128, 64, &Wire, -1) describes a 128 by 64 panel on the Wire bus with no reset pin. display.begin(SSD1306_SWITCHCAPVCC, 0x3C) starts the controller at its address and returns false if nothing answers there, which the sketch reports on the serial monitor rather than drawing into thin air.

Every drawing call (println, drawRect, fillRect) changes a copy of the screen in the board’s RAM. Nothing reaches the glass until display() sends the whole frame, 1024 bytes, over I2C. That is why the loop clears its box, draws the new number and calls display() once.

The frame buffer is 1 KB, which the RP2040 has room for many times over. The font in the simulator is a 5 by 7 one with capitals, digits and punctuation, so lower case prints as capitals here.

Common mistakes with the SSD1306 OLED on the Raspberry Pi Pico

Forgetting display()

Every call before display() only changes the copy in RAM. A sketch that draws and never calls display() leaves the screen black, and that is the most common "my OLED does not work" there is.

Using I2C1 pins with Wire

Wire is the Pico’s I2C0 on GP4 and GP5. Tutorials for MicroPython often use GP0 and GP1 or I2C1 on GP2 and GP3; with Wire.begin() and no arguments the display has to be on GP4 and GP5.

Mixing up the 128x32 module

The 128 by 32 OLED uses the same chip and the same address, but the constructor needs 128, 32. Built for 64 rows, everything is drawn half off the panel.

Questions and answers

Can I test an SSD1306 OLED with a Raspberry Pi Pico without the hardware?

Yes. The circuit at the top of this page is a Raspberry Pi Pico with a SSD1306 OLED, running in your browser on a simulated RP2040. Every pixel the sketch sends is drawn on the simulated panel, so you can lay out a screen before the module arrives. Press Run it in the editor to change the wiring or the code; it is free and needs no account.

Which pins are SDA and SCL on the Raspberry Pi Pico?

On the Pico, Wire.begin() puts SDA on GP4 and SCL on GP5, physical pins 6 and 7.

Does the display work at 3.3 V?

Yes, and on a Raspberry Pi Pico it should be powered from 3V3. The common modules have a regulator and pull-ups that then pull SDA and SCL to 3.3 V, which is what the RP2040 expects.

Can I use U8g2 instead of the Adafruit library?

U8g2lib.h compiles here too. The page uses Adafruit_SSD1306 because it is what most tutorials start from, and its calls (setCursor, print, display) carry over to the other Adafruit displays.

Build your own SSD1306 OLED project

Open this circuit in the editor, change the wiring or the code, and keep your version in a free account.