CircuitPython Grayscale Usage
This page goes over how to use the 2.9" Grayscale eInk displays with CircuitPython.
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.
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. The 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.
SSD1680 Updated Version
If you have the SSD1680 version of the 2.9" Grayscale FeatherWing, use this example code to get started.
# SPDX-FileCopyrightText: 2026 Mikey Sklar, written for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
"""4-gray grayscale for the Adafruit 2.9" SSD1680 eInk FeatherWing (#4777), via adafruit_epd.
The framebuf path (companion to the displayio adafruit_ssd1680 driver). Reach for adafruit_epd
when you want external-SRAM offload or direct framebuffer access. 296x128 GDEM029T94 /
FPC-7519rev.b. Uses the upstream Adafruit_SSD1680_Grayscale4 class (colstart=0 hardcoded, 296
gate handled) — no library change; just vcom=0x24 for this panel.
FeatherWing wiring notes (differ from the #4197 EYESPI breakout):
CS=D9 DC=D10 SCK/MOSI on the shared bus.
BUSY is not connected on the Wing -> busy_pin=None (timed refresh).
RST is on the Feather RESET line, not a GPIO -> the panel can only be woken by a Feather
hardware reset, so we never deep-sleep it (power_down -> no-op). Run after a power-on/reset.
"""
import time
import board
import digitalio
from adafruit_epd.epd import Adafruit_EPD
from adafruit_epd.ssd1680 import Adafruit_SSD1680_Grayscale4
class WingGrayscale4(Adafruit_SSD1680_Grayscale4):
# FeatherWing: RST is on the Feather RESET line, so the panel can't be GPIO-reset to wake
# from deep sleep -> never deep-sleep it.
def power_down(self):
pass
spi = board.SPI()
cs = digitalio.DigitalInOut(board.D9)
dc = digitalio.DigitalInOut(board.D10)
rst = digitalio.DigitalInOut(board.D11) # harmless on the Wing (RST not routed here)
display = WingGrayscale4(
128,
296,
spi,
cs_pin=cs,
dc_pin=dc,
sramcs_pin=None,
rst_pin=rst,
busy_pin=None, # BUSY not connected on the Wing
vcom=0x24, # FPC-7519rev.b (the class default 0x1C is for GDEY0213B74)
)
display.rotation = 3 # landscape; matches the displayio driver's 270
W = display.width
print("Init OK — drawing 4-gray info card...")
display.fill(Adafruit_EPD.WHITE)
display.text("Adafruit ThinkInk", 6, 6, Adafruit_EPD.BLACK, size=2)
display.text('2.9" 296x128', 6, 28, Adafruit_EPD.BLACK, size=2)
display.text("4-Gray E-Ink", 6, 50, Adafruit_EPD.DARK, size=2)
display.text("SSD1680 #4777", 6, 74, Adafruit_EPD.BLACK, size=1)
# 4-level gray ramp across the bottom: black | dark | light | white
RAMP_TOP, RAMP_H = 100, 24
SEG = W // 4
ramp = (Adafruit_EPD.BLACK, Adafruit_EPD.DARK, Adafruit_EPD.LIGHT, Adafruit_EPD.WHITE)
for i, color in enumerate(ramp):
x = i * SEG
display.fill_rect(x, RAMP_TOP, SEG if i < 3 else W - x, RAMP_H, color)
display.rect(0, RAMP_TOP, W, RAMP_H, Adafruit_EPD.BLACK)
for i in range(1, 4):
display.vline(i * SEG, RAMP_TOP, RAMP_H, Adafruit_EPD.BLACK)
print("Refreshing...")
t0 = time.monotonic()
display.display()
print(f"Done in {time.monotonic() - t0:.1f}s")
displayio. See the Support Matrix to determine if displayio is available on a given board: https://circuitpython.readthedocs.io/en/latest/shared-bindings/support_matrix.html
Adafruit_CircuitPython_IL0373
The GrayScale FeatherWings use the Adafruit_CircuitPython_IL0373 library. To easily get all the required files and libraries, you can click the Download Project Bundle link at the top of the example code below. Just unzip, open the folder that corresponds to the version of CircuitPython you have installed, and copy the contents to the CIRCUITPY drive.
Image File
To show you how to use the eInk with displayio, you'll draw a bitmap onto it. First start by downloading display-ruler.bmp
Copy display-ruler.bmp into the root directory of your CIRCUITPY drive.
Grayscale Display Usage
In the examples folder for your IL0373 displayio driver, there should be a test for your display which is listed here:
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT
"""Simple test script for 2.9" 296x128 grayscale display.
Supported products:
* Adafruit 2.9" Grayscale
* https://www.adafruit.com/product/4777
"""
import time
import board
import busio
import displayio
import fourwire
import adafruit_il0373
displayio.release_displays()
# This pinout works on a Feather M4 and may need to be altered for other boards.
spi = busio.SPI(board.SCK, board.MOSI) # Uses SCK and MOSI
epd_cs = board.D9
epd_dc = board.D10
display_bus = fourwire.FourWire(spi, command=epd_dc, chip_select=epd_cs, baudrate=1000000)
time.sleep(1)
display = adafruit_il0373.IL0373(
display_bus,
width=296,
height=128,
rotation=270,
black_bits_inverted=False,
color_bits_inverted=False,
grayscale=True,
refresh_time=1,
)
g = displayio.Group()
pic = displayio.OnDiskBitmap("/display-ruler.bmp")
t = displayio.TileGrid(pic, pixel_shader=pic.pixel_shader)
g.append(t)
display.root_group = g
display.refresh()
print("refreshed")
time.sleep(120)
You will want to change the epd_reset and epd_busy to the correct values. If you wired it up as shown on the Wiring page, you will want to change it to these values:
epd_reset = board.D8 epd_busy = board.D7
Save it to your CIRCUITPY drive as code.py and it should automatically run. Your display will look something like this:
Page last edited July 06, 2026
Text editor powered by tinymce.