ESP32 · SSD1306 OLED

ESP32 SSD1306 OLED Simulator: Wiring, Code and a Live Circuit

This is a 0.96 inch SSD1306 OLED, 128 by 64 pixels, wired to an ESP32 DevKit 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 GPIO 21 (D21) and SCL to GPIO 22 (D22). The ESP32 is a 3.3 V board, so the display runs from 3V3.

  • 3.3 V logic
  • Library: Adafruit_SSD1306.h
  • I2C address 0x3C
  • SDA 21, SCL 22
ESP32 · 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 ESP32

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

SSD1306 OLED pinESP32 pinWhy
VCC3V3The usual blue module runs from 3.3 V, and its I2C pull-ups then pull to 3.3 V too.
GNDGNDCommon ground.
SDAGPIO 21 (D21)ESP32’s I2C data line, where Wire.begin() puts it.
SCLGPIO 22 (D22)ESP32’s I2C clock line.

On an ESP32 DevKit, Wire.begin() with no arguments puts SDA on GPIO 21 and SCL on GPIO 22, labeled D21 and D22. The display answers at address 0x3C, the address almost every 0.96 inch module ships with.

Pins to leave alone on the ESP32

GPIO 34, 35, 36 (VP) and 39 (VN) are input only: they cannot drive a pin or take an internal pull-up. GPIO 0, 2, 5, 12 and 15 are strapping pins, read at power-on, and GPIO 6 to 11 are the flash chip.

On a real bench

The thirty-pin DevKit straddles a breadboard with one row of holes free on each side, which is where the SSD1306 OLED’s jumpers go. Many ESP32 boards are wider and cover both rows; then use two breadboards side by side. Hold BOOT while uploading if the IDE cannot connect.

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 ESP32 I2C
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// 128 x 64 pixels, on the I2C bus: SDA GPIO 21 (D21), SCL GPIO 22 (D22)
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("ESP32");
  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 ESP32 (Xtensa LX6) 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 ESP32

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.

Expecting the bus on the old ESP8266 pins

Tutorials written for the ESP8266 put I2C on GPIO 4 and 5. On an ESP32 DevKit Wire.begin() uses GPIO 21 (D21) and GPIO 22 (D22). Either wire it there or call Wire.begin(sda, scl) before display.begin() with the pins you used.

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 an ESP32 DevKit without the hardware?

Yes. The circuit at the top of this page is an ESP32 DevKit with a SSD1306 OLED, running in your browser on a simulated ESP32 (Xtensa LX6). 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 ESP32?

On an ESP32 DevKit, Wire.begin() with no arguments puts SDA on GPIO 21 and SCL on GPIO 22, labeled D21 and D22.

Does the display work at 3.3 V?

Yes, and on an ESP32 DevKit 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 ESP32 (Xtensa LX6) 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.