Pico HDMI Board on CircuitPython

picodvi is a CircuitPython library of low-level routines for interacting with PicoDVI Output. This exercise run on Raspberry Pi Pico (RP2040) running CircuitPython 10.0.3 to display on HDMI monitor with Spotpear Pico HDMI Board.


pico-hdmi.py, basic test.
"""
Pico HDMI Board on CircuitPython
Basic test.

details:
https://coxxect.blogspot.com/2026/02/pico-hdmi-board-on-circuitpython.html

Ref:
https://docs.circuitpython.org/en/latest/shared-bindings/picodvi/
https://learn.adafruit.com/using-dvi-video-in-circuitpython/using-a-framebuffer-and-picodvi

lib needed:
- adafruit_display_text folder

Install lib using circup:
circup install adafruit_display_text
"""
import os, sys
import board
import displayio
import framebufferio
import picodvi
from adafruit_display_text import label
import terminalio
import time
import gc

displayio.release_displays()


#=======================================
info = os.uname()[4] + "\n" + \
       sys.implementation[0] + " " + os.uname()[3] + "\n" + \
       picodvi.__name__ + "\n" + \
       framebufferio.__name__
print("=======================================")
print(info)
print("=======================================")
print()

# Create picodvi.Framebuffer, specified GPIOs
try:
    fb = picodvi.Framebuffer(
        width=320,
        height=240,
        clk_dp=board.GP9,   # Clock+
        clk_dn=board.GP8,   # Clock-
        red_dp=board.GP11,  # Data0+
        red_dn=board.GP10,  # Data0-
        green_dp=board.GP13, # Data1+
        green_dn=board.GP12, # Data1-
        blue_dp=board.GP15,  # Data2+
        blue_dn=board.GP14,  # Data2-
        color_depth=8
        )
except ValueError as e:
    print("Framebuffer error: ", e)
    sys.exit(e)

display = framebufferio.FramebufferDisplay(fb)

#----------------------------------------
# Make the display context
bgGroup = displayio.Group()

#display.show(bgGroup)
display.root_group = bgGroup

bg_bmp= displayio.Bitmap(display.width, display.height, 2)
palette = displayio.Palette(2)
palette[0] = 0x000000
palette[1] = 0xFFFFFF

for x in range(display.width):
    bg_bmp[x, 0] = 1
    bg_bmp[x, display.height-1] = 1
for y in range(display.height):
    bg_bmp[0, y] = 1
    bg_bmp[display.width-1, y] = 1

bg = displayio.TileGrid(bg_bmp, pixel_shader=palette)
bgGroup.append(bg)

# Draw label
text_group = displayio.Group(scale=1, x=20, y=120)
text_area = label.Label(terminalio.FONT, text=info, color=0xF0F000)
text_group.append(text_area)  # Subgroup for text scaling
bgGroup.append(text_group)
time.sleep(5)

text_area.text="Hello Pico HDMI"
text_area.scale=3
time.sleep(5)

bgGroup.remove(text_group)

#prepare color bar
color_bar_width = 256
color_bar_height = 10
red_bmp= displayio.Bitmap(color_bar_width, color_bar_height, color_bar_width)
red_palette = displayio.Palette(color_bar_width)
green_bmp= displayio.Bitmap(color_bar_width, color_bar_height, color_bar_width)
green_palette = displayio.Palette(color_bar_width)
blue_bmp= displayio.Bitmap(color_bar_width, color_bar_height, color_bar_width)
blue_palette = displayio.Palette(color_bar_width)

#fill in color palette
for i in range(color_bar_width):
    red_palette[i]   = i*0x010000
    green_palette[i] = i*0x000100
    blue_palette[i]  = i*0x000001

#fill in color bar bitmap
for x in range(color_bar_width):
    for y in range(color_bar_height):
        red_bmp[x, y] = x
    for y in range(color_bar_height):
        green_bmp[x, y] = x
    for y in range(color_bar_height):
        blue_bmp[x, y] = x
        
red_bar = displayio.TileGrid(red_bmp, pixel_shader=red_palette, x=20, y=80)
bgGroup.append(red_bar)
green_bar = displayio.TileGrid(green_bmp, pixel_shader=green_palette, x=20, y=100)
bgGroup.append(green_bar)
blue_bar = displayio.TileGrid(blue_bmp, pixel_shader=blue_palette, x=20, y=120)
bgGroup.append(blue_bar)

time.sleep(3)
bgGroup.remove(red_bar)
bgGroup.remove(green_bar)
bgGroup.remove(blue_bar)
bgGroup.remove(bg)

gc.collect()
print("mem_free:", gc.mem_free())

colorSet = ((0xFF0000, "RED"),
            (0x00FF00, "GREEN"),
            (0x0000FF, "BLUE"),
            (0xFFFFFF, "WHITE"),
            (0x000000, "BLACK"))

color_bitmap = displayio.Bitmap(display.width, display.height, 1)  # with one color
color_palette = displayio.Palette(1)
color_palette[0] = 0x000000  # BLACK
color_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
bgGroup.append(color_sprite)

# Draw label
text_group = displayio.Group(scale=5, x=20, y=120)
text_area = label.Label(terminalio.FONT, text="", color=0xFFFFFF)
text_group.append(text_area)  # Subgroup for text scaling
bgGroup.append(text_group)

while True:
    for i in colorSet:
        color_palette[0] = i[0]
        text_area.text = i[1]
        text_area.color = i[0] ^ 0xFFFFFF
        time.sleep(3)


pico-hdmi_star.py, Animated Star using vectorio.Polygon.
"""
Pico HDMI Board on CircuitPython
Animated Star using vectorio.Polygon

details:
https://coxxect.blogspot.com/2026/02/pico-hdmi-board-on-circuitpython.html

Ref:
https://docs.circuitpython.org/en/latest/shared-bindings/picodvi/
https://learn.adafruit.com/using-dvi-video-in-circuitpython/using-a-framebuffer-and-picodvi
"""
import os, sys
import board
import displayio
import framebufferio
import picodvi
from vectorio import Polygon
#import time
import math

displayio.release_displays()

#=======================================
info = os.uname()[4] + "\n" + \
       sys.implementation[0] + " " + os.uname()[3] + "\n" + \
       picodvi.__name__ + "\n" + \
       framebufferio.__name__
print("=======================================")
print(info)
print("=======================================")
print()

# Create picodvi.Framebuffer, specified GPIOs
try:
    fb = picodvi.Framebuffer(
        width=640,
        height=480,
        clk_dp=board.GP9,   # Clock+
        clk_dn=board.GP8,   # Clock-
        red_dp=board.GP11,  # Data0+
        red_dn=board.GP10,  # Data0-
        green_dp=board.GP13, # Data1+
        green_dn=board.GP12, # Data1-
        blue_dp=board.GP15,  # Data2+
        blue_dn=board.GP14,  # Data2-
        color_depth=1
        )
except ValueError as e:
    print("Framebuffer error: ", e)
    sys.exit(e)

display = framebufferio.FramebufferDisplay(fb)

#----------------------------------------
# Make the display context
bgGroup = displayio.Group()

#display.show(bgGroup)
display.root_group = bgGroup

bg_bmp= displayio.Bitmap(display.width, display.height, 2)
palette = displayio.Palette(2)
palette[0] = 0x000000
palette[1] = 0xFFFFFF

for x in range(display.width):
    bg_bmp[x, 0] = 1
    bg_bmp[x, display.height-1] = 1
for y in range(display.height):
    bg_bmp[0, y] = 1
    bg_bmp[display.width-1, y] = 1

bg = displayio.TileGrid(bg_bmp, pixel_shader=palette)
bgGroup.append(bg)

# Generate Star
def star_points(r1, r2, angle_deg=0, num_points=5):
    points = []
    angle_rad = math.radians(angle_deg)
    step = math.pi / num_points  # angle step

    for i in range(num_points * 2):
        r = r1 if i % 2 == 0 else r2
        theta = angle_rad + i * step
        x = int(r * math.cos(theta))
        y = int(r * math.sin(theta))
        points.append((x, y))
    return points

center_x = display.width // 2
center_y = display.height // 2

polygon_palette = displayio.Palette(1)
polygon_palette[0] = 0xFFFFFF

# init star
points = star_points(r1=100, r2=40, angle_deg=0)
polygon = Polygon(
    pixel_shader=polygon_palette,
    points=points,
    x=center_x,
    y=center_y
)

bgGroup.append(polygon)

while True:
    for angle in range(0, 360, 5):  # step degree
        polygon.points = star_points(50, 30, angle)
        display.refresh()  # 
        #time.sleep(0.05)   #



Comments

Popular posts from this blog

Drive 320x240 ILI9341 SPI TFT using ESP32-S3 (NodeMCU ESP-S3-12K-Kit) using TFT_eSPI library, in Arduino Framework.

480x320 TFT/ILI9488 SPI wih EP32C3 (arduino-esp32) using Arduino_GFX Library