NAME
RPi::OLED::SSD1306::128_64 - Interface to the SSD1306-esque 128x64 OLED displays
SYNOPSIS
use RPi::OLED::SSD1306::128_64;
# The panel defaults to I2C address 0x3C
my $oled = RPi::OLED::SSD1306::128_64->new;
$oled->text_size(1);
# Draw text and push it to the screen. A trailing 1 on string() calls
# display() for you; "\n" starts a new line, and long lines wrap.
$oled->string("Hello, OLED!\nline two", 1);
# Drawing primitives fill the in-memory buffer; call display() to show them
$oled->clear;
$oled->rect(0, 0, 40, 20, 1); # filled rectangle
$oled->horizontal_line(0, 32, 128, 1); # a horizontal line
$oled->pixel(64, 40, 1); # a single pixel
$oled->display;
# Flicker-free continuous refresh: rebuild the whole frame in the buffer
# each pass, then push it once (no blank flash between frames)
while (1) {
$oled->clear_buffer; # zero buffer + home cursor
$oled->string(sprintf("tick %d", time)); # draw (no auto-display)
$oled->display; # single push to the panel
select(undef, undef, undef, 0.2);
}
$oled->clear; # blank the panel when done
DESCRIPTION
Provides the ability to use the 128x64 SSD1306 type OLED displays.
This distribution requires wiringPi version 3.18+ to be installed (the canonical minimum for the whole RPi:: family is published as WIRINGPI_MIN_VERSION in RPi::Const, which this distribution's Makefile.PL consumes).
METHODS
new([$i2c_addr])
Instantiates and returns a new RPi::OLED::SSD1306::128x64 object.
Note that this module is a singleton; if you've already instantiated a new OLED device object, it will be returned if new() is called again.
Parameters:
$i2c_addr
Optional, Integer. The I2C address of your OLED screen. Defaults to 0x3C, which is extremely common.
clear
Wipes the display clean, and sets the cursor to the top-left position on the screen.
Returns 1 on success.
clear_buffer
Zeroes the in-memory framebuffer and homes the cursor, but does not push the result to the panel (unlike "clear", which also refreshes the screen). Pair it with a single "display" to rebuild and draw a whole frame in one write - handy for a continuously-updating screen, where clearing straight to the panel each frame would flicker.
Returns 1 on success.
text_size($size)
By default, we use the smallest text size (1) when displaying characters to the OLED. You can increase or decrease the text size with this call.
Parameters:
$size
Mandatory, Integer: A number to increase or decrease the font size to. Any number is valid, but be realistic... this screen is only 128x64 pixels.
Returns 1 on success.
display
Draws whatever you've put into the buffer to the screen. All calls that add to the buffer (eg: rect(), string(), pixel(), char() etc) require a call to this method after you've filled the buffer.
string($str, [$display])
Send a string to the display for printing.
Parameters:
$str
Mandatory, String: The string you want put into the buffer for display.
$display
Optional, Bool: All calls for displaying something to the screen require an additional call to display(). Send in a positive value (1) as the second parameter to this call and we'll call display automatically for you.
Returns 1 on success.
rect($x, $y, $w, $h, $colour)
Prepares a rectangle for display on the screen. To actually display the rectangle, a subsequent call to display() is required.
Parameters:
$x
Mandatory, Integer: The X-axis (horizontal) position from the left of the screen to begin drawing the rectangle.
$y
Mandatory, Integer: The Y-axis (vertical) position from the top of the screen to begin drawing the rectangle.
$w
Mandatory, Integer: How many pixels wide to draw the rect.
$h
Mandatory, Integer: How many pixels tall (from the top) to draw the rect.
$colour
Optional, Bool: By default, we use 1 which is standard colour (white). Send in 0 and we'll use black, which will effectively wipe out whatever was on the display in the area of the rectangle.
Returns 1 on success.
char($x, $y, $char, $size, $colour)
Creates a buffer with a single ASCII char. As with other buffer calls, a call to display() is required once you're ready to display the buffer.
Parameters:
$x
Mandatory, Integer: The X-axis (horizontal) position from the left of the screen to begin drawing the char.
$y
Mandatory, Integer: The Y-axis (vertical) position from the top of the screen to begin drawing the char.
$char
Mandatory, Integer: The integer representation of the ASCII char to draw. Valid values are 0-255.
$size
Optional, Integer: The size of the char on the screen. Defaults to 2.
$colour
Optional, Bool: By default, we use 1 which is standard colour (white). Send in 0 and we'll use black, which will effectively wipe out whatever was on the display in the area of the char.
Returns 1 on success.
pixel($x, $y, $colour)
Draw a single pixel to the screen.
Parameters:
$x
Mandatory, Integer: The X-axis (horizontal) position from the left of the screen to place the pixel.
$y
Mandatory, Integer: The Y-axis (vertical) position from the top of the screen to place the pixel.
$colour
Optional, Bool: By default, we use 1 which is standard colour (white). Send in 0 and we'll use black, which will effectively wipe out whatever was on the display in the area of the pixel.
Returns 1 on success.
horizontal_line($x, $y, $w, $colour)
Draw a single pixel wide horizontal line.
Parameters:
$x
Mandatory, Integer: The X-axis (horizontal) position from the left of the screen to begin drawing the horizontal line.
$y
Mandatory, Integer: The Y-axis (vertical) position from the top of the screen to begin drawing the horizontal line.
$w
Mandatory, Integer: How many pixels wide to draw the horizontal line.
$colour
Optional, Bool: By default, we use 1 which is standard colour (white). Send in 0 and we'll use black, which will effectively wipe out whatever was on the display in the area of the rectangle.
Returns 1 on success.
vertical_line($x, $y, $h, $colour)
Draw a single-pixel wide vertical line.
Parameters:
$x
Mandatory, Integer: The X-axis (horizontal) position from the left of the screen to begin drawing the vertical line.
$y
Mandatory, Integer: The Y-axis (vertical) position from the top of the screen to begin drawing the vertical line.
$w
Mandatory, Integer: How many pixels tall to draw the vertical line.
$colour
Optional, Bool: By default, we use 1 which is standard colour (white). Send in 0 and we'll use black, which will effectively wipe out whatever was on the display in the area of the rectangle.
Returns 1 on success.
dim($bool)
The screen has two brightness levels, dim and full.
Parameters:
$bool
Optional, Bool: Send in 1 to dim the display, and 0 to turn it to its maximum brightness. Defaults to 0 if not sent in.
Returns 1 on success.
invert_display($bool)
By default, the screen background is black, and anything you draw will be white. Inverting the screen will reverse those two colours.
Parameters:
$bool
Optional, Bool: 1 will invert the screen (black on white background), and 0 will set it back to normal (white on black background). Defaults to 0 if not sent in.
Returns 1 on success.
TECHNICAL INFORMATION
The bus work lives in the bundled C layer (ssd1306_i2c.c, a port of the Adafruit SSD1306 library); the Perl methods draw into a 1KB framebuffer on the Pi and push it to the panel over I2C.
DEVICE SPECIFICS
- SSD1306: 128x64 monochrome OLED controller/driver
- Graphics RAM is 1KB, arranged as 8 pages of 128 bytes; each byte
is a vertical strip of 8 pixels
- This driver mirrors that RAM in a Pi-side buffer: the draw calls
only touch the buffer, and display() pushes all 1024 bytes out
- I2C address 0x3C (the module default), or 0x3D with the SA0 line
strapped high
- I2C clocks up to 400kHz (t_cycle 2.5us minimum); the Pi's default
100kHz works fine
- Logic supply 1.65-3.3V; the higher OLED panel voltage is made by
the chip's internal charge pump, switched on during init
- The bare chip also speaks SPI and parallel buses; I2C breakout
boards hardwire the interface-select pins
Wiring a typical 4-pin I2C breakout: VCC to 3.3V, GND to ground, SDA to GPIO 2 (pin 3), SCL to GPIO 3 (pin 5). i2cdetect -y 1 shows the panel at 0x3C.
COMMAND SET
Every byte sent to the chip is framed by a control byte (see "ON THE WIRE") marking it as either a command or display data - there are no addressable registers. The commands this driver uses:
0xAE / 0xAF Display off / on
0x81 xx Contrast (init sets 0xCF; dim() sends 0x00)
0xA4 Resume displaying the RAM contents
0xA6 / 0xA7 Normal / inverted video (invert_display())
0x20 00 Memory addressing mode: horizontal, auto-wrapping
0x21 s e Column address window (display() uses 0-127)
0x22 s e Page address window (display() uses 0-7)
0x40+n Display start line (init: line 0)
0xA1 Segment remap - X flip (init)
0xC8 COM scan direction - Y flip (init)
0xA8 3F Multiplex ratio: 64 rows
0xD3 00 Display offset: none
0xD5 80 Display clock divide ratio / oscillator
0xD9 F1 Precharge periods
0xDA 12 COM pins layout for 128x64
0xDB 40 VCOMH deselect level
0x8D 14 Charge pump on
0x2E Deactivate scroll
new() runs the whole bring-up sequence above; after that the only traffic is the odd contrast/invert command and display() pushes.
ON THE WIRE
The C layer writes through the kernel's /dev/i2c-1, and every frame is three bytes: the chip address, a control byte, then one payload byte. The control byte is 0x00 for a command and 0x40 for display data (bit 6 is D/C#, bit 7 is Co):
S = START P = STOP A = ACK (receiver pulls SDA low)
A command - here 0xAF (display on) at address 0x3C, which is 0x78 on the wire:
+---+------+---+------+---+------+---+---+
| S | 0x78 | A | 0x00 | A | 0xAF | A | P |
+---+------+---+------+---+------+---+---+
addr+W Control Command
(0x3C) = command
The framebuffer streams out in a single transaction - one 0x40 control byte (Co = 0, so every byte after it is display data), then all 1024 buffer bytes, before the STOP:
+---+------+---+------+---+------+-- --+------+---+---+
| S | 0x78 | A | 0x40 | A | 0xFF | ... | 0x00 | A | P |
+---+------+---+------+---+------+-- --+------+---+---+
addr+W Control 1024 data bytes, eight
= data vertical pixels each
A full display() is six command frames (resetting the column and page windows to 0-127 / 0-7) followed by that one 1025-byte data transaction - about 0.09s per refresh at the Pi's default 100kHz, which is bus-bound (raise dtparam=i2c_arm_baudrate to go faster). Earlier releases sent a control+data frame per byte (~1024 transactions, ~0.3s); the driver now streams the whole buffer after a single control byte, falling back to the byte-by-byte path only if an adapter caps the single transfer.
DATASHEET
The Solomon Systech SSD1306 datasheet (rev 1.1) is distributed with this software as docs/datasheet/SSD1306.pdf. It covers the command set, the GDDRAM layout, the I2C control byte framing, and the charge pump this driver enables.
AUTHOR
Steve Bertrand, <steveb at cpan.org>
LICENSE AND COPYRIGHT
Copyright 2018-2026 Steve Bertrand.
BSD License