Screens/Screens with their own memory/I2C OLED
Lesson 3 of 16 · in 3D and VR

I2C OLED

An SSD1306 OLED holds its picture in 1,024 bytes of its own display memory, filled one page at a time over I²C. The glass shows that memory, not your software buffer, and the bus is not what keeps it lit.

Lonely BinaryUpdated 2026-10-014 min readNo board required

View it in VR

Lesson 3 of the Screens course opens in a VR headset, on a table in front of you, and a voice starts three seconds after you arrive. Type this short address into the browser on a headset such as Meta Quest or Apple Vision Pro, and press Enter VR. No headset? Press Start the lesson: the same lesson, full screen.

learn.lonelybinary.com/vr/screens/3

The wires are the ones from the I²C course. This lesson follows what happens after the bytes reach the display. A common 0.96-inch 128 × 64 module answers at 0x3C. The SSD1306's SA0 pin selects 0x3C or 0x3D, which is worth knowing before you scan for addresses.

Command or data

Each transfer starts with a control byte. 0x00 says the bytes that follow are commands. 0x40 says they are display data. The same two wires carry both, and getting the byte wrong sends pixels into the command decoder.

The display memory, GDDRAM, is 128 × 64 bits, exactly 1,024 bytes. In the default page addressing mode it is split into eight pages, each eight pixels tall, and each byte is a column of eight pixels. A full update writes page zero through page seven in turn.

Half an update

Interrupt the update after page three and the top half of the glass shows the new picture while the bottom half still holds the old one. Changing a pixel in your software buffer does nothing to the glass. The new data has to cross the bus and land in GDDRAM first.

At 400 kHz, the 1,024 data bytes alone need at least 23.04 ms, at eight data clocks plus an acknowledge per byte. Control bytes and commands make a real update longer, around 25 ms in our example.

The bus is not the refresh

Stop the I²C traffic and the picture stays. The SSD1306 scans its own memory, so nothing on the bus refreshes it. That is the stored-frame case from lesson two.

On a common module, the panel supply comes from an internal charge pump. Command 0x8D selects it and 0x14 enables it. Without that, the OLED does not light correctly. Other modules may power the panel differently, so check the one you have. Every ESP32 has I²C controllers, so this works across the family, and the ESP32 I²C page covers the pins.

Common mistakes

  • Changing one pixel changes the glass at once. The change exists only in your buffer until the bytes reach GDDRAM. A page-by-page update that stops early shows old and new together.
  • Forgetting the pull-ups. I²C needs a resistor on each line to make a clean high. Remove them and the bus stops producing valid logic highs. See pull-up resistors.
  • Skipping the charge pump. The controller answers and the bus looks perfect, yet the panel stays dark because command 0x8D and then 0x14 never enabled it.

Edit this page — content/fundamentals/screens/i2c-oled.mdx

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Fundamentals on the forum →