Skip to content
FGCV / Engineering Notes

How to use a 2.08 inch 256x64 OLED display with Python?

admin By the admin

To get a 2.08 inch 256x64 oled display working with Python, you need to connect it via SPI (Serial Peripheral Interface) and use a library like luma.oled or Adafruit CircuitPython SSD1306 (though SSD1306 is for 128x64, the 256x64 variant uses a similar protocol but with a different controller like SH1106 or SSD1322). The display is a monochrome OLED with a resolution of 256 pixels by 64 pixels, typically driven by a controller such as the SSD1322 (16-level grayscale) or SH1106 (1-bit monochrome). For Python, the most reliable approach is to use the luma.oled library, which supports multiple OLED controllers including SSD1322. First, install the library via pip: pip install luma.oled. Then, wire the display to your Raspberry Pi or any Linux SBC: connect VCC to 3.3V, GND to ground, MOSI to GPIO 10 (SPI0 MOSI), SCK to GPIO 11 (SPI0 SCLK), DC to GPIO 24 (or any free GPIO), RST to GPIO 25, and CS to GPIO 8 (SPI0 CE0). The display uses a 4-wire SPI interface, which requires 6 pins including power and ground. The data transfer rate is typically 10 MHz, but you can adjust it in the library. The 2.08 inch 256x64 oled display has a pixel pitch of 0.185 mm, giving a physical size of about 47.4 mm x 11.8 mm, and it supports a wide viewing angle of 160 degrees. The power consumption is around 20 mA at full brightness, which is low for an OLED. In Python, after initializing the device with from luma.core.interface.serial import spi, bitbang and from luma.core.render import canvas, you can draw shapes, text, and images. The framebuffer is 256x64 pixels, and each pixel is either on or off (for monochrome) or 4-bit grayscale (for SSD1322). The library uses the Pillow library for image handling, so you can load PNG or BMP files and display them. The SPI bus speed is critical: if you set it too high (e.g., above 20 MHz), the display may glitch. The default is 8 MHz, which works reliably. The display also supports partial refresh, which reduces power consumption by only updating changed regions. For example, you can update a 100x50 pixel area in 5 ms instead of the full frame in 20 ms. The controller can handle up to 10 frames per second for full-screen updates, but partial updates can go up to 60 fps. The display uses a passive matrix OLED technology, which means each pixel is a self-emitting organic LED, so no backlight is needed. The contrast ratio is 10000:1, and the brightness is typically 100 cd/m², which is readable in direct sunlight. The operating temperature range is from -40°C to 80°C, making it suitable for industrial applications. The SPI interface uses 3.3V logic levels, but it is 5V tolerant on the data lines. The display has a built-in DC-DC converter that generates the necessary 12V for the OLED panel from the 3.3V supply. The current consumption peaks at 30 mA during a full white screen, but typical use draws 15 mA. The display module includes a 16-pin FPC connector with a 0.5 mm pitch, so you need a breakout board or a custom PCB with a 0.5 mm pitch FPC connector. The pinout is: pin 1 (VCC), pin 2 (GND), pin 3 (SCLK), pin 4 (MOSI), pin 5 (DC), pin 6 (RST), pin 7 (CS), pin 8 (NC), pin 9 (NC), pin 10 (NC), pin 11 (NC), pin 12 (NC), pin 13 (NC), pin 14 (NC), pin 15 (NC), pin 16 (NC). The NC pins are for future use or for additional features like touch or backlight (though OLED doesn't need backlight). The display driver IC is the SSD1322, which has a 256x64 pixel RAM buffer. The IC supports 4-bit grayscale (16 levels) per pixel, but the module is often sold as monochrome (1-bit) because the grayscale is not always used. To use grayscale, you need to set the display mode in the initialization sequence. The luma.oled library supports grayscale mode for SSD1322 by setting grayscale=True in the device constructor. The grayscale mode uses 4 bits per pixel, so the framebuffer is 256x64x4 bits = 8 KB, compared to 2 KB for monochrome. The SPI transfer for a full grayscale frame takes 8 KB / 8 MHz = 1 ms, but the actual update time is longer due to the controller's internal processing. The display supports hardware scrolling and contrast adjustment. The contrast can be set via a command from 0x00 to 0xFF, where 0xFF is maximum brightness. The default contrast is 0x7F. The display also has a built-in charge pump for the OLED voltage, which can be enabled or disabled via a command. The charge pump is enabled by default. The display's refresh rate is 100 Hz, but the actual frame rate depends on the SPI speed and the software. In Python, you can achieve 10-20 fps for full-screen updates with the luma.oled library on a Raspberry Pi 4. For higher frame rates, you can use a C library or a microcontroller like an ESP32 with MicroPython. The ESP32 can drive the display at 40 MHz SPI, achieving 30 fps for full-screen updates. The display's pixel size is 0.185 mm x 0.185 mm, so the text is readable at a distance of 30 cm. The font size in Python can be set using the Pillow library's ImageFont. For example, a 8x8 pixel font gives 32 characters per line and 8 lines. A 16x16 font gives 16 characters per line and 4 lines. The display supports custom fonts, but the standard library includes the default font. The luma.oled library also supports the show() method to update the display, and clear() to clear the buffer. The display's memory is organized as a column-major array, so the first byte corresponds to the top-left pixel. The library handles the byte ordering automatically. The display's SPI protocol is standard: the DC pin controls whether the data is a command (DC low) or data (DC high). The CS pin is active low. The RST pin is active low and must be held high for normal operation. The initialization sequence for the SSD1322 includes commands like: 0xFD (set command lock), 0x12 (unlock), 0xAE (display off), 0xA4 (display normal), 0xA1 (set segment remap), 0xA2 (set display offset), 0xAB (enable charge pump), 0x81 (set contrast), 0xB1 (set phase length), 0xB3 (set display clock divide ratio), 0xBC (set pre-charge voltage), 0xBE (set COM deselect voltage), 0xAF (display on). The luma.oled library handles this sequence automatically. You can also send custom commands using the command() method. The display's resolution is 256x64, which is not a standard VGA size, but it's perfect for text-heavy applications like status displays, oscilloscopes, or data loggers. The display's response time is 10 microseconds, so it can show fast-moving data without ghosting. The display's lifetime is 100,000 hours at 50% brightness, which is typical for OLEDs. The display's operating voltage is 3.3V, but the logic level can be 5V if you use a level shifter. The display's SPI interface is compatible with 5V microcontrollers if you use a voltage divider on the MOSI line. The display's power consumption is 0.066 watts at full brightness, which is very low. The display's weight is 5 grams, making it suitable for wearable devices. The display's thickness is 1.2 mm, including the glass. The display's viewing angle is 160 degrees in both horizontal and vertical directions. The display's contrast ratio is 10000:1, which means black pixels are truly black. The display's color is white or blue, depending on the model. The white model has a higher brightness of 100 cd/m², while the blue model has 80 cd/m². The display's pixel format is 256 columns by 64 rows. The display's driver IC supports hardware scrolling in both horizontal and vertical directions. The scrolling can be set to continuous or single-shot. The luma.oled library supports scrolling via the scroll() method. The display's SPI clock speed can be set in the library's serial interface. For example, spi(port=0, device=0, cs_high=False, reset_high=True, gpio_DC=24, gpio_RST=25, bus_speed_hz=8000000). The bus_speed_hz parameter sets the SPI clock speed. The display's temperature range is -40°C to 80°C, so it can be used in outdoor applications. The display's humidity range is 0% to 95% non-condensing. The display's storage temperature is -40°C to 85°C. The display's ESD protection is 2 kV for the human body model. The display's RoHS compliance is standard. The display's package includes a 16-pin FPC cable with a length of 10 cm. The display's mounting holes are 2.5 mm in diameter, spaced 50 mm apart horizontally and 20 mm vertically. The display's overall dimensions are 55 mm x 20 mm x 1.5 mm. The display's active area is 47.4 mm x 11.8 mm. The display's pixel density is 135 PPI (pixels per inch). The display's font rendering in Python can be done with the Pillow library's ImageDraw. For example, to draw text at position (10, 10) with a 8x8 font, you use draw.text((10, 10), "Hello", font=font, fill=255). The fill parameter is 255 for white (on) and 0 for black (off). The display's image display can be done with image = Image.open("image.png").convert("1") and then device.display(image). The image must be 256x64 pixels. The display's animation can be done by updating the buffer in a loop. For example, a bouncing ball animation can be done with a 10 ms delay between frames. The display's power management is important: you can turn off the display with device.hide() and turn it on with device.show(). The display's sleep mode can be entered with a command 0xAE, which reduces power consumption to 1 microamp. The display's wake-up time from sleep is 10 ms. The display's initialization time is 100 ms. The display's SPI bus can be shared with other devices if they use different CS pins. The display's CS pin must be pulled high when not in use. The display's DC pin must be set before each SPI transaction. The display's RST pin is used to reset the controller. The display's reset sequence is: pull RST low for 10 ms, then pull high. The display's library luma.oled also supports I2C interface, but the 256x64 display uses SPI only. The I2C version is for smaller displays. The display's Python code can be run on a Raspberry Pi, BeagleBone, or any Linux board with SPI support. The display's GPIO pins are 3.3V logic, so do not connect 5V directly. The display's power supply must be capable of 30 mA. The display's capacitor is 10 microfarad on the VCC line. The display's layout on a breadboard is straightforward: connect the FPC breakout board to the breadboard with jumper wires. The display's FPC connector is a ZIF type, so you need to insert the cable and lock the lever. The display's cable is a 0.5 mm pitch, 16-pin, 10 cm long. The display's pin 1 is marked with a dot on the cable. The display's orientation is landscape, with the cable coming out from the bottom. The display's software library luma.oled is well-documented with examples on GitHub. The library supports Python 3.6 and above. The library's dependencies are Pillow, luma.core, and spidev. The library's installation on Raspberry Pi requires enabling SPI via raspi-config. The library's example code for the 256x64 display is in the examples/ folder. The library's device initialization for SSD1322 is: from luma.oled.device import ssd1322 and then device = ssd1322(serial_interface, width=256, height=64, rotate=0). The rotate parameter can be 0, 1, 2, or 3 for 90-degree increments. The display's rotation is hardware-supported, so no pixel mapping is needed. The display's grayscale mode is set with mode="1" for monochrome or mode="L" for grayscale. The grayscale mode uses 8-bit images, but only 4 bits are used. The library's contrast control is device.contrast(0x80). The library's display on/off is device.show() and device.hide(). The library's clear is device.clear(). The library's pixel-level drawing is device.pixel(x, y, 1). The library's rectangle drawing is draw.rectangle([(10, 10), (100, 50)], outline=255, fill=0). The library's line drawing is draw.line([(0, 0), (255, 63)], fill=255). The library's circle drawing is draw.ellipse([(50, 20), (100, 50)], outline=255, fill=0). The library's polygon drawing is draw.polygon([(10, 10), (20, 30), (30, 20)], outline=255). The library's image display is device.display(image). The library's scrolling is device.scroll(horizontal=1, vertical=0). The library's partial update is device.display(image, bounding_box=(10, 10, 100, 50)). The library's performance can be improved by using the luma.core.framebuffer module. The library's error handling is minimal, so you need to check the SPI connection. The display's common issues include: no display (check wiring, power, and SPI enable), flickering (check power supply and SPI speed), wrong resolution (check initialization parameters), and garbled data (check byte order and DC pin). The display's troubleshooting steps: measure voltage on VCC (3.3V), check GPIO pins with a multimeter, run a simple test script like device.clear() and device.show(), and check the kernel messages for SPI errors. The display's Python script for a simple test is:

from luma.core.interface.serial import spi
from luma.oled.device import ssd1322
serial = spi(port=0, device=0, cs_high=False, reset_high=True, gpio_DC=24, gpio_RST=25, bus_speed_hz=8000000)
device = ssd1322(serial, width=256, height=64, rotate=0)
device.clear()
device.show()

This script initializes the display and clears it. The display's brightness is set to default. The display's contrast can be adjusted with device.contrast(0x80). The display's power consumption is 20 mA at this brightness. The display's temperature rise is 5 degrees Celsius above ambient. The display's lifetime is 50,000 hours at 100 cd/m². The display's storage is in a dry environment. The display's handling is with gloves to avoid fingerprints. The display's cleaning is with a soft cloth and isopropyl alcohol. The display's mounting is with double-sided tape or screws. The display's connector is fragile, so handle with care. The display's Python library also supports the SSD1322's built-in font table, but it's rarely used. The library's font rendering is via Pillow, which supports TrueType fonts. The display's text size can be set with font = ImageFont.truetype("arial.ttf", 12). The display's text alignment can be done with the draw.textbbox() method. The display's multi-line text can be done with draw.text((10, 10), "Line1\nLine2", font=font, fill=255). The display's scrolling text can be done by updating the position in a loop. The display's animation can be done with a timer. The display's data logging can be done by updating the display every second. The display's graph plotting can be done with the draw.line() method. The display's bar chart can be done with draw.rectangle(). The display's image slideshow can be done by loading images from a folder. The display's performance is limited by the SPI speed and the Python

// Next step

See FGCV running against your model, your data, your latency budget.

Get a Production Demo
Back to all articles