Small displays
I wanted a small display to show the status of CamillaDSP in my set-up. The excellent guide on https://github.com/mdsimon2/RPi-CamillaDSP (and the related forum thread about the guide) pointed me to a suitable one. I have written my own driver code for it using the Luma library. I wanted to connect the display with SPI rather than a parallel bus.
Demo video
Impression of screens my driver can create. This is with the 4-wire SPI interface:
This is with my driver and 6800 parallel interface:
Character and graphical displays
The displays on this page are graphical, meaning that they can display any bitmap image. Another category of displays is character displays with a built-in font and fixed row(s) where the text is displayed. They are easier to write a low-level driver for, but you're limited in what can be shown. By using Luma it's not very hard to use a graphical display either and it's more flexible.
Display from Audiophonics
The manufacturer of the circuit board is unknown, but it is clear which display and driver chip are used. Its features:
- 256×64 pixels
- 16 grayscale levels
- Display is about 8×2 cm (the portion with pixels)
- SSD1322 driver chip
This one can be bought on: www.audiophonics.fr The screen has white pixels. Make sure to also order some jumper wires to connect it to the Raspberry Pi. This webshop only offers this board with a “4-SPI” interface, but that is the best option.
Technical details: The interface type can be changed by yourself, but it does require soldering. It can be done in exactly the same way as for the display shown below.
I've tried this display with an SPI interface. At max contrast this display makes some noise (sounds like coil whine) that is audible in a quiet room at 3 m distance. If the contrast is halved in software (level 120/255), it is not audible anymore from 20 cm distance. It might be permanently fixable by applying super glue on the coil at the back. I haven't tried that.
Display from EastRising
The display and the driver chip are the same as the previous one (so they are software compatible), but the circuit board is different.
This is the EastRising ER-OLEDM032-1W and can be bought on: www.buydisplay.com (white pixels). They also offer a version with blue, yellow and green pixels. Make sure to also order plenty jumper wires to connect it to the Raspberry Pi. (Warning: option “Dupont Wire for Raspberry Pi” on the webshop is a set of 7 wires, which is only just enough for SPI and not enough for parallel.) This webshop allows you to choose the interface type you want. I recommend the 4-wire SPI interface. See also my recommendations below.
Technical details: The interface type can be changed by yourself, but it requires soldering. You need to move 0Ω resistors on the back of the display's circuit board. This interfacing document (from the webshop) shows an overview of where the 0Ω resistors should be connected to select the different interface types. Locations R18, R19, R20, R21 are labeled on both this circuit board and the one from Audiophonics.
SSD1322 chip
Interface types
I've tried both the 4-wire SPI interface and 6800 parallel interface on a Raspberry Pi 5 with an unmodified Luma library. You can see a video demo of both above. The SPI interface is the clear winner. It's much faster and I can show a pretty smooth spectrum analyzer and other animations. The parallel interface is fine enough for mostly static screens (with status and volume), but is too slow for a spectrum analyzer to be usable.
It might be possible to speed up the communication for 6800. I have not fully investigated that. Python is relatively slow for bit banging, which doesn't help. A potential fast way for the Pi 5 specifically is using its PIO controller. What is clear is that it is much easier to get fast communication with SPI, which should be working for both the Pi 4 (not tested yet) and Pi 5.
Type | Description |
---|---|
6800 parallel |
|
8080 parallel |
Technical details: It seems doable to add support to Luma. It is almost the same as 6800 with a minor difference in the use of the pins. See the datasheet. |
3-wire SPI |
Technical details: It involves sending 9 bits per SPI frame. The first bit does the same as the D/C pin in the “4-pin SPI” interface. See the datasheet. It looks like 9-bit SPI frames are supported by the SPI controller in the Pi 4 (is shown in documentation) and Pi 5 (kernel driver sets “Data Frame Size” in controller register CTRLR0). The Python spidev library accepts bits_per_word=8..32. So it might work at a hardware and kernel driver level. Luma seems to assume 8-bit SPI frames and a D/C pin though. That would need to be changed. As a back-up option you could always use bit banging, but that would be slower than 6800 or 8080. |
4-wire SPI |
Technical details: The name “4-wire SPI” is rather confusing/bad. There are actually only 3 SPI pins (clock, select and data towards the display). They are likely referring to the D/C pin as the fourth pin, which won't be connected to the SPI controller of the Raspberry Pi, but to any random GPIO pin. |
Connecting the Pi
You can connect either display as follows if you use the “4-wire SPI” interface. You need to pick one specific SPI interface/controller on the Raspberry Pi. By SPIx I mean that you need to consistently use e.g. SPI0 or SPI1 for all those pins.
Display board pin | Pi 4 pin | Pi 5 pin |
---|---|---|
1 = ground | Any ground pin | Any ground pin |
2 = power | 3.3V or 5V pin | 3.3V or 5V pin |
4 = SPI clock | SPIx_SCLK | SPIx_SCLK |
5 = SPI data | SPIx_MOSI | SPIx_SIO[0] |
14 = D/C (0=command, 1=data) | Any free GPIO pin | Any free GPIO pin |
15 = RST (0=reset display) | Any free GPIO pin | Any free GPIO pin |
16 = SPI select | SPIx_CE0_N | SPIx_CSn[0] |
If you use a parallel interface, then connect power and ground the same way. The R/W# pin must be connected to ground on the Raspberry Pi to permanently select writing to the display. (Is explained in the datasheet.) All the other display pins can be connected to any free GPIO pin of the Pi.
See also Pinning & interfaces for an overview of the pins of the Raspberry Pi and links to the official documentation. You need to pick pins that are not occupied yet in your situation. If you have a HAT connected to the Pi, then you need to check in the documentation of that HAT which GPIO pins are used by the HAT to figure out which are still free to use for the display.
If you want to use SPI, then you need to enable one of the SPI controllers in the Raspberry Pi by using overlays. See page Linux: overlays about how to use them. I enabled interface SPI0 on my Raspberry Pi 5 by using overlay “spi0-1cs”. Those pins were still free with the HiFiBerry DAC8x HAT attached in my set-up.
Your user in Linux needs to be added to these groups to have access to the GPIO pins and SPI interfaces/controllers. (See also Linux:users for more about Linux groups and Linux groups for Raspberry Pi OS for other relevant groups.)
sudo usermod -a -G spi,gpio $(whoami)
Hardware support in the Pi
Raspberry Pi | 6800 parallel | SPI |
---|---|---|
Pi 4 | bit banging via GPIO | 2 SPI controllers in BCM2711 chip |
Pi 5 | bit banging via GPIO | 6 SPI controllers in RP1 chip |
Performance when driving the display with Luma:
Luma library
The Luma library for Python is convenient for using displays with the SSD1322 and similar chips. It supports:
- Control display settings: contrast, sleep mode
- Drawing shapes and text (using a font)
- Image manipulation (resize, rotate and much more)
- Loading image file
- Only updates changed parts of the screen to improve performance
Multiple libraries are used. The bottom rows show the Linux kernel interface and hardware.
python3-rpi-lgpio for Pi4/5") d2("python3-spidev") space k1("With rpi.gpio: sysfs
With lgpio: /dev/gpiochip") k2("kernel driver spidev") space pi1("Hardware:
Pi4/5 GPIO pins") pi2("Hardware:
Pi4/5 SPI controller") classDef hw_class fill:#EACCB9 class pi1,pi2 hw_class
The components are (the links lead to their documentation):
- Python class my_oled_driver: Because I'm very good at naming things, this is my code that uses Luma and draws things that are useful for my set-up.
- luma.oled: Gives support for specific OLED display chips.
- luma.core: The backbone.
- Pillow: A fork/branch of the Python Image Library (PIL) for drawing shapes, fonts and doing image manipulation.
- python3-rpi.gpio: Library for the GPIO pins. Does not support the Raspberry Pi 5.2)
- python3-rpi-lgpio: Library for the GPIO pins that supports both the Pi 4 and 5. Talks to the kernel driver that Raspberry recommends.
- spidev: Library for the SPI interface. Talks to Linux kernel driver spidev which in turn supports the SPI controllers in the Raspberry Pi 4 and 5.
Installing Luma
# Install luma.oled, luma.core, pil and spidev:
sudo apt-get install python3-luma.oled
# For GPIO pins on Raspberry Pi 4 or 5:
sudo apt-get remove python3-rpi.gpio
sudo apt-get install python3-rpi-lgpio
# Alternatively you can use this instead on a Pi 4 (but not on Pi 5):
sudo apt-get install python3-rpi.gpio
sudo apt-get remove python3-rpi-lgpio
You must not have python3-rpi.gpio and python3-rpi-lgpio installed at the same time.3)
Download my driver code
You can upload it from Windows to the Pi with WinSCP and extract the archive as explained here. You could also download it directly in Linux with:
curl https://www.jarkko.nl/dokuwiki/_media/raspberry_pi/my_oled_driver_v1.1.tar.gz -O
The scripts inside:
- In my_oled_driver.py: Open this file and change the interface type (it supports 4-wire SPI and 6800 parallel) and GPIO numbers to match how you connected the display to your Raspberry Pi. All class functions are documented inside this file. You are free to modify this code to change it to your needs.
- In my_oled_driver_demo.py: You can execute this to check whether it is working. It should show various things on the display. It also serves as example code to show how my class can be used in your own code.
The fonts inside:
- They are expected to be in directory ~/fonts (in your home directory in Linux).
- Font awesome comes from https://fontawesome.com. It is filled with icons, including mute, pause, play, backward, forward and more useful ones for audio applications. See the notes inside my_oled_driver_demo.py about how you can use them.
- Font Iosevka comes from https://www.nerdfonts.com and is narrow, which makes it suitable to show the volume on the display.
To get the other fonts that are referenced in my code:
sudo apt-get install ttf-mscorefonts-installer
sudo apt-get install ttf-bitstream-vera
sudo apt-get install fonts-liberation
sudo apt-get install fonts-dejavu-core
Rewritten oled.py from mdsimon2
As an example of what can be done with my driver, this is a rewritten version of oled.py from mdsimon2 on github. The original version contains a low-level driver for the OLED display (supporting 6800). This version only has the control logic left to poll CamillaDSP and update the display in case of any change in volume or state. All low-level driver code is offloaded to Luma. As a new feature it shows a mute icon when CamillaDSP is muted and you can choose to have either 2 or 3 status lines.
It can be downloaded directly in Linux with:
curl https://www.jarkko.nl/dokuwiki/_media/raspberry_pi/mdsimon2_plus_my_oled_driver.py -O
This works very well with an SPI interface. I have not yet compared whether there is a difference in performance for a 6800 parallel connection.
Other example code
- https://github.com/mdsimon2/RPi-CamillaDSP (for 6800 parallel interface, written in Python)
- https://github.com/topherCantrell/EROLEDM0321 (for SPI interface, written in Python)
- https://www.buydisplay.com/white-3-2-inch-arduino-raspberry-pi-oled-display-module-256x64-spi (for SPI interface, written in C)
- https://github.com/rm-hull/luma.examples (Example code for Luma)