After you've followed the steps on the Python Setup page, you can get started with using the 2.13" 250x122 Quad-Color eInk display with the Adafruit CircuitPython EPD library and a Raspberry Pi single-board computer.
Note this is not a kernel driver that will let you have the console appear on the eInk. However, this is handy when you want to use the eInk display purely from 'user Python' code!
You can only use this technique with Linux/computer devices that have hardware SPI support, and not all single board computers have an SPI device, so check before continuing
Python Wiring
The following is the display connected to a Raspberry Pi with an EYESPI Pi Beret using the EYESPI connector:
Plug the EYESPI Pi Beret into the Raspberry Pi 2x20 header. It has the following pin connections:
- Pi 3.3V to breakout Vin
- Pi GND to breakout Gnd
- Pi SCK to breakout SCK
- Pi MOSI to breakout MOSI
- Pi MISO to breakout MISO
- Pi GPIO 27 to breakout RST
- Pi GPIO 25 to breakout DC
- Pi GPIO CE0 to breakout CS
- Pi GPIO 17 to breakout BUSY
Attach the eInk display to the EYESPI breakout with an EYESPI cable as described on the Plugging in an EYESPI Cable page.
The following is the breakout wired to a Raspberry Pi using a solderless breadboard:
- Pi 3.3V to breakout Vin (red wire)
- Pi GND to breakout Gnd (black wire)
- Pi SCK to breakout SCK (yellow wire)
- Pi MOSI to breakout MOSI (blue wire)
- Pi MISO to breakout MISO (green wire)
- Pi GPIO 27 to breakout RST (orange wire)
- Pi GPIO 25 to breakout DC (pink wire)
- Pi GPIO CE0 to breakout CS (purple wire)
- Pi GPIO 17 to breakout BUSY (white wire)
Pillow Graphics Demo
The great part about using a display on a Raspberry Pi is that you can use Pillow graphics alongside the CircuitPython driver.
The following example uses Pillow for text and drawing shapes. Copy or download the following example to your computer, and run the following, replacing code.py with whatever you named the file:
python3 code.py
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT
"""Blinka EPD Demo for the Quad Color eInk"""
import board
import digitalio
from PIL import Image, ImageDraw, ImageFont
from adafruit_epd.epd import Adafruit_EPD
from adafruit_epd.jd79661 import Adafruit_JD79661
# create the spi device and pins we will need
spi = board.SPI()
ecs = digitalio.DigitalInOut(board.CE0)
dc = digitalio.DigitalInOut(board.D25)
srcs = None
rst = digitalio.DigitalInOut(board.D27) # can be None to not use this pin
busy = digitalio.DigitalInOut(board.D17) # can be None to not use this pin
display = Adafruit_JD79661(122, 250, spi,
cs_pin=ecs, dc_pin=dc, sramcs_pin=srcs,
rst_pin=rst, busy_pin=busy)
display.rotation = 3
width = display.width
height = display.height
image = Image.new("RGB", (width, height))
WHITE = (0xFF, 0xFF, 0xFF)
YELLOW = (0xFF, 0xFF, 0x00)
RED = (0xFF, 0x00, 0x00)
BLACK = (0x00, 0x00, 0x00)
# clear the buffer
display.fill(Adafruit_EPD.WHITE)
# Get drawing object to draw on image.
draw = ImageDraw.Draw(image)
# empty it
draw.rectangle((0, 0, width, height), fill=WHITE)
# Draw an outline box
draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE)
# Draw some shapes.
# First define some constants to allow easy resizing of shapes.
padding = 5
shape_width = 30
top = padding
bottom = height - padding
# Move left to right keeping track of the current x position for drawing shapes.
x = padding
# Draw an ellipse.
draw.ellipse((x, top, x + shape_width, bottom), outline=YELLOW, fill=WHITE)
x += shape_width + padding
# Draw a rectangle.
draw.rectangle((x, top, x + shape_width, bottom), outline=RED, fill=BLACK)
x += shape_width + padding
# Draw a triangle.
draw.polygon(
[(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)],
outline=BLACK,
fill=RED,
)
x += shape_width + padding
# Draw an X.
draw.line((x, bottom, x + shape_width, top), fill=YELLOW)
draw.line((x, top, x + shape_width, bottom), fill=YELLOW)
x += shape_width + padding
# Load default font.
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20)
draw.text((x, top), "Hello", font=font, fill=YELLOW)
draw.text((x, top + 20), "World!", font=font, fill=YELLOW)
# Display image.
display.image(image)
display.display()
Pillow Image Demo
Pillow is really useful for displaying image files as well.
The following example uses Pillow to display a .PNG file. The image is available to download here or via the Project Bundle with the code.py file.
Copy or download the following example to your computer, and run the following, replacing code.py with whatever you named the file:
python3 code.py
# SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries
# SPDX-License-Identifier: MIT
"""
Image resizing and drawing using the Pillow Library for Quad Color eInk
"""
import board
import digitalio
from PIL import Image, ImageEnhance
from adafruit_epd.jd79661 import Adafruit_JD79661
# create the spi device and pins we will need
spi = board.SPI()
ecs = digitalio.DigitalInOut(board.CE0)
dc = digitalio.DigitalInOut(board.D25)
srcs = None
rst = digitalio.DigitalInOut(board.D27) # can be None to not use this pin
busy = digitalio.DigitalInOut(board.D17) # can be None to not use this pin
# give them all to our driver
display = Adafruit_JD79661(122, 250, # 2.13" Quad-color display
spi,
cs_pin=ecs,
dc_pin=dc,
sramcs_pin=srcs,
rst_pin=rst,
busy_pin=busy,
)
display.rotation = 3
image = Image.open("blinka.png")
# Scale the image to the smaller screen dimension
image_ratio = image.width / image.height
screen_ratio = display.width / display.height
if screen_ratio < image_ratio:
scaled_width = image.width * display.height // image.height
scaled_height = display.height
else:
scaled_width = display.width
scaled_height = image.height * display.width // image.width
image = image.resize((scaled_width, scaled_height), Image.BICUBIC)
# Crop and center the image
x = scaled_width // 2 - display.width // 2
y = scaled_height // 2 - display.height // 2
image = image.crop((x, y, x + display.width, y + display.height)).convert("RGB")
quad_colors = [
(0, 0, 0), # Black
(255, 255, 255), # White
(255, 0, 0), # Red
(255, 255, 0), # Yellow
]
palette_image = Image.new('P', (1, 1))
# Create palette data - PIL expects 768 values (256 colors * 3 channels)
palette_data = []
for color in quad_colors:
palette_data.extend(color)
# Fill remaining palette entries with black
for i in range(4, 256):
palette_data.extend([0, 0, 0])
palette_image.putpalette(palette_data)
enhancer = ImageEnhance.Color(image)
image = enhancer.enhance(1.5)
temp_image = image.quantize(palette=palette_image, dither=Image.Dither.FLOYDSTEINBERG)
pixels = temp_image.load()
width, height = temp_image.size
final_palette = Image.new('P', (1, 1))
final_palette.putpalette(palette_data)
final_image = Image.new('P', (width, height))
final_pixels = final_image.load()
# Copy pixels, ensuring they use indices 0-3
for y in range(height):
for x in range(width):
# Clamp pixel values to 0-3 range
final_pixels[x, y] = min(pixels[x, y], 3)
final_image.putpalette(palette_data)
# Convert back to RGB for display
image = final_image.convert('RGB')
# Display image.
display.image(image)
display.display()
Page last edited August 06, 2025
Text editor powered by tinymce.