Using the EYESPI BFF with CircuitPython involves wiring up the BFF to your QT Py or Xiao form factor board and plugging in your EYESPI-compatible display via an EYESPI cable. Then, you load the code and necessary libraries onto your QT Py to see the graphics test on the display.
This page uses the 1.54" 240x240 ST7789 TFT display for demonstrating CircuitPython usage. You can use the same concepts to get going with any EYESPI-compatible display.
CircuitPython Microcontroller Wiring
Plug an EYESPI BFF into your QT Py or Xiao form factor board exactly as shown below. Here's an example of connecting a QT Py RP2040 to the BFF.
Connect the QT Py RP2040 with plug headers into the EYESPI BFF with socket headers. They should be plugged in with the backs of the boards facing each other.
For more information on soldering socket headers, check out this Learn Guide.
Then, connect the 1.54" display to the EYESPI BFF with an EYESPI cable. The blue stripe on the EYESPI cable should be facing up towards you in both of the EYESPI connectors.
CircuitPython Usage
To use with CircuitPython, you need to first install the necessary libraries, and their dependencies, into the lib folder on your CIRCUITPY drive. Then you need to update code.py with the example script.
Thankfully, we can do this in one go. In the example below, click the Download Project Bundle button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file.
Connect the microcontroller to your computer via a known-good USB power+data cable. The board shows up as a thumb drive named CIRCUITPY. Copy the entire lib folder, the Helvetica-Bold-16.pcf font file, the blinka_computer.bmp image file and the code.py file to your CIRCUITPY drive.
Your CIRCUITPY/lib folder should contain the following folders and files:
- /adafruit_bitmap_font
- /adafruit_display_shapes
- /adafruit_display_text
- adafruit_st7789.mpy
- simpleio.mpy
Once you have copied over the necessary folders and files, your CIRCUITPY drive should resemble the following:
# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries # SPDX-FileCopyrightText: Adapted from Phil B.'s 16bit_hello Arduino Code # # SPDX-License-Identifier: MIT '''Graphics example for the EYESPI BFF''' import gc import math from random import randint import time import displayio import board import vectorio import terminalio import simpleio from adafruit_st7789 import ST7789 from adafruit_bitmap_font import bitmap_font from adafruit_display_text import label, wrap_text_to_lines from adafruit_display_shapes.rect import Rect from adafruit_display_shapes.circle import Circle from adafruit_display_shapes.roundrect import RoundRect from adafruit_display_shapes.triangle import Triangle from adafruit_display_shapes.line import Line displayio.release_displays() spi = board.SPI() tft_cs = board.TX tft_dc = board.RX display_bus = displayio.FourWire( spi, command=tft_dc, chip_select=tft_cs, reset=None ) display = ST7789(display_bus, width=240, height=240, rowstart=80) bitmap = displayio.Bitmap(display.width, display.height, 3) red = 0xff0000 yellow = 0xcccc00 orange = 0xff5500 blue = 0x0000ff pink = 0xff00ff purple = 0x5500ff white = 0xffffff green = 0x00ff00 aqua = 0x125690 palette = displayio.Palette(3) palette[0] = 0x000000 # black palette[1] = white palette[2] = yellow palette.make_transparent(0) tile_grid = displayio.TileGrid(bitmap, pixel_shader=palette) group = displayio.Group() def clean_up(group_name): for _ in range(len(group_name)): group_name.pop() gc.collect() def show_shapes(): gc.collect() cx = int(display.width / 2) cy = int(display.height / 2) minor = min(cx, cy) pad = 5 size = minor - pad half = int(size / 2) rect = Rect(cx - minor, cy - minor, size, size, stroke = 1, fill=red, outline = red) tri = Triangle(cx + pad, cy - pad, cx + pad + half, cy - minor, cx + minor - 1, cy - pad, fill=green, outline = green) circ = Circle(cx - pad - half, cy + pad + half, half, fill=blue, stroke = 1, outline = blue) rnd = RoundRect(cx + pad, cy + pad, size, size, int(size / 5), stroke = 1, fill=yellow, outline = yellow) group.append(rect) group.append(tri) group.append(circ) group.append(rnd) rect.fill = None tri.fill = None circ.fill = None rnd.fill = None time.sleep(2) rect.fill = red tri.fill = green circ.fill = blue rnd.fill = yellow time.sleep(2) clean_up(group) del rect del tri del circ del rnd gc.collect() def sine_chart(): gc.collect() cx = int(display.width / 2) cy = int(display.height / 2) minor = min(cx, cy) major = max(cx, cy) group.append(Line(cx, 0, cx, display.height, blue)) # v group.append(Line(0, cy, display.width, cy, blue)) # h for i in range(10): _n = simpleio.map_range(i, 0, 10, 0, major - 1) n = int(_n) group.append(Line(cx - n, cy - 5, cx - n, (cy - 5) + 11, blue)) # v group.append(Line(cx + n, cy - 5, cx + n, (cy - 5) + 11, blue)) # v group.append(Line(cx - 5, cy - n, (cx - 5) + 11, cy - n, blue)) # h group.append(Line(cx - 5, cy + n, (cx - 5) + 11, cy + n, blue)) # h for x in range(display.width): y = cy - int(math.sin((x - cx) * 0.05) * float(minor * 0.5)) bitmap[x, y] = 1 group.append(tile_grid) time.sleep(2) clean_up(group) def widget0(): gc.collect() data = [31, 42, 36, 58, 67, 88] num_points = len(data) text_area = label.Label(terminalio.FONT, text="Widget Sales", color=white) text_area.anchor_point = (0.5, 0.0) text_area.anchored_position = (display.width / 2, 3) group.append(text_area) for i in range(11): _x = simpleio.map_range(i, 0, 10, 0, display.width - 1) x = int(_x) group.append(Line(x, 20, x, display.height, blue)) _y = simpleio.map_range(i, 0, 10, 20, display.height - 1) y = int(_y) group.append(Line(0, y, display.width, y, blue)) prev_x = 0 _prev_y = simpleio.map_range(data[0], 0, 100, display.height - 1, 20) prev_y = int(_prev_y) for i in range(1, num_points): _new_x = simpleio.map_range(i, 0, num_points - 1, 0, display.width - 1) new_x = int(_new_x) _new_y = simpleio.map_range(data[i], 0, 100, display.height - 1, 20) new_y = int(_new_y) group.append(Line(prev_x, prev_y, new_x, new_y, aqua)) prev_x = new_x prev_y = new_y for i in range(num_points): _x = simpleio.map_range(i, 0, num_points - 1, 0, display.width - 1) x = int(_x) _y = simpleio.map_range(data[i], 0, 100, display.height - 1, 20) y = int(_y) group.append(Circle(x, y, 5, fill=None, stroke = 2, outline = white)) time.sleep(2) clean_up(group) def widget1(): gc.collect() data = [31, 42, 36, 58, 67, 88] num_points = len(data) bar_width = int(display.width / num_points) - 4 x_mapped_w = display.width + 2 h_mapped_h = display.height + 20 text_area = label.Label(terminalio.FONT, text="Widget Sales", color=white) text_area.anchor_point = (0.5, 0.0) text_area.anchored_position = (display.width / 2, 3) group.append(text_area) for i in range(11): _y = simpleio.map_range(i, 0, 10, 20, display.height - 1) y = int(_y) group.append(Line(0, y, display.width, y, blue)) for i in range(num_points): _x = simpleio.map_range(i, 0, num_points, 0, x_mapped_w) x = int(_x) _height = simpleio.map_range(data[i], 0, 100, h_mapped_h, 0) height = int(_height) group.append(vectorio.Rectangle(pixel_shader=palette, width=bar_width, height=display.height + 1, x=x, y=height, color_index = 2)) time.sleep(2) clean_up(group) def text_align(): gc.collect() TEXT = "hello world" text_area_top_left = label.Label(terminalio.FONT, text=TEXT, color=red) text_area_top_left.anchor_point = (0.0, 0.0) text_area_top_left.anchored_position = (0, 0) text_area_top_middle = label.Label(terminalio.FONT, text=TEXT, color=orange) text_area_top_middle.anchor_point = (0.5, 0.0) text_area_top_middle.anchored_position = (display.width / 2, 0) text_area_top_right = label.Label(terminalio.FONT, text=TEXT, color=yellow) text_area_top_right.anchor_point = (1.0, 0.0) text_area_top_right.anchored_position = (display.width, 0) text_area_middle_left = label.Label(terminalio.FONT, text=TEXT, color=green) text_area_middle_left.anchor_point = (0.0, 0.5) text_area_middle_left.anchored_position = (0, display.height / 2) text_area_middle_middle = label.Label(terminalio.FONT, text=TEXT, color=aqua) text_area_middle_middle.anchor_point = (0.5, 0.5) text_area_middle_middle.anchored_position = (display.width / 2, display.height / 2) text_area_middle_right = label.Label(terminalio.FONT, text=TEXT, color=blue) text_area_middle_right.anchor_point = (1.0, 0.5) text_area_middle_right.anchored_position = (display.width, display.height / 2) text_area_bottom_left = label.Label(terminalio.FONT, text=TEXT, color=purple) text_area_bottom_left.anchor_point = (0.0, 1.0) text_area_bottom_left.anchored_position = (0, display.height) text_area_bottom_middle = label.Label(terminalio.FONT, text=TEXT, color=pink) text_area_bottom_middle.anchor_point = (0.5, 1.0) text_area_bottom_middle.anchored_position = (display.width / 2, display.height) text_area_bottom_right = label.Label(terminalio.FONT, text=TEXT, color=white) text_area_bottom_right.anchor_point = (1.0, 1.0) text_area_bottom_right.anchored_position = (display.width, display.height) group.append(text_area_top_middle) group.append(text_area_top_left) group.append(text_area_top_right) group.append(text_area_middle_middle) group.append(text_area_middle_left) group.append(text_area_middle_right) group.append(text_area_bottom_middle) group.append(text_area_bottom_left) group.append(text_area_bottom_right) time.sleep(2) clean_up(group) def custom_font(): gc.collect() my_font = bitmap_font.load_font("/Helvetica-Bold-16.pcf") text_sample = "The quick brown fox jumps over the lazy dog." text_sample = "\n".join(wrap_text_to_lines(text_sample, 28)) text_area = label.Label(my_font, text="Custom Font", color=white) text_area.anchor_point = (0.0, 0.0) text_area.anchored_position = (0, 0) sample_text = label.Label(my_font, text=text_sample) sample_text.anchor_point = (0.5, 0.5) sample_text.anchored_position = (display.width / 2, display.height / 2) group.append(text_area) group.append(sample_text) time.sleep(2) clean_up(group) del my_font gc.collect() def bitmap_example(): gc.collect() blinka_bitmap = displayio.OnDiskBitmap("/blinka_computer.bmp") blinka_grid = displayio.TileGrid(blinka_bitmap, pixel_shader=blinka_bitmap.pixel_shader) gc.collect() group.append(blinka_grid) time.sleep(2) clean_up(group) del blinka_grid del blinka_bitmap gc.collect() def sensor_values(): gc.collect() text_x = "X: %d" % randint(-25, 25) text_y = "Y: %d" % randint(-25, 25) text_z = "Z: %d" % randint(-25, 25) x_text = label.Label(terminalio.FONT, text=text_x, color=red) x_text.anchor_point = (0.0, 0.0) x_text.anchored_position = (2, 0) y_text = label.Label(terminalio.FONT, text=text_y, color=green) y_text.anchor_point = (0.0, 0.0) y_text.anchored_position = (2, 10) z_text = label.Label(terminalio.FONT, text=text_z, color=blue) z_text.anchor_point = (0.0, 0.0) z_text.anchored_position = (2, 20) group.append(x_text) group.append(y_text) group.append(z_text) for i in range(40): if i == 10: group.scale = 2 elif i == 20: group.scale = 3 elif i == 30: group.scale = 4 x_text.text = "X: %d" % randint(-50, 50) y_text.text = "Y: %d" % randint(-50, 50) z_text.text = "Z: %d" % randint(-50, 50) time.sleep(0.1) time.sleep(0.1) clean_up(group) group.scale = 1 display.root_group = group while True: show_shapes() sine_chart() widget0() widget1() text_align() custom_font() bitmap_example() sensor_values()
This example is a port of the Arduino 16bit_hello code written by Phil B. with some slight variation to show off some of the unique abilities of displayio.
The example begins by showing a rectangle, circle, triangle and rounded rectangle and changing the fill attribute from None
to a color.
Then, a few chart variations are shown, including a sine wave pattern, line graph and bar graph.
Next is a text alignment example, showing how to use the anchor_point
and anchor_position
functions in the adafruit_display_text library.
Following that is a custom text example, loading a bitmap font instead of the built-in terminalio font.
Then there is a quick break from fonts to show off a bitmap image, specifically Blinka happily using her computer.
Finally, an example shows how to update the text in a Label
object for projects where you want to display text information that updates over time.
It's important to note that the example code is optimized to be able to run all of the examples in a loop, which you more than likely won't want to do for your projects. As a result, the clean_up(group)
function is run after each example to use pop()
to remove all of the graphical elements of the displayio group
. Garbage collection (gc.collect()
) is also run to conserve memory. Additionally, each graphical element is created and deleted each time in each of the functions.
If you were to run, for example, the sensor_values()
function on its own for a project, you would instantiate the graphical elements once, before the loop, and then update the text with the "values" in the loop:
... text_x = "X: %d" % randint(-25, 25) text_y = "Y: %d" % randint(-25, 25) text_z = "Z: %d" % randint(-25, 25) x_text = label.Label(terminalio.FONT, text=text_x, color=red) x_text.anchor_point = (0.0, 0.0) x_text.anchored_position = (2, 0) y_text = label.Label(terminalio.FONT, text=text_y, color=green) y_text.anchor_point = (0.0, 0.0) y_text.anchored_position = (2, 10) z_text = label.Label(terminalio.FONT, text=text_z, color=blue) z_text.anchor_point = (0.0, 0.0) z_text.anchored_position = (2, 20) group.append(x_text) group.append(y_text) group.append(z_text) while True: for i in range(40): if i == 10: group.scale = 2 elif i == 20: group.scale = 3 elif i == 30: group.scale = 4 x_text.text = "X: %d" % randint(-50, 50) y_text.text = "Y: %d" % randint(-50, 50) z_text.text = "Z: %d" % randint(-50, 50) time.sleep(0.1)
Text editor powered by tinymce.