Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.

SSD1306 OLED with NodeMCU ESP8266 — I2C wiring and code

Wire a 0.96″ SSD1306 I2C OLED to a NodeMCU ESP8266 on D1 (SCL) and D2 (SDA) at 3.3 V and print text with the Adafruit SSD1306 library.

Arduino C++Verified — core esp8266 3.1.2, Adafruit SSD1306 2.5.17, 3 Nov 2026Compile-only

Community draft — report a mistake

A small OLED is the easiest way to give a NodeMCU a screen, and it only needs two signal wires. Wire SCL to D1 and SDA to D2, power it from 3V3, and the default Wire.begin() finds it with no pin numbers in the code.

The ESP8266 does I2C in software, so the core can put it on almost any pin — but D1/D2 are the defaults, they don’t affect booting, and every OLED example for this board assumes them.

Wiring

NodeMCU ESP8266Only the pins used are shown · 3.3 V logicSSD1306 OLED 0.96″ (128×64, I2C)GND3V3D1D2GNDVCCSCLSDA
Every connection
NodeMCU ESP8266SSD1306 OLED 0.96″ (128×64, I2C)WireNotes
3V3VCCredPower from 3V3 so the module’s I2C pull-ups go to 3.3 V, not 5 V.
GNDGNDblack
D1SCLyellowD1 is GPIO5 — the ESP8266 core’s default SCL.
D2SDAblueD2 is GPIO4 — the default SDA.

3.3–5 V (on-board regulator) part, 3.3 V board. Most modules have a regulator and run from 3.3 V or 5 V. Their I2C pull-ups go to VCC, so on ESP32 and Pico power the OLED from 3.3 V to keep SDA/SCL at a safe level.

Board quirks

  • On the ESP8266 Wire.begin() means SDA = D2 (GPIO4), SCL = D1 (GPIO5). It is easy to swap them because D1 comes first on the header but carries SCL.
  • The ESP8266 has no I2C hardware — the core bit-bangs it. Any two pins can be I2C with Wire.begin(sda, scl), except D0 (GPIO16), which can’t do open-drain I2C. Keep off D3, D4 and D8 too: the OLED’s pull-ups would hold D8 (GPIO15) high at reset and the board would not boot.
  • The library allocates a 1 KB frame buffer at begin(). That is fine on the ESP8266 (about 50 KB of free heap with Wi-Fi off), and the sketch prints the free heap so you can see it.
  • The “0x78” printed on the back is the 8-bit form of address 0x3C. If nothing is found, try 0x3D, which some modules use when the address resistor is moved.

Code

ssd1306-nodemcu.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// 0.96" SSD1306 OLED (128x64, I2C) on a NodeMCU (ESP8266).
// VCC → 3V3, GND → GND, SCL → D1 (GPIO5), SDA → D2 (GPIO4).
// Wire.begin() with no arguments uses exactly these pins on the ESP8266 core.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

const uint8_t OLED_ADDR = 0x3C;  // the "0x78" printed on the back is the same address shifted left
Adafruit_SSD1306 display(128, 64, &Wire, -1);  // -1: the 4-pin module has no reset pin

void setup() {
  Serial.begin(115200);
  Serial.println();
  Wire.begin();  // SDA = D2 (GPIO4), SCL = D1 (GPIO5)
  if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
    Serial.println("SSD1306 not found at 0x3C - check SDA/SCL and try 0x3D");
    while (true) delay(100);  // delay() feeds the ESP8266 watchdog
  }
  Serial.println("SSD1306 found at 0x3C");
  Serial.printf("Free heap after display buffer: %u bytes\n", ESP.getFreeHeap());
  display.setTextColor(SSD1306_WHITE);
}

void loop() {
  unsigned long s = millis() / 1000;
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("NodeMCU ESP8266");
  display.println("SDA D2  SCL D1");
  display.setTextSize(2);
  display.setCursor(0, 32);
  display.printf("%lus", s);
  display.display();
  Serial.printf("Uptime %lus\n", s);
  delay(1000);
}

Library: Adafruit SSD1306 (Adafruit (also install Adafruit GFX Library)) — compiled with Adafruit SSD1306 2.5.17.

Expected serial output

Serial Monitor · 115200Output
SSD1306 found at 0x3C
Free heap after display buffer: 49712 bytes
Uptime 0s
Uptime 1s
Uptime 2s

Common errors

“SSD1306 not found at 0x3C”

SDA and SCL swapped (SDA is D2, SCL is D1), a loose jumper, or a 0x3D module. Run the I2C scanner to see what answers.

Screen shows random noise or only the top part

You have a 128×32 module. Change Adafruit_SSD1306 display(128, 64, …) to (128, 32, …).

Board resets in a loop after wiring the OLED

The display is wired to D3, D4 or D8. Its pull-ups change the boot levels — move SDA/SCL back to D2/D1.

↑↓ to move · Enter to open