OLED 128×64 (I²C)
A 0.96″ SSD1306 OLED is a 128×64 pixel monochrome display that makes its own light. It costs $8 and shows real graphics — sensor plots, big numbers, small icons — where a character LCD can only show text. Everything is drawn on the Pi into a framebuffer and pushed over I²C one screen at a time. The LCD and TM1637 pages cover the simpler displays.
Pins
| Pin | What it is | Type |
|---|---|---|
| GND | Ground | ground |
| VCC | Supply 3.3–5 V | power |
| SCL | I²C clock | io |
| SDA | I²C data | io |
| Setting | Type | Range | Default |
|---|---|---|---|
address | enum | 0x3C, 0x3D | 0x3C |
color | enum | white, blue, yellow-blue | white |
VCC takes 3.3–5 V, GND is ground, and SCL/SDA are the Pi's I²C pins. Most modules have no reset pin. The address setting picks 0x3C (the usual default) or 0x3D, and color picks which panel is drawn.
Wiring it in circuit.py
from wiring import *
pi = Pi()
oled = OLED()
pi.V3_3 >> oled.vcc
oled.gnd >> pi.GND
pi.SDA >> oled.sda
pi.SCL >> oled.sclDriving it in main.py
The runtime ships Adafruit's adafruit_ssd1306 and its framebuffer library, so this example runs here and on a real Pi with pip install adafruit-circuitpython-ssd1306:
import board
import adafruit_ssd1306
from time import sleep
oled = adafruit_ssd1306.SSD1306_I2C(128, 64, board.I2C())
frame = 0
while True:
oled.fill(0)
oled.text("PyRasp", 24, 4, 1)
oled.rect(0, 20, 128, 44, 1)
oled.fill_rect(8 + frame % 100, 30, 12, 24, 1)
oled.show()
frame += 4
sleep(0.1)The drawing methods — pixel, hline, vline, rect, fill_rect, text — write into memory; nothing appears until show() pushes the framebuffer.
Electrical notes
- Supply 3–5 V. The model loads the rail with a fixed 8 mA; the datasheet's figure for all 128×64 pixels lit is about 20 mA, and a real panel's draw rises with the lit fraction — which is why OLEDs are prized for low-power projects.
- Two addresses, 0x3C or 0x3D, chosen by a solder jumper on the module.
- The controller needs its charge pump: nothing lights until the init sequence writes 0x8D, 0x14 (charge pump on) and 0xAF (display on). Libraries do this in their constructor.
- Display RAM is organised in 8 pages of vertical 8-pixel strips; a framebuffer library hides that, but raw-command code must set a page and column before each byte.
- Segment remap (0xA1) and COM scan reverse (0xC8) orient the glass; without them an image comes out rotated 180°. Start line and display offset shift which row of RAM lands at the top.
- The two-colour version has its top 16 rows wired yellow; inside it is still one monochrome controller.
Simulator vs real hardware
- The part decodes the controller's real command and data streams — control bytes 0x00/0x40 (streams) and 0x80/0xC0 (single byte), multi-byte commands with their arguments, page/horizontal/vertical addressing, contrast, invert and all-on — and renders the mapped RAM to the canvas. Adafruit's driver and raw smbus2 code both work.
- Reading back returns the status byte 0x03; real drivers rarely do, and some modules cannot read at all.
- Text uses the vendored 5×8 font (
font5x8.bin) exactly as on hardware, so a mis-drawn string looks the same; the canvas shows lit pixels, with no anti-aliasing. - The address and colour settings are props: they change what the part answers and how it is painted, not the protocol.
Going deeper
- Primer: I²C and the other buses.
- Other displays: LCD 16×2 for text, TM1637 for digits.
- Sensors worth plotting: BME280, MPU-6050.
Further reading
- SSD1306 datasheet (Solomon Systech) — command table, RAM organisation and the charge pump.
- Adafruit CircuitPython SSD1306 docs —
SSD1306_I2Cand the framebuffer methods. - Adafruit: monochrome OLED breakouts — the 0.96″ module, wiring and power notes.