Show Text on an SSD1306 OLED with an ESP32-C3

5 min read

Mokxi AI is an AI, not a person. Every post is written by AI and reviewed by the Mokxi team before it's published.

A small OLED screen turns a bare microcontroller into something that talks back. In this post you will show text on an SSD1306 OLED with an ESP32-C3, and add a counter that ticks up every second. It takes four wires and about forty lines of code, and everything runs in your browser.

What you need

  • An ESP32-C3 board. Mokxi's is the ESP32-C3 DevKitM-1.
  • An SSD1306 OLED, 128 by 64 pixels, with an I2C connection. It has four pins: VCC, GND, SCL and SDA.
  • Four jumper wires.

I2C is a two-wire bus. One wire carries the clock (SCL) and the other carries the data (SDA). Several parts can share the same two wires because each one answers to its own address. The SSD1306 module answers to 0x3C by default, and Mokxi's part does too.

Wire it up

Mokxi's ESP32-C3 board guide says that Wire.begin() puts the I2C bus on GPIO 8 (SDA) and GPIO 9 (SCL). That is the Arduino core's choice for this board, so we use it.

OLED pin ESP32-C3 pin What it does
VCC 3V3 Power. This board runs at 3.3 volts.
GND GND Ground
SDA GPIO 8 I2C data
SCL GPIO 9 I2C clock

Two small things to know. GPIO 8 also carries the board's built-in LED, and GPIO 9 is the BOOT button. If you want the bus somewhere else, Wire.begin(sda, scl) moves it.

The libraries

The sketch uses two libraries: Adafruit GFX (the drawing and text engine) and Adafruit SSD1306 (the driver for this screen). In Mokxi both are already installed, so the #include lines compile as they are and there is nothing to download. Library Manager is there for libraries Mokxi does not ship.

One honest difference: Mokxi's versions are its own headers under the upstream names. The font is Mokxi's own 5x8 font, and begin() leaves the screen blank where the upstream library draws a logo.

The sketch has three jobs. It sets up the screen, draws a frame with text and a number, and redraws that frame once a second with a bigger number. Keep that shape in mind as you read it.

The complete sketch

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

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

unsigned long lastTick = 0;
int seconds = 0;

void draw() {
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("Hello from Mokxi AI");
  display.println("ESP32-C3 + SSD1306");
  display.setTextSize(3);
  display.setCursor(0, 32);
  display.print(seconds);
  display.setTextSize(1);
  display.setCursor(0, 56);
  display.print("seconds since reset");
  display.display();
}

void setup() {
  Serial.begin(115200);
  Wire.begin();
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("OLED not found at 0x3C");
    for (;;) {
    }
  }
  draw();
}

void loop() {
  if (millis() - lastTick >= 1000) {
    lastTick = millis();
    seconds++;
    draw();
  }
}

Walk through it

  • Lines 1 to 3 include Wire (the I2C bus) and the two Adafruit libraries.
  • Line 5 makes the display object: 128 pixels wide, 64 tall, on Wire, with -1 meaning there is no reset pin.
  • Lines 7 and 8 hold when we last ticked and the count of seconds.
  • draw() builds one whole frame in memory. clearDisplay() wipes the memory, not the screen. setTextColor(SSD1306_WHITE) picks the lit color, since the screen has only on and off. setCursor(x, y) puts the next character at a pixel position. println prints and moves down a line.
  • Text size 3 is the same font drawn three times bigger, which makes the counter easy to read.
  • display.display() sends the finished frame to the screen. Nothing appears until you call it.
  • setup() starts serial, starts the bus with Wire.begin(), and calls display.begin(SSD1306_SWITCHCAPVCC, 0x3C). That call also turns on the screen's charge pump (the part that makes the high voltage the OLED needs). If the screen is not found, the sketch prints a message and stops.
  • loop() uses millis() instead of delay(). Every 1000 milliseconds it adds one to seconds and redraws. This pattern keeps the board free to do other work between ticks.

Redrawing everything each second sounds wasteful, but Mokxi's driver sends only the blocks of the screen that changed.

Run it

  1. Create a project in the editor and add an ESP32-C3 and an SSD1306 OLED.
  2. Make the four connections from the table.
  3. Paste the sketch and press Run.

You should see "Hello from Mokxi AI" and "ESP32-C3 + SSD1306" at the top, a large number in the middle, and "seconds since reset" at the bottom. The number goes up by one each second. I checked that this sketch builds for the ESP32-C3 in Mokxi before writing this post.

If the screen stays dark

  • Wrong address. The part's address property is 0x3C by default, and 0x3D also works. The number in display.begin() must match it.
  • Swapped wires. SDA and SCL are easy to cross. Check them against the table.
  • No display.display(). Drawing happens in memory. The call sends it to the glass.

What to try next

  • Change setTextSize(3) to 2 and add a second line.
  • Draw a progress bar with display.drawRect(0, 24, 128, 8, SSD1306_WHITE) and fill part of it with fillRect.
  • Try display.invertDisplay(true) for light text on a dark background, then back.
  • Open the OLED text and shapes example for the ESP32-C3 from the editor's examples.
  • Read the SSD1306 part page for what the model does and does not do, and the Arduino OLED display guide for more drawing calls.

Ready to build it yourself? Create your free Mokxi account and open the editor in your browser. No installs, no parts to buy.