CircuitPython 9.2.5 adds a new property to the supervisor Runtime object, display.
If your board has a built in display that is automatically configured by the CircuitPython core (e.g., boards like the Feather ESP32-S3 Reverse TFT), then this display is available as supervisor.runtime.display in addition to board.DISPLAY.
So what's different about the new supervisor.runtime.display?
- This property is available on all boards that support
displayio, not just boards with built in displays - Unlike
board.DISPLAY, this property is settable, and remembers its value after your code file finishes running. This means you can set this property once in boot.py and then use the display each time yourcode.pyruns, or re-use a display set by a previous run of code.py. - Due to technical limitations in CircuitPython, when a display is released,
board.DISPLAYbecomes a "None-like object": one that prints asNonebut fails the checkÂboard.DISPLAY is None.Âsupervisor.runtime.display is Noneworks correctly to check whether a default display is configured.
Setting supervisor.runtime.display
There are two approaches:
- Do it unconditionally in boot.py and depend on this in code.py
- Do it conditionally in code.py, if
supervisor.runtime.display is None
... in boot.py
Here's a code snippet that shows configuring a 240x240 ST7789 display connected to an EyeSpi BFF on a QT Py board like the QT Py RP2040:
# Place in boot.py and then hard-reset your board
import board
import displayio
import fourwire
import supervisor
from adafruit_st7789 import ST7789
displayio.release_displays()
spi = board.SPI()
tft_cs = board.TX
tft_dc = board.RX
display_bus = fourwire.FourWire(
spi, command=tft_dc, chip_select=tft_cs, reset=None
)
supervisor.runtime.display = ST7789(display_bus, width=240, height=240, rowstart=80)
Then, in your code.py, fetch the already-configured display like so:
import supervisor display = supervisor.runtime.display
... in code.py
The first time through, the check supervisor.runtime.display is None will succeed, and the code inside the if-block will be run. When it finishes, it sets supervisor.runtime.display to the newly-created display.
On the next run of code.py, that block will be skipped, because supervisor.runtime.display will be the previously configured display, not None.
Either way, on the last line, the value of supervisor.runtime.display is grabbed and assigned to the display variable for use as normal.
import board
import displayio
import fourwire
import supervisor
from adafruit_st7789 import ST7789
if supervisor.runtime.display is None:
displayio.release_displays()
spi = board.SPI()
tft_cs = board.TX
tft_dc = board.RX
display_bus = fourwire.FourWire(
spi, command=tft_dc, chip_select=tft_cs, reset=None
)
supervisor.runtime.display = ST7789(display_bus, width=240, height=240, rowstart=80)
display = supervisor.runtime.display
With this variant, an existing display will be used if it is configured; otherwise, the display will be set up and assigned to the supervisor.runtime.display property so that on the next run it can be used without configuration.
Caveats
- Setting
supervisor.runtime.displayin boot.py interacts poorly with fake deep sleep (#10070)
This page (supervisor.runtime.display in CircuitPython 9.2.5+) was last updated on February 18, 2025.
Text editor powered by tinymce.