This method works for CircuitPython 9.2 and later, including CircuitPython 10
The way the DVI/HDMI connection is established is using a framebuffer. The modules used to do this are board, framebufferio, displayio and picodvi. Their use is as follows:
board is used to define the clock, red, green, and blue differential wire pins used by the development board. These can vary from board to board, so a general definition is coded into the board definition for our use.
framebufferio defines a memory space to store the graphics placed onto the screen.
picodvi is a library that provides DVI/HDMI use via the CircuitPython displayio graphics system.
displayio is the high level graphics system used most often in CircuitPython to write to displays. See the guide linked below if you want to delve into how displayio works.
For smaller displays, there is some hardware that must be set up using the connectivity the display uses before using the Terminal and displayio. There is setup that an HDMI display needs too.
import sys
import board
import displayio
import terminalio
import framebufferio
import picodvi
displayio.release_displays()
try:
fb = picodvi.Framebuffer(320, 240, clk_dp=board.CKP, clk_dn=board.CKN,
red_dp=board.D0P, red_dn=board.D0N,
green_dp=board.D1P, green_dn=board.D1N,
blue_dp=board.D2P, blue_dn=board.D2N,
color_depth=8)
except ValueError as e:
print("Framebuffer error: ", e)
sys.exit(e)
display = framebufferio.FramebufferDisplay(fb)
If you wish to set the system display, as is done in the adafruit_fruitjam request_display_config():
supervisor.runtime.display = framebufferio.FramebufferDisplay(fb)
Above creates a displayio display object for DVI/HDMI display. A more complete program is below. This is suitable for creating a 320pixel x 240pixel (pixel doubled behind the scenes) x 8bit display suitable for an RP2040 or RP2350 microcontroller.
The display is released (if in use) in the first line.
Then a framebuffer is created using the picodvi library. The first two numbers are the width and height of the display in pixels. You will want to refer to the documentation here for valid values.
The _dp values map the pins the HSTX bus from the microcontroller is mapped. Using the board library, these are mapped to the appropriate values, you do not need to know which pins have which functions.
The color_depth parameter may be 1, 2, 4, 8, 16, or 32 bits with 1, 2, and 4 being grayscale. Again see the documentation for valid values. The larger the number, the more RAM used.
The exception handling catches instances where the size and color depth are not valid values. If you have a set value and you know it works, you may omit the exception handling.
Finally a displayio display is created from the framebuffer.
# SPDX-FileCopyrightText: 2025 Anne Barela for Adafruit Industries
#
# SPDX-License-Identifier: MIT
#
# Set up a DVI display using Framebufferio and displayio
# Text and drawing is all done vis displayio
#
import sys
import microcontroller
import board
import displayio
import terminalio
import framebufferio
import picodvi
from adafruit_display_text import label
# Initialize displayio
displayio.release_displays()
try:
fb = picodvi.Framebuffer(640, 480, clk_dp=board.CKP, clk_dn=board.CKN,
red_dp=board.D0P, red_dn=board.D0N,
green_dp=board.D1P, green_dn=board.D1N,
blue_dp=board.D2P, blue_dn=board.D2N,
color_depth=4)
except ValueError as e:
print("Framebuffer error: ", e)
# Per picodvi/Framebuffer_RP2350.c only 320x240 at 8 & 16 bits work
# Show error
sys.exit(e)
display = framebufferio.FramebufferDisplay(fb)
display_group = displayio.Group()
display.root_group = display_group
# Create labels
# pylint: disable=line-too-long
text = " 1 2 3 4 5 6 7 8 9 0 1 2"
text_area = label.Label(terminalio.FONT, text=text, color=0xFFFFFF)
text_area.x = 0
text_area.y = 5
display_group.append(text_area)
# pylint: disable=line-too-long
text = "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
text_area = label.Label(terminalio.FONT, text=text, color=0xFFFFFF)
text_area.x = 0
text_area.y = 15
display_group.append(text_area)
text = f"Microcontroller speed: {microcontroller.cpu.frequency}"
text_area = label.Label(terminalio.FONT, text=text, color=0xFFFFFF)
text_area.x = 5
text_area.y = 40
display_group.append(text_area)
while True:
pass
Page last edited July 16, 2025
Text editor powered by tinymce.