OLED Animation Maker OLED Maker

ESP32-C3 0.42 OLED board: pinout, U8g2 code and 72x40 fixes

ESP32-C3 0.42 OLED board with a tiny 72x40 screen showing text

The ESP32-C3 0.42 OLED board is a thumb-sized ESP32-C3 with a tiny screen already soldered on. It is cheap and popular, but almost everyone gets a blank or shifted screen on the first try. The reason is simple. The screen sits on unusual pins and needs a special 72x40 driver. This guide gives you the pinout, the exact Arduino IDE settings, a complete test sketch and fixes for every common problem.

Quick answer. The built-in OLED is an SSD1306 at I2C address 0x3C on GPIO 5 (SDA) and GPIO 6 (SCL). It shows 72 by 40 pixels. Install the U8g2 library and use the constructor U8G2_SSD1306_72X40_ER_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, 6, 5);. This driver already adds the 28 pixel column offset, so text lands in the right place.

What the ESP32-C3 0.42 OLED board is

The board is a small ESP32-C3 module with a USB-C port, a BOOT button, a RESET button and a 0.42 inch OLED on top. Sellers list it under names like "ESP32-C3 OLED development board" or "ESP32-C3 SuperMini with 0.42 inch OLED". It usually costs well under $10 on Amazon US or AliExpress.

The ESP32-C3 chip has a single RISC-V core at up to 160 MHz, WiFi and Bluetooth Low Energy. It runs Arduino code just like a bigger ESP32. The screen is driven by an SSD1306 controller, the same chip used on the common 0.96 inch modules. The difference is the glass. The controller has memory for 128 by 64 pixels, but this panel only shows a 72 by 40 window from the middle of that memory.

That window is the whole story. If your code draws at x = 0, the pixels go into memory the glass cannot show. So you see nothing, or half a word.

ESP32-C3 0.42 OLED pinout

These are the pins that matter for the screen and the buttons. Generic ESP32-C3 examples often use GPIO 8 and 9 for I2C. Do not copy them for this board.

FunctionPinNotes
OLED SDA (data)GPIO 5Wired on the board. Share it with other I2C parts.
OLED SCL (clock)GPIO 6Wired on the board.
OLED I2C address0x3CU8g2 wants the 8-bit form: 0x3C << 1 = 0x78.
Visible area72 × 40 pixelsStarts at column 28 of the 128 column memory.
BOOT buttonGPIO 9Reads LOW when pressed. Also a strapping pin.
PowerUSB-C 5 VLogic is 3.3 V. Never feed 5 V into a GPIO.

A strapping pin is a pin the chip reads at power-up to decide how to start. GPIO 9 is one of them. Holding BOOT while you power up or press RESET puts the chip into download mode. Reading the button later, inside your sketch, is completely safe.

If you already own a separate 0.96 inch OLED, you do not need any wiring for this board. The screen is already connected. For an ESP32-C3 SuperMini without a built-in screen, the ESP32 desk robot with OLED eyes shows how to wire an external SSD1306 to GPIO 8 and 9 instead.

Arduino IDE setup for the ESP32-C3

  1. Open Tools → Board → Boards Manager, search for esp32 and install esp32 by Espressif Systems.
  2. Pick Tools → Board → esp32 → ESP32C3 Dev Module.
  3. Set USB CDC On Boot to Enabled. Without it, the Serial Monitor stays empty.
  4. Open Sketch → Include Library → Manage Libraries, search for U8g2 and install the one by oliver.
  5. Plug the board in with a USB-C data cable and pick its port under Tools → Port.

Some cheap cables only carry power. If no new port appears, try another cable before you blame the board. The Espressif Arduino-ESP32 documentation explains every option in the Tools menu if you want the details.

Why U8g2 works and Adafruit SSD1306 struggles

U8g2 is a display library with a separate driver for almost every OLED panel. It has a driver written for this exact 0.42 inch glass. I checked the driver source, u8x8_d_ssd1306_72x40.c, in the U8g2 repository on GitHub. It sets a default x offset of 28, a width of 72 and a height of 40. It also sets the multiplex ratio to 40 rows and turns on an internal current setting that the 0.42 inch panel needs.

The Adafruit SSD1306 library has no offset setting. If you create it as 72 by 40, it writes your image to columns 0 to 71. The glass only shows columns 28 to 99, so the left part of your picture is lost and junk appears on the right. You can work around it with a 128 by 64 buffer and by adding 28 to every x value. That works, but it is fiddly, so U8g2 is the better tool for this board.

If you are new to U8g2, the U8g2 tutorial for SSD1306 and SH1106 explains fonts, the full buffer mode and drawing functions in more depth. The U8g2 vs Adafruit SSD1306 comparison covers speed and memory.

The constructor, line by line

The constructor is the line that creates the display object. Here is the one for this board.

U8G2_SSD1306_72X40_ER_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, 6, 5);
  • SSD1306_72X40_ER picks the 0.42 inch driver with the built-in offset.
  • F means full buffer. The whole 360 byte frame lives in RAM, which the ESP32-C3 has plenty of.
  • HW_I2C means hardware I2C through the Wire library.
  • U8G2_R0 is no rotation. Use U8G2_R2 to turn the picture upside down.
  • U8X8_PIN_NONE means there is no reset pin.
  • 6, 5 are the clock (SCL) and data (SDA) pins. The order is clock first, then data.

On ESP32 boards, U8g2 passes those two pins to Wire.begin() for you. So you do not need your own Wire.begin(5, 6) line.

Complete ESP32-C3 0.42 OLED test sketch

This sketch draws a border, shows the board name and an uptime counter, and switches to a bouncing ball when you press BOOT. The border is the best first test. If you can see all four edges, the offset and size are correct.

// ESP32-C3 0.42" OLED board (72x40 SSD1306): first test sketch
// Board: ESP32C3 Dev Module, USB CDC On Boot: Enabled. Library: U8g2
#include <Arduino.h>
#include <U8g2lib.h>

#define SDA_PIN  5     // OLED data pin on this board
#define SCL_PIN  6     // OLED clock pin on this board
#define BTN_PIN  9     // BOOT button, LOW when pressed
#define OLED_ADDR 0x3C // 7-bit address of the built-in screen

// 72x40 driver with the 28 pixel offset built in. Pins: reset, clock, data
U8G2_SSD1306_72X40_ER_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, SCL_PIN, SDA_PIN);

uint8_t page = 0;         // 0 = info page, 1 = bouncing ball
bool lastBtn = HIGH;
int ballX = 20, ballY = 15;
int dx = 2, dy = 1;
const int R = 3;          // ball radius in pixels

void setup() {
  Serial.begin(115200);
  pinMode(BTN_PIN, INPUT_PULLUP);
  u8g2.setI2CAddress(OLED_ADDR << 1);  // U8g2 wants the 8-bit form, before begin()
  u8g2.begin();
  u8g2.setContrast(200);               // 0 to 255, lower it to save power
  Serial.println("OLED started");
}

void drawInfo() {
  char buf[16];
  u8g2.setFont(u8g2_font_6x10_tf);     // 6 px wide, so 11 characters fit
  u8g2.drawStr(3, 12, "ESP32-C3");
  u8g2.drawStr(3, 24, "72x40 OK");
  snprintf(buf, sizeof(buf), "up %lus", millis() / 1000);
  u8g2.drawStr(3, 36, buf);
}

void drawBall() {
  ballX += dx;
  ballY += dy;
  if (ballX <= R + 1 || ballX >= 70 - R) dx = -dx;  // bounce off the left and right border
  if (ballY <= R + 1 || ballY >= 38 - R) dy = -dy;  // bounce off the top and bottom border
  u8g2.drawDisc(ballX, ballY, R);
}

void loop() {
  bool btn = digitalRead(BTN_PIN);
  if (lastBtn == HIGH && btn == LOW) {  // button just pressed
    page = (page + 1) % 2;
    Serial.print("Page ");
    Serial.println(page);
  }
  lastBtn = btn;

  u8g2.clearBuffer();              // start a fresh frame in RAM
  u8g2.drawFrame(0, 0, 72, 40);    // border around the visible area
  if (page == 0) drawInfo();
  else drawBall();
  u8g2.sendBuffer();               // send the frame to the screen
  delay(30);                       // about 30 frames per second
}

What you should see: a thin white border on all four edges, "ESP32-C3" and "72x40 OK" on two lines, and a counter that goes up once a second. Press BOOT and a small ball bounces inside the border. Press it again to go back. The Serial Monitor at 115200 baud prints "OLED started" and the page number.

The only lines you may need to change are the four #define lines at the top. On almost every board of this type, the values shown are correct.

ESP32-C3 OLED troubleshooting

These are the problems people report most often with this board. Each one shows what you see, why it happens and how to fix it.

The screen stays black

Why: the sketch uses GPIO 8 and 9, or the default Wire.begin() pins, and neither is connected to the screen. Fix: use 6 and 5 in the constructor, as above. If it is still black, run an I2C scanner with Wire.begin(5, 6). It should report a device at 0x3C. If nothing answers, the board may use other pins, so check the seller's photo of the board's back.

Text is shifted, cut off or mixed with noise

Why: you used a 128x64 driver, or the Adafruit library set to 72 by 40. Neither adds the 28 column offset. Fix: switch to U8G2_SSD1306_72X40_ER_F_HW_I2C. Our general SSD1306 OLED blank screen fix covers the other causes, such as a wrong address or a bad cable.

The picture is upside down

Why: the screen is mounted the other way on some versions. Fix: change U8G2_R0 to U8G2_R2. U8g2 keeps the offset correct after the flip.

The Serial Monitor shows nothing

Why: the ESP32-C3 talks over its own USB port, not a USB-to-serial chip. Fix: set USB CDC On Boot to Enabled, upload again and reopen the Serial Monitor at 115200 baud.

Upload fails or the port disappears

Why: a sketch that crashes early can stop the USB port from starting. Fix: hold BOOT, tap RESET, then let go of BOOT. The chip now waits in download mode, so upload again. Press RESET once the upload finishes.

WiFi is weak or drops out

Why: the tiny ceramic antenna on many of these clone boards performs poorly. Fix: keep fingers, metal and USB cables away from the antenna end. Some makers also report better results after calling WiFi.setTxPower(WIFI_POWER_8_5dBm) right after WiFi.begin(). Test it on your own board, since results vary.

Using the Adafruit library anyway

Maybe you have a project already written with Adafruit GFX and do not want to port it. You can still use it. Create the display as 128 by 64, call Wire.begin(5, 6) before display.begin(), and add 28 to every x position. The vertical position also changes in 128 by 64 mode, and makers report different values for different batches.

The easy way to find your vertical offset is a test. Draw a 72 by 40 rectangle at x = 28, then move it down a few pixels at a time until all four edges show. Then remember to call display.display() after every drawing, or nothing changes on the glass. In my opinion it is less work to switch the project to U8g2.

Animations and pictures on a 72x40 OLED

A full 72 by 40 frame is only 360 bytes. That is about a third of a 128 by 64 frame. The ESP32-C3 has 4 MB of flash on most of these boards, so it can store hundreds of frames.

The free OLED Animation Maker has a 0.42 inch 72×40 display option. Follow these steps:

  1. Set Display to 0.42" 72×40 before you pick or draw anything.
  2. Set Board to ESP32-C3 Mini and the library to U8g2.
  3. Pick a template, draw your own frames, or import a GIF.
  4. Click Get the Code and paste the sketch into the Arduino IDE.
  5. The generated sketch uses the ESP32-C3 Mini default pins, 8 and 9. Change every 8 to 5 and every 9 to 6 in the pin lines, including the constructor.

For a single logo or icon, the Image to Byte Array tool has a 72x40 size. Draw the result with u8g2.drawXBMP(0, 0, 72, 40, myImage). Keep pictures bold and simple. Thin lines and small text vanish at this size. The ESP32 OLED animation guide explains how frame arrays and timing work in more detail.

Power and battery tips

The board is small enough for a keychain or a badge, so battery life matters. An OLED only uses power for lit pixels. A mostly black screen with small text uses much less than a full white one. Lower the contrast with u8g2.setContrast() and turn the screen off with u8g2.setPowerSave(1) when nobody is looking.

WiFi uses far more current than the screen does. Turn it off when you do not need it. The OLED power consumption and battery life guide has measured numbers and the deep sleep approach.

Next steps: project ideas for this board

  • Tiny WiFi clock: get the time from an NTP server and show hours and minutes in a large font.
  • Mini robot eyes: two rounded rectangles that blink. Scale down the Arduino OLED robot eyes code to fit 72 by 40.
  • Name badge: a scrolling name on a lanyard, powered by a small USB power bank.
  • Sensor readout: add a temperature sensor on GPIO 5 and 6 and show the reading in big digits.
  • 3D printed case: design a small box with a window for the screen and a hole over BOOT, so the button still works.

Frequently asked questions

Which pins does the ESP32-C3 0.42 OLED use?

The built-in screen is wired to GPIO 5 (SDA) and GPIO 6 (SCL) at I2C address 0x3C. Some listings say GPIO 8 and 9, but on these boards the screen answers on 5 and 6.

Can I use the Adafruit SSD1306 library with the 0.42 inch OLED?

It can work, but Adafruit SSD1306 has no setting for the 28 pixel column offset of this panel, so you must use a 128x64 buffer and move every drawing yourself. U8g2 has a ready-made 72x40 driver and is the easier choice.

Why is my 0.42 OLED picture shifted or cut off?

The controller has 128 columns of memory but the glass only shows 72 of them, starting at column 28. A 128x64 or plain 72x40 driver without that offset draws in the wrong place. Use U8G2_SSD1306_72X40_ER_F_HW_I2C.

Can I connect other I2C sensors to the ESP32-C3 OLED board?

Yes, if the sensor has a different address from 0x3C. Wire its SDA to GPIO 5 and SCL to GPIO 6 and it shares the bus with the screen.

Can I play animations on a 72x40 OLED?

Yes. One full 72x40 frame is only 360 bytes, so the ESP32-C3 can hold hundreds of frames. Make the frames at 72x40, not 128x64, and draw them with drawXBMP.

Related guides

Free tools: the OLED Animation Maker for frame animations and name effects, the OLED Robot Eyes Generator for animated eyes with moods. Try Image to Byte Array for logos and icons, and Text to STL for name plates and keychains. See all tools.