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.
Download the Project Bundle
Your project will use a specific set of CircuitPython libraries, and the code.py file. To get everything you need, click on the Download Project Bundle link below, and uncompress the .zip file.
Connect the MatrixPortal to your computer with a known good data+power USB cable. The board should show up in your File Explorer / Finder (depending on your operating system) as a flash drive named CIRCUITYPY.
Drag the contents of the uncompressed bundle directory onto your board's CIRCUITPY drive, replacing any existing files or directories with the same names, and adding any new ones that are necessary.
# SPDX-FileCopyrightText: 2023 John Park for Adafruit Industries # # SPDX-License-Identifier: MIT # LCARS MatrixPortal Display # LED brigthness code by Jan Goolsbey import time import os import board import displayio from digitalio import DigitalInOut, Pull from simpleio import map_range # For color brightness calculation from adafruit_matrixportal.matrix import Matrix from adafruit_debouncer import Debouncer import supervisor supervisor.runtime.autoreload = True SPRITESHEET_FOLDER = "/bmps" DEFAULT_FRAME_DURATION = 0.7 # 100ms AUTO_ADVANCE_LOOPS = 3 bitmap = "" brightness = 15 # ### Integer value from 0 to 15 # --- Display setup --- matrix = Matrix(bit_depth=4, width=128, height=64) sprite_group = displayio.Group() matrix.display.root_group = sprite_group # --- Button setup --- 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) auto_advance = False file_list = sorted( [ f for f in os.listdir(SPRITESHEET_FOLDER) if (f.endswith(".bmp") and not f.startswith(".")) ] ) if len(file_list) == 0: raise RuntimeError("No images found") current_image = None current_frame = 0 current_loop = 0 frame_count = 0 frame_duration = DEFAULT_FRAME_DURATION def image_brightness(new_bright=0): """Calculate the white color brightness. Returns a white RBG888 color value proportional to `new_bright`.""" # Scale brightness value bright = int(map_range(new_bright, 0, 15, 0x00, 0xFF)) # Recombine and return a composite RGB888 value return (bright << 16) + (bright << 8) + bright def load_image(): """ Load an image as a sprite """ # pylint: disable=global-statement global current_frame, current_loop, frame_count, frame_duration, bitmap while sprite_group: sprite_group.pop() filename = SPRITESHEET_FOLDER + "/" + file_list[current_image] bitmap = displayio.OnDiskBitmap(filename) ### Change the palette value proportional to BRIGHTNESS bitmap.pixel_shader[1] = image_brightness(brightness) sprite = displayio.TileGrid( bitmap, pixel_shader=bitmap.pixel_shader, tile_width=bitmap.width, tile_height=matrix.display.height, ) sprite_group.append(sprite) current_frame = 0 current_loop = 0 frame_count = int(bitmap.height / matrix.display.height) frame_duration = DEFAULT_FRAME_DURATION def advance_image(): """ Advance to the next image in the list and loop back at the end """ # pylint: disable=global-statement global current_image if current_image is not None: current_image += 1 if current_image is None or current_image >= len(file_list): current_image = 0 load_image() def advance_frame(): """ Advance to the next frame and loop back at the end """ # pylint: disable=global-statement global current_frame, current_loop current_frame = current_frame + 1 if current_frame >= frame_count: current_frame = 0 current_loop = current_loop + 1 sprite_group[0][0] = current_frame advance_image() last_time = time.monotonic() while True: button_down.update() button_up.update() if button_up.fell: advance_image() if button_down.fell: brightness = (brightness + 2) % 16 print(brightness) bitmap.pixel_shader[1] = image_brightness(brightness) # ### Change the brightness if time.monotonic() - last_time > frame_duration: advance_frame() last_time = time.monotonic()
Bitmaps
Included are the following 4-bit 128x64 pixel bitmap files. One is blank (for "off"), one has white pixels that align with the lit LCARS segments, and the third one is a vertical sprite sheet that animates the segments.
How it Works
Libraries
First, to import the time, os, board, displayio, digitalio, simpleio, adafruit_matrixportal,
and adafruit_debouncer
libraries.
import time import os import board import displayio from digitalio import DigitalInOut, Pull from simpleio import map_range # For color brightness calculation from adafruit_matrixportal.matrix import Matrix from adafruit_debouncer import Debouncer
Variables
Next, to set up variables for the sprite playback.
SPRITESHEET_FOLDER = "/bmps" DEFAULT_FRAME_DURATION = 0.7 # 100ms AUTO_ADVANCE_LOOPS = 3 brightness = 15
Display Setup
The display setup instantiates the matrix display with the proper bit depth, width and height settings.
# --- Display setup --- matrix = Matrix(bit_depth=4, width=128, height=64) sprite_group = displayio.Group() matrix.display.root_group = sprite_group
Button Setup
Use the two user buttons on the Matrix Portal to adjust the brightness of the panel and to pick different sprites (still, animated, blank).
# --- Button setup --- 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)
File List
This code is used to check for the images inside of the ".bmp" folder on the CIRCUITPY drive.
file_list = sorted( [ f for f in os.listdir(SPRITESHEET_FOLDER) if (f.endswith(".bmp") and not f.startswith(".")) ] ) if len(file_list) == 0: raise RuntimeError("No images found") current_image = None current_frame = 0 current_loop = 0 frame_count = 0 frame_duration = DEFAULT_FRAME_DURATION
Image Brightness Function
This handy function (created by Jan Goolsbey, thanks Jan!) is used to adjust the brightness value of the RGB LED matrix.
def image_brightness(new_bright=0): """Calculate the white color brightness. Returns a white RBG888 color value proportional to `new_bright`.""" # Scale brightness value bright = int(map_range(new_bright, 0, 15, 0x00, 0xFF)) # Recombine and return a composite RGB888 value return (bright << 16) + (bright << 8) + bright
Load Image, Advance Image and Advance Frame Functions
These functions are used to load images as sprites and advance between them (with a button press later).
The advance_frame()
function is used to move among the frames of a sprite sheet for animation.
def load_image(): """ Load an image as a sprite """ # pylint: disable=global-statement global current_frame, current_loop, frame_count, frame_duration, bitmap while sprite_group: sprite_group.pop() filename = SPRITESHEET_FOLDER + "/" + file_list[current_image] bitmap = displayio.OnDiskBitmap(filename) ### Change the palette value proportional to BRIGHTNESS bitmap.pixel_shader[1] = image_brightness(brightness) sprite = displayio.TileGrid( bitmap, pixel_shader=bitmap.pixel_shader, tile_width=bitmap.width, tile_height=matrix.display.height, ) sprite_group.append(sprite) current_frame = 0 current_loop = 0 frame_count = int(bitmap.height / matrix.display.height) frame_duration = DEFAULT_FRAME_DURATION def advance_image(): """ Advance to the next image in the list and loop back at the end """ # pylint: disable=global-statement global current_image if current_image is not None: current_image += 1 if current_image is None or current_image >= len(file_list): current_image = 0 load_image() def advance_frame(): """ Advance to the next frame and loop back at the end """ # pylint: disable=global-statement global current_frame, current_loop current_frame = current_frame + 1 if current_frame >= frame_count: current_frame = 0 current_loop = current_loop + 1 sprite_group[0][0] = current_frame
Main Loop
The main loop of the program checks for button presses and then calls a function.
When the down button is pressed, the image brightness increases (each click increases brightness until we loop back around to 0 on the eighth click).
When the up button is pressed, the advance_image()
function is called, and the next image in the .bmp folder is displayed.
When the current time.monotonic()
minus the last_time
is greater than the frame_duration
, the next frame of the sprite sheet is displayed.
while True: button_down.update() button_up.update() if button_up.fell: advance_image() if button_down.fell: brightness = (brightness + 2) % 16 print(brightness) bitmap.pixel_shader[1] = image_brightness(brightness) # ### Change the brightness if time.monotonic() - last_time > frame_duration: advance_frame() last_time = time.monotonic()
Text editor powered by tinymce.