Once you've finished setting up your Feather RP2040 Propmaker with CircuitPython, you can access the code and necessary libraries by downloading the Project Bundle.
To do this, click on the Download Project Bundle button in the window below. It will download to your computer as a zipped folder.
# SPDX-FileCopyrightText: 2017 Limor Fried for Adafruit Industries
#
# SPDX-License-Identifier: MIT
# Dotstar POV Display! Can handle up to ~2300 pixel size image (e.g. 36 x 64)
import gc
import time
from adafruit_motorkit import MotorKit
import board
import busio
import digitalio
kit = MotorKit(i2c=board.I2C())
FILENAME = "nyan-xmas.bmp"
IMAGE_DELAY = 0.001
REPEAT = True
BRIGHTNESS = 0.3
PIXEL_DELAY = 0.003
dotstar = busio.SPI(board.SCK, board.MOSI)
while not dotstar.try_lock():
pass
dotstar.configure(baudrate=44000000)
# we'll resize this later
databuf = bytearray(0)
led = digitalio.DigitalInOut(board.D13)
led.switch_to_output()
def read_le(s):
# as of this writting, int.from_bytes does not have LE support, DIY!
result = 0
shift = 0
for byte in bytearray(s):
result += byte << shift
shift += 8
return result
class BMPError(Exception):
pass
try:
with open("/" + FILENAME, "rb") as f:
print("File opened")
if f.read(2) != b'BM': # check signature
raise BMPError("Not BitMap file")
bmpFileSize = read_le(f.read(4))
f.read(4) # Read & ignore creator bytes
bmpImageoffset = read_le(f.read(4)) # Start of image data
headerSize = read_le(f.read(4))
bmpWidth = read_le(f.read(4))
bmpHeight = read_le(f.read(4))
flip = True
print("Size: %d\nImage offset: %d\nHeader size: %d" %
(bmpFileSize, bmpImageoffset, headerSize))
print("Width: %d\nHeight: %d" % (bmpWidth, bmpHeight))
if read_le(f.read(2)) != 1:
raise BMPError("Not singleplane")
bmpDepth = read_le(f.read(2)) # bits per pixel
print("Bit depth: %d" % (bmpDepth))
if bmpDepth != 24:
raise BMPError("Not 24-bit")
if read_le(f.read(2)) != 0:
raise BMPError("Compressed file")
print("Image OK!")
rowSize = (bmpWidth * 3 + 3) & ~3 # 32-bit line boundary
# its huge! but its also fast :)
databuf = bytearray(bmpWidth * bmpHeight * 4)
for row in range(bmpHeight): # For each scanline...
if flip: # Bitmap is stored bottom-to-top order (normal BMP)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize
else: # Bitmap is stored top-to-bottom
pos = bmpImageoffset + row * rowSize
# print ("seek to %d" % pos)
f.seek(pos)
for col in range(bmpWidth):
b, g, r = bytearray(f.read(3)) # BMP files store RGB in BGR
# front load brightness, gamma and reordering here!
order = [b, g, r]
idx = (col * bmpHeight + (bmpHeight - row - 1)) * 4
databuf[idx] = 0xFF # first byte is 'brightness'
idx += 1
for color in order:
databuf[idx] = int(
pow((color * BRIGHTNESS) / 255, 2.7) * 255 + 0.5)
idx += 1
except BMPError as e:
print("Failed to parse BMP: " + e.args[0])
gc.collect()
print(gc.mem_free())
print("Ready to go!")
kit.motor1.throttle = 1
while True:
print("Draw!")
index = 0
for col in range(bmpWidth):
row = databuf[index:index + bmpHeight * 4]
dotstar.write(bytearray([0x00, 0x00, 0x00, 0x00]))
dotstar.write(row)
dotstar.write(bytearray([0x00, 0x00, 0x00, 0x00]))
index += bmpHeight * 4
time.sleep(PIXEL_DELAY)
# clear it out
dotstar.write(bytearray([0x00, 0x00, 0x00, 0x00]))
for r in range(bmpHeight * 5):
dotstar.write(bytearray([0xFF, 0x00, 0x00, 0x00]))
dotstar.write(bytearray([0xff, 0xff, 0xff, 0xff]))
gc.collect()
if not REPEAT:
break
time.sleep(IMAGE_DELAY)
Upload the code, images and Libraries to the Feather RP2040
After downloading the Project Bundle, plug your Feather RP2040 into the computer's USB port with a known good USB data+power cable. You should see a new flash drive appear in the computer's File Explorer or Finder (depending on your operating system) called CIRCUITPY. Unzip the folder and copy the following items to the Feather RP2040's CIRCUITPY drive.
- lib folder
- code.py
- blinka.bmp
- sans.bmp
- dreidel.bmp
- nyan-xmas.bmp
- pipesky.bmp
- xmas.bmp
- xmastree.bmp
Your Feather RP2040 CIRCUITPY drive should look like this after copying the lib folder, images and the code.py file.
Adjusting Image
At the top of the code, there are some user configurable settings that you can edit.
-
FILENAMEis the title of the image the display will draw. Change this variable to the desired image name to display -
BRIGHTNESSaffects the overall brightness of the LEDs -
PIXEL_DELAYaffects how the image is scaled when in motion. If the image appears stretched, lower the number. If it appears squished, increase the number
FILENAME = "nyan-xmas.bmp" IMAGE_DELAY = 0.001 REPEAT = True BRIGHTNESS = 0.3 PIXEL_DELAY = 0.003
Page last edited January 22, 2025
Text editor powered by tinymce.