Introduction: Continuum - Slow Motion LED Art Display
Continuum is a light art display that is continuously in motion, with options to move quickly, slowly, or incredibly slow. The RGB LEDs in the display are updated 240 times per second, with unique colors calculated each update. A slider on the side of the display controls if the LEDs play back the content - currently Animated GIFs - in realtime, 1000x slower than realtime, or anywhere in-between.
The frame is powered by the Teensy 4.1, and the SmartMatrix Library, using the SmartLED Shield for Teensy 4. The LED panels are 32x32 pixel P5 (5mm pitch) RGB HUB75 panels combined to make a 96x96 pixel 480mm (18.9") square display that fits into an Ikea Ribba shadowbox frame. HUB75 panels require constant refreshing with data to display an image at a high rate: refreshed at least 100 times a second to look flicker-free to most people, and at least 200 times a second to look good on camera. The SmartMatrix Library and SmartLED Shield are designed to refresh HUB75 panels quickly and with high quality graphics, using up to 48-bit color depth to avoid the stepping effect seen when making subtle color changes with low color depth. Normally the SmartMatrix Library works with source content that is updated much slower than refresh rate, for example 30 frames per second for videos and a single image at a time. With this project, the library looks at two images at a time for each refresh, and creates a new image to refresh using linear interpolation. This wouldn’t be possible without the powerful Teensy 4, which has enough memory to store the additional pixel data and do all the computation necessary to calculate unique pixels for a 96x96 HUB75 display and refresh the display 240 times per second.
In addition to driving HUB75 LEDs, I’m using the APA102 LED support in SmartMatrix Library, and the JST-SM cable and 5V buffers built into SmartLED Shield to drive two meters of 60 LED/meter APA102 LED strip to light up the wall behind the frame in an Amibilight-like effect. APA102 LEDs are a good choice for this compared to WS2812/Neopixels as they have a 5-bit Global Brightness Control setting per LED, allowing them to be driven with pseudo 39-bit color depth vs 24-bit WS2812/Neopixels. This allows for smooth color changes without stepping seen with lower color depth LEDs. The colors for the APA102 LEDs are taken from the edges of the images driven to the panel, and interpolated over time just like the main panels.
The display’s controls are intentionally simple, with a mixer-style slider (linear potentiometer) for controlling the playback speed, and two rotary encoders: one for changing the content, the other for controlling brightness.
The LEDs are diffused with a frosted acrylic panel spaced far enough away from the LEDs that adjacent lights blend together a little bit. It dramatically improves the look of certain types of content, giving the display a very unique look.
I had the general idea for this display for some time, inspired by the Very Slow Movie Player project, and the smooth linear interpolation used by the Fadecandy LED controller. I really liked the idea behind the Very Slow Movie Player: a display that appeared to be stationary but when you looked at it again could be displaying new content. Unlike that project, I wanted to hide the transitions so even if you were staring directly at the display as it transitioned to a new frame, you wouldn’t be able to see the transition, or any movement at all.
To build the 96x96 frame you’ll need
- Ikea Ribba 50x50cm frame
- Acrylite Satinice 0D010 3mm sheet cut to 500x500mm
- An alternate diffuser can be used for cheaper, even printer paper (if you can find it in the right size) can work well as a diffuser, but the frame really looks fantastic with a quality diffuser
- 9x P5 32x32 HUB75 panels
- I used panels I purchased years ago, and it seems like inexpensive P5 32x32 panels have been discontinued, since replace with P5 64x32 panels that won’t work for a 96x96 display. P5 32x32 “Outdoor” panels are available, but they’re more expensive as they’re brighter and have waterproof coatings. They also may be thicker, so you’ll have to adjust the positioning of the panels further back in the frame somehow to get the same diffuse look
- SmartLED Shield for Teensy 4
- This is currently in a crowdfunding campaign on Crowd Supply, but it’s Open Source Hardware and the hardware design of the prototype and the latest SmartMatrix Library code is available on GitHub if you want to build your own
- Teensy 4.1
- Get it with pins already soldered from PJRC or SparkFun if you want to build this without soldering
- microSD Card
- A small size is fine
- You’ll also need a reader to load the GIF files
- You’ll need longer cables than are typically supplied with the HUB75 panels to connect the HUB75 panels between rows
- The cheapest option is probably to get a roll of 16-conductor ribbon cable, and a pack of 16-pin IDC connectors, and to crimp your own. Note that if you can’t find 16-conductor cable you can find wider (e.g. 20-pin) and just separate the 16 wires you need you need
- You can get a special IDC crimping tool, or just use a bench vice
- I used model KY-040, available from sites that sell Chinese electronics
- I used the Chinese-source 10k potentiometer with red PCB, yellow slider, and dual linear output
- The value doesn’t matter too much, I also used a 220uF I had on hand
- Power cables for each panel
- Short ribbon cables (you’ll need 9x)
- If you’re using a breadboard, you’ll need long pins like these: https://www.adafruit.com/product/400
- These panels use up to 3A at full brightness, so I’d need 27A total, plus enough for the LED strips. A smaller supply would probably work as I’m not driving content containing full brightness white across all panels. I happened to have a 40A supply handy, and it fit behind the display, so I just used that instead of optimizing.
- A couple longer screws would be handy too to potentially attach the power supply to the back of the frame.
- I happened to have #4 1/2" screws so I used those
- This is to mount the SmartLED Shield to the frame
- I used a 20mm M3 M-F standoff screwed into one of the HUB75 panel holes, and a 6mm M3 screw to attach the shield to the standoff. If you use perfboard instead of a breadboard, it will be thinner and you’ll need a shorter standoff
- e.g. Masking Tape
- The encoder doesn’t come with a plastic knob, just the metal encoder shaft. Find one you think looks good.
- The slider does come with a cap, but it’s bright yellow, and maybe not the right look against the black picture frame. Find one you think looks good.
- 2m 60 LED/m APA102 strip
- APA102 Strip Right Angle Connectors
- This makes wiring up the right angles much easier, otherwise just use short wire
- JST-SM Male and Female pigtails
- Barrel plug to terminal block adapter (for APA102 Strip)
- Jumper Wire to connect power supply and barrel plug
- Wire/crimp terminals to connect APA102 barrel plug to power supply
- Ikea Mosslanda Shelf
- to hold frame on wall
- 3mm MDF
- the 2mm MDF included in the Ribba frame isn’t sturdy enough to hold the panels with bowing in the middle. It’s not a problem at least initially if the frame is mounted upright on a wall, but over time it may sag. If you have easy access to 3mm MDF or another thicker wood panel, it may be a good upgrade to do at the beginning
- 34mm Hole saw
- I used the small saw in the Ikea Fixa Kit
- A slightly larger hole is probably fine
- I used a 5/32" (~4mm) drill for the screw holes
- A larger bit for the polarizing pegs
- A 17/64" (6.75mm) drill for the encoder shaft
- An 16mm (or 18mm?) forstner bit for drilling space for the encoders and potentiometer
- A small bit for the encoder and potentiometer pilot holes
Step 1: Planning Build
The instructions are to build a 96x96 frame, but this project can scale to other size displays. You could start small with a 32x32 P6 (6mm pitch) panel that also fits nicely into commonly available shadowbox picture frames (see SmartMatrix Display). You could get four times as many pixels with the same size frame using a 64x64 P3 panel instead. It’s possible to drive a display larger than 96x96, 128x128 is possible but with a compromise of a lower refresh rate (about 160 Hz).
Step 2: Make Template
You’ll make a template that can be used to mark the holes that need drilling in the back of the frame. You can make a template using a large sheet of paper, or a few sheets taped together.
Lay out all your panels as they will be installed in the frame, LED side down. Apply tape to the outside edges where two panels meet, making sure the panels are pushed close together. You want the template to keep the panels tight together, otherwise there may be a visible gap in the lights where there’s extra space between two panels.
The template needs to capture the features of the center panel, and at a minimum the closest screw holes on the outer panels, one from each panel. Make sure your paper is large enough to capture all these features.
Put the paper down on the back of the panels. There are some features on the back of the panels that prevent the paper from sitting flat. The polarizing pegs (the pegs that stick up from the back of the panel) are in the way, as are the power connectors. Make some small holes so that these features can go through the paper so it sits flat. Now tape the paper down so it’s pulled tight flat against the back of the panels.
Using your finger, rub the features of the panels under the template so they’re embossed on the paper. Make sure you cover all the screw holes, the 2x8 HUB75 connectors, and the power connector from the central panel, and at least the closest screw holes from the outer panels. Now remove the tape from the panels.
Mark the side of the template that was facing you during embossing using a pencil. The template represents the bottom of the panels, so write “BOTTOM” on the side facing you. Figure out which side of the panels is “Up” (the panels usually have arrows on the back, one indicating the data flow from one HUB75 connector to the other, and another pointing to the top of the panel). Draw an arrow pointing Up, and write Up on the template.
Step 3: Transfer Template on to Back of Frame
Bend the tabs on the back of the frame out and disassemble the frame if you haven’t already. Grab the MDF sheet that makes up the back of the frame and set the other pieces aside. If you decided to use a thicker 3mm MDF sheet, grab that instead. If you care about the orientation of the MDF sheet once it’s inside the frame, put the side you want facing out on a table facing you, and put the edge you want to be on top, away from you on the table. Now put the template on top, with “BOTTOM” visible, and the “Up” arrow facing away from you. Center the template so the center of the center panel is in the center of the MDF sheet. Tape the template down so it won’t move during marking.
Make pin holes in the center of each feature that needs drilling on the template: screw holes, polarizing pegs (there should already be holes there), HUB75 connector, power connector. Now use a pen or pencil to mark the center of these features on the MDF sheet. If your template wasn’t large enough to capture all the features of all panels, remove the template, and reposition so you cover another panel, using the screw hole features you already marked to align the template. Repeat until all features are marked.
Now go back over the MDF making sure all features are marked. Optionally, you can write “PEG” next to the polarizing pegs, and “BIG” next to the HUB75 and power connectors, so you know which holes need to be drilled bigger.
Step 4: Drill Holes in MDF Sheet
Drill all the center panel holes first. Start with the 5/32" (4mm) bit. Switch to a slightly larger bit for the polarizing pegs, which aren’t marked as accurately on the template, and so need a larger hole for the looser tolerances. Use the hole saw to drill the HUB75 connector and power connector holes.
Do a test fit with one of the panels - remember the panel is going to be mounted with LED side down on the table, under the MDF sheet - do the holes line up with the panel? Re-drill if needed.
Step 5: Test Fit Before Drilling More Holes
Now drill some (not all) holes for the panels adjacent to the center panel. Just two screw holes per panel, plus the larger holes for the polarizing pegs is enough. Attach the center panel loosely with a couple screws. Now use another panel to make sure the few holes you drilled for the outer panels were aligned properly. If you're not seeing the center of the panel's screw holes when you press the panel tight against the central panel, then something is off. Make any adjustments needed in your remaining marks to make sure the panels will be mounted tight together, before drilling remaining holes for the adjacent panels.
Now that just leaves the corner panels. You know what to do now: drill a few holes, check fit, adjust, then drill the remaining holes.
Step 6: Mount and Test Power Supply
The power supply can be mounted to the back of the MDF sheet. See if existing holes for the panel are in a convenient place to mount the power supply, and use a longer screw if needed to attach the power supply through the MDF to one of the panels.
Wire up the power supply to wall power if it doesn't come pre-wired. Be very careful with this step, and refer to the power supply instructions and warnings, and other tutorials for instructions, as you're working with dangerous voltage levels. When you're confident in the wiring, plug the power into the wall and use a multimeter to check that you have 5V coming out of the supply. Some supplies have an adjustment screw that may need to be turned to dial in the voltage to the correct level.
Step 7: Mount Panels
Use screws to attach all the panels to the back of the MDF. Four screws per panel is probably enough, but feel free to use all the screws if you want.
Step 8: Wire Up Panels
Plug the ribbon cables into the HUB75 panels. The SmartLED Shield will be mounted in the bottom right of the frame (when viewing from the back). Use a long ribbon cable to connect the shield to input of the bottom left panel. Now wire up the panels with short ribbon cables from left to right, and long ribbon cables from the outputs on the right side of the panels, to the inputs on the left side of the panel, from bottom to top. Leave the last HUB75 output unconnected.
Plug power supply cables into the panels, and connect them to the 5V power supply outputs (red wire is 5V, black wire is Ground).
Step 9: Assemble SmartLED Shield and Teensy 4
Follow the [SmartLED Shield for Teensy 4 instructions](http://docs.pixelmatix.com/SmartMatrix/shield-t4.html) to assemble the Teensy and shield.
Step 10: Program Teensy With Simple Sketch for Testing
Use the FastLED_Functions sketch to test your panels. Change the example to match the size of your panels, and wiring orientation (top to bottom or bottom to top). Power on the panels and Teensy, and upload the sketch via USB. If you see nay issues, adjust the wiring or the sketch until everything is displaying properly.
Step 11: Optional: Wire Up APA102 Strips
The APA102 strips require a bit more work to assemble and soldering to make the strips fit on the back fo the frame. Cut the strips to length to fit on the back, and solder the corners using right angle adapters starting from the lower right, and covering the top, left, then bottom. If you're mounting the frame on a shelf, you may want the bottom strip to be mounted under the shelf, in which case you'll need to solder JST-SM pigtails to make the connection, and have the shelf strip be removable when you pull the frame down.
Step 12: Plan to Cut Holes in Frame
The rotary encoders and slide potentiometer need holes drilled in the sides of the frame for mounting and access. I used a forstner bit to drill holes that didn't go all the way through the MDF frame, but if I were to do this again I would use different tools. The MDF clogged up the bits frequently and would start to burn from the friction. I have a feeling that a combination of knife and chisel (or something else to gouge out material), would work better.
Mark the position for the encoders and Slide potentiometer. The encoders have more connections so I put them on the right side of the frame (when facing the back), so they're closer to the SmartLED Shield to simplify wiring. I put the slider on the opposite side of the frame so that it's easy to use the controls by feel, without accidentally touching the wrong control. Feel free to put the controls in a different place, in which case, you may want to move the SmartLED Shield to be closer to the controls.
Step 13: Cut Holes for Encoders
Mark the location for the first encoder on the inside of the frame. Make sure the hole is centered in the depth of the frame, when measured from the outside. If you're using a forster bit, drill down most of the way, but don't go all the way through the frame. Go at least as deep as the metal shell of the encoder. Now drill the center hole using a 17/64" (6.75mm) bit.
The encoder won't fit in as is, but you can at least mark the position of the mounting hole, and then drill a small pilot hole for the mounting screw.
Repeat for the second encoder.
Step 14: Cut Holes for Slide Potentiometer
Mark the location for the slide potentiometer on the inside of the frame. I marked the location of the metal shield, and the length of the slot. Make sure the slot for the slide is centered in the depth of the frame, when measured from the outside. If you're using a forster bit, drill down most of the way, but don't go all the way through the frame. Go at least as deep as the metal shell of the potentiometer. Repeat drilling for the length of the metal shield. Use a knife and steel ruler to cut the slot on the outside of the frame. Keep taking away material until it's wide enough for the slide to go through its full range of motion without making contact.
The slide won't fit in as is, but you can at least mark the position of the mounting hole, and then drill a small pilot hole for the mounting screw.
Step 15: Bend Connectors for Controls and Test Fit
The controls all have pins inconveniently facing into the frame instead of away from the frame where they can be accessed. You could use a soldering iron to reorient the connectors, but it's quicker and easier to just use needle nose pliers. Carefully wiggle the plastic spacer off the pins. Then bend each pin so it's still a right angle, but flat against the board. Now bend it a little bit further so it's pointed back a bit and there's room to connect a crimped wire to it.
Now the connectors should be able to fit into the frame. Do a test fit, and take away material as needed until they fit well. Don't mount them yet as it's easier to do after the diffuser is added.
Step 16: Cut Holes in MDF Sheet for Control Connectors
The MDF sheet needs holes to allow the control connectors to poke out. Cut away a few mm from the sheet where the connectors will go.
Step 17: Add Diffuser
If you're using the Acrylite frosted acrylic, add it to the frame now. If you're using another rigid diffuser, add it instead. If you're using a paper or film for diffuser, you may want to tape it to the flexible plastic that comes with the frame, so it stays in place after the frame is assembled. Add whatever diffuser you're using now.
Step 18: Attach Slide and Encoders
Now the controls can be added to the frame, with mounting screws to hold them in place. Make a note of the names of the pins before they are screwed in and inaccessible. You may want to write the signal names onto the back of the MDF sheet. Tighten the nuts on the encoders on the outside of the frame.
Step 19: Assemble Frame
Now the display portion of the frame can be assembled and tested. Carefully insert the spacer into the frame, avoiding the controls. Insert the MDF sheet with panels, and fold a few tabs down to keep it from falling out. Power on and do a visual inspection to make sure there's no dust or debris or anything on the inside of the diffuser that's going to be difficult to remove once the entire frame is assembled. Clean up as necessary, then fold down all the tabs.
Step 20: Wire Up Slide and Encoders
Use jumper wires to connect the control signals to the breadboard or perfboard. You’ll need to make multiple connections to these signals, so dedicate a row to each if you’re using a breadboard: 3.3V, GND.
- Pin 23
- Add the capacitor between 3.3V and AGND (“-” marking goes to AGND)
Encoder 1 connections:
- CLK 16
- DAT 17
- SW 18
Encoder 2 Connections:
- CLK 19
- DAT 20
- SW 21
Step 21: Prep GIFs
Follow this tutorial on Adafruit Learning System to prepare GIFs for the frame. I used these GIFs and the GIFBrewery software on MacOS for the GIFs you see in the demo video.
- Tunnel by u/rddigi on Reddit/r/perfectloops
- Trippy psychedelic liquid GIF on GIFER - by Felolune
- “Jungle Terror” by Protobacillus CC BY-SA
- “Process Growth Pains”
Load the GIFs into a fresh microSD card, put in a new directory name “gif”. Eject the card and add to the Teensy 4.1.
Step 22: Load Sketch and Test
Download the GifInterpolation sketch, compile and upload.
Make sure the encoders are working (changing brightness and GIF content), and the slider is working (changing GIF playback speed).