It's easy to use the DVI Sock with CircuitPython and the PicoDVI core module. This module has been added to CircuitPython as of 8.1.0b2 - but note that it uses a lot of memory so in particular if you want to use Pico W with WiFi support, you'll likely only be able to get away with monochrome display.
Wiring
Attach the Sock to the bottom pins of your Pico board, or solder it directly onto the 'end' like a li'l PCB sock.
CircuitPython Usage
To use with CircuitPython, you need to first install the PicoDVI dependencies into the lib folder onto your CIRCUITPY drive. Then you need to update code.py with the example script.
Thankfully, we can do this in one go. In the example below, click the Download Project Bundle button below to download the necessary libraries and the code.py file in a zip file.
Connect your Pico board to your computer via a known good data+power USB cable. The board should show up in your File Explorer/Finder (depending on your operating system) as a flash drive named CIRCUITPY.
Extract the contents of the zip file, and copy the entire lib folder, the Helvetica-Bold-16.pcf font file, blinka_computer.bmp bitmap file and code.py file to your CIRCUITPY drive.
Your CIRCUITPY/lib folder should contain the following folders and file:
- adafruit_bitmap_font/
- adafruit_display_shapes/
- adafruit_display_text/
- simpleio.mpy

Hello World DVI Output Example
Once everything is saved to theĀ CIRCUITPY drive, you can connect the DVI Sock to an HDMI monitor and connect your Pico to USB power. You'll see the Hello World example display on the screen.
# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries # SPDX-FileCopyrightText: Adapted from Phil B.'s 16bit_hello Arduino Code # # SPDX-License-Identifier: MIT import gc import math from random import randint import time import displayio import picodvi import board import framebufferio import vectorio import terminalio import simpleio from adafruit_bitmap_font import bitmap_font from adafruit_display_text import label, wrap_text_to_lines from adafruit_display_shapes.rect import Rect from adafruit_display_shapes.circle import Circle from adafruit_display_shapes.roundrect import RoundRect from adafruit_display_shapes.triangle import Triangle from adafruit_display_shapes.line import Line # pin defs for DVI Sock displayio.release_displays() fb = picodvi.Framebuffer(320, 240, clk_dp=board.GP14, clk_dn=board.GP15, red_dp=board.GP12, red_dn=board.GP13, green_dp=board.GP18, green_dn=board.GP19, blue_dp=board.GP16, blue_dn=board.GP17, color_depth=8) display = framebufferio.FramebufferDisplay(fb) bitmap = displayio.Bitmap(display.width, display.height, 3) red = 0xff0000 yellow = 0xcccc00 orange = 0xff5500 blue = 0x0000ff pink = 0xff00ff purple = 0x5500ff white = 0xffffff green = 0x00ff00 aqua = 0x125690 palette = displayio.Palette(3) palette[0] = 0x000000 # black palette[1] = white palette[2] = yellow palette.make_transparent(0) tile_grid = displayio.TileGrid(bitmap, pixel_shader=palette) group = displayio.Group() def clean_up(group_name): for _ in range(len(group_name)): group_name.pop() gc.collect() def show_shapes(): gc.collect() cx = int(display.width / 2) cy = int(display.height / 2) minor = min(cx, cy) pad = 5 size = minor - pad half = int(size / 2) rect = Rect(cx - minor, cy - minor, size, size, stroke = 1, fill=red, outline = red) tri = Triangle(cx + pad, cy - pad, cx + pad + half, cy - minor, cx + minor - 1, cy - pad, fill=green, outline = green) circ = Circle(cx - pad - half, cy + pad + half, half, fill=blue, stroke = 1, outline = blue) rnd = RoundRect(cx + pad, cy + pad, size, size, int(size / 5), stroke = 1, fill=yellow, outline = yellow) group.append(rect) group.append(tri) group.append(circ) group.append(rnd) rect.fill = None tri.fill = None circ.fill = None rnd.fill = None time.sleep(2) rect.fill = red tri.fill = green circ.fill = blue rnd.fill = yellow time.sleep(2) clean_up(group) del rect del tri del circ del rnd gc.collect() def sine_chart(): gc.collect() cx = int(display.width / 2) cy = int(display.height / 2) minor = min(cx, cy) major = max(cx, cy) group.append(Line(cx, 0, cx, display.height, blue)) # v group.append(Line(0, cy, display.width, cy, blue)) # h for i in range(10): _n = simpleio.map_range(i, 0, 10, 0, major - 1) n = int(_n) group.append(Line(cx - n, cy - 5, cx - n, (cy - 5) + 11, blue)) # v group.append(Line(cx + n, cy - 5, cx + n, (cy - 5) + 11, blue)) # v group.append(Line(cx - 5, cy - n, (cx - 5) + 11, cy - n, blue)) # h group.append(Line(cx - 5, cy + n, (cx - 5) + 11, cy + n, blue)) # h for x in range(display.width): y = cy - int(math.sin((x - cx) * 0.05) * float(minor * 0.5)) bitmap[x, y] = 1 group.append(tile_grid) time.sleep(2) clean_up(group) def widget0(): gc.collect() data = [31, 42, 36, 58, 67, 88] num_points = len(data) text_area = label.Label(terminalio.FONT, text="Widget Sales", color=white) text_area.anchor_point = (0.5, 0.0) text_area.anchored_position = (display.width / 2, 3) group.append(text_area) for i in range(11): _x = simpleio.map_range(i, 0, 10, 0, display.width - 1) x = int(_x) group.append(Line(x, 20, x, display.height, blue)) _y = simpleio.map_range(i, 0, 10, 20, display.height - 1) y = int(_y) group.append(Line(0, y, display.width, y, blue)) prev_x = 0 _prev_y = simpleio.map_range(data[0], 0, 100, display.height - 1, 20) prev_y = int(_prev_y) for i in range(1, num_points): _new_x = simpleio.map_range(i, 0, num_points - 1, 0, display.width - 1) new_x = int(_new_x) _new_y = simpleio.map_range(data[i], 0, 100, display.height - 1, 20) new_y = int(_new_y) group.append(Line(prev_x, prev_y, new_x, new_y, aqua)) prev_x = new_x prev_y = new_y for i in range(num_points): _x = simpleio.map_range(i, 0, num_points - 1, 0, display.width - 1) x = int(_x) _y = simpleio.map_range(data[i], 0, 100, display.height - 1, 20) y = int(_y) group.append(Circle(x, y, 5, fill=None, stroke = 2, outline = white)) time.sleep(2) clean_up(group) def widget1(): gc.collect() data = [31, 42, 36, 58, 67, 88] num_points = len(data) bar_width = int(display.width / num_points) - 4 x_mapped_w = display.width + 2 h_mapped_h = display.height + 20 text_area = label.Label(terminalio.FONT, text="Widget Sales", color=white) text_area.anchor_point = (0.5, 0.0) text_area.anchored_position = (display.width / 2, 3) group.append(text_area) for i in range(11): _y = simpleio.map_range(i, 0, 10, 20, display.height - 1) y = int(_y) group.append(Line(0, y, display.width, y, blue)) for i in range(num_points): _x = simpleio.map_range(i, 0, num_points, 0, x_mapped_w) x = int(_x) _height = simpleio.map_range(data[i], 0, 100, h_mapped_h, 0) height = int(_height) group.append(vectorio.Rectangle(pixel_shader=palette, width=bar_width, height=display.height + 1, x=x, y=height, color_index = 2)) time.sleep(2) clean_up(group) def text_align(): gc.collect() TEXT = "hello world" text_area_top_left = label.Label(terminalio.FONT, text=TEXT, color=red) text_area_top_left.anchor_point = (0.0, 0.0) text_area_top_left.anchored_position = (0, 0) text_area_top_middle = label.Label(terminalio.FONT, text=TEXT, color=orange) text_area_top_middle.anchor_point = (0.5, 0.0) text_area_top_middle.anchored_position = (display.width / 2, 0) text_area_top_right = label.Label(terminalio.FONT, text=TEXT, color=yellow) text_area_top_right.anchor_point = (1.0, 0.0) text_area_top_right.anchored_position = (display.width, 0) text_area_middle_left = label.Label(terminalio.FONT, text=TEXT, color=green) text_area_middle_left.anchor_point = (0.0, 0.5) text_area_middle_left.anchored_position = (0, display.height / 2) text_area_middle_middle = label.Label(terminalio.FONT, text=TEXT, color=aqua) text_area_middle_middle.anchor_point = (0.5, 0.5) text_area_middle_middle.anchored_position = (display.width / 2, display.height / 2) text_area_middle_right = label.Label(terminalio.FONT, text=TEXT, color=blue) text_area_middle_right.anchor_point = (1.0, 0.5) text_area_middle_right.anchored_position = (display.width, display.height / 2) text_area_bottom_left = label.Label(terminalio.FONT, text=TEXT, color=purple) text_area_bottom_left.anchor_point = (0.0, 1.0) text_area_bottom_left.anchored_position = (0, display.height) text_area_bottom_middle = label.Label(terminalio.FONT, text=TEXT, color=pink) text_area_bottom_middle.anchor_point = (0.5, 1.0) text_area_bottom_middle.anchored_position = (display.width / 2, display.height) text_area_bottom_right = label.Label(terminalio.FONT, text=TEXT, color=white) text_area_bottom_right.anchor_point = (1.0, 1.0) text_area_bottom_right.anchored_position = (display.width, display.height) group.append(text_area_top_middle) group.append(text_area_top_left) group.append(text_area_top_right) group.append(text_area_middle_middle) group.append(text_area_middle_left) group.append(text_area_middle_right) group.append(text_area_bottom_middle) group.append(text_area_bottom_left) group.append(text_area_bottom_right) time.sleep(2) clean_up(group) def custom_font(): gc.collect() my_font = bitmap_font.load_font("/Helvetica-Bold-16.pcf") text_sample = "The quick brown fox jumps over the lazy dog." text_sample = "\n".join(wrap_text_to_lines(text_sample, 28)) text_area = label.Label(my_font, text="Custom Font", color=white) text_area.anchor_point = (0.0, 0.0) text_area.anchored_position = (0, 0) sample_text = label.Label(my_font, text=text_sample) sample_text.anchor_point = (0.5, 0.5) sample_text.anchored_position = (display.width / 2, display.height / 2) group.append(text_area) group.append(sample_text) time.sleep(2) clean_up(group) del my_font gc.collect() def bitmap_example(): gc.collect() blinka_bitmap = displayio.OnDiskBitmap("/blinka_computer.bmp") blinka_grid = displayio.TileGrid(blinka_bitmap, pixel_shader=blinka_bitmap.pixel_shader) gc.collect() group.append(blinka_grid) time.sleep(2) clean_up(group) del blinka_grid del blinka_bitmap gc.collect() def sensor_values(): gc.collect() text_x = "X: %d" % randint(-25, 25) text_y = "Y: %d" % randint(-25, 25) text_z = "Z: %d" % randint(-25, 25) x_text = label.Label(terminalio.FONT, text=text_x, color=red) x_text.anchor_point = (0.0, 0.0) x_text.anchored_position = (2, 0) y_text = label.Label(terminalio.FONT, text=text_y, color=green) y_text.anchor_point = (0.0, 0.0) y_text.anchored_position = (2, 10) z_text = label.Label(terminalio.FONT, text=text_z, color=blue) z_text.anchor_point = (0.0, 0.0) z_text.anchored_position = (2, 20) group.append(x_text) group.append(y_text) group.append(z_text) for i in range(40): if i == 10: group.scale = 2 elif i == 20: group.scale = 3 elif i == 30: group.scale = 4 x_text.text = "X: %d" % randint(-50, 50) y_text.text = "Y: %d" % randint(-50, 50) z_text.text = "Z: %d" % randint(-50, 50) time.sleep(0.1) time.sleep(0.1) clean_up(group) group.scale = 1 display.root_group = group while True: show_shapes() sine_chart() widget0() widget1() text_align() custom_font() bitmap_example() sensor_values()
This example is a port of the Arduino 16bit_hello code written by Phil B. with some slight variation to show off some of the unique abilities of displayio.
The example begins by showing a rectangle, circle, triangle and rounded rectangle and changing the fill attribute from None
to a color.
Then, a few chart variations are shown, including a sine wave pattern, line graph and bar graph.
Next is a text alignment example, showing how to use the anchor_point
and anchor_position
functions in the adafruit_display_text library.
Following that is a custom text example, loading a bitmap font instead of the built-in terminalio font.
Then there is a quick break from fonts to show off a bitmap image, specifically Blinka happily using her computer.
Finally, an example shows how to update the text in a Label
object for projects where you want to display text information that updates over time.
Page last edited January 22, 2025
Text editor powered by tinymce.