Using the EYESPI Pi Beret is quite straightforward. Attach it to your Pi, plug in a display, and you're ready to go. This demo will test the display and button features of the Beret with an animated GIF player.
Raspberry Pi Setup
To prepare the Pi for this demo, follow the setup instructions here.
Hardware Setup
The first step is attaching the EYESPI Pi Beret to your Raspberry Pi, and then connecting a display using an EYESPI-compatible ribbon cable.
Attach the Beret by pressing the assembled header on the bottom of the Beret onto the GPIO header on the Raspberry Pi.
Then plug an EYESPI cable into the connector on the Beret, and into the connector on a compatible display.
GIF Player Example Code
Copy the following code into a file named rgb_display_eyespi_beret_animated_gif.py, into whatever directory on your Raspberry Pi you wish to run it from.
# SPDX-FileCopyrightText: 2021 Melissa LeBlanc Williams for Adafruit Industries
# SPDX-License-Identifier: MIT
"""
EYESPI Pi Beret GIF Player Demo
Extracts the frames and other parameters from an animated gif
and then runs the animation on the display.
Save this file as eyespi_beret_gif_player.py to your Raspberry Pi.
Usage:
python3 eyespi_beret_gif_player.py
This example is for use on Raspberry Pi that are using CPython with
Adafruit Blinka to support CircuitPython libraries. CircuitPython does
not support PIL/pillow (python imaging library)!
Author(s): Melissa LeBlanc-Williams for Adafruit Industries
Mike Mallett <[email protected]>
"""
import os
import time
import board
import digitalio
import numpy
from PIL import Image, ImageOps
from adafruit_rgb_display import (
hx8357,
ili9341,
ssd1331,
ssd1351,
st7735,
st7789,
)
# Button pins for EYESPI Pi Beret
BUTTON_NEXT = board.D5
BUTTON_PREVIOUS = board.D6
# CS and DC pins for EYEPSPI Pi Beret:
cs_pin = digitalio.DigitalInOut(board.CE0)
dc_pin = digitalio.DigitalInOut(board.D25)
# Reset pin for EYESPI Pi Beret
reset_pin = digitalio.DigitalInOut(board.D27)
# Backlight pin for Pi Beret
backlight = digitalio.DigitalInOut(board.D18)
backlight.switch_to_output()
backlight.value = True
# Config for display baudrate (default max is 64mhz):
BAUDRATE = 64000000
# Setup SPI bus using hardware SPI:
spi = board.SPI()
# fmt: off
# Create the display.
disp = ili9341.ILI9341(spi, rotation=90, # 2.2", 2.4", 2.8", 3.2" ILI9341
# disp = st7789.ST7789(spi, rotation=90, # 2.0" ST7789
# disp = st7789.ST7789(spi, height=240, y_offset=80, rotation=180, # 1.3", 1.54" ST7789
# disp = st7789.ST7789(spi, rotation=90, width=135, height=240, x_offset=53, y_offset=40, # 1.14" ST7789
# disp = st7789.ST7789(spi, rotation=90, width=172, height=320, x_offset=34, # 1.47" ST7789
# disp = st7789.ST7789(spi, rotation=270, width=170, height=320, x_offset=35, # 1.9" ST7789
# disp = hx8357.HX8357(spi, rotation=180, # 3.5" HX8357
# disp = st7735.ST7735R(spi, rotation=90, # 1.8" ST7735R
# disp = st7735.ST7735R(spi, rotation=270, height=128, x_offset=2, y_offset=3, # 1.44" ST7735R
# disp = st7735.ST7735R(spi, rotation=90, bgr=True, width=80, # 0.96" MiniTFT Rev A ST7735R
# disp = st7735.ST7735R(spi, rotation=90, invert=True, width=80, x_offset=26, y_offset=1, # 0.96" MiniTFT Rev B ST7735R # noqa: E501
# disp = ssd1351.SSD1351(spi, rotation=180, # 1.5" SSD1351
# disp = ssd1351.SSD1351(spi, height=96, y_offset=32, rotation=180, # 1.27" SSD1351
# disp = ssd1331.SSD1331(spi, rotation=180, # 0.96" SSD1331
cs=cs_pin,
dc=dc_pin,
rst=reset_pin,
baudrate=BAUDRATE,
)
# fmt: on
def init_button(pin):
button = digitalio.DigitalInOut(pin)
button.switch_to_input()
button.pull = digitalio.Pull.UP
return button
class Frame:
def __init__(self, duration=0):
self.duration = duration
self.image = None
class AnimatedGif:
def __init__(self, display, width=None, height=None, folder=None):
self._frame_count = 0
self._loop = 0
self._index = 0
self._duration = 0
self._gif_files = []
self._frames = []
if width is not None:
self._width = width
else:
self._width = display.width
if height is not None:
self._height = height
else:
self._height = display.height
self.display = display
self.advance_button = init_button(BUTTON_NEXT)
self.back_button = init_button(BUTTON_PREVIOUS)
if folder is not None:
self.load_files(folder)
self.run()
def advance(self):
self._index = (self._index + 1) % len(self._gif_files)
def back(self):
self._index = (self._index - 1 + len(self._gif_files)) % len(self._gif_files)
def load_files(self, folder):
gif_files = [f for f in os.listdir(folder) if f.endswith(".gif")]
for gif_file in gif_files:
gif_file = os.path.join(folder, gif_file) # noqa: PLW2901, loop var overwrite
image = Image.open(gif_file)
# Only add animated Gifs
if image.is_animated:
self._gif_files.append(gif_file)
print("Found", self._gif_files)
if not self._gif_files:
print("No Gif files found in current folder")
exit() # noqa: PLR1722, use sys.exit
def preload(self):
image = Image.open(self._gif_files[self._index])
print(f"Loading {self._gif_files[self._index]}...")
if "duration" in image.info:
self._duration = image.info["duration"]
else:
self._duration = 0
if "loop" in image.info:
self._loop = image.info["loop"]
else:
self._loop = 1
self._frame_count = image.n_frames
self._frames.clear()
for frame in range(self._frame_count):
image.seek(frame)
# Create blank image for drawing.
# Make sure to create image with mode 'RGB' for full color.
frame_object = Frame(duration=self._duration)
if "duration" in image.info:
frame_object.duration = image.info["duration"]
frame_object.image = ImageOps.pad(
image.convert("RGB"),
(self._width, self._height),
method=Image.NEAREST,
color=(0, 0, 0),
centering=(0.5, 0.5),
)
self._frames.append(frame_object)
def play(self):
self.preload()
_prev_advance_btn_val = self.advance_button.value
_prev_back_btn_val = self.back_button.value
# Check if we have loaded any files first
if not self._gif_files:
print("There are no Gif Images loaded to Play")
return False
while True:
for frame_object in self._frames:
start_time = time.monotonic()
self.display.image(frame_object.image)
_cur_advance_btn_val = self.advance_button.value
_cur_back_btn_val = self.back_button.value
if not _cur_advance_btn_val and _prev_advance_btn_val:
self.advance()
return False
if not _cur_back_btn_val and _prev_back_btn_val:
self.back()
return False
_prev_back_btn_val = _cur_back_btn_val
_prev_advance_btn_val = _cur_advance_btn_val
while time.monotonic() < (start_time + frame_object.duration / 1000):
pass
if self._loop == 1:
return True
if self._loop > 0:
self._loop -= 1
def run(self):
while True:
auto_advance = self.play()
if auto_advance:
self.advance()
if disp.rotation % 180 == 90:
disp_height = disp.width # we swap height/width to rotate it to landscape!
disp_width = disp.height
else:
disp_width = disp.width
disp_height = disp.height
gif_player = AnimatedGif(disp, width=disp_width, height=disp_height, folder=".")
This demo is explained in detail here. The explanation is for a slightly different version of the code, but most of it is identical. This demo code was rearranged a bit, and the pins are different. Everything else is the same.
If you are using a display other than the 2.2", 2.4", 2.8", or 3.2" ILI9341 display, you'll need to comment out the first line under # Create the display, and uncomment the line below it that applies to your display. Check out the demo explanation for details.
Usage
Place two or more GIF files in the same directory as you saved the code file. You can find animated GIFs all over the internet. A great website for finding a large collection of them is giphy.com. Once you find them, you'll need to get them over to your Raspberry Pi. The easiest way would be to just use FTP or downloading them directly from the internet on your Pi if that's what you would prefer. Just make sure they're in the same folder as the script.
Then, run the code by typing the following into your command line.
python3 rgb_display_eyespi_beret_animated_gif.py
The first GIF should begin playing on the display.
To cycle through the other GIFs, press the buttons on the Pi Beret. The button marked 6 will advance to the next one, and the button marked 5 will go back to the previous one.
Page last edited January 19, 2025
Text editor powered by tinymce.