← LOGBOOK LOG-350
EXPLORING · ELECTRONICS ·
OLEDI2CSPISSD1306DISPLAYPROTOCOLS

I2C vs SPI OLED Displays

Understanding the difference between I2C and SPI variants of the SSD1306 OLED — wiring, speed, trade-offs, and when to use each.

The Question

After getting the I2C OLED working, I noticed some SSD1306 modules sold as “SPI” with 7 pins instead of 4. Same chip, different interface. Spent time today understanding what actually changes between the two.


I2C OLED

The 4-pin modules (VCC, GND, SCL, SDA) use the I2C protocol. Everything in the previous session used this variant.

How it works: I2C is a two-wire serial bus. SCL is the clock line, SDA carries data in both directions. Multiple devices share the same two wires — each device has a unique 7-bit address. The SSD1306 typically sits at 0x3C or 0x3D depending on the state of the address pin.

Key characteristics:

  • Only 2 signal wires (+ power)
  • Can share the bus with other I2C devices (MPU-6050 at 0x68, etc.)
  • Slower: standard mode 100 kHz, fast mode 400 kHz
  • Half-duplex (data flows one direction at a time)
  • Address conflicts are possible if two devices have the same fixed address

Wiring:

SSD1306 (I2C)    Arduino Uno
VCC           →  3.3V
GND           →  GND
SCL           →  A5
SDA           →  A4

SPI OLED

The 7-pin modules expose the SPI interface: VCC, GND, D0 (CLK), D1 (MOSI), RES (reset), DC (data/command), CS (chip select).

How it works: SPI uses separate clock and data lines, plus a dedicated chip-select pin per device. The master (Arduino) drives the clock; data flows only from master to slave (for displays, it’s write-only). No addresses — CS pin selects which device is active.

Key characteristics:

  • 5 signal wires (CLK, MOSI, RES, DC, CS) + power
  • Faster: typically 4–8 MHz, some displays support up to 20 MHz
  • Full-duplex capable, but displays are write-only
  • Each SPI device needs its own CS pin — more devices means more pins used
  • No address conflicts

Wiring:

SSD1306 (SPI)    Arduino Uno
VCC           →  3.3V
GND           →  GND
D0 (CLK)      →  Pin 13 (SCK)
D1 (MOSI)     →  Pin 11 (MOSI)
RES           →  Pin 8
DC            →  Pin 9
CS            →  Pin 10 (SS)

The DC pin distinguishes command bytes (config, cursor position) from data bytes (pixel buffer). The display driver needs this to know how to interpret incoming bytes.

Sketch difference — constructor changes, everything else stays the same:

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

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_MOSI  11
#define OLED_CLK   13
#define OLED_DC    9
#define OLED_CS    10
#define OLED_RESET 8

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
  OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("SPI OLED");
  display.display();
}

The Adafruit library handles both — just the constructor argument determines which interface gets used.


Trade-off Summary

I2CSPI
Wires2 signal5 signal
Speed~400 kHz~4–20 MHz
Bus sharingYes (by address)Yes (by CS pin)
Pin costLowHigher
Best forBreadboard prototyping, multi-sensor buildsFast refresh, dedicated display projects

For a 128×64 monochrome display, I2C is fast enough for most uses — a full buffer flush is ~1ms at 400 kHz. SPI matters when you’re animating fast or running a higher-resolution display.


The DC Pin — What It’s Actually Doing

The DC (data/command) line was the most interesting thing to understand. The SSD1306 has two modes:

  • Command mode (DC low): incoming byte is a configuration instruction — set contrast, scroll, invert, sleep, etc.
  • Data mode (DC high): incoming byte goes into the GDDRAM pixel buffer

So when the Adafruit library calls display.display(), it sets DC low to send position commands, then DC high to stream the entire 1024-byte pixel buffer. The display chip doesn’t need a CS pin to distinguish these on I2C — the register address in the I2C packet does the same job.


What’s Next

Want to test a 4-pin I2C and 7-pin SPI module side by side if I can get an SPI one. Also curious whether the speed difference is perceptible when animating sensor data on the OLED.