OLED Display (SSD1306) – Compact high-contrast display
The SSD1306 is a single-chip CMOS OLED driver that controls a 128×64 (or 128×32) dot-matrix OLED display. Each pixel emits its own light — no backlight needed — resulting in deep blacks, high contrast, and low power consumption (≈20 mA typical). Communication is over I²C or SPI. These small monochrome displays are widely used in embedded projects for status readouts, sensor data, menu systems, and wearable devices.
For this interfacing you need the following components:
- Arduino board (Uno, Nano, Mega, etc.)
- SSD1306 OLED display module (128×64, I²C or SPI)
- Breadboard and jumper wires
- USB cable to connect Arduino to your computer
Schematic
I²C wiring (most common — 4 pins)
SSD1306 (I²C) Arduino
------------- -------
VCC --> 5V (or 3.3V — most modules include a regulator)
GND --> GND
SCL --> A5 (Uno/Nano) or SCL (Mega)
SDA --> A4 (Uno/Nano) or SDA (Mega)
SPI wiring (6–7 pins, faster refresh)
SSD1306 (SPI) Arduino
------------- -------
VCC --> 5V
GND --> GND
CS --> Digital Pin 10
DC --> Digital Pin 9
RESET (RST) --> Digital Pin 8
MOSI (SDA) --> Digital Pin 11 (MOSI)
SCK (SCL) --> Digital Pin 13 (SCK)
SPI provides faster refresh rates than I²C, useful for animations.
Pin Map
I²C pins
| Module Pin | Name | Arduino Connection |
|---|---|---|
| VCC | Power | 5V or 3.3V |
| GND | Ground | GND |
| SCL | I²C Clock | A5 (Uno), SCL (Mega) |
| SDA | I²C Data | A4 (Uno), SDA (Mega) |
SPI pins
| Module Pin | Name | Arduino Connection |
|---|---|---|
| VCC | Power | 5V or 3.3V |
| GND | Ground | GND |
| CS | Chip Select | Pin 10 |
| DC | Data / Command | Pin 9 |
| RESET (RST) | Reset | Pin 8 |
| MOSI (SDA) | SPI Data | Pin 11 |
| SCK (SCL) | SPI Clock | Pin 13 |
I²C address
The SSD1306 I²C address is typically 0x3C (or 0x3D on some modules). If the display doesn’t respond, try the alternate address.
Install necessary Library
Install the following libraries via the Library Manager (Tools > Manage Libraries):
- Adafruit SSD1306 by Adafruit
- Adafruit GFX by Adafruit (required dependency)
Alternatively, using arduino-cli:
arduino-cli lib install "Adafruit SSD1306"
arduino-cli lib install "Adafruit GFX"
Code with complete explanation
This sketch demonstrates text, shapes, and bitmap display on the SSD1306 OLED via I²C.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
// I²C address — change to 0x3D if needed
#define OLED_ADDR 0x3C
// Reset pin — set to -1 if tied to VCC (most I²C modules)
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
void setup()
{
Serial.begin(9600);
// Initialise display
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR))
{
Serial.println("SSD1306 allocation failed");
while (1) {}
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("OLED Ready!");
display.display();
delay(1500);
// Run demos
demoText();
demoShapes();
demoBitmap();
}
void loop()
{
// Nothing in loop — run setup once
}
void demoText()
{
display.clearDisplay();
display.setTextSize(2);
display.setCursor(10, 0);
display.println("Hello!");
display.setTextSize(1);
display.setCursor(0, 20);
display.print("Temp: ");
display.print(22.5);
display.println(" C");
display.setCursor(0, 30);
display.print("Hum: 65 %");
display.setTextSize(1);
display.setCursor(0, 50);
display.println("128 x 64 OLED");
display.display();
delay(3000);
}
void demoShapes()
{
display.clearDisplay();
display.drawRect(10, 10, 30, 20, SSD1306_WHITE);
display.fillRect(50, 10, 30, 20, SSD1306_WHITE);
display.drawCircle(20, 50, 10, SSD1306_WHITE);
display.fillCircle(60, 50, 10, SSD1306_WHITE);
display.drawTriangle(90, 10, 100, 30, 110, 10, SSD1306_WHITE);
display.display();
delay(3000);
}
void demoBitmap()
{
// Simple 16x16 smiley face bitmap
static const uint8_t PROGMEM smiley[] = {
0b00001111, 0b11110000,
0b00010000, 0b00001000,
0b00100000, 0b00000100,
0b01000000, 0b00000010,
0b01000000, 0b00000010,
0b10000000, 0b00000001,
0b10000110, 0b01100001,
0b10001001, 0b10010001,
0b10010000, 0b00001001,
0b10010000, 0b00001001,
0b10001001, 0b10010001,
0b10000110, 0b01100001,
0b10000000, 0b00000001,
0b01000000, 0b00000010,
0b00100000, 0b00000100,
0b00011111, 0b11111000
};
display.clearDisplay();
display.drawBitmap(56, 24, smiley, 16, 16, SSD1306_WHITE);
display.display();
delay(3000);
}
Code breakdown
Adafruit_SSD1306 display(width, height, &Wire, reset)— creates an SSD1306 display object for I²C. For SPI, useAdafruit_SSD1306 display(width, height, &SPI, DC, RST, CS).display.begin(SSD1306_SWITCHCAPVCC, addr)— initialises the display.SSD1306_SWITCHCAPVCCenables the internal charge pump (required for 3.3V operation).display.clearDisplay()— clears the internal buffer (all pixels off).display.display()— sends the buffer to the display. Changes only take effect after this call.display.setCursor(x, y)— sets the text cursor position (in pixels).display.setTextSize(n)— sets text size multiplier (1 = 6×8 pixel font, 2 = 12×16, etc.).display.setTextColor(color)— sets the text/foreground colour. On monochrome OLED:SSD1306_WHITE(on) orSSD1306_BLACK(off, for inverting).display.println(text)— prints text and advances to the next line.display.drawRect(x, y, w, h, color)— draws a rectangle outline.display.fillRect(x, y, w, h, color)— draws a filled rectangle.display.drawCircle(x, y, r, color)— draws a circle outline.display.drawBitmap(x, y, bitmap, w, h, color)— draws a monochrome bitmap from PROGMEM.
Using the SPI interface
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_CS 10
#define OLED_DC 9
#define OLED_RST 8
Adafruit_SSD1306 display(128, 64, &SPI, OLED_DC, OLED_RST, OLED_CS);
void setup()
{
display.begin(SSD1306_SWITCHCAPVCC);
// No I²C address needed for SPI
}
Inverted display and scrolling
// Invert entire display
display.invertDisplay(true); // true = inverted, false = normal
// Horizontal scroll
display.startscrollright(0x00, 0x0F); // Scroll right, start page 0, end page 15
// display.startscrollleft(0x00, 0x0F);
// display.stopscroll();
Steps to perform this interfacing
- Determine whether your OLED module uses I²C (4 pins) or SPI (6–7 pins). Most 0.96” modules are I²C.
- Connect the OLED to the Arduino as shown in the relevant schematic.
- Install the Adafruit SSD1306 and Adafruit GFX libraries.
- Copy the code into the Arduino IDE. If using SPI, uncomment the SPI constructor.
- Select the correct board and port (
Tools > BoardandTools > Port). - Upload the sketch to the Arduino.
- The display will show “OLED Ready!”, then text, then shapes, then a smiley face bitmap.
Troubleshooting
- Display blank: Adjust the contrast potentiometer (if present) or check that I²C address matches (try 0x3C and 0x3D).
- Garbled or no display: Check wiring, especially VCC/GND. For I²C, verify SDA/SCL are not swapped. For SPI, ensure CS and DC are on the correct pins.
- Faint display: The SSD1306 needs the internal charge pump enabled. Ensure
SSD1306_SWITCHCAPVCCis passed tobegin().
Caution
- I²C address: Most SSD1306 modules use address 0x3C. Some (particularly 128×32 or certain batches) use 0x3D. If the display doesn’t initialise, try the other address in
display.begin(). - Pull-up resistors: I²C modules include onboard pull-up resistors on SDA and SCL. If using the module without onboard pull-ups, add external 4.7 kΩ resistors from SDA to VCC and SCL to VCC. Without pull-ups, the I²C bus will not work.
- Charge pump: The SSD1306 requires the internal DC-DC charge pump to generate the OLED drive voltage (≈7–15 V). This is enabled by
SSD1306_SWITCHCAPVCC. If the display is very faint, the charge pump may not be running — ensure VCC is ≥ 3.3 V and the charge pump setting is correct. - Current draw: The OLED draws 15–25 mA in normal use (all pixels on white). This is higher than a character LCD but lower than a TFT display (which has a backlight). The peak current during charge pump start-up can reach 30 mA.
- Burn-in: Like all OLEDs, the SSD1306 is susceptible to permanent burn-in if the same static image is displayed for extended periods. Avoid displaying fixed patterns (e.g., a static menu) for days at a time. Use screen savers or periodic inversion if the display must remain on continuously.
- SPI vs I²C speed: The SPI interface is significantly faster (up to 10 MHz SPI clock vs 400 kHz I²C). For animated content or high frame rates, use SPI. For static text displays, I²C is adequate and uses fewer pins.