How to Drive an SSD1315 I2C OLED Display on ESP32-C5_MINI with MicroPython

In this post, we will look at how to interface and display data on a 0.96-inch 128x64 SSD1315 I2C OLED display using ESP32-C5_MINI and MicroPython.

For these exercises, we will use the official micropython-ssd1306 driver. Because the SSD1315 shares the exact same command structure for basic operations as the classic SSD1306, this library works flawlessly out of the box.

Getting the Library

There are two easy ways to install the driver on your board:

  • Via Thonny IDE: Go to Tools ➔ Manage packages..., search for micropython-ssd1306, and click Install.
  • Manual Installation: Download ssd1306.py directly from the official MicroPython-lib repository and save it onto your ESP32-C5 file system.
Connection
SDA - IO3
SCL - IO4
VCC - 3V3
GND - GND

Exercise Code

mpy_C5_ssd1306.py, basic setup and test.
"""
Exercise on ESP32-C5_MINI/MicroPython v1.29.0-preview
Display on 0.96 inch 128x64 SSD1315 I2C OLED (SSD1306 compatible),
using micropython-ssd1306 lib (https://github.com/stlehmann/micropython-ssd1306).

https://coxxect.blogspot.com/2026/07/how-to-drive-ssd1315-i2c-oled-display.html
Connection: PIN_SDA - IO3 PIN_SCL - IO4 """ import os, sys import machine import ssd1306 import time import micropython PIN_SDA = micropython.const(3) PIN_SCL = micropython.const(4) # Initialize I2C peripheral on the ESP32-C5 # Using software I2C (-1) or hardware I2C (0) i2c = machine.I2C(0, sda=machine.Pin(PIN_SDA), scl=machine.Pin(PIN_SCL), freq=400000) print("=========================================================") print(sys.implementation[0], os.uname()[3], "\nrun on", os.uname()[4]) print("=========================================================") freq_mhz = machine.freq() / 1_000_000 print("CPU Frequency: {:.2f} MHz".format(freq_mhz)) print("Memory info:") micropython.mem_info() print() # Scan for the I2C device address (usually 0x3C / 60) print("Scanning I2C bus...") devices = i2c.scan() if devices: print(f"I2C device(s) found at address: {[hex(d) for d in devices]}") else: print("No I2C device found. Check your connections!") # Initialize the 128x64 OLED display oled = ssd1306.SSD1306_I2C(128, 64, i2c) # Clear display oled.fill(0) # Draw some text and shapes oled.text("ESP32-C5_MINI", 0, 0) oled.text("MicroPython!", 0, 16) oled.rect(0, 35, 128, 20, 1) # Write to the physical screen oled.show() for x in range(0, 128): oled.line(x, 35, x, 55, 1) oled.show() for x in range(0, 128): oled.line(x, 35, x, 55, 0) oled.show()

mpy_C5_ssd1306_multiline_text.py, display multi-line text.
"""
Exercise on ESP32-C5_MINI/MicroPython v1.29.0-preview
Display on 0.96 inch 128x64 SSD1315 I2C OLED (SSD1306 compatible),
using micropython-ssd1306 lib
: Display multi-line text.

https://coxxect.blogspot.com/2026/07/how-to-drive-ssd1315-i2c-oled-display.html Connection: PIN_SDA - IO3 PIN_SCL - IO4 """ import os, sys import machine import ssd1306 import time import micropython PIN_SDA = micropython.const(3) PIN_SCL = micropython.const(4) # Initialize I2C peripheral on the ESP32-C5 # Using software I2C (-1) or hardware I2C (0) i2c = machine.I2C(0, sda=machine.Pin(PIN_SDA), scl=machine.Pin(PIN_SCL), freq=400000) info = "=========================================================\n" +\ sys.implementation[0] + os.uname()[3] + "\n" +\ "run on" + os.uname()[4] + "\n" +\ "=========================================================" print(info) freq_mhz = machine.freq() / 1_000_000 print("CPU Frequency: {:.2f} MHz".format(freq_mhz)) print("Memory info:") micropython.mem_info() print() # Scan for the I2C device address (usually 0x3C / 60) print("Scanning I2C bus...") devices = i2c.scan() if devices: print(f"I2C device(s) found at address: {[hex(d) for d in devices]}") else: print("No I2C device found. Check your connections!") # Initialize the 128x64 OLED display oled = ssd1306.SSD1306_I2C(128, 64, i2c) def draw_multiline_text(device, text, start_x, start_y, line_height=8): """ Splits text by newline characters and draws each line sequentially. """ lines = text.split('\n') for i, line in enumerate(lines): # Calculate the y position for each individual line current_y = start_y + (i * line_height) # Prevent drawing off the bottom edge of the screen if current_y > 64 - line_height: break device.text(line, start_x, current_y) # Clear display oled.fill(0) # Use our helper function instead of oled.text() draw_multiline_text(oled, info, 0, 0) # Render to screen oled.show()

mpy_C5_ssd1306_Scrolling.py, scrolling horizontally.
"""
Exercise on ESP32-C5_MINI/MicroPython v1.29.0-preview
Display on 0.96 inch 128x64 SSD1315 I2C OLED (SSD1306 compatible),
using micropython-ssd1306 lib
: Scrolling horizontally

https://coxxect.blogspot.com/2026/07/how-to-drive-ssd1315-i2c-oled-display.html Connection: PIN_SDA - IO3 PIN_SCL - IO4 """ import os, sys import machine import ssd1306 import time import micropython PIN_SDA = micropython.const(3) PIN_SCL = micropython.const(4) # Initialize I2C peripheral on the ESP32-C5 # Using software I2C (-1) or hardware I2C (0) i2c = machine.I2C(0, sda=machine.Pin(PIN_SDA), scl=machine.Pin(PIN_SCL), freq=400000) print("=========================================================") print(sys.implementation[0], os.uname()[3], "\nrun on", os.uname()[4]) print("=========================================================") freq_mhz = machine.freq() / 1_000_000 print("CPU Frequency: {:.2f} MHz".format(freq_mhz)) print("Memory info:") micropython.mem_info() print() # Scan for the I2C device address (usually 0x3C / 60) print("Scanning I2C bus...") devices = i2c.scan() if devices: print(f"I2C device(s) found at address: {[hex(d) for d in devices]}") else: print("No I2C device found. Check your connections!") # Initialize the 128x64 OLED display oled = ssd1306.SSD1306_I2C(128, 64, i2c) # Clear display oled.fill(0) oled.fill(0) # Draw some text and shapes oled.text("ESP32-C5_MINI", 0, 0) oled.text("MicroPython!", 0, 16) oled.rect(0, 35, 128, 20, 1) oled.show() time.sleep(2) while True: # 1. Shift the frame buffer right by 2 pixels oled.scroll(2, 0) # 2. FIX: Erase the leftmost columns (0 and 1) that kept the old line data oled.vline(0, 0, 64, 0) oled.vline(1, 0, 64, 0) # 3. Render the clean frame oled.show() #time.sleep(0.05)

mpy_C5_ssd1306_continuously_scroll_multiline_text_hori.py, continuously scroll a multi-line block of text horizontally.
"""
Exercise on ESP32-C5_MINI/MicroPython v1.29.0-preview
Display on 0.96 inch 128x64 SSD1315 I2C OLED (SSD1306 compatible),
using micropython-ssd1306 lib
:continuously scroll a multi-line block of text horizontally

https://coxxect.blogspot.com/2026/07/how-to-drive-ssd1315-i2c-oled-display.html
Connection: PIN_SDA - IO3 PIN_SCL - IO4 """ import os, sys import machine import ssd1306 import time import micropython PIN_SDA = micropython.const(3) PIN_SCL = micropython.const(4) # 1. Initialize I2C and OLED i2c = machine.I2C(0, sda=machine.Pin(PIN_SDA), scl=machine.Pin(PIN_SCL), freq=400000) oled = ssd1306.SSD1306_I2C(128, 64, i2c) # 2. Build your system information string info = ("=========================================================\n" + sys.implementation[0] + " " + os.uname()[3] + "\n" + "run on " + os.uname()[4] + "\n" + "=========================================================") # Split into lines info_lines = info.split('\n') # 3. Calculate the maximum line length so we know exactly when to reset max_chars = max(len(line) for line in info_lines) max_text_width = max_chars * 8 # 8 pixels wide per character # Configuration LINE_HEIGHT = 12 # Spaced slightly apart (12px instead of 8px) for readability SCROLL_SPEED = 2 # Pixels per frame # Start off-screen to the right x_pos = 128 while True: oled.fill(0) # Clear frame buffer # Draw each line at its respective row, moving horizontally based on x_pos for index, line in enumerate(info_lines): line_y = 4 + (index * LINE_HEIGHT) # Vertical spacing oled.text(line, x_pos, line_y) oled.show() # Shift left x_pos -= SCROLL_SPEED # Reset when the longest line disappears entirely off the left side if x_pos < -max_text_width: time.sleep(0.5) # Brief pause before wrapping x_pos = 128 # Reset to the right edge time.sleep(0.01)

mpy_C5_ssd1306_continuously_scroll_multiline_text_vert.py, continuously scroll a multi-line block of text vertically.
"""
Exercise on ESP32-C5_MINI/MicroPython v1.29.0-preview
Display on 0.96 inch 128x64 SSD1315 I2C OLED (SSD1306 compatible),
using micropython-ssd1306 lib
:continuously scroll a multi-line block of text vertically

https://coxxect.blogspot.com/2026/07/how-to-drive-ssd1315-i2c-oled-display.html
Connection: PIN_SDA - IO3 PIN_SCL - IO4 """ import os, sys import machine import ssd1306 import time import micropython PIN_SDA = micropython.const(3) PIN_SCL = micropython.const(4) # 1. Initialize I2C and OLED i2c = machine.I2C(0, sda=machine.Pin(PIN_SDA), scl=machine.Pin(PIN_SCL), freq=400000) oled = ssd1306.SSD1306_I2C(128, 64, i2c) # 2. Build your system information string info = ("=========================================================\n" + sys.implementation[0] + " " + os.uname()[3] + "\n" + "run on " + os.uname()[4] + "\n" + "=========================================================") print(info) # 3. Split the text into an array of lines once to save CPU cycles in the loop info_lines = info.split('\n') # Configuration constants LINE_HEIGHT = 8 TOTAL_TEXT_HEIGHT = len(info_lines) * LINE_HEIGHT # 4 lines * 8px = 32px SCROLL_SPEED = 1 # Move up by 1 pixel per frame # Start position: completely below the bottom edge of the 64px tall screen y_pos = 64 while True: oled.fill(0) # Clear the frame buffer # Draw each line relative to the shifting 'y_pos' for index, line in enumerate(info_lines): line_y = y_pos + (index * LINE_HEIGHT) # Only render the line if it's actually visible within the screen boundary (0 to 63) if -LINE_HEIGHT < line_y < 64: oled.text(line, 0, line_y) oled.show() # Shift the text upward y_pos -= SCROLL_SPEED # If the bottom of the last line climbs past the top edge (y=0), reset to bottom if y_pos < -TOTAL_TEXT_HEIGHT: time.sleep(0.5) # Brief pause when it finishes scrolling out y_pos = 64 # Reset to the bottom edge time.sleep(0.02) # Adjust frame delay to control scrolling speed smoothness


Comments

Popular posts from this blog

480x320 TFT/ILI9488 SPI wih EP32C3 (arduino-esp32) using Arduino_GFX Library

Drive ST7796 SPI TFT with XPT2046 Touch on ESP32-C3-DevKitM-1 (arduino-esp32), using TFT_eSPI.