Raspberry Pi SH1106

Neil HaddleyJuly 24, 2023

OLED display

The Raspberry Pi can output text (and simple graphics) to an OLED display using Python.

OLED wiring

OLED wiring

i2cdetect -y 1

i2cdetect -y 1

Luma-OLED Driver

I installed the Luma-OLED driver by following these instructions:

https://luma-oled.readthedocs.io/en/latest/install.html

I installed the driver with this command

$ sudo -H pip3 install --upgrade luma.oled

I enabled I2C communications using the raspi-config application

$ sudo raspi-config

Interface Options | I2C | enable ARM I2C

i2c permissions

I followed the steps described by Alexander Rüedlinger to allow non-root users to access i2c devices (specifically the OLED display).

1) Create new user group called i2c:

$ sudo groupadd i2c

2) Change the group ownership of /dev/i2c-1 to i2c:

$ sudo chown :i2c /dev/i2c-1

3) Change the file permissions of the device /dev/i2c-1 so users of the i2c group can read and write to the device:

$ sudo chmod g+rw /dev/i2c-1

4) Add your user to the group i2c:

$ sudo usermod -aG i2c <username>

Python code

Python code

The hello.py code running on configured hardware

The hello.py code running on configured hardware

Displaying an image on the OLED display

I downloaded a stop sign image and updated the hello.py code to display the image on the OLED display.

Stop sign

Stop sign

Using OpenCV and luma.oled to display video on the OLED display

OpenCV (Open Source Computer Vision Library) is an open-source computer vision and machine learning software library. It provides a comprehensive set of tools and functions that enable developers to perform various computer vision tasks, such as image and video processing, object detection, facial recognition, and feature extraction.

I used the cv2 library to read frames from a dog video I downloaded from:

https://pixabay.com/videos/puppy-dog-playful-beach-sand-play-4740/

Then I updated the code to send image captured by the webcam to the OLED display.

Dog video

Dog video

Webcam

Webcam

hello.py

TEXT
1from luma.core.interface.serial import i2c, spi, pcf8574
2from luma.core.interface.parallel import bitbang_6800
3from luma.core.render import canvas
4from luma.oled.device import ssd1306, ssd1309, ssd1325, ssd1331, sh1106, sh1107, ws0010
5from time import sleep
6
7# rev.1 users set port=0
8# substitute spi(device=0, port=0) below if using that interface
9# substitute bitbang_6800(RS=7, E=8, PINS=[25,24,23,27]) below if using that interface
10serial = i2c(port=1, address=0x3C)
11
12# substitute ssd1331(...) or sh1106(...) below if using that device
13device = sh1106(serial)
14
15with canvas(device) as draw:
16    draw.rectangle(device.bounding_box, outline="white", fill="black")
17    draw.text((30, 40), "Hello World", fill="white")
18
19sleep(10)

stop_sign_display.py

TEXT
1from luma.core.interface.serial import i2c, spi, pcf8574
2from luma.core.interface.parallel import bitbang_6800
3from luma.core.render import canvas
4from luma.oled.device import ssd1306, ssd1309, ssd1325, ssd1331, sh1106, sh1107
5from time import sleep
6
7from PIL import Image
8
9serial = i2c(port=1, address=0x3C)
10device = sh1106(serial)
11
12width =  device.width
13height = device.height
14
15image = Image.open("stop.png")
16
17image_r = image.resize((width,height), Image.LANCZOS)
18# Image.BICUBIC is another option
19image_bw = image_r.convert("1")
20
21device.display(image_bw)
22
23sleep(10)

dog_display_window_and_oled.py

TEXT
1from luma.core.interface.serial import i2c, spi, pcf8574
2from luma.core.interface.parallel import bitbang_6800
3from luma.core.render import canvas
4from luma.oled.device import ssd1306, ssd1309, ssd1325, ssd1331, sh1106, sh1107
5
6from time import sleep
7
8import cv2
9
10# OpenCV follows BGR color convention and PIL follows RGB color convention
11
12# Python Imaging Library
13from PIL import Image
14
15serial = i2c(port=1, address=0x3C)
16device = sh1106(serial)
17
18width =  device.width
19height = device.height
20
21cap = cv2.VideoCapture("dog.mp4")
22while True:
23    ret, frame = cap.read()
24    if not ret:
25        break
26    cv2.imshow("Img", frame)
27    
28    color_coverted = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
29    pil_image = Image.fromarray(color_coverted)
30    image_r = pil_image.resize((width,height), Image.LANCZOS) 
31    # Image.BICUBIC is another option
32    image_bw = image_r.convert("1")
33
34    device.display(image_bw)
35
36    key = cv2.waitKey(1)
37    if key == 27:
38        break
39        
40cap.release()
41cv2.destroyAllWindows()

webcam_display_window_and_oled.py

TEXT
1...
2cap = cv2.VideoCapture(0)
3...