Raspberry Pi Pico 2 W/CircuitPython 10.0.3: Load animated GIFs from MicroSD, display them on a 240*240 GC9A01 LCD using gifio.OnDiskGif.
Previous posts show
Basic setup of 1.28 inch 240x240 Round Display with GC9A01 SPI on Raspberry
Pi Pico 2 W/CircuitPython 10.0.3 and
display bmp images from SD using
displayio.OnDiskBitmap()/adafruit_imageload.load() This post shows how to display animated GIFs from MicroSD.
The connection between Raspberry Pi Pico 2 W, GC9A01 LCD and the MicroSD Module refers to the last post, display bmp images from SD using displayio.OnDiskBitmap()/adafruit_imageload.load()
Ref:
https://docs.circuitpython.org/en/latest/shared-bindings/gifio/index.html#gifio.OnDiskGif
Exercise Code:
cpy_rpPicoW_gc9a01_sd_OnDiskGif.py. Cooperate with displayio, this mode is relatively slow.
cpy_rpPicoW_gc9a01_sd_OnDiskGif_direct_blit.py. Directly blitted to the full screen, faster.
The connection between Raspberry Pi Pico 2 W, GC9A01 LCD and the MicroSD Module refers to the last post, display bmp images from SD using displayio.OnDiskBitmap()/adafruit_imageload.load()
Ref:
https://docs.circuitpython.org/en/latest/shared-bindings/gifio/index.html#gifio.OnDiskGif
Exercise Code:
cpy_rpPicoW_gc9a01_sd_OnDiskGif.py. Cooperate with displayio, this mode is relatively slow.
"""
Raspberry Pi Pico 2 W/CircuitPython 10.0.3
with 1.28" 240x240 Round GC9A01 SPI IPS LCD
Display animated GIF in SD, using gifio.OnDiskGif.
Cooperate with displayio, this mode is relatively slow.
https://coxxect.blogspot.com/2026/02/raspberry-pi-pico-2-wcircuitpython-1003.html
ref:
https://docs.circuitpython.org/en/latest/shared-bindings/gifio/index.html#gifio.OnDiskGif
Prepare Libraries
-----------------
CircuitPython Libraries Bundle for Version 9.x needed:
(https://circuitpython.org/libraries)
- adafruit_gc9a01a.mpy
To install libraries using circup, enter the command:
> circup install adafruit_gc9a01a
For CircUp, read:
https://coxxect.blogspot.com/2024/12/install-and-using-circup-circuitpython.html
"""
import os, sys
import board
import time
import displayio
import busio
import adafruit_gc9a01a
from fourwire import FourWire
import sdcardio
import storage
import gifio
displayio.release_displays()
tft_blk = board.GP22
tft_cs = board.GP17
tft_dc = board.GP21
tft_res = board.GP20
tft_sda = board.GP19
tft_scl = board.GP18
sd_miso = board.GP12
sd_cs = board.GP13
sd_clk = board.GP14
sd_mosi = board.GP15
# Release any resources currently in use for the displays
displayio.release_displays()
info = os.uname()[4] + "\n" + \
sys.implementation[0] + " " + os.uname()[3] + "\n" + \
adafruit_gc9a01a.__name__ + " " + adafruit_gc9a01a.__version__
print("=======================================")
print(info)
print("=======================================")
print()
disp_spi = busio.SPI(clock=tft_scl, MOSI=tft_sda)
display_bus = FourWire(spi_bus=disp_spi,
command=tft_dc,
chip_select=tft_cs,
reset=tft_res)
display = adafruit_gc9a01a.GC9A01A(display_bus, width=240, height=240, backlight_pin=tft_blk)
#=======================================
# Init SD
sd_spi = busio.SPI(clock=sd_clk, MOSI=sd_mosi, MISO=sd_miso)
sd = sdcardio.SDCard(sd_spi, sd_cs)
vfs = storage.VfsFat(sd)
storage.mount(vfs, '/sd')
def list_files_with_ext(path, ext):
"""Return sorted list of files in path with given extension."""
files = []
for name in os.listdir(path):
full_path = path + "/" + name
st = os.stat(full_path)
mode = st[0]
# check regular file (0x8000) only
if mode & 0x8000:
if name.lower().endswith("." + ext.lower()):
files.append(name)
files.sort()
return files
gif_folder = "/sd/GIFs_10/"
gif_files = list_files_with_ext(gif_folder, "gif")
print(gif_files)
def showGIF(g_folder, g_file):
print("------------------")
print("GIF:", g_file)
odg = gifio.OnDiskGif(g_folder+g_file) # Create an OnDiskGif object with the given file.
print("W x H:", odg.width, "x", odg.height)
print("duration:", odg.duration, "sec")
print("frame_count:", odg.frame_count)
start = time.monotonic()
next_delay = odg.next_frame() # Load the first frame
end = time.monotonic()
overhead = end - start
face = displayio.TileGrid(
odg.bitmap,
pixel_shader=displayio.ColorConverter(
input_colorspace=displayio.Colorspace.RGB565_SWAPPED
),
x = int((display.width-odg.width)/2),
y = int((display.height-odg.height)/2),
)
if len(main_group) > 0:
main_group[0] = face
else:
main_group.append(face)
display.refresh()
for r in range(odg.frame_count-1):
time.sleep(max(0, next_delay - overhead))
next_delay = odg.next_frame() #load next frame
print("- showGIF ended -")
main_group = displayio.Group()
display.root_group = main_group
while True:
for f in gif_files:
showGIF(gif_folder, f)
cpy_rpPicoW_gc9a01_sd_OnDiskGif_direct_blit.py. Directly blitted to the full screen, faster.
"""
Raspberry Pi Pico 2 W/CircuitPython 10.0.3
with 1.28" 240x240 Round GC9A01 SPI IPS LCD
Display animated GIF in SD, using gifio.OnDiskGif.
Directly blitted to the full screen, faster.
https://coxxect.blogspot.com/2026/02/raspberry-pi-pico-2-wcircuitpython-1003.html
Ref:
https://docs.circuitpython.org/en/latest/shared-bindings/gifio/index.html#gifio.OnDiskGif
Prepare Libraries
-----------------
CircuitPython Libraries Bundle for Version 9.x needed:
(https://circuitpython.org/libraries)
- adafruit_gc9a01a.mpy
To install libraries using circup, enter the command:
> circup install adafruit_gc9a01a
For CircUp, read:
https://coxxect.blogspot.com/2024/12/install-and-using-circup-circuitpython.html
"""
import os, sys
import board
import time
import displayio
import busio
import adafruit_gc9a01a
from fourwire import FourWire
import sdcardio
import storage
import gifio
import struct, gc
displayio.release_displays()
tft_blk = board.GP22
tft_cs = board.GP17
tft_dc = board.GP21
tft_res = board.GP20
tft_sda = board.GP19
tft_scl = board.GP18
sd_miso = board.GP12
sd_cs = board.GP13
sd_clk = board.GP14
sd_mosi = board.GP15
# Release any resources currently in use for the displays
displayio.release_displays()
info = os.uname()[4] + "\n" + \
sys.implementation[0] + " " + os.uname()[3] + "\n" + \
adafruit_gc9a01a.__name__ + " " + adafruit_gc9a01a.__version__
print("=======================================")
print(info)
print("=======================================")
print()
def change_spi_baudrate(spi, rate):
while not spi.try_lock():
pass
spi.configure(baudrate=rate)
print("Updated SPI settings:")
print("Baudrate:", spi.frequency)
spi.unlock()
disp_spi = busio.SPI(clock=tft_scl, MOSI=tft_sda)
display_bus = FourWire(spi_bus=disp_spi,
command=tft_dc,
chip_select=tft_cs,
reset=tft_res)
display = adafruit_gc9a01a.GC9A01A(display_bus, width=240, height=240, backlight_pin=tft_blk)
#=======================================
# Init SD
sd_spi = busio.SPI(clock=sd_clk, MOSI=sd_mosi, MISO=sd_miso)
sd = sdcardio.SDCard(sd_spi, sd_cs)
vfs = storage.VfsFat(sd)
storage.mount(vfs, '/sd')
def list_files_with_ext(path, ext):
"""Return sorted list of files in path with given extension."""
files = []
for name in os.listdir(path):
full_path = path + "/" + name
st = os.stat(full_path)
mode = st[0]
# check regular file (0x8000) only
if mode & 0x8000:
if name.lower().endswith("." + ext.lower()):
files.append(name)
files.sort()
return files
gif_folder = "/sd/GIFs_10/"
gif_files = list_files_with_ext(gif_folder, "gif")
print(gif_files)
# Take over display to drive directly
display.auto_refresh = False
display_bus = display.bus
def showGIF(g_folder, g_file):
print("------------------")
print("GIF:", g_file)
# Create OnDiskGif object
odg = gifio.OnDiskGif(g_folder + g_file)
print("W x H:", odg.width, "x", odg.height)
print("duration:", odg.duration, "sec")
print("frame_count:", odg.frame_count)
start = time.monotonic()
next_delay = odg.next_frame() # Load the first frame
end = time.monotonic()
overhead = end - start
# Loop through all frames
for frame in range(odg.frame_count-1):
# Sleep for the frame delay specified by the GIF
time.sleep(max(0, next_delay - overhead))
# Advance to next frame
next_delay = odg.next_frame()
# Send frame directly to display
display_bus.send(42, struct.pack(">hh", 0, odg.bitmap.width - 1)) # column range
display_bus.send(43, struct.pack(">hh", 0, odg.bitmap.height - 1)) # row range
display_bus.send(44, odg.bitmap) # pixel data
print("- showGIF ended -")
# Free resources
odg.deinit()
odg = None
gc.collect()
# Example main loop
while True:
for f in gif_files: # gif_files is list containing GIF filenames
showGIF(gif_folder, f)
Comments
Post a Comment