Skip to content

How to use a 2.42 inch OLED with MicroPython?

By admin Kushnaryov Editorial

To use a 2.42 inch OLED with MicroPython, you need to connect it via SPI or I2C, install the appropriate driver library, and write code to initialize the display and send pixel data. The specific model we’re focusing on is the 2.42 inch 128x64 oled display, which is a monochrome (white or blue) OLED with a resolution of 128x64 pixels, driven by the SSD1309 controller (or sometimes SH1106, but for this size, SSD1309 is more common). This display uses SPI by default, but some variants support I2C. I’ll give you the hard facts: the pinout, power requirements, wiring, library installation, and code examples with real-world data. No fluff, just what you need to get it working.

Hardware Specifications and Pinout

The 2.42 inch OLED display typically operates at 3.3V logic level, but the power supply can be 3.3V to 5V (the onboard regulator handles it). The current draw is around 20-30 mA when all pixels are on, and about 10-15 mA for typical usage. The SPI interface uses 7 pins: GND, VCC (3.3-5V), D0 (SCLK), D1 (MOSI), RES (reset), DC (data/command), and CS (chip select). Some modules also have a BS0/BS1 pin for selecting interface mode—if you’re using SPI, set BS0 to 0 and BS1 to 1 (check your module’s datasheet). The display resolution is 128x64, which means 8192 pixels total. In monochrome mode, each pixel is 1 bit, so the frame buffer is 1024 bytes (128 * 64 / 8).

Here’s a table of the pin connections for a typical ESP32 or Raspberry Pi Pico (both common with MicroPython):

OLED PinESP32 PinRaspberry Pi Pico Pin
GNDGNDGND
VCC3.3V or 5V3.3V or 5V
D0 (SCLK)GPIO 18 (SPI2 SCK)GPIO 2 (SPI0 SCK)
D1 (MOSI)GPIO 23 (SPI2 MOSI)GPIO 3 (SPI0 MOSI)
RESGPIO 16GPIO 4
DCGPIO 17GPIO 5
CSGPIO 5GPIO 6

Note: The ESP32 uses SPI2 by default in MicroPython, but you can use VSPI or HSPI. The Pico uses SPI0. You can change these pins as long as you configure the SPI hardware correctly. The display’s SPI clock frequency can go up to 10 MHz, but for stability, start with 1-4 MHz. The frame rate at 4 MHz is about 30-40 fps for full-screen updates, which is smooth for most applications.

MicroPython Library Installation

MicroPython doesn’t have a built-in driver for the SSD1309 or SH1106, but you can use the micropython-ssd1306 library, which supports SSD1306, SSD1309, and SH1106 controllers. The library is available on GitHub and can be installed via upip or by copying the file directly to your board. For the 2.42 inch 128x64 oled display, the SSD1309 driver works well, but you need to specify the correct dimensions and I2C/SPI interface. If your display uses SH1106 (common in some 2.42 inch variants), the library still works, but you’ll need to adjust the initialization sequence. The library is about 4-5 KB in size, so it fits easily on any MicroPython board with at least 256 KB flash.

To install via upip on an ESP32 or Pico with internet access, run this in the MicroPython REPL:

import upip
upip.install('micropython-ssd1306')

If you don’t have internet, download the ssd1306.py file from the official repository and copy it to the board’s root directory using ampy or Thonny. The file size is 4.2 KB. After installation, you can import it with from ssd1306 import SSD1306_SPI.

Wiring and Initialization Code

Let’s wire up the display. Connect the pins as per the table above. For the ESP32, I’ll use SPI2 (pins 18, 23, 5, 16, 17). Here’s the initialization code:

from machine import Pin, SPI
import ssd1306

spi = SPI(2, baudrate=4000000, polarity=0, phase=0, sck=Pin(18), mosi=Pin(23))
dc = Pin(17, Pin.OUT)
res = Pin(16, Pin.OUT)
cs = Pin(5, Pin.OUT)

# Reset the display
res.value(0)
import time
time.sleep_ms(10)
res.value(1)
time.sleep_ms(10)

oled = ssd1306.SSD1306_SPI(128, 64, spi, dc, res, cs)
oled.init_display()
oled.fill(0)
oled.show()

For the Raspberry Pi Pico, use SPI0 (pins 2, 3, 6, 4, 5):

spi = SPI(0, baudrate=4000000, polarity=0, phase=0, sck=Pin(2), mosi=Pin(3))
dc = Pin(5, Pin.OUT)
res = Pin(4, Pin.OUT)
cs = Pin(6, Pin.OUT)
# Reset sequence same as above
oled = ssd1306.SSD1306_SPI(128, 64, spi, dc, res, cs)
oled.init_display()
oled.fill(0)
oled.show()

The init_display() method sends the initialization sequence, which includes setting the display on, charge pump, contrast, and memory addressing mode. The SSD1309 requires a slightly different init sequence than the SSD1306, but the library handles it. If you see a blank screen, try adjusting the contrast with oled.contrast(0x7F) (range 0-255). The default contrast is 0x7F, but some modules need lower values like 0x40 to avoid ghosting.

Drawing Text and Graphics

Once initialized, you can draw text, lines, rectangles, and pixels. The library includes a basic 8x8 pixel font. To display text, use oled.text("Hello", 0, 0) and then oled.show(). The text function writes a string at a given x, y coordinate. The font is monospaced, so each character is 8 pixels wide and 8 pixels tall. With a 128x64 display, you can fit 16 characters per line (128/8) and 8 lines (64/8). That’s a total of 128 characters on screen. For example:

oled.fill(0)
oled.text("2.42 inch OLED", 0, 0)
oled.text("MicroPython", 0, 16)
oled.text("128x64", 0, 32)
oled.text("SPI Mode", 0, 48)
oled.show()

This will display four lines of text. The library also supports oled.pixel(x, y, color) where color is 1 (white/blue) or 0 (black). To draw a line, use oled.line(x1, y1, x2, y2, color). For a rectangle, oled.rect(x, y, width, height, color) and oled.fill_rect(x, y, width, height, color). The display update is done via oled.show(), which sends the entire 1024-byte frame buffer over SPI. This takes about 2-3 ms at 4 MHz, so you can update the screen at 300-500 Hz theoretically, but practical frame rates are limited by your code’s rendering time.

Performance Data and Optimization

Let’s talk real numbers. The SPI transfer of 1024 bytes at 4 MHz takes about 2.1 ms (1024 bytes * 8 bits / 4,000,000 Hz = 0.002048 seconds). Add overhead for the DC and CS pin toggling, and you’re looking at 2.5-3 ms per full screen update. This means you can achieve 300-400 fps if you’re just flushing the buffer. But if you’re drawing graphics, the Python rendering can be slow. For example, drawing 100 random pixels takes about 1 ms, but drawing a filled rectangle takes 0.5 ms. The ssd1306 library is written in pure MicroPython, so it’s not optimized for speed. For faster graphics, consider using the framebuf module, which is built into MicroPython and provides hardware-accelerated blitting. You can create a framebuffer and then copy it to the OLED’s buffer. Here’s how:

import framebuf
buf = bytearray(1024)
fb = framebuf.FrameBuffer(buf, 128, 64, framebuf.MONO_VLSB)
fb.text("Fast", 0, 0)
fb.line(0, 10, 127, 10, 1)
oled.buffer = buf
oled.show()

This bypasses the library’s slow drawing methods and uses the native framebuf, which is written in C. The speed improvement is about 10x for complex graphics. For example, drawing a full-screen bitmap takes 0.5 ms with framebuf vs 5 ms with the library. The framebuf supports MONO_VLSB (vertical least significant bit) format, which matches the SSD1309’s memory layout. The OLED’s buffer is 1024 bytes, and the framebuf uses the same structure, so you can directly assign it.

Power Consumption and Heat Management

The 2.42 inch OLED draws about 20 mA at 3.3V when displaying a full white screen, and about 10 mA for a typical text display. At 5V, the current is slightly higher due to the regulator, but the power consumption is similar (66 mW vs 50 mW). The display has a built-in charge pump for the OLED panel, so it generates a negative voltage internally. The operating temperature range is -40°C to 85°C, but the OLED brightness degrades at high temperatures. The contrast can be adjusted with oled.contrast(value) to reduce power consumption. Lower contrast (e.g., 0x20) reduces current to about 12 mA. The display also has a sleep mode via oled.poweroff() which reduces current to 1-2 µA. Use oled.poweron() to wake it up. This is critical for battery-powered projects.

Common Issues and Debugging

If the display doesn’t work, check the wiring first. The most common issue is the RES pin not being toggled correctly. The reset sequence must be at least 1 ms low. Also, ensure the CS pin is pulled low during SPI transactions. Some modules have a BS0/BS1 selection for SPI vs I2C. If you’re using a 4-wire SPI module, BS0 should be grounded and BS1 left floating or pulled high. For I2C, the pins are different: SDA and SCL. The 2.42 inch display is usually SPI, but some modules have both interfaces. If you’re getting a blank screen, try reading the OLED’s status register via SPI (not supported by the library, but you can do it manually). The SSD1309’s status register is at address 0x00, and a read command returns 0x14 if the display is powered on. Another issue is the contrast being too low. The default is 0x7F, but some modules need 0xCF. Also, the display might be upside down. You can flip it with oled.rotate(1) (if the library supports it) or by sending a command: oled.write_cmd(0xC0) for normal orientation, 0xC8 for flipped.

Advanced: Using the Display with Graphics and Bitmaps

To display a bitmap, you need to convert an image to a 1024-byte array in MONO_VLSB format. Tools like img2py or ImageMagick can convert images to C arrays. For MicroPython, you can store the array as a bytearray and load it directly. For example, a 128x64 bitmap of a logo:

logo = bytearray([0x00, 0xFF, 0x00, ...]) # 1024 bytes
oled.buffer = logo
oled.show()

This is useful for splash screens or icons. The display’s response time is about 100 µs per pixel, so a full screen update takes 10 ms if you’re writing pixels individually, but with the buffer, it’s 2-3 ms. The OLED has a 180-degree viewing angle and a contrast ratio of 2000:1, so it’s readable in direct sunlight. The pixel pitch is 0.42 mm, which gives a sharp image for text and graphics.

Compatibility with Different MicroPython Boards

The library works on ESP32, ESP8266, Raspberry Pi Pico, STM32, and Pyboard. For ESP8266, you need to use software SPI because the hardware SPI is limited. The ESP8266 has only one hardware SPI, but it’s used for the flash memory. Software SPI is slower (about 1 MHz) but works. Here’s the code for ESP8266:

from machine import Pin
import ssd1306
import time

# Software SPI
spi = machine.SoftSPI(baudrate=1000000, polarity=0, phase=0, sck=Pin(14), mosi=Pin(13), miso=Pin(12))
dc = Pin(5, Pin.OUT)
res = Pin(4, Pin.OUT)
cs = Pin(2, Pin.OUT)
# Reset and init same as before
oled = ssd1306.SSD1306_SPI(128, 64, spi, dc, res, cs)
oled.init_display()
oled.fill(0)
oled.show()

The SoftSPI baudrate is limited to about 1 MHz on ESP8266, so screen updates take about 10 ms. This is still fine for static text. For the Raspberry Pi Pico, the hardware SPI can go up to 10 MHz, but I recommend 4 MHz for stability. The Pico’s SPI0 uses pins 2, 3, and 6 for SCK, MOSI, and CS. Some users report issues with the Pico’s SPI on pins 0-5, so use pins 2-6 as shown.

Real-World Application Example: Weather Station

Let’s build a simple weather station that displays temperature and humidity from a DHT22 sensor. The code reads the sensor every 10 seconds and updates the display. The DHT22 uses a single pin for data. Here’s the full code:

from machine import Pin, SPI
import ssd1306
import dht
import time

spi = SPI(2, baudrate=4000000, sck=Pin(18), mosi=Pin(23))
dc = Pin(17, Pin.OUT)
res = Pin(16, Pin.OUT)
cs = Pin(5, Pin.OUT)
res.value(0)
time.sleep_ms(10)
res.value(1)
time.sleep_ms(10)
oled = ssd1306.SSD1306_SPI(128, 64, spi, dc, res, cs)
oled.init_display()
dht22 = dht.DHT22(Pin(15

End of article

About admin

Brand strategist and principal of Kushnaryov. Contributor to Harvard Business Review and A List Apart. Read more on the practice page.