ESP32 Built-in OLED Board (Wemos Lolin32): Pinout, Libraries and OLED Control

The Wemos Lolin32 OLED is an ESP32 development board with built-in OLED display. In this guide, we’ll take a quick look at the board, its pinout, and how to control the OLED display with Arduino IDE or MicroPython.

Wemos LoLin32 ESP32 SSD1306 OLED: Pinout, Libraries and OLED Control (Arduino IDE and MicroPython)

Wemos Lolin32 ESP32 OLED Overview

The WeMos Lolin32 OLED is a development board with ESP32 and built-in 0.96 inch 128×64 I2C OLED display.

WeMos Lolin32 ESP32 built-in OLED Display SSD1306

As a regular ESP32 board, it features a BOOT and a EN (RST) button. Some models have the buttons at the back, some have both at the front, and others have one at the front and other at the back. However, all boards should work in a similar way.

WeMos Lolin32 ESP32 built-in OLED Display SSD1306 BOOT button and RESET Enable button

Where to buy?

You can go to the WeMos Lolin32 ESP32 OLED page on Maker Advisor to find the best price at different stores.

Lolin32 OLED Pinout

The Lolin32 OLED board doesn’t have as much accessible GPIOs as a regular ESP32. However, it can be really handy in projects that require an OLED display, without the need for extra circuitry.

The following figure shows the Lolin32 ESP32 OLED board pinout.

Pinout GPIOs pins WeMos Lolin32 ESP32 built-in OLED Display SSD1306
Picture adapted from (view source)

The OLED display communicates with the ESP32 using I2C communication protocol. It uses the following pins for SDA/SCL:

SDAGPIO 5
SCLGPIO 4

Recommended reading: ESP32 Pinout Reference Guide

Control the OLED with Arduino IDE

To control the board using Arduino IDE, you need the ESP32 add-on installed. You can follow the next guide:

OLED libraries for Arduino IDE

There are several libraries available to control the OLED display with the ESP32. In this tutorial we’ll use two Adafruit libraries: Adafruit_SSD1306 library and Adafruit_GFX library.

Follow the next steps to install those libraries.

1. Open your Arduino IDE and go to Sketch Include Library > Manage Libraries. The Library Manager should open.

2. Type “SSD1306” in the search box and install the SSD1306 library from Adafruit.

Installing the Adafruit SSD1306 library for OLED display Arduino IDE

3. After installing the SSD1306 library from Adafruit, type “GFX” in the search box and install the library.

Installing GFX Library for ESP32 Arduino IDE

4. After installing the libraries, restart your Arduino IDE.

Control the OLED

The Adafruit libraries use GPIO 22 and GPIO 21 as default I2C pins, but you can change the pins just by adding two lines of code.

In the setup(), you need to start an I2C communication using GPIO 5 and GPIO 4. So, you need to add the following line:

Wire.begin(5, 4);

After that, initialize the display with the following parameters:

if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C, false, false)) { 

The parameters set as false ensure that the library doesn’t use the default I2C pins and use the pins defined in the code (GPIO 5 and GPIO 4).

If you add these two lines of code, you can use any examples that use these libraries to control this OLED display.

To test your OLED display, you can copy the following code to your Arduino IDE.

/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com  
*********/

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

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

static const uint8_t image_data_Saraarray[1024] = {
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x14, 0x9e, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x36, 0x3f, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x6d, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xfb, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x03, 0xd7, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x07, 0xef, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xdf, 0xff, 0x90, 0x07, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xbf, 0xff, 0xd0, 0x07, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x1d, 0x7f, 0xff, 0xd0, 0x07, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x01, 0x1b, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x02, 0xa7, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xff, 0x80, 0x00, 0x0b, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0x07, 0xff, 0xf8, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0e, 0x01, 0xff, 0xc0, 0x38, 0x07, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1c, 0x46, 0xff, 0xb1, 0x18, 0x07, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0x97, 0xff, 0xc0, 0x7a, 0x07, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0x3f, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xbf, 0xff, 0xff, 0xff, 0xfe, 0x81, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xbf, 0xff, 0xff, 0xff, 0xfc, 0x81, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0xfe, 0xff, 0xfd, 0x83, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xbf, 0xff, 0xfe, 0xff, 0xfd, 0x01, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xfb, 0x03, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xdc, 0xff, 0xfa, 0x03, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xd8, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xd0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0x90, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x02, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xb0, 0x00, 0x0f, 0xf5, 0xff, 0xd7, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xb0, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x5f, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xa0, 0x00, 0x0f, 0xfb, 0xff, 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x0f, 0xfd, 0xff, 0xdf, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x07, 0xff, 0xff, 0xbf, 0xf0, 0x00, 0x0f, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x07, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x87, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x43, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0x60, 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x73, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xfe, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0x80, 0x00, 0x7b, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xfd, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x00, 0x33, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xfd, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0xf8, 0x00, 0x00, 0x27, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0x60, 0x00, 0x00, 0x67, 0xff, 0xe0, 0x00, 0x00, 0x1b, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xfd, 0x40, 0x00, 0x00, 0xf3, 0xff, 0xc4, 0x00, 0x00, 0x0b, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xfe, 0x80, 0x00, 0x00, 0xfc, 0xff, 0x8c, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x7f, 0x3c, 0x3c, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x3f, 0xc0, 0x7c, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 
    0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfc, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff
};
 
void setup() {
  Serial.begin(115200);
  
  // Start I2C Communication SDA = 5 and SCL = 4 on Wemos Lolin32 ESP32 with built-in SSD1306 OLED
  Wire.begin(5, 4);

  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C, false, false)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  delay(2000); // Pause for 2 seconds
 
  // Clear the buffer.
  display.clearDisplay();
  
  // Draw bitmap on the screen
  display.drawBitmap(0, 0, image_data_Saraarray, 128, 64, 1);
  display.display();
}
 
void loop() {
  
}

View raw code

For a more in-depth guide on how to use the OLED display, you can follow the next tutorial:

All the examples provided in the tutorial are compatible with this display as long as you add the lines of code we’ve referred previously to set the proper I2C pins.

Uploading the Code

To upload the code to the Lolin32 OLED board, plug it into your computer. In your Arduino IDE, go to Tools > Port and select the COM port it is connected to.

Then, go to Tools > Board and select WEMOS LOLIN32.

Upload Code WeMos Lolin32 ESP32 OLED in Arduino IDE

Demonstration

After uploading the code, you should get a face displayed on your display.

Wemos Lolin32 ESP32 OLED Control with Arduino IDE

Control the OLED with MicroPython

In this section, we’ll show you how to control the OLED with MicroPython. If you’re not familiar with MicroPython, you can get started with our guide:

OLED library for MicroPython

To control the OLED display with MicroPython, we use the ssd1306 library by Adafruit. The code for the library we’re using can be found here, save it to your ESP with the name ssd1306.py:

#MicroPython SSD1306 OLED driver, I2C and SPI interfaces created by Adafruit

import time
import framebuf

# register definitions
SET_CONTRAST        = const(0x81)
SET_ENTIRE_ON       = const(0xa4)
SET_NORM_INV        = const(0xa6)
SET_DISP            = const(0xae)
SET_MEM_ADDR        = const(0x20)
SET_COL_ADDR        = const(0x21)
SET_PAGE_ADDR       = const(0x22)
SET_DISP_START_LINE = const(0x40)
SET_SEG_REMAP       = const(0xa0)
SET_MUX_RATIO       = const(0xa8)
SET_COM_OUT_DIR     = const(0xc0)
SET_DISP_OFFSET     = const(0xd3)
SET_COM_PIN_CFG     = const(0xda)
SET_DISP_CLK_DIV    = const(0xd5)
SET_PRECHARGE       = const(0xd9)
SET_VCOM_DESEL      = const(0xdb)
SET_CHARGE_PUMP     = const(0x8d)


class SSD1306:
    def __init__(self, width, height, external_vcc):
        self.width = width
        self.height = height
        self.external_vcc = external_vcc
        self.pages = self.height // 8
        # Note the subclass must initialize self.framebuf to a framebuffer.
        # This is necessary because the underlying data buffer is different
        # between I2C and SPI implementations (I2C needs an extra byte).
        self.poweron()
        self.init_display()

    def init_display(self):
        for cmd in (
            SET_DISP | 0x00, # off
            # address setting
            SET_MEM_ADDR, 0x00, # horizontal
            # resolution and layout
            SET_DISP_START_LINE | 0x00,
            SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
            SET_MUX_RATIO, self.height - 1,
            SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
            SET_DISP_OFFSET, 0x00,
            SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12,
            # timing and driving scheme
            SET_DISP_CLK_DIV, 0x80,
            SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,
            SET_VCOM_DESEL, 0x30, # 0.83*Vcc
            # display
            SET_CONTRAST, 0xff, # maximum
            SET_ENTIRE_ON, # output follows RAM contents
            SET_NORM_INV, # not inverted
            # charge pump
            SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,
            SET_DISP | 0x01): # on
            self.write_cmd(cmd)
        self.fill(0)
        self.show()

    def poweroff(self):
        self.write_cmd(SET_DISP | 0x00)

    def contrast(self, contrast):
        self.write_cmd(SET_CONTRAST)
        self.write_cmd(contrast)

    def invert(self, invert):
        self.write_cmd(SET_NORM_INV | (invert & 1))

    def show(self):
        x0 = 0
        x1 = self.width - 1
        if self.width == 64:
            # displays with width of 64 pixels are shifted by 32
            x0 += 32
            x1 += 32
        self.write_cmd(SET_COL_ADDR)
        self.write_cmd(x0)
        self.write_cmd(x1)
        self.write_cmd(SET_PAGE_ADDR)
        self.write_cmd(0)
        self.write_cmd(self.pages - 1)
        self.write_framebuf()

    def fill(self, col):
        self.framebuf.fill(col)

    def pixel(self, x, y, col):
        self.framebuf.pixel(x, y, col)

    def scroll(self, dx, dy):
        self.framebuf.scroll(dx, dy)

    def text(self, string, x, y, col=1):
        self.framebuf.text(string, x, y, col)


class SSD1306_I2C(SSD1306):
    def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False):
        self.i2c = i2c
        self.addr = addr
        self.temp = bytearray(2)
        # Add an extra byte to the data buffer to hold an I2C data/command byte
        # to use hardware-compatible I2C transactions.  A memoryview of the
        # buffer is used to mask this byte from the framebuffer operations
        # (without a major memory hit as memoryview doesn't copy to a separate
        # buffer).
        self.buffer = bytearray(((height // 8) * width) + 1)
        self.buffer[0] = 0x40  # Set first byte of data buffer to Co=0, D/C=1
        self.framebuf = framebuf.FrameBuffer1(memoryview(self.buffer)[1:], width, height)
        super().__init__(width, height, external_vcc)

    def write_cmd(self, cmd):
        self.temp[0] = 0x80 # Co=1, D/C#=0
        self.temp[1] = cmd
        self.i2c.writeto(self.addr, self.temp)

    def write_framebuf(self):
        # Blast out the frame buffer using a single I2C transaction to support
        # hardware I2C interfaces.
        self.i2c.writeto(self.addr, self.buffer)

    def poweron(self):
        pass


class SSD1306_SPI(SSD1306):
    def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
        self.rate = 10 * 1024 * 1024
        dc.init(dc.OUT, value=0)
        res.init(res.OUT, value=0)
        cs.init(cs.OUT, value=1)
        self.spi = spi
        self.dc = dc
        self.res = res
        self.cs = cs
        self.buffer = bytearray((height // 8) * width)
        self.framebuf = framebuf.FrameBuffer1(self.buffer, width, height)
        super().__init__(width, height, external_vcc)

    def write_cmd(self, cmd):
        self.spi.init(baudrate=self.rate, polarity=0, phase=0)
        self.cs.high()
        self.dc.low()
        self.cs.low()
        self.spi.write(bytearray([cmd]))
        self.cs.high()

    def write_framebuf(self):
        self.spi.init(baudrate=self.rate, polarity=0, phase=0)
        self.cs.high()
        self.dc.high()
        self.cs.low()
        self.spi.write(self.buffer)
        self.cs.high()

    def poweron(self):
        self.res.high()
        time.sleep_ms(1)
        self.res.low()
        time.sleep_ms(10)
        self.res.high()

View raw code

Upload the library to your board. If you don’t know how to upload the library, you can follow our in-depth OLED tutorial with MicroPython.

MicroPython Script – Control OLED

After uploading the library to the ESP32, copy the following code to the boot.py file. It simply prints the ‘Hello, World!‘ message three times in the display.

# Complete project details at https://RandomNerdTutorials.com

from machine import Pin, SoftI2C
import ssd1306
from time import sleep

# Start I2C Communication SCL = 4 and SDA = 5 on Wemos Lolin32 ESP32 with built-in SSD1306 OLED
i2c = SoftI2C(scl=Pin(4), sda=Pin(5))

oled_width = 128
oled_height = 64
oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)

oled.text('Hello, World 1!', 0, 0)
oled.text('Hello, World 2!', 0, 10)
oled.text('Hello, World 3!', 0, 20)
        
oled.show()

View raw code

In our examples with MicroPython, we usually use the default ESP32 I2C pins (GPIO 21 and GPIO 22). However, the Wemos Lolin32 OLED board uses GPIO 4 and GPIO 5. So, we need to set up that in the script.

To define your OLED display I2C pins, pass the SCL and SDA pins as follows:

i2c = SoftI2C(scl=Pin(4), sda=Pin(5))

For an explanation on how to write text and display shapes on the OLED display with MicroPython, refer to the next tutorial:

All the examples are compatible with this board as long as you set the right I2C pins in your scripts.

Demonstration

After restarting the board and running the uploaded script, you should get something similar in your display:

Wemos Lolin32 ESP32 OLED Control with MicroPython

Wrapping Up

We hope you’ve found this guide with the Wemos Lolin32 OLED board useful. Controlling the ESP32 built-in OLED display is the same as controlling a standalone 0.96 inch I2C OLED – you just need to assign the right I2C pins in your code.

Learn how to write text, set different fonts, draw shapes and display bitmaps images with the OLED display:

Thanks for reading.



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Enjoyed this project? Stay updated by subscribing our newsletter!

35 thoughts on “ESP32 Built-in OLED Board (Wemos Lolin32): Pinout, Libraries and OLED Control”

  1. Hi Rui,
    I tried this project on my new ESP32 OLED using the MicroPython example – the one with 3 lines of text, and it worked fine. Next, I tried to use Arduino IDE to down load some example and it did not recognized the board. Yes, I installed the libraries for the Wemos Lolin32 OLED board as you suggested but it keeps timing out during the download. Is it because I used MicroPython first? I tried it on a fresh second board and got the same. Do I have to get rid of the MicroPython first? Any ideas? Thanks.
    Jacob

    Reply
    • Hi Jacob.
      What is the exact error that you’re getting when trying to download?
      You may need to press the BOOT button when you start seeing the dots ….___….___…. on your Serial Monitor.
      Regards,
      Sara

      Reply
  2. Thanks ! Very useful !

    Wire.begin(5, 4);
    if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C, false, false)) {

    And all the ssd1306_demos work !

    Regards
    Christophe

    Reply
  3. Great! Thank you! However, how can aI create another array image?
    Another things, there is any special mode of GPIO15 pin? I can’t use it.
    Regards.

    Reply
  4. I know I can be very stupid at times but I only want to write text to the display! All I seem to get is “fail to compile for board” errors. Is it possible to do a “baby steps” explanation of the fundamentals? The opening file on the board was no help as I cannot find a version outside the board.

    Reply
  5. Great project. thank you for posting it. I did the Arduino IDE method. I have not done the MicroPython yet. How did you take a picture and convert it to the code needed to display on this ESP32 OLED?

    Reply
  6. Hi,
    I spent 3 or 4 hours trying to get my Wemos Lolin32 OLED to work with the Adafruit SSD1306 library and Example sketch. Then I found this article and had it working in 10 minutes. Thank you so much!
    Regards,
    Amy

    Reply
  7. Hi,
    Thanks so much for this, it was very hard to find any information on forcing pin assignments when using the Adafruit library, “,false ,false” was all I was looking for 😉
    I needed it for the ESP32 Wroom Oled 18650 board.
    Keep up the great work.

    Reply
  8. Thanks for all your work.
    Much to my surprise I got it to work before I found this article!
    Does this particular board have a LED_BUILTIN?
    According to Wemos the non-OLED version D32 of this board has one on gpio5.

    Reply
  9. Do you know where to find the electrical schematic of the Wemos Lolin32 OLED module?
    I have made a PCB with 5V dc supply from a LiIon battery 2C (7.4V), giving about 5.4Vdc, but once connected there is a boot problem.
    On a USB supply it works.
    Any idea?

    Reply
      • Hi,
        I managed it somehow on teh hardware side.
        The problem I have now is to read the analog voltage and display it on the WebServer example of Rui Santos.
        The code is:
        const uint8_t ldr_in = A11;
        LDR_Value = analogRead(ldr_in);
        display.println(“LDR = “);
        display.setCursor(40, 22);
        display.print(LDR_Value);
        and read allways zero, even if I measure the voltage 0.9V.
        Is the analogRead function without any declaration functional?

        Reply
  10. Thanks and congrats for the projets. It’s working.
    I have 2 questions:
    1) Why we should add some codes in boot.py instead in main.py?
    2) Is there a function to clean the screen before print again? I’m using to show a specific stock price, but when the price changes some number shows confuse in display. Like they were overwritten.

    Reply
  11. Helpful instruction, indeed. I got my OLED to work following this tutorial. However, I could not find a proper documentation of this particular board as it might be a clone. Can you help me with finding the exact pinout diagram of this device?

    Reply
  12. Hi Sara,
    thanks to your tutorial I was able to have an image displayed on the OLED screen but if I try to display a timestamp from a RTC or temp and humidity data from BME280 and SHT3X sensors ( all connected to the same pins 4 and 5 of the OLED screen ) I have no response and I2C scanner test says that no I2C device are found.
    So which are the pins to be used for I2C ?
    Thanks for yor help
    Bruno

    Reply
  13. Hi Sara,
    following your suggestion I carefully read the tutorial
    https://randomnerdtutorials.com/esp32-i2c-communication-arduino-ide/
    However, I was not able to solve my problem (I’m old for age but a newbie for ESP)
    I understand that the Wemos Lolin32 uses by default the pins 5 and 4 for SDA and SCL to connect the OLED and, if I use the Adafruit library, I have to insert the code line you indicated to override the pins 21 and 22. However when I did this I still have the problem of connect two other I2C devices ( a BME280 and a RTC clock). If I try to use the same pins (5 and 4) nothing happens and I2C scanner says no I2C device found. If I define, following your suggestion, other pins for SDA and SCL for BME 280 modifying the Adafruit library, on the serial monitor < see the correct values from. the sensor but I am not able to see them on the display. I’ve also tried the library “SSD1306Wire.h” but the negative result was the same.
    In conclusion, after having defined pins for OLED display as 5 and 4, how can I define other SDA and SCL pins to connect I2C sensors and RTC clock ? I’ve also tried to use Wire and Wire1 ( even if the devices have different addresses) but with no success.
    I was not able to find a single example of this on the web and in an Arduino forum discussion a forumer with High Karma says that according to Espressif port B cannot be used in ESP32 for I2C.
    I’m just asking for a solution to this very usual problem that in my poor hands is still unsolved and in this case I2C scanner seems not properly working.
    Thx, as usual, for your help
    Bruno
    PS If I use a “usual”ESP32 or ESP8266 with a separated OLED I2C screen I have no problem.
    One more question: which are the pins that can be used for this variant of ESP32(WemosLolin32 with OLED) if I have to connect a SPI SD card module ? I was not able to find any info on this important issue

    Reply
  14. Hi Sara,
    sorry for bothering you again for the same problem but it’s still unsolved. In fact, if I use your suggestion to define for I2C the pins 4 & 5 and the line of code to override the default pins of the Adafruit library I’m able to show your image on the oled but I was not able to show any other info
    The problem is that I need to show on the screen the data from a BME280 and from a SHT3X but for the BME280 if I follow the suggestion of your I2C tutorial I’m able to get data on the serial monitor BUT nothing on the display ( and I was not able to get any data even in the serial monitor from the SHT3X)
    Probably I’m very dumb but you have to forgive me since I’m old (73) and I have probably not understood your suggestion.
    Could you explain me with a practical example how to wire a BME280 to this board and which code to use to show data from the sensors on the OLED ?
    By the way, after an extensive googling and asking Arduino forum I didn’t find any useful answer and at the present I’m still stuck as I was one month ago.
    Thanks for your help
    Best regards

    Reply
  15. Hi Sara,
    just to let you know that, thanks to your tutorial on uPy I was able to use this undocumented board as a datalogger of data from a BME280and with an OLED 1306ssd. I found on a forum discussion in French a hint on the SPI pins that have to be used
    sck=machine.Pin(25),
    mosi=machine.Pin(14),
    miso=machine.Pin(13))
    whilecs is Pin 15.
    Hope this could save time to other people
    Best

    Reply

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.