You will need a Metro capable of running CircuitPython such as the Metro M0 Express or the Metro M4 Express. We recommend the Metro M4 Express because it's much faster and works better for driving a display. The steps should be about the same for the Metro M0 Express. If you haven't already, be sure to check out our Adafruit Metro M4 Express featuring ATSAMD51 guide.

Angled shot of a Adafruit Metro M4 feat. Microchip ATSAMD51.
Are you ready? Really ready? Cause here comes the fastest, most powerful Metro ever. The Adafruit Metro M4 featuring the Microchip ATSAMD51. This...
$27.50
In Stock

You could use a Grand Central which also has an M4 Processor. For this board, be sure to check out our Introducing the Adafruit Grand Central M4 Express guide.

Top down shot of a Adafruit Grand Central M4 Express featuring the SAMD51.
Are you ready? Really ready? Cause here comes the Adafruit Grand Central featuring the Microchip ATSAMD51. This dev board is so big, it's not...
$39.95
In Stock

If you need WiFi capabilities for your project, you could also use the Metro M4 Airlift Lite. For this board, be sure to check out our Adafruit Metro M4 Express AirLift guide.

Adafruit Metro M4 Airlift Lite dev board with SAMD51 an ESP32 Wifi Co-processor.
Give your next project a lift with AirLift - our witty name for the ESP32 co-processor that graces this Metro M4. You already know about the Adafruit Metro...
Out of Stock

Preparing the Shield

2.8" Capacitive TFT Touch Shield

This shield should be ready to go. By default, the SPI connections should be using the ICSP header. If you have modified it on the underside to use Pins 11-13, this will need to be changed back in order to work with displayio. After that the shield should be ready to go.

The following steps are not necessary with the newer v2 version of the sheild!

2.8" Resistive TFT Touch Shield v1

The earlier v1 version of the shield will need a slight modification to use with our boards capable of running CircuitPython. This is because the SPI interface is only available through the ICSP header.

First start by taking a sharp knife and cutting the traces that connect to pins 11-13.

Next, take a multimeter set to the continuity setting and test that the traces were successfully separated.

Next, apply a little solder to create a solder bridge on all three of the ICSP pads.

Once all three are solder bridged, then the shield should be all 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_ili9341

Before continuing make sure your board's lib folder or root filesystem has the adafruit_ili9341 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.

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.

CircuitPython Code Example

# 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.

Pinouts are for the 2.8" TFT Shield
"""
import board
import terminalio
import displayio
import fourwire
from adafruit_display_text import label
import adafruit_ili9341

# Release any resources currently in use for the displays
displayio.release_displays()

# Use Hardware SPI
spi = board.SPI()

# Use Software SPI if you have a shield with pins 11-13 jumpered
# import busio
# spi = busio.SPI(board.D11, board.D13)

tft_cs = board.D10
tft_dc = board.D9

display_bus = fourwire.FourWire(spi, command=tft_dc, chip_select=tft_cs)
display = adafruit_ili9341.ILI9341(display_bus, width=320, height=240)

# Make the display context
splash = displayio.Group()
display.root_group = splash

# Draw a green background
color_bitmap = displayio.Bitmap(320, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x00FF00  # Bright Green

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(280, 200, 1)
inner_palette = displayio.Palette(1)
inner_palette[0] = 0xAA0088  # Purple
inner_sprite = displayio.TileGrid(inner_bitmap, pixel_shader=inner_palette, x=20, y=20)
splash.append(inner_sprite)

# Draw a label
text_group = displayio.Group(scale=3, x=57, y=120)
text = "Hello World!"
text_area = label.Label(terminalio.FONT, text=text, color=0xFFFF00)
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 SPIdisplayio,terminalio for the font, a label, and the adafruit_ili9341 driver.

import board
import displayio
import terminalio
from adafruit_display_text import label
import adafruit_ili9341

Next we release any previously used displays. This is important because if the Metro 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.D10
tft_dc = board.D9

In the next line, we set the display bus to FourWire which makes use of the SPI bus.

display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs)

Finally, we initialize the driver with a width of 320 and a height of 240. 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 = adafruit_ili9341.ILI9341(display_bus, width=320, height=240)

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. 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 0x00FF00 which happens to be green. Colors are Hexadecimal values in the format of RRGGBB. 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(320, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x00FF00 # Bright Green

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 rectangle. 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 20 pixels smaller on each side. The screen is 320x240, so we'll want to subtract 40 from each of those numbers.

We'll also want to place it at the position (20, 20) so that it ends up centered.

# Draw a smaller inner rectangle
inner_bitmap = displayio.Bitmap(280, 200, 1)
inner_palette = displayio.Palette(1)
inner_palette[0] = 0xAA0088 # Purple
inner_sprite = displayio.TileGrid(inner_bitmap,
                                  pixel_shader=inner_palette,
                                  x=20, y=20)
splash.append(inner_sprite)

Since we are adding this after the first rectangle, 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 three. To scale the label only, we will make use of a subgroup, which we will then add to the main group.

Labels are centered vertically, so we'll place it at 120 for the Y coordinate, and around 57 pixels make it appear to be centered horizontally, but if you want to change the text, change this to whatever looks good to you. Let's go with some yellow text, so we'll pass it a value of 0xFFFF00.

# Draw a label
text_group = displayio.Group(max_size=10, scale=3, x=57, y=120)
text = "Hello World!"
text_area = label.Label(terminalio.FONT, text=text, color=0xFFFF00)
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

Using Touch

We won't be covering how to use the touchscreen on the shield with CircuitPython in this guide, but the libraries required to use it are:

Where to go from here

Be sure to check out this excellent guide to CircuitPython Display Support Using displayio

This guide was first published on Jan 03, 2014. It was last updated on Dec 06, 2023.

This page (CircuitPython Displayio Quickstart - Rev B) was last updated on Dec 06, 2023.

Text editor powered by tinymce.