Example: A Name Badge

The final example displays text over a bitmap on the eInk display, making a name badge useful for gatherings or conferences.

Images

This example uses a square picture file in BMP format to display on the left side of the display. It could be someone's picture, a logo, or other art.

For using the 2.13" display with a height of 104 pixels, make your image 104x104.

For using the 2.7" display with a height of 176 pixels, make your image 176x176.

As the eInk display can only use 3 colors, see the companion guide Preparing Graphics for E-Ink Displays. You may have to play with images to see how they might display best on your chosen display.

Here are sample pictures used with the examples. For the 2.13" display, use the smaller picture and for the 2.7" shield, use the larger picture. Copy the image to the board's CIRCUITPY drive as picture.bmp.

Code

The code below will display a square picture on the left and use the internal terminalio font to place two small lines of text on the right of the eInk display. You can set the foreground and background color. See the comments for how each step contributes to the process.

Please select the code specific to your display and microcontroller as the two code blocks below are not interchangeable for both sets of hardware. The examples are nearly identical though.

The 2.13" display shows more of a true red color and the 2.7" display uses more of a pinkish red. It is all based on how the displays are manufactured and not color issues with the display itself. Please factor this into your planning for color choices.

2.13" eInk FeatherWing Example

The pins reflect the combination of the FeatherWing eInk display and a Feather M4. It also has the pixel dimensions for the 2.13" display.

"""
Simple badge script for Adafruit 2.13" 212x104 tri-color display
Supported products:
  * Adafruit 2.13" Tri-Color Display Breakout
  * https://www.adafruit.com/product/4086 (breakout) or
  * https://www.adafruit.com/product/4128 (FeatherWing)

  This program requires the adafruit_il0373 library and the
  adafruit_display_text library in the CIRCUITPY /lib folder
  for CircuitPython 5.0 and above which has displayio support.
"""

import time
import board
import displayio
import adafruit_il0373
import terminalio
from adafruit_display_text import label

BLACK = 0x000000
WHITE = 0xFFFFFF
RED = 0xFF0000

# Change text colors, choose from the following values:
# BLACK, RED, WHITE

TEXT_COLOR = BLACK
BACKGROUND_COLOR = WHITE

# 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
spi = board.SPI()  # Uses SCK and MOSI
epd_cs = board.D9
epd_dc = board.D10
epd_reset = board.D5
epd_busy = board.D6

# Create the displayio connection to the display pins
display_bus = displayio.FourWire(spi, command=epd_dc, chip_select=epd_cs,
                                 reset=epd_reset, baudrate=1000000)
time.sleep(1)  # Wait a bit

DISPLAY_WIDTH = 212
DISPLAY_HEIGHT = 104
# Create the display object - the third color is red (0xff0000)
display = adafruit_il0373.IL0373(display_bus, width=DISPLAY_WIDTH,
                                 height=DISPLAY_HEIGHT,
                                 rotation=90, busy_pin=epd_busy,
                                 highlight_color=0xff0000)

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

# Set a background
background_bitmap = displayio.Bitmap(DISPLAY_WIDTH, DISPLAY_HEIGHT, 1)
# Map colors in a palette
palette = displayio.Palette(1)
palette[0] = BACKGROUND_COLOR

# Put the background into the display group
bg_sprite = displayio.TileGrid(background_bitmap,
                               pixel_shader=palette,
                               x=0, y=0)
g.append(bg_sprite)

# Display a picture from the root directory of the CIRCUITPY drive
# Picture should be HEIGHTxHEIGHT square idealy for a portrait
# But could be the entire WIDTHxHEIGHT for a non-portrait
f = open("/picture.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)

# Draw simple text using the built-in font into a displayio group
# For smaller text, change scale=2 to scale=1
text_group = displayio.Group(max_size=10, scale=2,
                             x=DISPLAY_HEIGHT + 10,
                             y=int(DISPLAY_HEIGHT/2) - 13)
first_name = "Limor"
text_area = label.Label(terminalio.FONT, text=first_name,
                        color=TEXT_COLOR)
text_group.append(text_area)  # Add this text to the text group
g.append(text_group)

# Draw simple text using the built-in font into a displayio group
text_group = displayio.Group(max_size=10, scale=2,
                             x=DISPLAY_HEIGHT + 10,
                             y=int(DISPLAY_HEIGHT/2) + 13)
last_name = "Ladyada"
text_area = label.Label(terminalio.FONT, text=last_name,
                        color=TEXT_COLOR)
text_group.append(text_area)  # Add this text to the text group
g.append(text_group)

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

# Refresh the display to have it actually show
# NOTE: Do not refresh eInk displays more often than 180 seconds!
display.refresh()

# Wait the minimum 3 minutes between refreshes. Then loop to freeze.
time.sleep(180)
while True:
    pass

2.7" eInk Shield Example

The pins reflect the combination of the shield eInk display and a Metro M4. It has the pixel dimensions of the 2.7" display.

"""
Simple Badge script for a 2.7" 264x176 Tri-Color eInk display shield
  Supported products:
  * Adafruit 2.7" Tri-Color ePaper Display Shield
    https://www.adafruit.com/product/4229

  This program requires the adafruit_il91874 and the
  adafruit_display_text library in /lib on the CIRCUITPY drive
  for CircuitPython 5.0 and above which has displayio support.
"""

import time
import board
import displayio
import adafruit_il91874
import terminalio
from adafruit_display_text import label

BLACK = 0x000000
WHITE = 0xFFFFFF
RED = 0xFF0000

# Change text colors, choose from the following values:
# BLACK, RED, WHITE

TEXT_COLOR = BLACK
BACKGROUND_COLOR = WHITE

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

# Define the pins needed for display use on the Metro
spi = board.SPI()
epd_cs = board.D10
epd_dc = board.D9

# Create the displayio connection to the display pins
display_bus = displayio.FourWire(spi, command=epd_dc, chip_select=epd_cs,
                                 baudrate=1000000)
time.sleep(1)  # Wait a bit

DISPLAY_WIDTH = 264
DISPLAY_HEIGHT = 176
# Create the display object - the third color is red (0xff0000)
display = adafruit_il91874.IL91874(display_bus, width=DISPLAY_WIDTH,
                                   height=DISPLAY_HEIGHT,
                                   highlight_color=0xff0000, rotation=90)

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

# Set a background
background_bitmap = displayio.Bitmap(DISPLAY_WIDTH, DISPLAY_HEIGHT, 1)
# Map colors in a palette
palette = displayio.Palette(1)
palette[0] = BACKGROUND_COLOR

# Put the background into the display group
bg_sprite = displayio.TileGrid(background_bitmap,
                               pixel_shader=palette,
                               x=0, y=0)

g.append(bg_sprite)

# Display a picture from the root directory of the CIRCUITPY drive
# Picture should be HEIGHTxHEIGHT square idealy for a portrait
# But could be the entire WIDTHxHEIGHT for a non-portrait
f = open("/picture.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)

# Draw simple text using the built-in font into a displayio group
# For smaller text, change scale=2 to scale=1 as scale 2 doesn't
# allow for much text but the text is bigger.
text_group = displayio.Group(max_size=10, scale=2,
                             x=DISPLAY_HEIGHT + 5,
                             y=int(DISPLAY_HEIGHT/2) - 13)
first_name = "Limor"
text_area = label.Label(terminalio.FONT, text=first_name,
                        color=TEXT_COLOR)
text_group.append(text_area)  # Add this text to the text group
g.append(text_group)

# Draw simple text using the built-in font into a displayio group
# For smaller text, change scale=2 to scale=1 as scale 2 doesn't
# allow for much text but the text is bigger.
text_group = displayio.Group(max_size=10, scale=2,
                             x=DISPLAY_HEIGHT + 5,
                             y=int(DISPLAY_HEIGHT/2) + 13)
last_name = "Fried"
text_area = label.Label(terminalio.FONT, text=last_name,
                        color=TEXT_COLOR)
text_group.append(text_area)  # Add this text to the text group
g.append(text_group)

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

# Refresh the display to have it actually show
# NOTE: Do not refresh eInk displays more often than 180 seconds!
display.refresh()

# Wait the minimum 3 minutes between refreshes. Then loop to freeze.
time.sleep(180)
while True:
    pass

Code Review

For an overview of using displayio for displays with CircuitPython, the excellent guide CircuitPython Display Support Using displayio is your first stop. If you would like a deeper dive into the model used for displays, refer to this guide.

Adafruit suggests using the displayio.release_displays() function before looking to execute additional code to ensure displays connected to the hardware are released by CircuitPython.

Next is to let displayio know which pins are used on the display. The specific pins used are very display dependent, it is suggested the guide on the display be referred to for known a known, working configuration prior to looking to change things up. displayio.FourWire sets up the displayio connection to the display bus.

The display dimensions (display-specific) are defined. Then the bus, the program establishes the connection to the display driver. The size of the display (width and height), the orientation (rotation), busy pin, and the highlight color are given. For this tri-color display, red (0xff0000) is specified.

The rest of the code is very similar to the last two examples. First a bitmap graphic named picture.bmp is read from the root directory of the CIRCUITPY drive. The graphic is set in the display group with displayio.TileGrid. Then two lines of text are defined. They are placed a few pixels to the right of the bitmap and equidistant to the middle of the display's height.

Not much text can fit in this manor. There are two methods you can get more text width:

  • Changing scale=2 to scale=1 will give more characters per line but the text will be smaller.
  • If you need ultimate flexibility, it is suggested you create all your design elements into one bitmap picture and use the first example to display just the bitmap.

The program places all the group elements on screen with display.show then refreshes the display with display.refresh to actually have the graphics show up. It takes 2-3 seconds for an eInk display to erase the previous image and display the new image.

Finally the program waits 3 minutes. A while True: and pass loop is at the end of the program so the REPL does not erase the badge graphics. Pressing the reset button will start the program again.

This guide was first published on Nov 13, 2019. It was last updated on Nov 13, 2019.
This page (Example: A Name Badge) was last updated on Jul 14, 2020.