This part has a page of its own, with a note on using it and a circuit to try: the part page.

SSD1306 OLED display

The 128x64 OLED module every hobby kit has, over I2C. Aliases: 0.96 inch OLED, I2C OLED display.

Two wires and power. The part is an I2C slave decoded straight off the pin edges, a command interpreter, and 1 KB of display RAM. There is no I2C peripheral on the Uno or the ESP32-C3 in Mokxi, so the bus is bit-banged, and the module's own 4k7 pull-ups (modeled here too) are what bring the lines back up.

Pins

Pin What it does
VCC Supply.
GND Ground.
SCL Open-drain clock.
SDA Open-drain data.

Properties

address: the I2C address, 0x3C by default (the alternate 0x3D also works).

What the model gets right

The part models the command set the common libraries actually send (display on and off, addressing mode, column and page windows, inverse, entire-display-on, contrast, segment remap and COM scan direction) in all three addressing modes, so a driver written against a real panel works here unchanged. A 128x64 monochrome frame is 1024 bytes; on an Uno, sending all of it over the bit-banged bus takes a third of a second, which is why the firmware library sends only the 8-column blocks of each page that actually changed.

What it does not model

It never stretches the clock. A real SSD1306 can hold SCL low to make the master wait; this one acknowledges every byte immediately and always. A driver that relies on clock stretching works here and might not on the bench, and, the other way around, a master that ignores stretching passes here and would corrupt a real panel.

The bus has no errors in it. The slave acknowledges its own address and every byte sent to it, and answers nothing else at all: there is no read transfer, no NACK, no arbitration, no bus timeout and no way to make it fail. Nothing checks the clock rate either, so a bit-banged bus at any speed works.

The charge pump is modeled. A module has one supply pin and the 7.5 V the panel needs comes from a pump inside the chip, which powers up off. 0x8D 0x14 starts it and 0x8D 0x10 stops it, and the glass is lit only when the display is on and the pump is running, so a driver that sends 0xAF and forgets 0x8D gets the same dark panel here that it gets on the bench, which is one of the two commonest reasons a real SSD1306 stays black.

Several other commands are taken and thrown away. The multiplex ratio, the display offset, the display clock divide, pre-charge, COM pin configuration, VCOMH deselect and the start line are all accepted and stored and change nothing on the glass. Hardware scrolling (0x26–0x2F) is accepted and ignored, so a scrolling banner stands still.

Contrast (0x81) reaches the canvas as one of sixteen brightness steps rather than as the real panel's 256, and there is no refresh rate, no pixel persistence and no burn-in. Reads from the panel are not modeled at all.

Code

The Adafruit tutorial compiles as it stands on every board but the ATtiny85:

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

Adafruit_SSD1306 display(128, 64, &Wire, -1);

void setup() {
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) for (;;);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Hello, world!");
  display.drawRect(0, 20, 40, 20, SSD1306_WHITE);
  display.display();
}

Both headers are Mokxi's own, on mokxi_ssd1306.h, so a frame costs what that driver's does: only the blocks that changed go over the bus. What is there: clearDisplay, display, drawPixel, lines, rectangles, rounded rectangles, circles and triangles outlined and filled, one-bit bitmaps, setTextSize, setTextColor, setCursor, print and println, setRotation, invertDisplay and dim. What differs from upstream:

  • The font is Mokxi's own 5x7, in the same 6x8 cell, with capitals, digits and punctuation. Lower case prints as capitals, and setFont is not there.
  • begin() leaves the panel blank where upstream draws its logo.
  • A 128, 32 sketch draws in the top half of this 128x64 part. The ssd1306x32 is the 0.91 inch strip such a sketch is written for, and the 1.3 inch module is an SH1106, which needs its own library.
  • Only the I2C constructors. The SPI ones name a module Mokxi does not have.
  • On an Uno the frame is 1 KB of the 2 KB of RAM, the same cost as upstream. The ATtiny85 has 512 bytes, so the header stops with a message there.

Common mistakes

Wiring 0xA0/0xC0 instead of 0xA1/0xC8 (or trusting the power-on default) and getting a mirrored picture. A real 128x64 module needs those two commands to draw upright, and every library sends them for exactly that reason.

See it in action

OLED pong, OLED dice and Binary clock all drive an SSD1306. Open them at /templates, and read the parts games are made of for the fuller story of the bus and the driver.