Overview
NeoPixel LED Holiday Tree
Build an animated LED holiday tree project using Adafruit Feather RP2040 Scorpio and NeoPixel LEDs. Use the NEOPIX8L library for CircuitPython to create advanced animations with buttery smooth frame rates.
3D print and assemble a tree structure that is adorned with NeoPixel LED strips. The Feather RP2040 Scorpio and a Perma-Proto board are housed in snap-fit enclosures.
Prerequisite Guides
Take a moment to review the following guides.
Page last edited March 08, 2024
Text editor powered by tinymce.
Circuit Diagram
The diagram below provides a visual reference for wiring of the components. This diagram was created using the software package Fritzing.
Adafruit Library for Fritzing
Use Adafruit's Fritzing parts library to create circuit diagrams for your projects. Download the library or just grab individual parts. Get the library and parts from GitHub - Adafruit Fritzing Parts.
Scorpio Power
See this guide for more about powering Scorpio projects.
Wired Connections
The Feather RP2040 Scorpio is powered by 5V USB power supply. The NeoPixel strips should be powered separately a 5V 10A power supply.
3-pin JST socket connectors are wired into a Perma-Proto board to allow the NeoPixel strips to plug into.
A wire is connected from the Feather RP2040 Scorpio ground pin to the ground rails on the Perma-Proto board.
The power and ground rails from the Perma-Proto are connected to a 2.1mm DC power jack.
A 2x8 IDC cable is used to connect the Feather RP2040 Scorpio to the Perma-Proto board.
Page last edited March 08, 2024
Text editor powered by tinymce.
Install CircuitPython
CircuitPython is a derivative of MicroPython designed to simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the CIRCUITPY drive to iterate.
CircuitPython Quickstart
Follow this step-by-step to quickly get CircuitPython running on your board.
Click the link above to download the latest CircuitPython UF2 file.
Save it wherever is convenient for you.
To enter the bootloader, hold down the BOOT/BOOTSEL button (highlighted in red above), and while continuing to hold it (don't let go!), press and release the reset button (highlighted in red or blue above). Continue to hold the BOOT/BOOTSEL button until the RPI-RP2 drive appears!
If the drive does not appear, release all the buttons, and then repeat the process above.
You can also start with your board unplugged from USB, press and hold the BOOTSEL button (highlighted in red above), continue to hold it while plugging it into USB, and wait for the drive to appear before releasing the button.
A lot of people end up using charge-only USB cables and it is very frustrating! Make sure you have a USB cable you know is good for data sync.
You will see a new disk drive appear called RPI-RP2.
Drag the adafruit_circuitpython_etc.uf2 file to RPI-RP2.
The RPI-RP2 drive will disappear and a new disk drive called CIRCUITPY will appear.
That's it, you're done! :)
Safe Mode
You want to edit your code.py or modify the files on your CIRCUITPY drive, but find that you can't. Perhaps your board has gotten into a state where CIRCUITPY is read-only. You may have turned off the CIRCUITPY drive altogether. Whatever the reason, safe mode can help.
Safe mode in CircuitPython does not run any user code on startup, and disables auto-reload. This means a few things. First, safe mode bypasses any code in boot.py (where you can set CIRCUITPY read-only or turn it off completely). Second, it does not run the code in code.py. And finally, it does not automatically soft-reload when data is written to the CIRCUITPY drive.
Therefore, whatever you may have done to put your board in a non-interactive state, safe mode gives you the opportunity to correct it without losing all of the data on the CIRCUITPY drive.
To enter safe mode when using CircuitPython, plug in your board or hit reset (highlighted in red above). Immediately after the board starts up or resets, it waits 1000ms. On some boards, the onboard status LED (highlighted in green above) will blink yellow during that time. If you press reset during that 1000ms, the board will start up in safe mode. It can be difficult to react to the yellow LED, so you may want to think of it simply as a slow double click of the reset button. (Remember, a fast double click of reset enters the bootloader.)
In Safe Mode
If you successfully enter safe mode on CircuitPython, the LED will intermittently blink yellow three times.
If you connect to the serial console, you'll find the following message.
Auto-reload is off. Running in safe mode! Not running saved code. CircuitPython is in safe mode because you pressed the reset button during boot. Press again to exit safe mode. Press any key to enter the REPL. Use CTRL-D to reload.
You can now edit the contents of the CIRCUITPY drive. Remember, your code will not run until you press the reset button, or unplug and plug in your board, to get out of safe mode.
Flash Resetting UF2
If your board ever gets into a really weird state and CIRCUITPY doesn't show up as a disk drive after installing CircuitPython, try loading this 'nuke' UF2 to RPI-RP2. which will do a 'deep clean' on your Flash Memory. You will lose all the files on the board, but at least you'll be able to revive it! After loading this UF2, follow the steps above to re-install CircuitPython.
Page last edited March 08, 2024
Text editor powered by tinymce.
Coding the Holiday Tree
Once you've finished setting up your Feather RP2040 Scorpio 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 as a zipped folder.
# SPDX-FileCopyrightText: 2023 Jeff Epler for Adafruit Industries
# SPDX-License-Identifier: MIT
import board
from adafruit_led_animation.animation.chase import Chase
from adafruit_led_animation.animation.comet import Comet
from adafruit_led_animation.animation.rainbow import Rainbow
from adafruit_led_animation.color import (JADE, RED, WHITE)
from adafruit_led_animation.group import AnimationGroup
from adafruit_led_animation.sequence import AnimationSequence
from adafruit_neopxl8 import NeoPxl8
from adafruit_pixelmap import PixelMap
strand_length = 30
pixel_brightness = 0.8
num_strands = 8
num_pixels = num_strands * strand_length
pixels = NeoPxl8(board.NEOPIXEL0, num_pixels, auto_write=False, brightness=pixel_brightness)
def strand(n):
return PixelMap(
pixels,
tuple(range(n * strand_length, (n + 1) * strand_length)),
individual_pixels=True,
)
pixel_strip_A = strand(0)
pixel_strip_B = strand(1)
pixel_strip_C = strand(2)
pixel_strip_D = strand(3)
pixel_strip_E = strand(4)
pixel_strip_F = strand(5)
pixel_strip_G = strand(6)
pixel_strip_H = strand(7)
animations = AnimationSequence(
AnimationGroup(
Rainbow(pixel_strip_A, speed=0.01, period=7),
Rainbow(pixel_strip_B, speed=0.01, period=7),
Rainbow(pixel_strip_C, speed=0.01, period=7),
Rainbow(pixel_strip_D, speed=0.01, period=7),
Rainbow(pixel_strip_E, speed=0.01, period=7),
Rainbow(pixel_strip_F, speed=0.01, period=7),
Rainbow(pixel_strip_G, speed=0.01, period=7),
Rainbow(pixel_strip_H, speed=0.01, period=7),
),
AnimationGroup(
Chase(pixel_strip_A, speed=0.05, color=WHITE, spacing=5, size=8),
Chase(pixel_strip_B, speed=0.05, color=RED, spacing=4, size=4),
Chase(pixel_strip_C, speed=0.05, color=RED, spacing=4, size=8),
Chase(pixel_strip_D, speed=0.05, color=JADE, spacing=5, size=5),
Chase(pixel_strip_E, speed=0.05, color=WHITE, spacing=5, size=5),
Chase(pixel_strip_F, speed=0.05, color=RED, spacing=4, size=5),
Chase(pixel_strip_G, speed=0.05, color=JADE, spacing=3, size=4),
Chase(pixel_strip_H, speed=0.05, color=RED, spacing=4, size=8),
sync=False,
),
AnimationGroup(
Comet(pixel_strip_A, 0.01, color=WHITE, tail_length=12, bounce=True),
Comet(pixel_strip_B, 0.01, color=RED, tail_length=12, reverse=True),
Comet(pixel_strip_C, 0.01, color=RED, tail_length=12, bounce=True),
Comet(pixel_strip_D, 0.01, color=JADE, tail_length=12, reverse=True),
Comet(pixel_strip_E, 0.01, color=WHITE, tail_length=12, bounce=True),
Comet(pixel_strip_F, 0.01, color=RED, tail_length=12, reverse=True),
Comet(pixel_strip_G, 0.01, color=JADE, tail_length=12, bounce=True),
Comet(pixel_strip_H, 0.01, color=RED, tail_length=12, reverse=True),
sync=True,
),
advance_interval=9,
auto_clear=True,
)
while True:
animations.animate()
Upload the Code and Libraries to the Feather RP2040 Scorpio
After downloading the Project Bundle, plug your Feather RP2040 Scorpio 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 folder and file to the Feather RP2040 Scorpio's CIRCUITPY drive.
- /lib
- code.py
Copy the entire lib folder, including all of its contents.
Your Feather RP2040 Scorpio CIRCUITPY drive should resemble the following after copying the lib folder and the code.py file.
Page last edited March 08, 2024
Text editor powered by tinymce.
CAD Files
CAD Parts List
STL files for 3D printing are oriented to print "as-is" on FDM style machines. Parts are designed to 3D print without any support material with PLA filament. Original design source may be downloaded using the links below.
File Name List
A list of the parts that need to be 3D printed. Reference the prefix number for the quantity required for the assembly.
- 8x Bracket A.stl
- 1x Bracket B.stl
- 1x Bracket C.stl
- 1x Top Bracket.stl
- 8x Slat A.stl
- 8x Slat B.stl
- 8x Slat C.stl
- scorpio case.stl
- scorpio top.stl
- small mint case.stl
- small mint top cover.stl
Build Volume
The parts require a 3D printer with a minimum build volume.
- 195mm (X) x 195mm (Y) x 50mm (Z)
Design Source Files
The project assembly was designed in Fusion 360. This can be downloaded in different formats like STEP, STL and more. Electronic components like Adafruit's boards, displays, connectors and more can be downloaded from the Adafruit CAD parts GitHub Repo.
Page last edited March 08, 2024
Text editor powered by tinymce.
Wiring
Large LED Projects
For projects that use more NeoPixels, reference the wiring diagram in the Circuit Diagram page for using external power.
Small LED Projects
This section shows how to power projects that use a small amount of NeoPixel LEDs with low to medimum brightness settings.
In this project, the Feather RP2040 Scorpio is powered by a 5V 1A USB power supply and uses a total of 240 NeoPixel LEDs. The eight NeoPixel LED strips are powered directly from the Feathers RP2040 Scorpio's USB and ground pins.
Headers & JST Cable for Feather Scorpio
A 2-pin JST plug cable is connected to the Feather RP2040 Scorpio.
A 2x8 right-angled header is soldered to the NeoPixel pins on the Feather RP2040 Scorpio.
Solder Headers & JST Cable
The 2x8 right-angled header is soldered to the top side of the Feather RP2040 Scorpio.
The 2-pin JST plug cable is soldered to the ground and USB pin on the Feather RP2040 Scorpio.
Perma-Proto & Cables
The Perma-Proto board will use several cables to connect to the Feather RP2040 Scorpio and the 8x NeoPixel strips.
- 8x 3-pin JST socket cables
- 1x 2-pin JST socket cable
- 1x 2x8 IDC ribbon cable
2x8 IDC Cable Setup
Divide the 2x8 IDC cable and cut in half using wire cutters.
Separate the individual wires from the IDC cables by peeling them apart.
Locate the notch of the cable to reference the first wire that will be soldered to NeoPixel #0.
Only eight signal wires be used to connect the NeoPixel strips. Locate the wire with the white marking. Cut every other wire after the wire with the white marking.
Wired Perma-Proto
Solder the 3pin JST plug cables to the Perma-Proto board as follows:
The red wires are soldered to the pads on the voltage rail.
The black wires are soldered to the pads on the ground rail.
The white wires are soldered to unique columns on the Perma-Proto.
The wires from the IDC ribbon cable are soldered to pads that are shared with the white wires from the 3-pin JST cables as shown.
Page last edited March 08, 2024
Text editor powered by tinymce.
Assembly
Hardware for Bracket Set A
The following hardware is used to assemble the Bracket A set.
- 8x M3 x 10mm long screws
- 8x M3 hex nuts
Joining Brackets A
The bracket set A will be joined together using an M3 x 10mm long screw and hex nut.
Start by joining two of the brackets A.
Installing Hex Nuts for Bracket A
Place an M3 hex nut over the tab with the hexagon shaped cavity. Insert an M3 screw through the other side of the tab and begin to fasten the screw. The M3 screw will force the M3 hex nut to be pressed into the cavity.
Remove the M3 screw when the hex nut is fully seated into the cavity.
Joined Bracket A
Insert the M3 screw through the tab on the other bracket and begin to fasten the two brackets together.
Repeat this process to create four sets of bracket A.
Joining Slats A & B
Slats A & B feature tabs that will be inserted into the finger joints of bracket B.
The tabs of slats A & B will overlap and press fitted into bracket B's finger joint.
An M3 x 10mm screw will be used to secure the slats to the bracket.
Slats A&B with Bracket B
Press fit the tabs from slat A & B into one of the finger joints on bracket B.
Adjust the tabs so the mounting holes are all lined up for the M3 x 10mm long screw.
Secure Slats A&B to Bracket B
Insert and fasten an M3 x 10mm long screw through the finger joint of bracket B.
Joined Slats A&B with Bracket B
Take a moment to inspect slats A and B have been properly secured to the finger joint of bracket B.
Assembled Bracket B with Slats A&B
Repeat the assembly process and proceed to secure the remaining slats to bracket B.
Insert Slats A to Bracket A
Begin inserting the ends of slat A to the square peg holes of bracket set A.
Press fit slats A into the square holes of bracket A.
Join Slats B&C to Bracket C
Place bracket c over the mounting tabs of slats B with the mounting tabs fitted into the finger joints.
Grab one slat C and begin inserting the mounting tab into the finger joints of bracket C.
Fasten Slats B&C to Bracket C
Insert and fasten an M3 x 10mm long screw through the finger joint of bracket c to secure slats B and C.
Assembled Bracket C with Slats B&C
Repeat the assembly process and proceed to secure slats B&C to bracket C.
Install Top Bracket to Slats C
Place the top bracket over the tips of slats C. Press fit the tips into the slots of the top bracket. The edges are angled to prevent the tips from separating.
Zip Ties for NeoPixel Strips
Self-locking nylon zip ties will be used to secure the NeoPixel strips to the slats of the tree assembly.
A minimum of three zip ties are used to secure a NeoPixel strip.
Secure NeoPixel Strip to Slats
Place a NeoPixel strip over one of the slats with the JST cable facing towards bracket A.
Use the zip ties to secure the NeoPixel strip to the slats.
Installed Zip Ties
Adjust the zip ties so they are not blocking the NeoPixel LEDs.
Proceed to repeat the assembly process and secure the remaining NeoPixel strips to the slats.
Secured NeoPixel Strips
Take a moment to inspect the NeoPixel strips are properly secured to the slats.
Hardware for Perma-Proto Case
Use the following hardware to secure the Perma-Proto board to the 3D printed case.
- 4x M3 x 10mm long screws
- 4x M3 hex nuts
Secure Perma-Proto
Place the Perma-Proto board onto the case with the mounting holes lined up.
Insert the M3 screws through the bottom of the case and secure the board using the hex nuts.
Install Perma-Proto Cover
Insert the various cables from the Perma-Proto through the opening in the center of the top cover.
Press the top cover onto the case to snap fit them together.
Assembled Perma-Proto Case
Take a moment to inspect the Perma-Proto board has been properly secured to the case.
Hardware for Scorpio Case
Use the following hardware to secure the Feather RP2040 Scorpio to the 3D printed case.
- 2x M2.5 x 10mm long screws
- 2x M2.5 hex nuts
Install JST cable
Insert the JST plug from the Feather RP2040 Scorpio through the center slot of the 3D printed case.
Install Feather to Case
Place the Feather RP2040 Scorpio into the case with the mounting holes lined up.
Insert 2x M2.5 x 10mm long screws through the holes on the bottom of the case.
Install Feather Scorpio Cover
Get the top cover ready to install onto the 3D printed case for the Feather RP2040 Scorpio board.
Orient the top cover with the Feather RP2040 Scorpio so the slots are lined up correctly with the pins on the board.
Place the top cover over the case and press down to snap fit them together.
Assembled Cases
Get the cases for the Perma-Proto and Feather RP2040 Scorpio and get them ready to connect together.
Connect IDC Cable
Plug the IDC ribbon cable into the 2x8 header of the Feather RP2040 Scorpio with the notch facing up.
The wire with the white marking should be connecting to NeoPixel #0.
Connect 2-pin JST Cable
Plug in the 2-pin JST cable from the Feather RP2040 to the 2-in JST cable on the Perma-Proto board.
Feather & Perma-Proto Connected
Take a moment to inspect the cables from the Feather RP2040 and Perma-Proto board have been properly connected.
Connect NeoPixel #0
Locate the 3-pin JST cable that is connected to NeoPixel #0 and plug it into one of the NeoPixel strips.
Connected NeoPixels
Proceed to connect the NeoPixel strips to the cables on the Perma-Proto consecutively.
Connected Holiday Tree
Take a moment to inspect the NeoPixel strips have been properly connected to the cables on the Perma-Proto.
USB Power
Plug in a USB-C cable to a 5V 1A power supply to power on the Feather RP2040 Scorpio. The NeoPixel strips should power on and begin animating.
Page last edited March 08, 2024
Text editor powered by tinymce.