Wiring
It's easy to connect everything together with the Mini PiTFT player. First connect the display to the Raspberry Pi:
Then just connect a STEMMA QT Rotary Encoded up the the STEMMA QT Connector on the Mini PiTFT.
Setup
You will want to start by installing the latest version of the Raspberry Pi Lite onto an SD card. You can refer to the CircuitPython Libraries on Linux and Raspberry Pi guide for more help setting it up.
Once you have everything set up, you will need to open a terminal and install Blinka. Refer to the Installing CircuitPython Libraries on Raspberry Pi page to quickly get up and running.
Install Required Libraries
You will need to have a few libraries installed before the script will run on your computer.
Install the required CircuitPython libraries:
pip3 install adafruit-circuitpython-rgb-display pip3 install adafruit-circuitpython-seesaw pip3 install --upgrade --force-reinstall spidev
Also, install NumPy since it will speed up the RGB Display library:
pip3 install numpy
DejaVu TTF Font
Raspberry Pi usually comes with the DejaVu font already installed, but in case it didn't, you can run the following to install it:
sudo apt-get install ttf-dejavu
Pillow Library
We also need PIL, the Python Imaging Library, to allow graphics and using text with custom fonts. There are several system libraries that PIL relies on, so installing via a package manager is the easiest way to bring in everything:
sudo apt-get install python3-pil
Download the Code
Copy mini_pitft_player.py and animatedgif.py onto the Raspberry Pi. You can download them by clicking on the Download Project Bundle below or you can use wget
to copy them right off the web into your current folder:
wget https://github.com/adafruit/Adafruit_Learning_System_Guides/raw/main/Raspberry_Pi_Animated_Gif_Player/mini_pitft_player.py wget https://github.com/adafruit/Adafruit_Learning_System_Guides/raw/main/Raspberry_Pi_Animated_Gif_Player/animatedgif.py
python3 mini_pitft_player.py
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-License-Identifier: MIT """ This example is for use on (Linux) computers 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 """ import digitalio import board from animatedgif import AnimatedGif import numpy # pylint: disable=unused-import from adafruit_seesaw import seesaw, rotaryio, digitalio as ss_digitalio from adafruit_rgb_display import st7789 i2c = board.I2C() # uses board.SCL and board.SDA # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller seesaw = seesaw.Seesaw(i2c, addr=0x36) seesaw_product = (seesaw.get_version() >> 16) & 0xFFFF print("Found product {}".format(seesaw_product)) if seesaw_product != 4991: print("Wrong firmware loaded? Make sure you have a rotary encoder connected.") seesaw.pin_mode(24, seesaw.INPUT_PULLUP) button = ss_digitalio.DigitalIO(seesaw, 24) encoder = rotaryio.IncrementalEncoder(seesaw) # Change to match your display BUTTON_UP = board.D23 BUTTON_DOWN = board.D24 # Configuration for CS and DC pins (these are PiTFT defaults): cs_pin = digitalio.DigitalInOut(board.CE0) dc_pin = digitalio.DigitalInOut(board.D25) def init_button(pin): digital_button = digitalio.DigitalInOut(pin) digital_button.switch_to_input(pull=digitalio.Pull.UP) return digital_button class TFTAnimatedGif(AnimatedGif): def __init__(self, display, include_delays=True, folder=None): self._width = display.width self._height = display.height self.up_button = init_button(BUTTON_UP) self.down_button = init_button(BUTTON_DOWN) self._last_position = None self._button_state = False super().__init__(display, include_delays=include_delays, folder=folder) def get_next_value(self): while self._running: position = -encoder.position if position != self._last_position: self._last_position = position return str(position) elif not button.value and not self._button_state: self._button_state = True return str("click") elif button.value and self._button_state: self._button_state = False if not self.up_button.value or not self.down_button.value: self._running = False return None def update_display(self, image): self.display.image(image) # Config for display baudrate (default max is 64mhz): BAUDRATE = 64000000 # Setup SPI bus using hardware SPI: spi = board.SPI() # Create the display: disp = st7789.ST7789( spi, height=240, y_offset=80, rotation=180, cs=cs_pin, dc=dc_pin, rst=None, baudrate=BAUDRATE, ) gif_player = TFTAnimatedGif(disp, include_delays=False, folder="images")
# SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries # # SPDX-License-Identifier: MIT import os import time from PIL import Image, ImageOps # pylint: disable=too-few-public-methods class Frame: def __init__(self, duration=0): self.duration = duration self.image = None # pylint: enable=too-few-public-methods class AnimatedGif: def __init__(self, display, include_delays=True, folder=None): self._frame_count = 0 self._loop = 0 self._index = 0 self._duration = 0 self._gif_files = [] self._frames = [] self._running = True self.display = display self.include_delays = include_delays 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")] gif_folder = folder if gif_folder[:-1] != "/": gif_folder += "/" for gif_file in gif_files: image = Image.open(gif_folder + gif_file) # Only add animated Gifs if image.is_animated: self._gif_files.append(gif_folder + gif_file) print("Found", self._gif_files) if not self._gif_files: print("No Gif files found in current folder") exit() # pylint: disable=consider-using-sys-exit def preload(self): image = Image.open(self._gif_files[self._index]) print("Loading {}...".format(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( # pylint: disable=no-member 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() current_frame = 0 last_action = None # Check if we have loaded any files first if not self._gif_files: print("There are no Gif Images loaded to Play") return False self.update_display(self._frames[current_frame].image) while self._running: action = self.get_next_value() if action: if not last_action: last_action = action if action == "click": self.advance() return False elif int(action) < int(last_action): current_frame -= 1 else: current_frame += 1 current_frame %= self._frame_count frame_object = self._frames[current_frame] start_time = time.monotonic() self.update_display(frame_object.image) if self.include_delays: remaining_delay = frame_object.duration / 1000 - ( time.monotonic() - start_time ) if remaining_delay > 0: time.sleep(remaining_delay) last_action = action if self._loop == 1: return True if self._loop > 0: self._loop -= 1 def run(self): while self._running: auto_advance = self.play() if auto_advance: self.advance()
Text editor powered by tinymce.