Installing or upgrading CircuitPython
You should ensure you have CircuitPython 5.3 or greater on your board. Plug your board in with a known good data + power cable (not the cheesy USB cable that comes with USB power packs, they are power only). You should see a new flash drive pop up.
If the drive is CIRCUITPY, then open the boot_out.txt file to ensure the version number is 5.3 or greater.
Adafruit CircuitPython 5.3.0 on 2020-04-29; Adafruit Feather M4 Express with samd51j19
If the version is less than 5 -or- you only get a drive named FEATHERBOOT then follow the Feather M4 guide on installing CircuitPython.
Download the Adafruit CircuitPython Library Bundle
In order to run the code, we'll need to download a few libraries. Libraries contain code to help interface with hardware a lot easier for us.
Use the Feather M4 page on Installing Libraries to get the library that matches the major version of CircuitPython you are using noted above.
The green button below links to a file containing all the libraries available for CircuitPython. To run the code for this project, we need a few of the libraries in the list below. Unzip the library bundle and search for the libraries. Drag and drop the files into a folder named lib on the CIRCUITPY drive (create the folder if it is not already on the Feather M4).
Required Libraries
- adafruit_bus_device (directory)
- adafruit_display_shapes (directory)
- adafruit_imageload (directory)
You'll also need the .bmp files. You can add your own files or customize ours. If you're adding your own .bmp files, be sure they're 64 pixels wide. I had the most success when I saved as 8 bit color-indexed files.
Once we have all the files we need, a directory listing will look similar to below as far as files and directories.
Upload Code
Click on the Download: Project Zip link below to grab the project files in a zip file directly from GitHub. Place the code.py file and bitmap graphics files onto the CIRCUITPY main (root) directory. The code will run properly when all of the files have been uploaded including libraries.
Use any text editor or favorite IDE to modify the code. We suggest using Mu as noted above.
# SPDX-FileCopyrightText: 2020 Jeff Epler for Adafruit Industries # SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries # # SPDX-License-Identifier: MIT """ RGB Matrix Ocean Scroller Adafruit invests time and resources providing this open source code. Please support Adafruit and open source hardware by purchasing products from Adafruit! Written by Jeff Epler & Limor Fried for Adafruit Industries Copyright (c) 2019-2020 Adafruit Industries Licensed under the MIT license. All text above must be included in any redistribution. """ import math import time import random import adafruit_imageload.bmp import board import displayio import framebufferio import rgbmatrix import ulab displayio.release_displays() class Reshader: '''reshader fades the image to mimic brightness control''' def __init__(self, palette): self.palette = palette ulab_palette = ulab.numpy.zeros((len(palette), 3)) for i in range(len(palette)): rgb = int(palette[i]) ulab_palette[i, 2] = rgb & 0xff ulab_palette[i, 1] = (rgb >> 8) & 0xff ulab_palette[i, 0] = rgb >> 16 self.ulab_palette = ulab_palette def reshade(self, brightness): '''reshader''' palette = self.palette shaded = ulab.numpy.array(self.ulab_palette * brightness, dtype=ulab.numpy.uint8) for i in range(len(palette)): palette[i] = tuple(shaded[i]) def do_crawl_down(image_file, *, speed=12, weave=4, pulse=.5, weave_speed=1/6, pulse_speed=1/7): # pylint:disable=too-many-locals '''function to scroll the image''' the_bitmap, the_palette = adafruit_imageload.load( image_file, bitmap=displayio.Bitmap, palette=displayio.Palette) shader = Reshader(the_palette) group = displayio.Group() tile_grid = displayio.TileGrid(bitmap=the_bitmap, pixel_shader=the_palette) group.append(tile_grid) display.root_group = group start_time = time.monotonic_ns() start_y = display.height # High enough to be "off the top" end_y = -the_bitmap.height # Low enough to be "off the bottom" # Mix up how the bobs and brightness change on each run r1 = random.random() * math.pi r2 = random.random() * math.pi y = start_y while y > end_y: now = time.monotonic_ns() y = start_y - speed * ((now - start_time) / 1e9) group.y = round(y) # wave from side to side group.x = round(weave * math.cos(y * weave_speed + r1)) # Change the brightness if pulse > 0: shader.reshade((1 - pulse) + pulse * math.sin(y * pulse_speed + r2)) display.refresh(minimum_frames_per_second=0, target_frames_per_second=60) def do_pulse(image_file, *, duration=4, pulse_speed=1/8, pulse=.5): '''pulse animation''' the_bitmap, the_palette = adafruit_imageload.load( image_file, bitmap=displayio.Bitmap, palette=displayio.Palette) shader = Reshader(the_palette) group = displayio.Group() tile_grid = displayio.TileGrid(bitmap=the_bitmap, pixel_shader=the_palette) group.append(tile_grid) group.x = (display.width - the_bitmap.width) // 2 group.y = (display.height - the_bitmap.height) // 2 display.root_group = group start_time = time.monotonic_ns() end_time = start_time + int(duration * 1e9) now_ns = time.monotonic_ns() while now_ns < end_time: now_ns = time.monotonic_ns() current_time = (now_ns - start_time) / 1e9 shader.reshade((1 - pulse) - pulse * math.cos(2*math.pi*current_time*pulse_speed)**2) display.refresh(minimum_frames_per_second=0, target_frames_per_second=60) matrix = rgbmatrix.RGBMatrix( width=64, height=32, bit_depth=5, rgb_pins=[board.D6, board.D5, board.D9, board.D11, board.D10, board.D12], addr_pins=[board.A5, board.A4, board.A3, board.A2], clock_pin=board.D13, latch_pin=board.D0, output_enable_pin=board.D1) display = framebufferio.FramebufferDisplay(matrix, auto_refresh=False) # Image playlist - set to run randomly. Set pulse from 0 to .5 while True: show_next = random.randint(1, 5) #change to reflect how many images you add if show_next == 1: do_crawl_down("/ray.bmp") elif show_next == 2: do_crawl_down("/waves1.bmp", speed=7, weave=0, pulse=.35) elif show_next == 3: do_crawl_down("/waves2.bmp", speed=9, weave=0, pulse=.35) elif show_next == 4: do_pulse("/heart.bmp", duration=4, pulse=.45) elif show_next == 5: do_crawl_down("/dark.bmp")
Page last edited January 22, 2025
Text editor powered by tinymce.