OK, let's setup an actual display so we can start showing stuff. There are two parts to this - the display itself, called Display, and how it is connected to the host controller via some "display bus" like FourWire or ParallelBus.

You first setup the display bus specific to your setup, be it FourWire, ParallelBus, etc. Then, when you setup your Display, you will pass this in so it can be used.

FourWire

The FourWire class is used to talk to displays over a spi_bus using the typical four pins associated with SPI - SCK, MOSI, MISO, and CS (aka, chip_select). One additional pin needed for the display is a pin to indicate if the information being sent over the bus is "data" (image information) or "command" (display control). This is done with the D/C pin specified via the command parameter.

To setup a FourWire bus, you would first create a spi_bus object in the normal way. You would then pass that in, along with specifications for the command and chip_select pins to use.

Here's the basic usage example for hardware SPI:

Download: file
display_bus = displayio.FourWire(board.SPI(),
                                 command=board.D10,
                                 chip_select=board.D9)

ParallelBus

A parallel bus is fast, but it takes a lot of pins. You'll need 8 pins for the main data, and they need to be in consecutive order on one of the microcontroller's ports and the first pin has to be on port number 0, 7, 15, or 23 (so we can write the byte in a single DMA command). Then you specify the first pin for data0 and the rest (the other 7) are inferred. Then you need 4 more digital pins that can be used for command, chip_select, write, and read. Oof. That's 12 pins.

The biggest road block will be finding a microcontroller with all those pins AND with 8 consecutive pins on the same port. What does "port" mean? It refers to something lower level that you may not generally worry about. Think of it as a group of pins that can be collectively manipulated quickly via commands that operate on the entire port.

How do you find 8 consecutive port pins? We'll, if you're starting from scratch, it'll take a bit on investigating. Here's one example. Take a look at the Metro M4 Express schematic and look in the general area where pin D13 is shown:

For example, D13 is wired to physical pin 35 which has several functions internally. The important one to note is PA16. This refers to the digital I/O on Port A at 16. Note that the pins below D13 go consecutively from PA16 to PA23. That's 8 pins on Port A we can use!

So, for a Metro M4 Express, you could use pins D13, D12, D10, D11, D9, D8, D1, and D0 for your 8 data pins. Then just pick any other 4 for the others.

Download: file
display_bus = displayio.ParallelBus(data0=board.D13,
                                    command=board.D7,
                                    chip_select=board.D6,
                                    write=board.D5,
                                    read=board.D4)

Display

To setup a Display you need four things:

  • A display bus (display_bus) for actually talking to the display.
  • An initialization sequence (init_sequence) to be used to setup the display for initial use
  • The width and...
  • The height of the display in pixels.

In general, you'll know the width and height for whatever display you are working with. The display_bus is one of the available display buses setup as described above. The init_sequence takes a bit of work to come up with. Typically it comes from reading datasheets or other sources. We'll talk more about this below. For now, just assume you have it created in something called INIT_SEQUENCE.

The basic Display setup would then look like this:

Download: file
display = displayio.Display(display_bus,
                            INIT_SEQUENCE,
                            width=320,
                            height=240)

Display Drivers

The init sequence (init_sequence) is a bit of a cryptic mess. We've worked it out for some displays and have created some light weight drivers that take care of the boiler plate. Instead of creating a Display object from scratch, you can use these drivers (and maybe more, check the guide for your display):

Then you would create your display like this:

Download: file
display = adafruit_ili9341.ILI9341(display_bus,
                                   width=320,
                                   height=240)

Note that it's basically the same as using Display, just without the init_sequence. That's taken care of for you.

Boards with Built In Displays

If you have a board like a HalloWing or a PyPortal that already has a display attached, then all this work has been done for you - both the setting up of the display bus and the display itself. The CircuitPython firmware build for these boards has the display ready to go. It is available via the DISPLAY object found in the board module. All you need to do is:

Download: file
import board
display = board.DISPLAY

Using a Display

Once a Display is setup, use show to specify the Group to use for displaying items on the screen. Creating a Group and the associated TileGrid(s) and Bitmap(s) and Palette(s) has been covered previously in this guide. Once you have your Group setup and ready to go, it's just a matter of calling:

Download: file
display.show(group)
This guide was first published on Apr 30, 2019. It was last updated on Apr 30, 2019.
This page (Display and Display Bus) was last updated on Oct 24, 2020.