It's easy to use OLEDs with Python and the Adafruit CircuitPython SSD1305 module. This module allows you to easily write Python code to control the display.
You can use this sensor with any computer that has GPIO and Python thanks to Adafruit_Blinka, our CircuitPython-for-Python compatibility library.
To demonstrate the usage, we'll initialize the library and use Python code to control the OLED from the board's Python REPL.
Since we are running full CPython on our Linux/computer, we can take advantage of the powerful Pillow image drawing library to handle text, shapes, graphics, etc. Pillow is a gold standard in image and graphics handling, you can read about all it can do here.
I2C Initialization
If your display is connected to the board using I2C you'll first need to initialize the I2C bus. First import the necessary modules:
import board import busio
Now for either board run this command to create the I2C instance using the default SCL and SDA pins of your I2C host:
i2c = busio.I2C(board.SCL, board.SDA)
After initializing the I2C interface for your firmware as described above you can create an instance of the SSD1305 I2C driver by running:
import adafruit_ssd1305 oled = adafruit_ssd1305.SSD1305_I2C(128, 64, i2c)
Note that the first two parameters to the SSD1305_I2C
class initializer are the width and height of the display in pixels. Be sure to use the right values for the display you're using!
Changing the I2C address
If you connect Pin #4 of the OLED to +3V instead of Ground the I2C address will be different different (0x3d
):
oled = adafruit_ssd1305.SSD1305_I2C(128, 64, i2c, addr=0x3d)
Adding hardware reset pin
If you have a reset pin, which may be required if your OLED does not have an auto-reset chip, also pass in a reset pin like so:
import digitalio reset_pin = digitalio.DigitalInOut(board.D4) # any pin! oled = adafruit_ssd1305.SSD1305_I2C(128, 32, i2c, reset=reset_pin)
At this point the I2C bus and display are initialized. Skip down to the example code section.
SPI Initialization
If your display is connected to the board using SPI you'll first need to initialize the SPI bus:
import adafruit_ssd1305 import board import busio import digitalio spi = busio.SPI(board.SCK, MOSI=board.MOSI) reset_pin = digitalio.DigitalInOut(board.D4) # any pin! cs_pin = digitalio.DigitalInOut(board.D5) # any pin! dc_pin = digitalio.DigitalInOut(board.D6) # any pin! oled = adafruit_ssd1305.SSD1305_SPI(128, 32, spi, dc_pin, reset_pin, cs_pin)
Note the first two parameters to the SSD1305_SPI
class initializer are the width and height of the display in pixels. Be sure to use the right values for the display you're using!
The next parameters to the initializer are the pins connected to the display's DC, reset, and CS lines in that order. Again make sure to use the right pin names as you have wired up to your board!
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-License-Identifier: MIT """ This demo will fill the screen with white, draw a black box on top and then print Hello World! in the center of the display This example is for use on (Linux) computers that are using CPython with Adafruit Blinka to support CircuitPython libraries. CircuitPython does not support PIL/pillow (python imaging library)! """ import board import digitalio from PIL import Image, ImageDraw, ImageFont import adafruit_ssd1305 # Define the Reset Pin oled_reset = digitalio.DigitalInOut(board.D4) # Change these # to the right size for your display! WIDTH = 128 HEIGHT = 64 # Change to 32 if needed BORDER = 8 # Use for SPI spi = board.SPI() oled_cs = digitalio.DigitalInOut(board.D5) oled_dc = digitalio.DigitalInOut(board.D6) oled = adafruit_ssd1305.SSD1305_SPI(WIDTH, HEIGHT, spi, oled_dc, oled_reset, oled_cs) # Use for I2C. # i2c = board.I2C() # uses board.SCL and board.SDA # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller # oled = adafruit_ssd1305.SSD1305_I2C(WIDTH, HEIGHT, i2c, addr=0x3c, reset=oled_reset) # Clear display. oled.fill(0) oled.show() # Create blank image for drawing. # Make sure to create image with mode '1' for 1-bit color. image = Image.new("1", (oled.width, oled.height)) # Get drawing object to draw on image. draw = ImageDraw.Draw(image) # Draw a white background draw.rectangle((0, 0, oled.width, oled.height), outline=255, fill=255) # Draw a smaller inner rectangle draw.rectangle( (BORDER, BORDER, oled.width - BORDER - 1, oled.height - BORDER - 1), outline=0, fill=0, ) # Load default font. font = ImageFont.load_default() # Draw Some Text text = "Hello World!" (font_width, font_height) = font.getsize(text) draw.text( (oled.width // 2 - font_width // 2, oled.height // 2 - font_height // 2), text, font=font, fill=255, ) # Display image oled.image(image) oled.show()
Let's take a look at the sections of code one by one. We start by importing the board
so that we can initialize SPI, digitalio
, several PIL
modules for Image Drawing, and the adafruit_ssd1305
driver.
import board import digitalio from PIL import Image, ImageDraw, ImageFont import adafruit_ssd1305
Next we define the reset line, which will be used for either SPI or I2C. If your OLED has auto-reset circuitry, you can set the oled_reset
line to None
oled_reset = digitalio.DigitalInOut(board.D4)
In order to make it easy to change display sizes, we'll define a few variables in one spot here. We have the display width, the display height and the border size, which we will explain a little further below. If your display is something different than these numbers, change them to the correct setting. For instance, you may want try changing the border size to 5 if you have a 128x32 display.
WIDTH = 128 HEIGHT = 64 # Change to 32 if needed BORDER = 8
If you're using I2C, you would use this section of code. We set the I2C object to the board's I2C with the easy shortcut function board.I2C()
. By using this function, it finds the SPI module and initializes using the default SPI parameters. We also set up the oled with SSD1305_I2C which makes use of the I2C bus.
# Use for I2C. i2c = board.I2C() oled = adafruit_ssd1305.SSD1305_I2C(WIDTH, HEIGHT, i2c, addr=0x3c, reset=oled_reset)
If you're using SPI, you would use this section of code. We set the SPI object to the board's SPI with the easy shortcut function board.SPI()
. By using this function, it finds the SPI module and initializes using the default SPI parameters. We set the OLED's CS (Chip Select), and DC (Data/Command) pins. We also set up the OLED with SSD1305_SPI which makes use of the SPI bus.
# Use for SPI spi = board.SPI() oled_cs = digitalio.DigitalInOut(board.D5) oled_dc = digitalio.DigitalInOut(board.D6) oled = adafruit_ssd1305.SSD1305_SPI(WIDTH, HEIGHT, spi, oled_dc, oled_reset, oled_cs)
Next we clear the display in case it was initialized with any random artifact data.
# Clear display. oled.fill(0) oled.show()
Next, we need to initialize PIL to create a blank image to draw on. Think of it as a virtual canvas. Since this is a monochrome display, we set it up for 1-bit color, meaning a pixel is either white or black. We can make use of the OLED's width and height properties as well. Optionally, we could have used our WIDTH and HEIGHT variables.
# Create blank image for drawing. # Make sure to create image with mode '1' for 1-bit color. image = Image.new('1', (oled.width, oled.height)) # Get drawing object to draw on image. draw = ImageDraw.Draw(image)
Now we start the actual drawing. Here we are telling it we want to draw a rectangle from (0,0)
, which is the upper left, to the full width and height of the display. We want it both filled in and having an outline of white, so we pass 255 for both numbers.
# Draw a white background draw.rectangle((0, 0, oled.width, oled.height), outline=255, fill=255)
If we ran the code now, it would still show a blank display because we haven't told python to use our virtual canvas yet. You can skip to the end if you would like to see how to do that. This is what our canvas currently looks like in memory.
Next we will create a smaller black rectangle. The easiest way to do this is to draw another rectangle a little smaller than the full screen with no fill or outline and place it in a specific location. In this case, we will create a rectangle that is 5 pixels smaller on each side. This is where the BORDER variable comes into use. It makes calculating the size of the second rectangle much easier. We want the starting coordinate, which consists of the first two parameters, to be our BORDER value. Then for the next two parameters, which are our ending coordinates, we want to subtract our border value from the width and height. Also, because this is a zero-based coordinate system, we also need to subtract 1 from each number.
# Draw a smaller inner rectangle draw.rectangle((BORDER, BORDER, oled.width - BORDER - 1, oled.height - BORDER - 1), outline=0, fill=0)
Here's what our virtual canvas looks like in memory.
Now drawing text with PIL is pretty straightforward. First we start by setting the font to the default system text. After that we define our text and get the size of the text. We're grabbing the size that it would render at so that we can calculate the center position. Finally, we take the font size and screen size to calculate the position we want to draw the text at and it appears in the center of the screen.
# Load default font. font = ImageFont.load_default() # Draw Some Text text = "Hello World!" (font_width, font_height) = font.getsize(text) draw.text((oled.width//2 - font_width//2, oled.height//2 - font_height//2), text, font=font, fill=255)
Finally, we need to display our virtual canvas to the OLED and we do that with 2 commands. First we set the image to the screen, then we tell it to show the image.
# Display image oled.image(image) oled.show()
Here's what the final output should look like.
If you have the 2.3" 128x32 OLED Display, here's what the final output looks like with the height set to 32 and the border size set to 5:
Text editor powered by tinymce.