This code will display a series of .bmp files in a folder as a slideshow. You can create as many folders as you'd like. The images in each folder will display as their own slideshow. 

Press the UP button to pause the slideshow on any image you'd like, and press it again to resume the slideshow.

Press the DOWN button to cycle to the next folder and show the next slideshow.

You can set the amount of time each slide stays on the screen separately for each folder - so you can have a fast scrolling animation for one folder and a slower slideshow for a different folder.

The slideshow will continue to play while you're holding your bag and moving around. If you set your bag down and it stops moving, the Matrix Portal will put the display to sleep after 2 minutes to save battery life. 

And of course, you can customize all the timing in the code. 

Libraries

We'll need to make sure we have these libraries installed. (Check out this link on installing libraries if needed.)

  • adafruit_bus_device
  • adafruit_debouncer
  • adafruit_lis3dh
  • adafruit_matrixportal
  • adafruit_slideshow

Text Editor

Adafruit recommends using the Mu editor for editing your CircuitPython code. You can get more info in this guide.

Alternatively, you can use any text editor that saves simple text files.

Code

Click the Download: Project Zip File link below in the code window to get a zip file with all the files needed for the project. Copy code.py from the zip file and place on the CIRCUITPY drive.

You'll also need to copy the following files to the CIRCUITPY drive. See the graphic at the top of the page as to filenames and where they go):

  • /bmps, /bmps2 and /bmps3 directories, which contain the graphics .bmp files for three different sample slide shows.

The button below contains our sample graphics: a VOTE sign, a nyancat animation, and a mermaid slideshow.

The program will automatically use any .bmp files in these directories. Make sure they have legal names (no spaces or weird characters!) and are a maximum of 64x32 pixels. 16-bit or 24-bit both work fine.
# SPDX-FileCopyrightText: 2020 Melissa LeBlanc-Williams for Adafruit Industries
# SPDX-FileCopyrightText: 2020 Erin St Blaine for Adafruit Industries
#
# SPDX-License-Identifier: MIT

"""
Slideshow Example using the Matrix Portal and 64 x 32 LED matrix display
Written by Melissa LeBlanc-Williams and Erin St Blaine for Adafruit Industries
Images smaller than 64 pixel width will be aligned alternating left or right
Press Up button to pause/resume Slideshow
Press Down button to cycle between slideshow folders
"""
import time
import board
import adafruit_lis3dh
import displayio
import busio
from digitalio import DigitalInOut, Pull
from adafruit_matrixportal.matrix import Matrix
from adafruit_slideshow import SlideShow, HorizontalAlignment
from adafruit_debouncer import Debouncer

'''
Display will go to sleep after SLEEP_DURATION seconds have elapsed with no accelerometer movement
Each slide will play for IMAGE_DURATION - customizable for each folder
Add folders to the list to add more slideshows.
'''

SLEEP_DURATION = 60
IMAGE_DURATION = (1, 0.5, 10)
IMAGE_FOLDER = (
    "/bmps",
    "/bmps2",
    "/bmps3",
)
# pylint: disable=invalid-name
# --- Display setup ---
matrix = Matrix(bit_depth=6)
display = matrix.display
ACCEL = adafruit_lis3dh.LIS3DH_I2C(busio.I2C(board.SCL, board.SDA),
                                   address=0x19)
_ = ACCEL.acceleration # Dummy reading to blow out any startup residue

pin_down = DigitalInOut(board.BUTTON_DOWN)
pin_down.switch_to_input(pull=Pull.UP)
button_down = Debouncer(pin_down)
pin_up = DigitalInOut(board.BUTTON_UP)
pin_up.switch_to_input(pull=Pull.UP)
button_up = Debouncer(pin_up)

ALIGN_RIGHT = True
auto_advance = True

i = 0
NUM_FOLDERS = 2 #first folder is numbered 0

slideshow = SlideShow(
    display,
    None,
    folder=IMAGE_FOLDER[i],
    order=0,
    auto_advance=False,
    fade_effect=False,
    dwell=IMAGE_DURATION[i],
    h_align=HorizontalAlignment.RIGHT,
)

LAST_ADVANCE = time.monotonic()
last_movement = time.monotonic()
MODE = 1

def advance():
    ''' go to the next slide '''
    # pylint: disable=global-statement
    global ALIGN_RIGHT, LAST_ADVANCE
    ALIGN_RIGHT = not ALIGN_RIGHT
    if ALIGN_RIGHT:
        slideshow.h_align = HorizontalAlignment.RIGHT
    else:
        slideshow.h_align = HorizontalAlignment.LEFT
    LAST_ADVANCE = time.monotonic()
    slideshow.advance()

empty_group = displayio.Group()

while True:
    if ACCEL.shake(shake_threshold=10):
        print("Moving!")
        if MODE == 0:
            slideshow = SlideShow(
                display,
                None,
                folder=IMAGE_FOLDER[i],
                order=0,
                auto_advance=False,
                fade_effect=False,
                dwell=IMAGE_DURATION[i],
                h_align=HorizontalAlignment.RIGHT,
            )
        last_movement = time.monotonic()
        MODE = 1
    elif time.monotonic() > last_movement + SLEEP_DURATION:
        MODE = 0
        display.root_group = empty_group
    if MODE == 1:
        if auto_advance and time.monotonic() > LAST_ADVANCE + IMAGE_DURATION[i]:
            advance()
        button_down.update()
        button_up.update()
        if button_up.fell:
            auto_advance = not auto_advance
        if button_down.fell:
            i = i + 1
            if i > NUM_FOLDERS:
                i = 0
            slideshow = SlideShow(
                display,
                None,
                folder=IMAGE_FOLDER[i],
                order=0,
                auto_advance=False,
                fade_effect=False,
                dwell=IMAGE_DURATION[i],
                h_align=HorizontalAlignment.RIGHT,
            )

Pixel Art Specs

If you want to create your own artwork for display, these are the specifications to follow:

  • Images should be a maximum of 32 pixels high
  • Images can be up to 64 pixels wide
  • Colors are 16-bit or 24-bit RGB
  • Save files as .bmp format

We've found that crisp images (not too much anti-aliasing) work best.

We have a whole page on Pixel Art Fundamentals here!

You can use nearly any paint program, but dedicated pixel art programs work best, such as Aseprite or the free pixel art app Piskel.

Art Collecting

If you want to search for ready-made art to display, here are some tips.

Game Frame Art

The excellent Game Frame product by Jeremy Williams pioneered the pixel art frame. You can check the LedSeq Game Frame forums for art gallery submissions. Although these tend to be 16x16 pixel images, you can scale them up (don't interpolate!) for use on the Matrix Portal.

Jeremy has also graciously made the code and art for Game Frame available for free download here.

Search

Another great tip from LedSeq is to use a Google image search to return results of "pixel art" or "video game" at a specific resolution, either 64x32 or 32x32:

https://www.google.com/search?q=pixel+art&tbm=isch&tbs=isz:ex,iszw:32,iszh:32

Itch.io Assets

Many talented artist post their pixel art game assets to Itch.io where you can name your price in many case for amazing artwork!

Shown here are the excellent PIPOYA FREE RPG Character Sprites.

How it Works

Libraries

Here's how the code works. First we import the libraries:

import time
import board
import adafruit_lis3dh
import displayio
import busio
from digitalio import DigitalInOut, Pull
from adafruit_matrixportal.matrix import Matrix
from adafruit_slideshow import SlideShow, HorizontalAlignment
from adafruit_debouncer import Debouncer

Variables

Then, we'll set the variables for SLEEP_DURATION(how long until the display goes dark if it's not moving) and IMAGE_DURATION (how long each image stays on the screen in each slide show) in seconds, as well as the path to the image folders.

Add as many folders as you like, but be sure to change the variable for NUM_FOLDERS further down if you add more.

SLEEP_DURATION = 60
IMAGE_DURATION = (1, 0.5, 10)
IMAGE_FOLDER = (
    "/bmps",
    "/bmps2",
    "/bmps3",
)

Display/Pin Setup

Next, we set up the display and the pins used for the buttons.

matrix = Matrix(bit_depth=6)
display = matrix.display

pin_down = DigitalInOut(board.BUTTON_DOWN)
pin_down.switch_to_input(pull=Pull.UP)
button_down = Debouncer(pin_down)
pin_up = DigitalInOut(board.BUTTON_UP)
pin_up.switch_to_input(pull=Pull.UP)
button_up = Debouncer(pin_up)

Slideshow Setup

The alignment of images narrower than 64 pixels wide will alternate, initially with right-side alignment. The auto_advance state is set to true initially, but can be changed by pressing the UP button later.

The slideshow is set up next using the settings shown here.

And take a look at the NUM_FOLDERS variable -- if you add or remove folders you'll want to change this number. Remember, the first folder is numbered 0, so change this variable to one fewer than you have.

ALIGN_RIGHT = True
auto_advance = True

i = 0
NUM_FOLDERS = 2  # The first folder is numbered 0

slideshow = SlideShow(
    display,
    None,
    folder=IMAGE_FOLDER[i],
    order=0,
    auto_advance=False,
    fade_effect=False,
    dwell=IMAGE_DURATION[i],
    h_align=HorizontalAlignment.RIGHT,
)

LAST_ADVANCE = time.monotonic()
last_movement = time.monotonic()
MODE = 1

Advance!

The advance() function will be used to drive the slideshow.advance() command using the alternating right/left alignment and auto-advance features.

def advance():
    # pylint: disable=global-statement
    global align_right, last_advance
    align_right = not align_right
    if align_right:
        slideshow.h_align = HorizontalAlignment.RIGHT
    else:
        slideshow.h_align = HorizontalAlignment.LEFT
    last_advance = time.monotonic()
    slideshow.advance()

Main Loop

Here's what happens during the main loop of the program:

  • Check if the display is in motion or not. If so, run the slideshows. If not, put the display to sleep.
  • Check if auto_advance is on, and if the time.monotonic() value is bigger than the last_advance time plus the IMAGE_DURATION time. If so, advance() to the next image!
  • Check for button presses:
    • If the UP button is pressed, toggle the auto_advance state
    • If the DOWN button is pressed, manually advance to the next image
while True:
    if ACCEL.shake(shake_threshold=10):
        print("Moving!")
        if MODE == 0:
            slideshow = SlideShow(
                display,
                None,
                folder=IMAGE_FOLDER[i],
                order=0,
                auto_advance=False,
                fade_effect=False,
                dwell=IMAGE_DURATION[i],
                h_align=HorizontalAlignment.RIGHT,
            )
        last_movement = time.monotonic()
        MODE = 1
    elif time.monotonic() > last_movement + SLEEP_DURATION:
        MODE = 0
        display.root_group = empty_group
    if MODE == 1:
        if auto_advance and time.monotonic() > LAST_ADVANCE + IMAGE_DURATION[i]:
            advance()
        button_down.update()
        button_up.update()
        if button_up.fell:
            auto_advance = not auto_advance
        if button_down.fell:
            i = i + 1
            if i > NUM_FOLDERS:
                i = 0
            slideshow = SlideShow(
                display,
                None,
                folder=IMAGE_FOLDER[i],
                order=0,
                auto_advance=False,
                fade_effect=False,
                dwell=IMAGE_DURATION[i],
                h_align=HorizontalAlignment.RIGHT,
            )

This guide was first published on Oct 21, 2020. It was last updated on 2023-12-06 14:32:18 -0500.

This page (Code the Slideshow) was last updated on Dec 06, 2023.

Text editor powered by tinymce.