Outputs and switching
SSD1306 OLED with ESP32
Why add a 0.96-inch screen to a project that already has a 7-inch panel? A small OLED is a handy status readout: mounted on a remote box, inside a cabinet or on the device while the main panel sits by the door. It takes two I2C wires and works from 3.3 V.
The usual first failure is the address. The back of the module often says 0x78, which is the 8-bit write address, while Arduino libraries want the 7-bit form: 0x3C. One example stayed dark with 0x78 and worked with 0x3C. Some modules use 0x3D, and the SA0 pad on the board switches between them, so two OLEDs can share one bus. The Adafruit header comments suggest 0x3D for 128x64, but many of these modules ship at 0x3C, so run a scan and believe the scan.
Draw on it with a normal graphics library. The Adafruit library keeps a full copy of the screen in RAM, about 1 KB on a 128x64 model, and an I2C refresh is slow compared with a parallel panel. If a display board has one I2C bus shared with its touch chip, send updates only when the content changes, so the touch stays responsive. Check for an address clash with the touch controller first. Text that never moves can leave marks on an OLED over time, so consider moving it or dimming it when idle.

Specifications
| Resolution | 128×64 or 128×32 |
|---|---|
| Interface | I2C (some modules SPI) |
| I2C address | 0x3C or 0x3D by SA0 |
| Back label | 0x78 = 7-bit 0x3C |
| Supply on ESP32 | 3.3 V |
| RAM buffer | About 1 KB at 128×64 |
Power and logic levels
3.3 V: safe to connect directly
| Supply | 3.3–5 V on most modules, use 3V3 |
|---|---|
| Signal level | I2C follows the module pull-ups |
| On an ESP32 | Run it from 3V3, so the I2C lines stay at 3.3 V. |
ESP32 pins, including those on a display board's connectors, work at 3.3 V and are not 5 V tolerant. Modules differ, so if in doubt, measure the signal before you connect it.
Wiring
| SSD1306 OLED | Connect to | Note |
|---|---|---|
| VIN / VCC | 3V3 | |
| GND | GND | |
| SDA | GPIO 8 | Any free pin, set in Wire.begin() |
| SCL | GPIO 9 | Any free pin, set in Wire.begin() |
Arduino code
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
const int SDA_PIN = 8, SCL_PIN = 9;
Adafruit_SSD1306 oled(128, 64, &Wire, -1);
void setup() {
Serial.begin(115200);
Wire.begin(SDA_PIN, SCL_PIN);
if (!oled.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // not 0x78
Serial.println("OLED not found, run an I2C scan");
while (true) delay(1000);
}
oled.clearDisplay();
oled.setTextSize(2);
oled.setTextColor(SSD1306_WHITE);
oled.setCursor(0, 0);
oled.println("21.4 C");
oled.display();
}
void loop() {}
Needs the Adafruit SSD1306 library. Compiled for ESP32-S3 with arduino-esp32 3.x. Not yet tested by us on a physical sensor. Change the pins to match your board.
On a display
Read the value in your sketch and pass it to a label, or send it over MQTT and show it with an MQTT value in the editor.
Design a display for SSD1306 OLEDBoards with a ready connector
Only boards whose connectors we have surveyed. Others may still work on free GPIOs.
| Elecrow CrowPanel ESP32 HMI 2.4" | I2C port: SDA 22, SCL 21Not shared with the touch controller (it is on SPI) — free for sensors |
| Elecrow CrowPanel ESP32 HMI 2.8" | I2C port: SDA 22, SCL 21Not shared with the touch controller (it is on SPI) — free for sensors |
| Elecrow CrowPanel ESP32 HMI 3.5" | I2C port: SDA 22, SCL 21Not shared with the touch controller (it is on SPI) — free for sensors |
| Elecrow CrowPanel ESP32-S3 HMI 5.0" | I2C port: SDA 19, SCL 20Same I2C bus as the GT911 touch (0x14 / 0x5D) and, on V3.0 boards, the PCA9557 touch-reset expander (0x18) |
| Elecrow CrowPanel ESP32-S3 HMI 7.0" | I2C port: SDA 19, SCL 20Same I2C bus as the GT911 touch (0x14 / 0x5D) and, on V3.0 boards, the PCA9557 touch-reset expander (0x18) |
| LilyGO T-Display-S3-Pro 2.33" | QWIIC RIGHT: SDA 5, SCL 6I2C only — same bus as the touch, the PMU (SY6970) and the light sensor |
| M5Stack AtomS3 0.85" | Bottom I2C pins: SDA 38, SCL 39Same I2C bus as the built-in IMU (MPU6886, 0x68) |
| Makerfabs MaTouch ESP32-S3 Rotary IPS 2.1 Round | Mabee I2C (J1): SDA 17, SCL 18Same I2C bus as the touch controller (CST826) |
| Makerfabs MaTouch ESP32-S3 Parallel TFT 4.3" | Mabee I2C: SDA 17, SCL 18Same I2C bus as the touch controller (GT911) |
| Makerfabs MaTouch ESP32-S3 Parallel TFT with Touch 5.0" | Mabee I2C: SDA 17, SCL 18Same I2C bus as the touch controller (GT911) |
| Makerfabs MaTouch ESP32-S3 Parallel TFT with Touch 7.0" | Mabee I2C: SDA 17, SCL 18Same I2C bus as the touch controller (GT911) |
| Sunton ESP32-4827S043R/C 4.3" | I2C header (P3): SDA 19, SCL 20Same I2C bus as the GT911 touch controller. P3 also carries GPIO 17 / 18. |
| Sunton ESP32-8048S043C 4.3" | I2C header (P3): SDA 19, SCL 20Same I2C bus as the GT911 touch controller. P3 also carries GPIO 17 / 18. |
| Sunton ESP32-8048S050C 5.0" | I2C header (P3): SDA 19, SCL 20Same I2C bus as the GT911 touch controller. P3 also carries GPIO 17 / 18. |
| Sunton ESP32-8048S070C 7.0" | I2C header (P3): SDA 19, SCL 20Same I2C bus as the GT911 touch controller. P3 also carries GPIO 17 / 18. |
| Waveshare ESP32-S3 Touch LCD 2.1" round | I2C connector: SDA 15, SCL 7Same I2C bus as the touch controller, the IO expander, the RTC and the IMU (addresses 0x15/0x5D, 0x20, 0x51, 0x6B, 0x7E taken) |
| Waveshare ESP32-S3 Touch LCD 2.8" | I2C connector: SDA 11, SCL 10Same I2C bus as the RTC and the IMU (0x51, 0x6B, 0x7E taken) — the touch has its own bus |
| Waveshare ESP32-S3 Touch LCD 2.8" Type B | I2C connector: SDA 15, SCL 7Same I2C bus as the touch controller, the IO expander, the RTC and the IMU (addresses 0x15/0x5D, 0x20, 0x51, 0x6B, 0x7E taken) |
| Waveshare ESP32-S3-Touch-LCD-2.8C | I2C connector: SDA 15, SCL 7Same I2C bus as the touch controller, the IO expander, the RTC and the IMU (addresses 0x15/0x5D, 0x20, 0x51, 0x6B, 0x7E taken) |
| Waveshare ESP32-S3-LCD-7B | I2C connector (H1): SDA 8, SCL 9Same I2C bus as the touch controller (GT911) and the IO expander (CH422G) |
Good to know
- 0x78 on the label means 0x3C in code.
- Scan the bus first.
- Refresh only when content changes.
- Static text can leave marks.
What it is good for
- Remote status readout
- Service information inside a cabinet
- Small second display
FAQ
Why is my OLED blank?
Try 0x3C, not 0x78, and run an I2C scan.
Can I use two on one bus?
Yes, set one to 0x3D with the SA0 pad.
Will it slow the main display?
I2C refreshes are slow, so update it only when needed.
Sources
Related parts
Use this information at your own risk. It is for general guidance only: the example code compiles, but it has not been tested on every part, and modules differ between sellers. Check the manufacturer's data before you build. Product names belong to their owners, and LCD Ultra Pro is not affiliated with them. See our Terms.