You will need a board capable of running CircuitPython such as the Metro M0 Express or the Metro M4 Express. You can also use boards such as the Feather M0 Express or the Feather M4 Express. We recommend either the Metro M4 or the Feather M4 Express because it's much faster and works better for driving a display. For this guide, we will be using a Feather M4 Express. The steps should be about the same for the Feather M0 Express or either of the Metros. If you haven't already, be sure to check out our Feather M4 Express guide.
Preparing the Breakout
Before using the TFT Breakout, you will need to solder the headers or some wires to it. Be sure to check out the Adafruit Guide To Excellent Soldering. After that the breakout should be ready to go.
Required CircuitPython Libraries
To use this display with displayio
, there is only one required library.
First, make sure you are running the latest version of Adafruit CircuitPython for your board.
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.
Remember for non-express boards, you'll need to manually install the necessary libraries from the bundle:
- adafruit_st7789
Before continuing make sure your board's lib folder or root filesystem has the adafruit_st7789 file copied over.
Code Example Additional Libraries
For the Code Example, you will need an additional library. We decided to make use of a library so the code didn't get overly complicated. You'll also need to copy over the following library from the bundle:
- adafruit_display_text
Go ahead and install this in the same manner as the driver library by copying the adafruit_display_text folder over to the lib folder on your CircuitPython device.
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-License-Identifier: MIT """ This test will initialize the display using displayio and draw a solid green background, a smaller purple rectangle, and some yellow text. """ import board import terminalio import displayio # Starting in CircuitPython 9.x fourwire will be a seperate internal library # rather than a component of the displayio library try: from fourwire import FourWire except ImportError: from displayio import FourWire from adafruit_display_text import label from adafruit_st7789 import ST7789 # First set some parameters used for shapes and text BORDER = 20 FONTSCALE = 2 BACKGROUND_COLOR = 0x00FF00 # Bright Green FOREGROUND_COLOR = 0xAA0088 # Purple TEXT_COLOR = 0xFFFF00 # Release any resources currently in use for the displays displayio.release_displays() spi = board.SPI() tft_cs = board.D5 tft_dc = board.D6 display_bus = FourWire(spi, command=tft_dc, chip_select=tft_cs) display = ST7789( display_bus, rotation=270, width=240, height=135, rowstart=40, colstart=53 ) # Make the display context splash = displayio.Group() display.root_group = splash color_bitmap = displayio.Bitmap(display.width, display.height, 1) color_palette = displayio.Palette(1) color_palette[0] = BACKGROUND_COLOR bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0) splash.append(bg_sprite) # Draw a smaller inner rectangle inner_bitmap = displayio.Bitmap( display.width - BORDER * 2, display.height - BORDER * 2, 1 ) inner_palette = displayio.Palette(1) inner_palette[0] = FOREGROUND_COLOR inner_sprite = displayio.TileGrid( inner_bitmap, pixel_shader=inner_palette, x=BORDER, y=BORDER ) splash.append(inner_sprite) # Draw a label text = "Hello World!" text_area = label.Label(terminalio.FONT, text=text, color=TEXT_COLOR) text_width = text_area.bounding_box[2] * FONTSCALE text_group = displayio.Group( scale=FONTSCALE, x=display.width // 2 - text_width // 2, y=display.height // 2, ) text_group.append(text_area) # Subgroup for text scaling splash.append(text_group) while True: pass
Let's take a look at the sections of code one by one. We start by importing the board so that we can initialize SPI
, displayio
,terminalio
for the font, a label
, and the adafruit_st7789
driver.
import board import displayio import terminalio from adafruit_display_text import label from adafruit_st7789 import ST7789
Next we define some parameters so that making changes to the shapes and text are easy. BORDER
will be the distance between the background and foreground rectangles. FONTSCALE
will be the multiplier for the font size. BACKGROUND_COLOR
is the color of the larger outer rectangle and is set to 0x00FF00
, which is bright green by default. Colors are Hexadecimal values in the format of RRGGBB. FOREGROUND_COLOR
is the color of the smaller inner rectangle and is set to purple by default. TEXT_COLOR
is the color of the text that appears in the label and by default is yellow.
BORDER = 20 FONTSCALE = 2 BACKGROUND_COLOR = 0x00FF00 # Bright Green FOREGROUND_COLOR = 0xAA0088 # Purple TEXT_COLOR = 0xFFFF00
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.
displayio.release_displays()
Next, we set the SPI object to the board's SPI with the easy shortcut function board.SPI()
. By using this function, it finds the SPI module and initializes using the default SPI parameters. Next we set the Chip Select and Data/Command pins that will be used.
spi = board.SPI() tft_cs = board.D5 tft_dc = board.D6
In the next line, we set the display bus to FourWire which makes use of the SPI bus. We would normally pass in reset with other displays, but this one has an automatic reset circuit built in.
display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs)
Finally, we initialize the driver with a width of 240 and a height of 135. Because the ST7789 chip is capable of driving both 320 and 240 pixel width displays. With the 240x135 display, the rectangle is in the middle of that space, we will need to tell the display that our row starts at 40 pixels over and our columns start 53 pixels down. If we stopped at this point and ran the code, we would have a terminal that we could type at and have the screen update.
display = ST7789(display_bus, rotation=270, width=240, height=135, rowstart=40, colstart=53)
Next we create a background splash image. We do this by creating a group that we can add elements to and adding that group to the display. In this example, we are limiting the maximum number of elements to 10, but this can be increased if you would like. The display will automatically handle updating the group.
splash = displayio.Group(max_size=10) display.show(splash)
Next we create a Bitmap, which is like a canvas that we can draw on, and set it to the same size as the display. In this case we are creating the Bitmap to be the same size as the screen, but only have one color. The Bitmaps can currently handle up to 256 different colors. We create a Palette with one color and set that color to the value of BACKGROUND_COLOR
. Even though the Bitmaps can only handle 256 colors at a time, you get to define what those 256 different colors are.
color_bitmap = displayio.Bitmap(display.width, display.height, 1) color_palette = displayio.Palette(1) color_palette[0] = BACKGROUND_COLOR
With all those pieces in place, we create a TileGrid by passing the bitmap and palette and draw it at (0, 0)
which represents the display's upper left.
bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0) splash.append(bg_sprite)
Next we will create a smaller purple square. The easiest way to do this is the create a new bitmap that is a little smaller than the full screen with a single color and place it in a specific location. In this case, we will create a bitmap that is the size of the display with the value of BORDER
, which is 20 pixels, subtracted from each side. The screen is 240x135, so we'll end up subtracting 40 from each of those numbers.
We'll also want to place it at the position (20, 20)
so that it ends up centered.
inner_bitmap = displayio.Bitmap(display.width - BORDER * 2, display.height - BORDER * 2, 1) inner_palette = displayio.Palette(1) inner_palette[0] = FOREGROUND_COLOR inner_sprite = displayio.TileGrid(inner_bitmap, pixel_shader=inner_palette, x=BORDER, y=BORDER) splash.append(inner_sprite)
Since we are adding this after the first square, it's automatically drawn on top. Here's what it looks like now.
Next let's add a label that says "Hello World!" on top of that. We're going to use the built-in Terminal Font and scale it up by a factor of two, which is what we have FONTSCALE
set to. To scale the label only, we will make use of a subgroup, which we will then add to the main group.
We create the label first so that we can get the width of the bounding box and multiply it by the FONTSCALE
. This gives us the actual with of the text.
Labels are automatically centered vertically, so we'll place it at half the display height for the Y coordinate, and we calculate the X coordinate to horizontally center the label. For the color, we just use the value inside of TEXT_COLOR
.
text = "Hello World!" text_area = label.Label(terminalio.FONT, text=text, color=TEXT_COLOR) text_width = text_area.bounding_box[2] * FONTSCALE text_group = displayio.Group(max_size=10, scale=FONTSCALE, x=display.width // 2 - text_width // 2, y=display.height // 2) text_group.append(text_area) # Subgroup for text scaling splash.append(text_group)
Finally, we place an infinite loop at the end so that the graphics screen remains in place and isn't replaced by a terminal.
while True: pass
Where to go from here
Be sure to check out this excellent guide to CircuitPython Display Support Using displayio
Text editor powered by tinymce.