CircuitPython Code

Do not update more than once every 180 seconds or you may permanently damage the display

CircuitPython Microcontroller Wiring

Using eInk displays with displayio is really easy. First, wire up your eInk breakout as shown below. All displays have the same pinout, so if your display differs from the one in the Fritzing diagram, you can wire it up the same way.

Breakout Wiring

  • Feather 3V to display VIN
  • Feather GND to display GND
  • Feather SCK to display SCK
  • Feather MOSI to display MOSI
  • Feather D10 to display D/C
  • Feather D9 to display ECS
  • Feather D6 to display BUSY
  • Feather D5 to display RST

FeatherWing Wiring

To use the eInk displays with displayio, you will need to use the latest version of CircuitPython 5.0.

CircuitPython eInk displayio Library Installation

To use displayio, you will need to install the appropriate library for your display. 

First make sure you are running the latest version of Adafruit CircuitPython for your board. You will need the latest version of CircuitPython 5.0. Even though it is in Alpha, it has been very stable.

Next you'll need to install the necessary libraries to use the hardware--carefully follow the steps to find and install these libraries from Adafruit's CircuitPython library bundle.  Our introduction guide has a great page on how to install the library bundle for both express and non-express boards.

You will need to copy the appropriate displayio driver from the bundle lib folder to a lib folder on your CIRCUITPY drive. The displayio driver contains the initialization codes specific to your display that are needed to for it to work. Since there is more than one driver, you will need to copy the correct file over. Here is a list of each of the displays and the correct driver for that display.

Adafruit_CircuitPython_IL0373

  • 1.54” Tri-Color eInk
  • 2.13” Tri-Color eInk
  • 2.13” Tri-Color eInk FeatherWing
  • 2.13” Flexible Monochrome eInk
  • 2.9” Flexible Monochrome eInk
  • 2.9” Tri-Color eInk

Copy the adafruit_il0373.mpy file from the bundle to the lib folder on your CIRCUITPY drive.

Adafruit_CircuitPython_SSD1608

  • 1.54” Monochrome eInk

Copy the adafruit_ssd1608.mpy file from the bundle to the lib folder on your CIRCUITPY drive.

Adafruit_CircuitPython_SSD1675

  • 2.13” Monochrome eInk
  • 2.13 Monochrome eInk FeatherWing

Copy the adafruit_ssd1675.mpy file from the bundle to the lib folder on your CIRCUITPY drive.

Adafruit_CircuitPython_IL91874

  • 2.7” Tri-Color eInk

Copy the adafruit_il91874.mpy file from the bundle to the lib folder on your CIRCUITPY drive.

Adafruit_CircuitPython_IL0398

  • 4.2” Tri-Color eInk

Copy the adafruit_il0398.mpy file from the bundle to the lib folder on your CIRCUITPY drive.

Usage

To show you how to use the eInk with displayio, we'll show you how to draw a bitmap onto it. First start by downloading display-ruler.bmp

Next copy display-ruler.bmp into the root directory of your CIRCUITPY drive.

In the examples folder for your displayio driver, there should be a test for your display, which will all be similar, but include specific parameters such as the width and height of the display. In this example, we will examine the 2.9" Tri-color breakout test. Here is the code in its entirety.

This code is specific to the 2.9" breakout and may not work with other displays! Look at the CircuitPython Bundle for examples specific to your display.
Download: file
import time
import board
import displayio

# Make sure your display driver is uncommented
import adafruit_il0373
#import adafruit_il91874
#import adafruit_ssd1608
#import adafruit_ssd1675
#import adafruit_il0398

# Set based on your display
FLEXIBLE = False
TRICOLOR = True
ROTATION = 90

# Used to ensure the display is free in CircuitPython
displayio.release_displays()

# Define the pins needed for display use
# This pinout is for a Feather M4 and may be different for other boards
# For the Metro/Shield, esc is board.D10 and dc is board.D9
spi = board.SPI()  # Uses SCK and MOSI
ecs = board.D9
dc = board.D10
rst = board.D5    # set to None for FeatherWing/Shield
busy = board.D6   # set to None for FeatherWing/Shield

if TRICOLOR:
    highlight = 0xff0000 #third color is red (0xff0000)
else:
    highlight = 0x000000

# Create the displayio connection to the display pins
display_bus = displayio.FourWire(spi, command=dc, chip_select=ecs,
                                 reset=rst, baudrate=1000000)

time.sleep(1)  # Wait a bit

# Create the display object
#display = adafruit_ssd1608.SSD1608(display_bus, width=200, height=200,   # 1.54" HD Monochrome
#display = adafruit_ssd1675.SSD1675(display_bus, width=122, height=250,   # 2.13" HD Monochrome
#display = adafruit_il91874.IL91874(display_bus, width=264, height=176,   # 2.7" Tri-color
#display = adafruit_il0398.IL0398(display_bus, width=400, height=300,     # 4.2" Tri-color
#display = adafruit_il0373.IL0373(display_bus, width=152, height=152,     # 1.54" Tri-color
#display = adafruit_il0373.IL0373(display_bus, width=296, height=128, swap_rams=FLEXIBLE, # 2.9" Tri-color OR Flexible Monochrome
display = adafruit_il0373.IL0373(display_bus, width=212, height=104, swap_rams=FLEXIBLE, # 2.13" Tri-color OR Flexible Monochrome
                                 busy_pin=busy, rotation=ROTATION, 
                                 highlight_color=highlight)

# Create a display group for our screen objects
g = displayio.Group()

# Display a ruler graphic from the root directory of the CIRCUITPY drive
f = open("/display-ruler.bmp", "rb")

pic = displayio.OnDiskBitmap(f)
# Create a Tilegrid with the bitmap and put in the displayio group
t = displayio.TileGrid(pic, pixel_shader=displayio.ColorConverter())
g.append(t)

# Place the display group on the screen
display.show(g)

# Refresh the display to have it actually show the image
# NOTE: Do not refresh eInk displays sooner than 180 seconds
display.refresh()
print("refreshed")

time.sleep(180)

We start by importing the libraries that we need. In this case we need time for adding delays, board the pin definitions, and of course displayio.

Download: file
import time
import board
import displayio

Next you want to uncomment the import statement for the correct driver for your display. This should match the file you copied over earlier. In our case, the 2.9" uses the adafruit_il0373 driver, so we can leave it as is.

Download: file
# Make sure your display driver is uncommented
import adafruit_il0373
#import adafruit_il91874
#import adafruit_ssd1608
#import adafruit_ssd1675
#import adafruit_il0398

Next we want to set these variables based on your display. If you have a flexible display, you would want to change FLEXIBLE to True. If you have a monochrome display, you would want to change TRICOLOR to False. If you would like to change the rotation, you can do that here as well.

Download: file
# Set based on your display
FLEXIBLE = False
TRICOLOR = True
ROTATION = 90

Next we release any previously used displays. This is important because if the Feather is reset, the display pins are not automatically released and this makes them available for use again.

Download: file
displayio.release_displays()

Next we assign the Pins to use. Note that we are not using the SRAM on the eInk display, so we only need to connect the SCK and MOSI SPI pins. We set the SPI object to the board's SPI with the easy shortcut function board.SPI(). We also have the ePaper Display Chip Select and Data/Command pins.

For the breakout boards only, we define the Reset and Busy pins, otherwise you would change these to None in the case of a shield or FeatherWing.

Download: file
spi = board.SPI()  # Uses SCK and MOSI
ecs = board.D9
dc = board.D10
rst = board.D5    # can be None to not use this pin
busy = board.D6   # can be None to not use this pin

In the next section, we set the highlight color to either red or black based on whether you have a monochrome or tri-color display. You can leave this alone.

Download: file
if TRICOLOR:
    highlight = 0xff0000 #third color is red (0xff0000)
else:
    highlight = 0x000000

In the next line, we set the display bus to FourWire which makes use of the SPI bus. We pass it the D/C, and CS pins, which are also usually found on TFT displays and if this is a breakout, we also pass in the reset pin.

We set the baudrate to 1 MHz instead of the default 24 MHz because the ePaper displays are not about the speed. They are about the patience of waiting many seconds for them to change and the infrequent updates.

After that, we pause for 1 second. Remember, patience.

Download: file
display_bus = displayio.FourWire(spi, command=epd_dc, chip_select=epd_cs,
                                 reset=epd_reset, baudrate=1000000)
time.sleep(1)

Next is the initializer. You will want to uncomment the one appropriate to your display. For the 2.9" display, we would want to comment out the line with 2.13" Tri-color OR Flexible Monochrome next to it and uncomment the line with 2.9" Tri-color OR Flexible Monochrome next to it.

Download: file
# Create the display object
#display = adafruit_ssd1608.SSD1608(display_bus, width=200, height=200,   # 1.54" HD Monochrome
#display = adafruit_ssd1675.SSD1675(display_bus, width=122, height=250,   # 2.13" HD Monochrome
#display = adafruit_il91874.IL91874(display_bus, width=264, height=176,   # 2.7" Tri-color
#display = adafruit_il0398.IL0398(display_bus, width=400, height=300,     # 4.2" Tri-color
#display = adafruit_il0373.IL0373(display_bus, width=152, height=152,     # 1.54" Tri-color
#display = adafruit_il0373.IL0373(display_bus, width=296, height=128, swap_rams=FLEXIBLE, # 2.9" Tri-color OR Flexible Monochrome
display = adafruit_il0373.IL0373(display_bus, width=212, height=104, swap_rams=FLEXIBLE, # 2.13" Tri-color OR Flexible Monochrome
                                 busy_pin=busy, rotation=ROTATION, 
                                 highlight_color=highlight)

Next we create a couple of variables including a displayio group and a file handle to the display-ruler.bmp that you placed in your CIRCUITPY root folder. You did do that, right?

Download: file
# Create a display group for our screen objects
g = displayio.Group()

# Display a ruler graphic from the root directory of the CIRCUITPY drive
f = open("/display-ruler.bmp", "rb")

Next we take the file handle and read the bitmap data into a TileGrid object. We also specify the pixel_shader to displayio.ColorConverter() because we want displayio to convert the image data into something that will look nice on the eInk. We take the TileGrid object and place it into the group.

Download: file
pic = displayio.OnDiskBitmap(f)
# Create a Tilegrid with the bitmap and put in the displayio group
t = displayio.TileGrid(pic, pixel_shader=displayio.ColorConverter())
g.append(t)

In the next line we tell the display to show everything in the group.

Download: file
display.show(g)

Finally, we tell the display to refresh so that everything in memory is written out to the display. 

Download: file
display.refresh()
print("refreshed")

Your display will look something like this:

After that we tell it to pause for 180 seconds or three minutes before continuing where your display would show the REPL.

Download: file
time.sleep(180)
This guide was first published on Jul 18, 2018. It was last updated on Jul 18, 2018. This page (CircuitPython Code) was last updated on Nov 12, 2019.