Built-in project · ESP32-C3-DevKitM-1

OLED on an ESP32-C3

The same 128x64 SSD1306 demo on the other board: one driver, two pin numbers changed. The whole build, an ESP32-C3 and 1 more part, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

IntermediateRuns in your browser. Free, and no account needed.

OLED on an ESP32-C3 · ESP32-C3-DevKitM-1live0.000 s 0.00x
Click to open it in the editor
The circuit itself, running here on the simulator. Press what can be pressed; click anything else to open it in the editor.

The code

The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.

sketch.ino · ESP32-C3-DevKitM-1
// OLED: text and shapes on a 128x64 SSD1306, over bit-banged I2C.
//
// Wiring, module to board:
//   SCL -> GPIO 5      SDA -> GPIO 4      VCC -> 3V3      GND -> GND
//
// There is no I2C peripheral in the ESP32-C3 model (docs/esp32c3.md section 3),
// so mokxi_i2c.h pulls the two lines down and lets them go, and the module's
// own 4k7 pull-ups bring them back up. Any two GPIOs will do.
//
// This is the same sketch as the Uno's `oled` example with two pin numbers
// changed, which is the point: the driver is the same header on both boards.
// What differs is the money: 400 KB of RAM here against 2 KB, so the 1 KB
// frame buffer that is half of an Uno's memory is a rounding error on this one.
//
// Each display() sends only the eight-column blocks of each page that actually
// changed, so a moving ball is a few dozen bytes rather than a kilobyte. This
// board bit-bangs the bus at about 196 kbit/s against the Uno's 32, and yet it
// runs this demo at ten frames a second where the Uno runs it at twenty-five,
// because the cost in the browser is the kernel carrying each bus edge, not the
// board making it, and this one makes them six times faster.

#include "mokxi_i2c.h"
#include "mokxi_ssd1306.h"

const uint8_t SCL_PIN = 5;
const uint8_t SDA_PIN = 4;

SoftI2c bus(SCL_PIN, SDA_PIN, 400);
Ssd1306 oled(bus, SSD1306_ADDRESS);

// The arena the ball bounces in, and the ball.
const int16_t AX = 2;
const int16_t AY = 21;
const int16_t AW = 60;
const int16_t AH = 41;
const int16_t R = 4;

int16_t bx = AX + R + 6;
int16_t by = AY + R + 4;
int16_t bdx = 2;
int16_t bdy = 1;

uint16_t ticks = 0;

const int FRAME_MS = 100;

// Everything that never moves, drawn once into the buffer.
static void furniture() {
  oled.clear();
  oled.text(3, 2, "MOKXI", 2);
  oled.text(88, 8, "ESP32", 1);
  oled.hLine(0, 18, 128);
  oled.rect(AX - 1, AY - 1, AW + 2, AH + 2);

  oled.rect(68, 22, 24, 16);
  oled.circle(110, 30, 7);
  oled.rect(106, 44, 20, 16);
}

void setup() {
  Serial.begin(115200);
  Serial.println("Mokxi ESP32-C3: SSD1306 over bit-banged I2C");
  bus.begin();
  if (!oled.begin()) {
    Serial.println("no OLED answered 0x3C; check SCL, SDA and power");
    return;
  }
  furniture();
  oled.display();
}

void loop() {
  oled.fillCircle(bx, by, R, false);

  bx = (int16_t)(bx + bdx);
  by = (int16_t)(by + bdy);
  if (bx - R <= AX) {
    bx = (int16_t)(AX + R);
    bdx = (int16_t)-bdx;
  } else if (bx + R >= AX + AW - 1) {
    bx = (int16_t)(AX + AW - 1 - R);
    bdx = (int16_t)-bdx;
  }
  if (by - R <= AY) {
    by = (int16_t)(AY + R);
    bdy = (int16_t)-bdy;
  } else if (by + R >= AY + AH - 1) {
    by = (int16_t)(AY + AH - 1 - R);
    bdy = (int16_t)-bdy;
  }
  oled.fillCircle(bx, by, R, true);

  // The counter and the bar move a good deal more picture than the ball does,
  // so they tick at a sixth of the frame rate and the lozenge at a third. The
  // driver only sends the eight-column blocks that changed, and a frame where
  // only the ball moved is a few dozen bytes on the bus instead of four hundred.
  ticks++;
  if (ticks % 6u == 0u) {
    oled.number(68, 44, (long)((ticks / 6u) % 1000u), 2, true, true);
    int16_t fill = (int16_t)(1 + ((ticks / 6u) % 16u));
    oled.fillRect(108, 46, 16, 12, false);
    oled.fillRect(108, 46, fill, 12, true);
  }
  if (ticks % 3u == 0u) {
    // The lozenge in the top box slides, so the shapes panel is not quite still.
    oled.fillRect(70, 24, 20, 12, false);
    oled.fillRect((int16_t)(70 + ((ticks / 3u) % 14u)), 24, 6, 12, true);
  }

  oled.display();
  delay(FRAME_MS);
}

Parts list

3 parts, plus the jumper wires. Every one is in the editor's parts bin.

How it is wired

4 connections, pin by pin, read from the circuit itself. Each line is one set of pins joined together, by a jumper wire or a breadboard strip.

  • ESP32-C3-DevKitM-1 pin 3V3; OLED display, 128x64 pin VCC
  • Ground: ESP32-C3-DevKitM-1 pin GND; OLED display, 128x64 pin GND
  • ESP32-C3-DevKitM-1 pin 4; OLED display, 128x64 pin SDA
  • ESP32-C3-DevKitM-1 pin 5; OLED display, 128x64 pin SCL

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.