DEV Community

張旭豐
張旭豐

Posted on

Why Your OLED Display Flickers (And How to Fix It)

Why Your OLED Display Flickers (And How to Fix It)

You connect an OLED display to your Arduino. The first hour, it works perfectly. Then it starts flickering. Or it works at room temperature but flickers when warm. Or it works on your desk but flickers when powered from a battery.

OLED display connected to Arduino showing I2C wiring and capacitor placement for flicker-free operation
OLED display wiring — add a 10µF capacitor directly across VCC and GND pins to stabilize VCOMH and eliminate flicker.

You buy a new display. The same problem happens again. The same problem happens again.

OLED flicker is not a defect. It is a characteristic of how OLED displays manage their own pixel refresh, and it is tied to the VCOM reference voltage. Understanding this reference fixes most flicker problems.


What Is VCOM and Why It Matters

OLED displays use current-driven pixels. Each pixel emits light proportional to the current flowing through it. The current is controlled by thin-film transistors (TFTs), and the reference for this current is the VCOMH voltage.

VCOMH is the voltage that drives the pixel select lines. When VCOMH drifts, the pixel driving current changes. When the current changes, the brightness changes. When the brightness changes faster than the eye can adapt, you see flicker.

VCOMH is generated inside the display driver chip (SSD1306 for most 128x64 OLED displays). The driver chip has an internal VCOMH regulator that should keep VCOMH stable. But this regulator has a limited tolerance, and it can be disturbed by noise on the power supply, the I2C bus, or the display refresh timing.


The I2C Clock Stretching Problem

The SSD1306 driver uses I2C communication. When you send a display command, the SSD1306 sometimes holds the SCL line low (clock stretching) while it processes the command. If the Arduino's Wire library is not configured to handle clock stretching properly, the command might not complete.

On older Arduino cores (before 1.5.0), the Wire library had a default timeout that was too short for the SSD1306. The library would give up before the display finished processing, and the display would be left in a partially updated state. This manifests as flicker on the next refresh.

The fix: increase the Wire timeout before initializing the display:

Wire.setClock(400000L); // 400kHz I2C
Wire.setTimeout(1000);   // 1ms timeout
Enter fullscreen mode Exit fullscreen mode

Or switch to SPI communication, which does not require clock stretching. SPI is faster and more robust than I2C for display communication.


The Power Supply Noise Problem

OLED displays draw current proportional to the number of lit pixels. A white screen draws more current than a dark screen. This varying current load creates noise on the power supply.

If the display is powered from the Arduino's 3.3V rail, the Arduino's regulator might not be able to supply the peak current fast enough during a full-screen refresh. The voltage droops slightly. The SSD1306's VCOMH regulator interprets the droop as a change in VCC and adjusts VCOMH. VCOMH drift causes brightness changes. Brightness changes at 60Hz look like flicker.

The fix: add a 10µF capacitor directly across the display's VCC and GND pins. This capacitor provides the instantaneous current for pixel updates without drawing it from the Arduino supply.

For battery-powered projects, use a separate 3.3V regulator for the display, or add a larger capacitor (47µF) to the display power pins.


The Frame Rate Mismatch Problem

OLED displays have a fixed refresh rate, typically 60Hz or 96Hz. The SSD1306 refreshes the display by scanning through all 8 pages (for 128x64) row by row. Each row is refreshed at 1/60 / 8 = 1/480 second, or about 2ms per page.

If your code updates the display buffer and immediately calls display.display(), the SSD1306 starts the next full refresh cycle. If the refresh cycle is in the middle of a scan when the new data arrives, the display shows half old content and half new content for one frame. At 60Hz, this is invisible unless the update frequency is synchronized with the refresh frequency.

The fix: use display.display() only when the data has actually changed, not every loop iteration. Or use a frame buffer that you update and then refresh at a fixed interval (like every 100ms) rather than as fast as possible.


The Temperature Coefficient

OLED materials have a temperature coefficient. As temperature increases, the OLED pixel efficiency decreases. To compensate, the display driver increases the pixel current. But the VCOMH reference does not compensate for this automatically in most OLED driver chips.

At room temperature, the display looks perfect. In a warm room (30°C+), the display overdrives the pixels slightly, causing increased current draw, more heating, and more flicker. This is why displays that flicker in summer but not in winter are experiencing temperature-induced VCOMH drift.

The fix for temperature-sensitive applications: use a display with an external temperature compensation circuit, or implement software brightness compensation based on a temperature sensor reading.


The Complete Flicker Diagnostic Sequence

When your OLED flickers:

  1. Add a 10µF capacitor across VCC and GND at the display. Most flicker problems are power-related.
  2. Increase I2C clock speed to 400kHz and add Wire.setTimeout(1000) before Wire.begin().
  3. Reduce the display refresh rate. If you are calling display.display() more than 30 times per second, reduce to 10-15 times per second.
  4. Power the display from a separate 3.3V regulator if possible. Separate the display power from the microcontroller power.
  5. If flickering is temperature-dependent, add a small fan or heatsink to keep the display cool. Or implement software brightness compensation.
  6. If flicker persists with all of the above, the display module might have a defective VCOMH regulator. Replace the display.

When SPI Is Better Than I2C

If your project uses I2C for multiple devices (sensors, real-time clock, etc.), the I2C bus can become congested. The SSD1306 clock stretching can conflict with other devices. In this case, switch to SPI.

Most OLED displays support both I2C and SPI. On the module, there is often a selection jumper or the display ships with I2C pins populated. To use SPI, you need:

  • D0 (SCK/CLK) pin
  • D1 (MOSI/SDA) pin
  • RES (Reset) pin
  • DC (Data/Command) pin
  • CS (Chip Select) pin

The Adafruit SSD1306 library supports both I2C and SPI modes. In SPI mode, you get faster communication and no clock stretching issues.


The flicker is not random. It is VCOMH drift caused by power noise, I2C timing, or temperature. Fix the power first, then the communication timing.

For flicker-free OLED projects:

Adafruit 128x64 OLED Display (I2C or SPI) — Well-supported library, quality driver, proper VCOMH regulation. More reliable than cheap clones. (Amazon)

10µF 16V Ceramic Capacitor — Add directly across display VCC and GND pins for stable VCOMH. Essential for any OLED project. (Amazon)

ESP32 with SPI Display — Use SPI mode for OLED displays with ESP32 to avoid I2C clock stretching conflicts. (Amazon)

I earn from qualifying purchases.


Article #019, 2026-04-18. Content Farm pipeline, Run #019.

Top comments (0)