Todbot's Displays Tricks

displayio is the native system-level driver for displays in CircuitPython. Several CircuitPython boards (FunHouse, MagTag, PyGamer, CLUE) have displayio-based displays and a built-in board.DISPLAY object that is preconfigured for that display. Or, you can add your own I2C or SPI display.

Get default display and change display rotation

Boards like FunHouse, MagTag, PyGamer, CLUE have built-in displays. display.rotation works with all displays, not just built-in ones.

import board
display = board.DISPLAY
print(display.rotation) # print current rotation
display.rotation = 0    # valid values 0,90,180,270

Display an Image

The adafruit_imageload library makes it easier to load images and display them. The images should be in palettized BMP3 format.

import board
import displayio
import adafruit_imageload

img_filename = "bg_jp200.bmp"
display = board.DISPLAY
img, pal = adafruit_imageload.load(img_filename)
group = displayio.Group()
group.append(displayio.TileGrid(img, pixel_shader=pal))
display.root_group = group

CircuitPython's displayio library works like:

  • an image Bitmap goes inside a TileGrid
  • a TileGrid goes inside a Group
  • the Group is set to be the root group on a Display.

Display Background Bitmap

Useful for display a solid background color that can be quickly changed.

import time, board, displayio
display = board.DISPLAY         # get default display (FunHouse,Pygamer,etc)
maingroup = displayio.Group()   # Create a main group to hold everything
display.root_group = maingroup  # put it on the display

# make bitmap that spans entire display, with 3 colors
background = displayio.Bitmap(display.width, display.height, 3)

# make a 3 color palette to match
mypal = displayio.Palette(3)
mypal[0] = 0x000000 # set colors (black)
mypal[1] = 0x999900 # dark yellow
mypal[2] = 0x009999 # dark cyan

# Put background into main group, using palette to map palette ids to colors
maingroup.append(displayio.TileGrid(background, pixel_shader=mypal))

background.fill(2)  # change background to dark cyan (mypal[2])
background.fill(1)  # change background to dark yellow (mypal[1])

Another way is to use vectorio:

import board, displayio, vectorio

display = board.DISPLAY  # built-in display
maingroup = displayio.Group()  # a main group that holds everything
display.root_group = maingroup

mypal = displayio.Palette(1)
mypal[0] = 0x999900
background = vectorio.Rectangle(

Or can also use adafruit_display_shapes:

import board, displayio
from adafruit_display_shapes.rect import Rect

display = board.DISPLAY
maingroup = displayio.Group()  # a main group that holds everything
display.root_group = maingroup # add main group to display

background = Rect(0,0, display.width, display.height, fill=0x000000 ) # background color

Image Slideshow

import time, board, displayio
import adafruit_imageload

display = board.DISPLAY     # get display object (built-in on some boards)
screen = displayio.Group()  # main group that holds all on-screen content
display.root_group = screen # add it to display

file_names = [ '/images/cat1.bmp', '/images/cat2.bmp' ]  # list of filenames

screen.append(displayio.Group())  # placeholder, will be replaced w/ screen[0] below
while True:
    for fname in file_names:
        image, palette = adafruit_imageload.load(fname)
        screen[0] = displayio.TileGrid(image, pixel_shader=palette)

Note: Images must be in palettized BMP3 format. For more details, see Preparing images for CircuitPython

Dealing with E-Ink "Refresh Too Soon" Error

E-Ink displays are damaged if refreshed too frequently. CircuitPython enforces this, but also provides display.time_to_refresh, the number of seconds you need to wait before the display can be refreshed. One solution is to sleep a little longer than that and you'll never get the error. Another would be to wait for time_to_refresh to go to zero, as shown below.

import time, board, displayio, terminalio
from adafruit_display_text import label
mylabel = label.Label(terminalio.FONT, text="demo", x=20,y=20,
                      background_color=0x000000, color=0xffffff )
display = board.DISPLAY  # e.g. for MagTag
display.root_group = mylabel
while True:
    if display.time_to_refresh == 0:
    mylabel.text = str(time.monotonic())

This guide was first published on Apr 02, 2022. It was last updated on May 15, 2024.

This page (Displays (LCD / OLED / E-Ink) and displayio) was last updated on Mar 23, 2024.

Text editor powered by tinymce.