A 0.96 inch OLED Display
| Difficulty | Intermediate |
|---|---|
| Category | Displays |
| Supported boards | Arduino Uno R3 and compatible ATmega328P boards |
| Time needed | 50 minutes |
| Prerequisites | A 16x2 LCD over I2C |
| Tested board | Not yet verified |
| Tested on | Not yet verified |
| Arduino IDE version | Not yet verified |
| Library | Not yet verified |
What it does
A small graphic display, 128 by 64 pixels, driven over the same two I2C wires as the LCD. Unlike a character display it can draw anything: text in several sizes, lines, shapes, a scrolling graph of a sensor reading.
OLED means each pixel makes its own light, so there is no backlight. A dark pixel is genuinely off, which is why the black looks black rather than grey, and why the display draws almost nothing when most of the screen is blank.
The catch is memory, and on an Uno that catch is severe. Most of this tutorial is about living within it.
Before you begin
Required parts and tools
- An Arduino Uno or compatible board.
- One 0.96 inch OLED module, four pins, I2C. This is Siratek product 2459.
- Four female-to-male jumper wires.
Read your own silkscreen
The pin labels on this module are not the ones you may be expecting. On the Siratek part, the four pads are marked, from pin 1:
GND VDD SCK SDA
Two things to notice.
VDD, not VCC. Same thing, different convention. It goes to 5V.
SCK, not SCL. This is the one that causes trouble. SCK is the name usually given to an SPI clock, and seeing it makes people reach for pin 13. On this module it is the I2C clock, and it goes to A5. Some boards from other suppliers print SCL, and some print D0 and D1 for the same two pins.
And the order varies between makers. Plenty of otherwise identical-looking 0.96 inch modules put VDD first and GND second. Reversing power on these does not always destroy them, but it sometimes does. Read the silkscreen on the part in your hand, every time, and do not wire from memory.
3.3 V or 5 V
The SSD1306 controller itself runs at 3.3 V. The module carries a regulator, so the common four-pin boards accept 5 V on VDD and are safe on an Uno. The Siratek part is one of these.
If you ever meet a bare module without that regulator, 5 V will damage it. The tell is a board with no small three-pin regulator package and no charge-pump components near the power pin, but this is genuinely hard to judge from a photograph, which is why it is worth buying the module rather than the bare panel.
The memory problem, which is the real subject here
A 128 by 64 monochrome screen is 1024 bytes of pixels. The usual Adafruit driver keeps a full copy of that in RAM so it can draw into it and push the result out in one go.
An Uno has 2048 bytes of RAM in total.
So half the board’s memory is gone to the screen buffer before your sketch declares a single variable. Adding the library’s own overhead, a plain “hello world” on this display typically leaves you a few hundred bytes. That is enough for a counter and a couple of sensor readings. It is not enough for long strings, large arrays, or a comfortable margin.
The symptom when you run out is not a compiler error. The sketch uploads and then behaves strangely: the display garbles, the board resets, or the text comes out as rubbish. The IDE will usually warn you, in orange, that low memory is available and stability problems may occur. On this display, take that warning seriously. It is the one case where it is routinely the actual cause.
Three things help, and they are all in the examples below: keep string constants out of RAM with F(), pick the smaller font, and if you need more room than that, move the project to a board with more memory.
Pin reference
| Pin or label | Connect to | Purpose | Notes |
|---|---|---|---|
GND |
Uno GND |
Ground | Pin 1 on this module |
VDD |
Uno 5V |
Power | Called VCC on some boards |
SCK |
Uno A5 |
I2C clock | Called SCL on some boards. Not SPI |
SDA |
Uno A4 |
I2C data |
Wiring steps
- Unplug the USB cable.
- Read the four labels on your module and check they are in the order
GNDVDDSCKSDA. If they are not, follow the labels, not this list. GNDtoGND.VDDto5V.SCKtoA5.SDAtoA4.- Plug the USB cable back in. Nothing will appear yet. An OLED stays dark until a sketch initialises it, which is different from the LCD’s backlight.
Software and libraries
Install two libraries through Library Manager:
- Adafruit SSD1306, the driver for this controller.
- Adafruit GFX Library, which does the drawing. Library Manager usually offers to install it alongside the first; accept.
See Installing and Managing Libraries if this is new.
Minimal working example
Scan for the address first. These modules are almost always 0x3C, occasionally 0x3D, and the scanner from I2C, Two Wires and Many Devices settles it in seconds.
// Siratek: hello on a 0.96 inch OLED.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
// -1 means this module has no reset pin of its own.
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
void setup() {
Serial.begin(9600);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("Siratek: display not found at 0x3C."));
for (;;) {
;
}
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println(F("Siratek"));
display.println(F("Kumasi, Ghana"));
display.display();
}
void loop() {
}
Three details carry their weight here.
display.display(). Nothing appears until you call it. Every print and every shape draws into the RAM buffer, and that one call pushes the buffer to the screen. A sketch that draws correctly and shows nothing has almost always forgotten it.
F("..."). The F() macro keeps the string in program memory instead of copying it into RAM at startup. With a 1024-byte screen buffer already spoken for, this is not a refinement. Use it around every fixed string you print.
The begin() check. If the address is wrong, this sketch says so on the serial monitor instead of failing silently. On a display that is dark until told otherwise, that is the difference between a diagnosis and a guess.
Something that changes
// Siratek: a counter, redrawing only when the value changes.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
Adafruit_SSD1306 display(128, 64, &Wire, -1);
unsigned long lastUpdate = 0;
int count = 0;
void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.setTextColor(SSD1306_WHITE);
}
void loop() {
if (millis() - lastUpdate >= 500) {
lastUpdate = millis();
count++;
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
display.println(F("Count"));
display.setTextSize(3);
display.setCursor(0, 20);
display.println(count);
display.display();
}
}
Here clearDisplay() is right, which is the opposite of the advice in the LCD tutorial. The reason is that it clears the RAM buffer, not the screen, and costs nothing visible. The screen only changes on display(), so the viewer never sees an intermediate blank. A character LCD has no buffer, so clearing it is visible as a flicker.
setTextSize(3) scales the built-in font by three. It is the quickest way to make a reading legible across a room.
Expected result
A dark screen until the sketch runs, then sharp white text. The counter example shows a small label and a large number ticking twice a second, with no flicker.
Check the compiler’s memory report after uploading. If it says you have under about 200 bytes of RAM free, treat that as a warning about whatever you add next.
Troubleshooting
| Symptom | Likely cause | Check or fix |
|---|---|---|
| Screen stays dark | display.display() never called |
Add it after drawing |
| Screen stays dark, serial says not found | Wrong address | Scan the bus; try 0x3D |
| Nothing found by the scanner | SCK wired to pin 13 |
SCK here is I2C clock, so A5 |
| Nothing found, wiring looks right | Power pins reversed | Read the silkscreen; order varies by maker |
| Garbled pixels, or random resets | Out of RAM | Wrap strings in F(), use a smaller text size |
| Low memory warning when compiling | The 1024-byte screen buffer | Expected on an Uno; keep the sketch lean |
| Text drawn off the edge | Cursor past 128 or 64 | Coordinates are pixels, not characters |
| Works alone, fails with another I2C device | Address clash | Scan with both connected |
| Faint or uneven brightness after long use | OLED ageing on a static image | Blank or move the display when idle |
| Compiles for an Uno but not for a smaller board | Buffer does not fit | A board with 2 KB of RAM is the floor |
Next steps
- Easier first: A 16×2 LCD over I2C, if two lines of text is all the project needs.
- Related: I2C, Two Wires and Many Devices, for sharing the bus with a sensor.
- Next project: a mini weather station, with a DHT11 reading drawn in large text.
Sources and attribution
All text, wiring guidance and code in this tutorial are original Siratek work.
- Arduino core documentation for the
Wirelibrary, and the Adafruit SSD1306 and GFX library documentation for the drawing calls. - The pin order given here,
GNDVDDSCKSDA, was read from the Siratek product photographs for item 2459.
Pin order and labelling vary between makers of otherwise identical modules, so this tutorial tells the reader to follow their own silkscreen. The ATmega328P RAM figure is from the Arduino Uno documentation. No third-party tutorial text, diagrams, photographs or code has been reproduced here.

