I've been experimenting with the APA102 LED lately due to their ability to operate at extraordinarily high frequencies. I want to see if I can use these for a persistence of vision (POV) display, and if I can, I'd like to see just how many LEDs I can run at a POV capable frame rate (typically something around 1000 FPS should work, but for wider displays where LEDs are swept across a larger space, higher frame rates are desired).
Persistence of Vision is a neat little phenomena that exists thanks to your brain and afterimages. An afterimage is an image that stays in your vision after you've looked away from the original visual stimuli. If you've ever gotten a picture taken of you with a bright flash or played with sparklers on the 4th of July, you'll know exactly what I'm talking about. This sort of effect occurs because sight is a photochemical process. In other words, light interacts with chemicals, your cells see this and send signals along the optic nerves to your brain based on these chemical signals. When you see something (especially something bright) the chemicals in your eyes become depleted. This causes an afterimage from the object even though you aren't necessarily looking at it anymore (don't stare at the sun, kids).
Thanks to these afterimages and this effect, we're able to perceive things like video, which is a series of photos flashed just quickly enough to blur together. This tends to be around 30 FPS for most video, although when things are moving quickly (like in sports or a fast-paced movie), frame rates as high as 60 FPS might be required for a smooth image.
Since these afterimages "stay" in one spot in our vision, by sweeping pixels through the air we can use LEDs to paint images seemingly in thin air. The fun with these displays is that you need to run your lights at a high refresh rate so you can have a high resolution as you sweep your pixels through the air. A higher frame rate means the pixel can be swept through the air faster. The larger a POV display gets, the faster the outer pixels will be swept through the air, so a higher frame rate translates to bigger displays. However, a bigger display means more LEDs, which in turn means a slower frame rate.
In order to accomplish an ultra-fast frame rate, we'll need some specific hardware. I went with the APA102 LED due to the fact that, unlike some other LEDs, like the WS2812, it has an external clock. Since the clock is provided by the microcontroller it's far easier to synchronize all of the LEDs and the controller, allowing for longer, faster strings. This has enabled various makers to push data cleanly through 1000+ pixel strings at speeds around 30 MHz.
Now we need something that can run our SPI bus at 30 MHz and still have clock cycles to chew on for any animations we want to run. For this I chose the Teensy, as it can run its SPI bus that fast, and I also discovered a little trick to get more out of fewer pins on the Teensy. I'm also using the FastLED library, which is devoted to running lights on as few clock cycles as possible.
The APA102 has a communication protocol that can be taken advantage of to control four LED strips with only four data pins (you should normally need eight). In order to accomplish this, I wired my four strips according to the table below.
Strip | Data | Clock |
---|---|---|
1 | 7 | 13 |
2 | 7 | 14 |
3 | 11 | 13 |
4 | 11 | 14 |
You can see all four pins have two wires connected to them, each wire being from a different strip. This setup takes advantage of the fact that when strip one is being driven, the data won't affect strip two due to the lack of a clock signal for strip two, while the clock won't affect strip three due to the lack of data for strip three. This sort of logic repeats for the rest of the strips, allowing our Teensy to be able to juggle four LED strips around on four data pins – pretty neat! Check out the below oscilloscope capture of pins 7 (yellow) and 13 (blue) to get more of an idea of what's going on.
This is also a great way to look at frame rate, which in this setup (a mere 60 LEDs) is hitting a whopping 10,000 FPS, which is overkill for most applications, but it's also not many LEDs. Increasing my number of LEDs to 1,000 brought me down to around 770 FPS, which is about the minimum for what I'd like for POV applications. A 500-LED display would put me at 1,500 FPS, the sweet spot for what I'd like to do.
Hypothetically, you'd be able to get 24,000 LEDs (four strings of 6,000 LEDs) running at around 30 FPS, but I don't know how clean the signal will look after being sent through 6,000 lights, I don't have that many LEDs lying around for a hypothetical. Also, powering something that size would be a neat little problem in itself.
After some initial testing I settled on a frame rate of 7,650 FPS to do some testing for some motion-activated color gradients. What I did was take a color gradient and cycle through at a speed high enough to run through the whole 255-color gradient 30 times every second without losing any resolution in the gradient. This flashes through all of the colors fast enough that if you hold the strip still, the afterimages stack on top of one another and you see an average of all the colors (the rainbow will show up white). Moving the LED around as it does this will allow you to see the rainbow, as now the afterimages are all in different locations instead of stacked on top of one another. I took some long exposure photos to visualize the effect and they came out great! You can actually see each individual frame refresh if you look closely at the image. The LEDs almost look like little stacks of colored coins, where each "coin" is a frame.
See our LED page for everything you need to know to start using these components in your project.
wow, I love colors...
What code are you using for the different patterns? How complex of sequences and collections of simultaneous different patterns are you running? I've been digging around for different code patterns for this, having written one that layers over NeoPixel library (aka NeoEffects on GitHub)
Neat stuff. not to nitpick, but it's an important distinction to make I think: The afterimage from a flash is a negative afterimage, as described in this post, and such an afterimage doesn't contribute to the POV effect, but may work against it.
Did the SPI multiplexing trick really gain anything? You have four data streams, but each is active only 50% of the time. You could have gotten the same throughput with two longer LED strings and no multiplexing, unless I'm missing something.
Also, don't forget that the Teensy 3.6 has THREE SPI peripherals, not two. The third is broken out on the board's underside.
Yes I absolutely could've achieved the same throughput with longer strings, however, I (a) wanted to show that this trick could be done and (b) the signal does suffer degradation over long strings, so it is advantageous to have shorter strings.
Best not to think in terms of "Frame Rate" for this sort of thing. Think line rate and 10,000 per second isn't even NTSC quality. So don't ask if you are pushing it too hard, ask if you can push harder. In general MOAR is always better.
Since I'm not making a regular old rectangular pixel matrix, line rate isn't necessarily the metric I'll use. POV displays are usually round instead of rectangular so you'll require different data rates as you use pixels further and further away from the axis of rotation. Also, frame rate is far easier to relate to the flicker-fusion barrier of the eye.
Not really, one rotation of the device is a frame, the pixels and scan lines are just radial in your case instead of top to bottom then retrace. Yes the difference between inner and outer sections can be taken into account, if you have to push the rate to get an acceptable display or are just a masochist. That way leads to CAV, CLV and ZCAV from laserdisc and high speed CD drives all over again except you are always moving the entire thing at a constant rate and varying the pixel rate based on distance from center. It gets messy fast.
AP102 is, mechanically, a good choice for POV stuff, but disagree with the frequent and intentional misinformation on the common venues such as SF, Adafruit, Hackaday, etc. Mostly because the Teensy WS1812 drivers are non-blocking, and code support for AP102 can be poor. And the Teensy 3.5 might be an easier solution per the 5V compatibility.
The AP102 will have 'clock recovery' problems for large projects. Have had many problems with the generic alibaba stuff, whereas the WS1812 common Chinese stuff just works.
All of this has been discussed, in detail, for several years and on several threads on the PJRC forum.
What's the intentional misinformation? That's a pretty bold statement to make.