ESP32: SSD1306 OLED Display is a runnable microcontroller simulation example on SensBench — open the wired circuit, inspect the code, and compile real firmware in your browser, no install needed. Last updated Aug 14, 2026.

FREE SIMULATOR EXAMPLE · INTERMEDIATE

ESP32: SSD1306 OLED Display

This example puts text and a live counter on a 128×64 SSD1306 OLED wired to the ESP32 over I2C — SDA on GPIO21, SCL on GPIO22, module address 0x3C. Press play and the screen shows two lines of double-size text plus a counter that ticks once per second, while the Serial Monitor prints a frame number for every refresh.

Board ESP32 DevKit (Xtensa LX6, 240 MHz)
Difficulty intermediate
Category displays
Libraries Adafruit SSD1306, Adafruit GFX Library, Adafruit BusIO
Runs in Sensbench browser simulator — free, no account
ESP32 DevKit wired to a 128x64 SSD1306 OLED over I2C on GPIO21 and GPIO22 in the Sensbench simulator

The exact circuit you get when you open this example — already wired, ready to run.

The sketch

// ESP32 — SSD1306 OLED Display (I2C 128×64)
// Requires: Adafruit SSD1306, Adafruit GFX Library
// Wiring: SDA → D21  |  SCL → D22  |  VCC → 3V3  |  GND → GND

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

int counter = 0;

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("SSD1306 not found!");
    while (true) delay(10);
  }
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Hello");
  display.println("sensbench!");
  display.display();
  Serial.println("OLED ready!");
}

void loop() {
  counter++;
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Hello");
  display.println("sensbench!");
  display.setTextSize(1);
  display.setCursor(0, 48);
  display.printf("Count: %d", counter);
  display.display();
  Serial.printf("Frame: %d\n", counter);
  delay(1000);
}

How it works

The sketch brings up I2C explicitly with Wire.begin(21, 22) — the ESP32’s default SDA and SCL — then calls display.begin(SSD1306_SWITCHCAPVCC, 0x3C) to probe the module at address 0x3C. If the probe fails it prints an error and parks in while (true) instead of running silently with a dead screen; on real hardware that halt is your first debugging clue. The constructor’s last argument, -1, tells the library there is no reset pin — these modules reset themselves at power-on.

Adafruit GFX works on a draw-then-push model. clearDisplay(), setCursor() and println() only write into a 1 KB frame buffer in the ESP32’s RAM — nothing reaches the panel until display.display() clocks the whole buffer over I2C. That is why the loop can erase and redraw every cycle without any flicker: the screen only ever changes in one atomic push.

The counter line uses display.printf(), which formats like C’s printf straight into the buffer — no String juggling. Cursor position (0, 48) drops it onto the bottom row of the 64-pixel panel at text size 1, and a matching Serial.printf() logs each frame so you can follow the refresh rhythm without watching the canvas.

Before you build it for real

Two things differ on a real bench. First, the address: most 128×64 modules are 0x3C, but plenty ship as 0x3D — if the screen stays black and Serial says not found, run an I2C scanner before suspecting the wiring. Second, speed: every display.display() pushes 1 KB over I2C, and at the default 100 kHz clock a full frame takes around 90 ms. One refresh per second is comfortable; smooth animation is not. Call Wire.setClock(400000) before display.begin() and the same frame drops to roughly a quarter of that — the SSD1306 handles 400 kHz without complaint.

Get the parts

Related examples

FAQ

The screen stays black. What do I check first?

Address first, wiring second. display.begin() returns false when the module does not answer at 0x3C, and this sketch prints a message and halts in that case — so a black screen with no serial output points at SDA and SCL swapped or a loose wire, while the error message points at a 0x3D module. An I2C scanner sketch settles it in seconds.

Can I use pins other than 21 and 22?

Yes. Wire.begin(sda, scl) accepts almost any free GPIO on the ESP32 — 21 and 22 are just the defaults the board silkscreen assumes. Stay clear of the strapping pins (0, 2, 12, 15) and the input-only pins 34-39, and the library does not care which pair you pick.