Teensy APA102 POV Poi / Pixel Poi Build. Tutorial

mortonkopf

Well-known member
Here is a build example for using apa102 led strips with a Teensy 3.1 as an example of making some relatively cheap pixel poi that are capable of displaying images or patterns. The images are displayed by loading pixel data held in arrays stored in flash memory, and patterns are made mathematically / through code routines. The attached code is written to accept any strip length, and uses the FastLED library. The poi are rechargeable via the single Teensy micro usb port, so no opening up to change batteries. A red light glows gentle through the plastic indicating charging.

The simple image utility for the APA102 24bit image arrays to use them in graphic poi / pixel poi can be found here:
http://www.orchardelica.com/poisonic/poi_page.html

EDIT: @howsthe weather has improved the browser based image converter utility: "If you'd like to use (or modify) my brother's enhanced version of Mortonkopf's image conversion utility, it is available here : https://jhorowitz.github.io/PoiSonicApa102ImageConverter/."

apa102_pov_poi.jpg APA102_snow.jpg

The finished pov / pixel / graphic poi are 185g each, and 51cm long.

Before going further, it is important to note that my requirements for pov poi may well be very different to yours. When designing pixel poi you need to consider: image pixel density, weight of final poi/baton, battery longevity, routine code size, length of baton / poi, brightness of leds. I decided to go for lightweight, short, fast spin potential, simple, all relating to space inside the tube housing. Therefore, I am not using a 5v level shifter for these leds, but you can easily fit one (I am saving the remaining space for a flash memory add-on). The trade off is that the battery will only last roughly half an hour when using images with lots of white in them. You will have to consider these issues when building your own version.

Led_reel_and_polycarb.jpg

BOM
APA102 pixel strips (4x60leds @ 144leds/m)
Polycarbonate clear tube (2x50cm)
Polycarbonate clear strip (2x50cm)
3.7v Lipo battery (2200mAh 14500 cell)
Pesky products Lipo charger
Polymorph
Teensy 3.1
2x switches
Various odds of wire
Sticky backed plastic
poi finger loops/handles

Total cost for these is less than £200 for the pair. That’s pretty good value.

The build:
The APA102 leds were chosen as they are the first affordable pixels to come on a high density strip, that also have a suitably high refresh rate. Previous experiments with led strips such as the ws281* did not perform well, gave a speckled image at best, and forced a very slow rotation speed to be used to get effect at all. The APA102 were ordered from China as they were so very much cheaper than buying them from a US or European supplier. Adafruit are more expensive and sell them under the ‘dotstar’ name, I don’t know why.

The leds come on a reel with joins in the continuous strip every 50cm. This may important for you, as where they are soldered together the gap between the pixels is ever so slightly greater than the rest of the pixels. This does not make much difference in general, but was a factor in me deciding to cut the strips at this point rather than have the solder point somewhere in the middle of the poi.

solder_point.jpg

The Polycarbonate tube and strip were ordered with the Teensy in mind. The internal diameter (22mm) is such that the Teensy 3.1 and the 14500 (AA size) 3.7v lipo battery can fit inside together. Polycarbonate is good material to use in that it is strong, can take a knock or two, does not react badly to strong glues, can be drilled and cut without shattering or splintering, and is reasonably lightweight. It is also readily available from mail order services that cut to size and spec. I went a such a tight squeeze so that I could keep the tube as small as possible = as light as possible.

tube and strip.jpg apa102 on internal mounting strip.jpg

The led strips were fixed to the polycarb strip that goes inside the tube. These strips come with sticky backing, so it was a simple peel and stick process. The second side of leds was matched up so that the leds were directly opposite each other. This way you can get away with just have two rows of leds that give a good coverage to the viewer. This gets mounted inside the polycarb tube, but not until the wiring is connected.

opposing leds.jpg

Next, assemble and test the lipo charger on the Teensy 3 with the battery. This charger is the one made by onehorse (add link). it allows you to embed the teensy in the casing and still charge it via the same micro usb port that you upload sketches with. It makes life really easy. I tried direct mounting to the teensy +ve, -ve and usb pins and I tried a different configuration using wires to have the charger remote from the board. This was to test out space requirements. In the end I went with directly mounting to the teensy. Board soldering it the board, I soldered on two wires for the battery terminals, and a wire to use a switch between the battery +ve and Vin.

lipo charger.jpg

The setup was tested before connecting to the led strips, and then tested again with the led strips connected.
t3_lipo_batt_leds.jpg

I then used polymorph to fashion a spinning eye and make a cap for the poi baton case. This was then secured using a couple of screws that i'd made holes for in the case. These screws go through the holes in the case and fix in to the polymorph providing a secure fixing for the spinning loops.
lipo_glow.jpg



Software:
The software uses FastLED to drive the APA102. At the moment this setup uses non spi pins, and there is further work to do related to using these and using the other spi pins to provide additional flash memory. The sketch attached is just an example of how to access and display the image arrays, you can easily add patterns, and also a button in hardware to switch between performance sets.

There are two parts to displaying an image. Firstly the image is stored in a 'const' array, and then this is accessed by the routine.

here is the code with the array elements reduced so that it can fit in this post. The full array is in the attachment. You will see below that the the void PoiSonic routines are consecutively numbered. This is due to the java programme I use to output image arrays in the correct values, It automatically produced the .ino file to upload to the Teensy. You can call the array whatever you and and change the code accordingly.

The key is the for loop
Code:
    for (int x=0;x<f;x++){
     for(z=NUM_LEDS;z>0;z--){
       leds[z-1]=array[x+((j-z)*f)];}
     FastLED.show();

Code:
/*
*This sketch outputs images to persistence of vision led strips
*It uses FastLed to drive APA102 leds, sending colour values from
*arrays held in flash memory (designated by 'const'). You need to
*set the number of slices you have made your image into, 
*e.g. bmp image of 60 pixels high by 150 wide
* would give 60 num_leds and 
* 150 slices (number of slices you have made your image into) 
*/

#include "FastLED.h"

#define NUM_LEDS 60 //number of leds in strip length on one side
#define DATA_PIN 2//7 = second hardware spi data
#define CLOCK_PIN 3//14 = second hardware spi clock
CRGB leds[NUM_LEDS];
int numberOfSlices = 150;

void setup() {

  delay(200);
    FastLED.addLeds<APA102, DATA_PIN, CLOCK_PIN>(leds, NUM_LEDS);
 }

const unsigned int array0[] = {0x80d06, 0x100,  0x0, 0x0, 0x10000, 0x20000, 0x10000, 0x4, 0x102, 0x100, 0x10001, 0x20801, 0x15370b, 0x468e31, 0x408a27, 0xd2405, 0x300, 0x0, 0x0, 0x0, 0x0
};//holly
const unsigned int array0[] = {0x0, 0x0, 0x0, 0x0, , 0x0, 0x0, 0x10100, 0x40000, 0x20002, 0x4, 0…….
};//snow


void loop() {
PoiSonic(2000,array0); //call method, with duration to show (2sec) and array name.
PoiSonic(2000,array1);
 }


void PoiSonic(unsigned long time, const unsigned int array[]){
unsigned long currentTime = millis();
 while (millis()< currentTime + (time)) {

int f= numberOfSlices;
int z; //a counter
int j=NUM_LEDS;

    for (int x=0;x<f;x++){
     for(z=NUM_LEDS;z>0;z--){
       leds[z-1]=array[x+((j-z)*f)];}
     FastLED.show();
     delayMicroseconds(40); //may need to increase / decrease depending on spin rate
     }       
    delayMicroseconds(1000); //may need to increase / decrease depending on spin rate
   }
 }
 
Last edited:
Awesome work.... I love the DNA!!
I always thought an accelerometer was needed to sync the images?
 
@wozzy, for photography its pretty simple as the shutter is half second, and the spin rate is120 beats per minute, so one revolution matches pretty well to the music. For real life, this is a reasonably good spin rate to get a POV amount on your eye. It all pretty low tech, and the professional kit is similar.
 
Looks amazing great job!!! What are you using to covert the images? Glad to see you working on the apa102 :) Only missing SD this looks like a win. Are you still having issues with SD/SPI_LED? Is it possible to link 2 teensy together to resolve the issue?
 
@TekJunky. I am using my own software, a java app that outputs an .ino file for upload to Teensy. It takes images and converts them to the hex value array for each consecutive image.
PoiSonic_grab.jpg

Its my first Java app, and has some problems with running very slowly, a lot of lag. Memory leaks and 'surviving generations' seem to be the culprit.

There are a number of online converters which work, you just copy and paste the output into the sketch posted above,

RE the SD card, I am not progressing with this option, I am going to use a flash memory expansion. Paul is currently working on something I believe that will allow true SPI to work with apa102 and flash add on.
 
Last edited:
Ok im a little more up to speed now :) Im about to order the flash memory expansion thing and the fast charger. Ive tried converting a image does this look right?

const unsigned char Test [] = {
0x1F, 0x1F, 0x1F, 0x3F, 0x3F, 0x7F, 0xFF, 0xFF............
 
@TekJunky, those values don't look right as the apa102 is expecting a 24bit colour value, but it depend on the value you are sending as to whether the values you posted are correct or not. Each of the R,G and G values will be 8 bits each so a value for a colour could be 0x with six places. I think that there is a converter available free for image to 24bit array if you are using win dose, but have not found one for Mac.

You could try a version of my app if you want to risk it, but I make not promises it will work. It is Java, so comes with the potential of possible back door issues.
 
@TekJunky, if you are on a mac I can send you the app dmg for the software I made to make a Teensy sketch from images. It looks like I was mistaken with free online software, only paid for software.
 
Hi, this build looks amazing, thanks for putting the time in to write it up.
I'm looking to build something similar, but slightly different according to my needs. I have few questions about your build if I may
How bright are the LED's? I'm assuming your running them at 3.7v rather than 5v.
What wall thickness of polycarbonate did you use?
Cheers.
 
@stuntmonkey, the polycarbonate wall thickness is either 2mm or 3mm, can't quite recall.

The leds are plenty bright enough for my use, but suspect that you may want to go with the level shifter to have the potential to max them out. I have not looked into voltage drop as I am using short lengths, and have not looked too far into luminosity - voltage curves. When I come back to improve these with the flash add-on, I will have aloof at using the level shifter, but it operates just fine without.
 
Cheers, I'm looking to use these for performance so yes brightness may be needed sometimes. Running time, not so much, if I can get ten minutes that's plenty for me. I'm looking to put in changeable batteries and ditch the internal charger. Just in case I have multiple shows/sets.
I must admit this is a really steep learning curve for me but I have a friend who can hold my hand through the coding side of things just trying to get a handle on the hardware to order without too many mistakes. Gonna have a look for a level shifter now, if you have any advise I'd really appreciate it.
 
For LEDs like ws2812's and apa102's, the typical level shifter that is recommended is the 74HCT245 that Paul used in the octows2811 adapter. According to the octows2811 page, you can also use the octows2811 to drive 4 streams of APA102's instead of 8 streams of WS2812's:

I know Adafruit resells the Octows2811 if you were already ordering other stuff from them.
 
Thanks Michael,
I have the apa102's on order. I've been looking at this thread https://forum.pjrc.com/threads/28484-Teensy-3-1-how-do-I-output-5v

The same solution was proposed there but I'd really like a smaller solution if possible, right now this:

A quick and dirty solution for testing is to see if you can drop the LED supply voltage to 4.5 volts (check the data sheet) which pushes the 3.3V Teensy output just clear of the default 0.7 Vin for a solid HIGH read.

Seems like the easiest compromise regarding space/brightness. Guess I might have to wait for the bits to turn up and test from there. Always thought I was fairly clever but my brain is aching at the mo.
 
FWIW, I've used this level shifter: https://www.pololu.com/product/2595. When I posted a query on their forum about whether it was fast enough for ws2812's, Pololu recommended that if it wasn't fast enough, to use external 10K pull-up resistors. For the small number of lights I typically drive (32) it works well.

This article from last year discussed some of the issues with the normal level shifters designed for i2c: http://happyinmotion.com/?p=1247.

The DSS circuits shifter that was recommended in the previous article is here: http://www.dsscircuits.com/sale/product/dssc0105

If you only have 1 string of LEDs, an alternative is to use the LC instead of 3.1/3.2, as it internally has 1 pin that is shifted (pin 17).
 
AFAIK APA102 are the LED and controller combined .. has anyone seen just the controller chips?
David
 
If you only have 1 string of LEDs, an alternative is to use the LC instead of 3.1/3.2, as it internally has 1 pin that is shifted (pin 17).
These are four wire SPI leds. Would that single 5v pin on the LC to shift the data out work with soft api settings where clock is not 5v logic pin?
 
@stuntmunky, these are the same issues that I have struggled with - the space issue forced me to go with the single cell 3.7v lipo and the super tiny usb charger from one horse, which is charging the kit within one and half hours giving a 30min playback time using a lot of white. Additional battery space for rechargables was not available.
 
These are four wire SPI leds. Would that single 5v pin on the LC to shift the data out work with soft api settings where clock is not 5v logic pin?

I forgot APA102's were 4 wire instead of 3 wire. Obviously, the LC would not be acceptable without some sort of shifting.
 
@Mortonkopf yes looking at using the same 14500 3.7v lipo as you but I'd like to be able to change it out. I have held off buying the polycarbonate for now untill I can fix the design down a bit more. I'm not too bothered if I have to make it a bit fatter to accommodate stuff but there is something nice about the simplicity of your design

I have been pondering a slightly different design though if I can run it by you:
To use 3 led strips mounted either on polycarbonate strips in a triangle or on a second thinner tube to create a void where 4 standard 1.2v rechargables could go, to be changed at the bottom end.

I had another look at the OctoWS2811 Adaptor and I think I may be able to butcher it to work and fit for my needs, does this sound feasable?:
If I remove the cable socket and cut to the same width as the teensy, then use connections 7&8 from jack 1 and 1,2,3 &4 from jack 2, re grounding 7,1&3 to the teensy. Seems a bit messy and I'm not sure I've understood the circuit diagram properly.

I've been looking at the various pov glowtoys projects on Adafruit: https://learn.adafruit.com/genesis-poi-dotstar-led-persistence-of-vision-poi?view=all
and: https://learn.adafruit.com/pov-dotstar-double-staff/introduction

am I correct in thinking that these are the same led's running at the same voltage as yours? if so they look plenty bright enough.
 
Yes, these are APA102. Why ada insists on renaming things (Dotstar = APA102, NeoPixel = WS281*) I don't know. It annoys me that they do a lot of good work, but sometimes you see things that are annoying.

Anyhow, yes, is also looks like the battery is the same, here is an image of the one I am using
lipo battery.jpg

I don't really like the fussy construction that they have used, such as running the wires the full length of the poi, and using wooden doweling. I don't know about the Trinket, does it output 5v logic? in which case, it is a different set up to the way I have it.

Is the only reason you are going to use a triangular construction so that you can fit the batteries in between? tho swill add more leds to drive, shorter battery life, and more weight. Also, the viewing angle is fine with back to back on the 5050 type leds.

I am not sure why you want to use the the ws2811 adapter. Is it just to access the level shifter? Might be easier to build your own? Regarding replaceable battery, you could use a single AA holder for the lipo, I guess, and slot this in and out with precharged batteries through the handle end using a screw fit closure?

BTW, you will need to think about how you will make your image arrays. You can see from the adafruit site that they have not dealt with this issue yet, they have a pretty involved process.
 
Last edited:
Adafruit sells 4 different things labeled trinket:
  • 3.3v Trinket -- ATtiny85 chip, 5 pins, 8K flash, 512 bytes of RAM, 512 bytes of EEPROM, 8Mhz;
  • 5v Trinket -- ATtiny85 chip, 5 pins, 8K flash, 512 bytes of RAM, 512 bytes of EEPROM, 8/16Mhz;
  • 3.3v Trinket Pro -- ATmega 328p, 18 GPIO, 2 extra analog inputs, 28K of flash, 2K of RAM, 1K EEPROM, 12Mhz;
  • 5v Trinket Pro -- ATmega 328p, 18 GPIO, 2 extra analog inputs, 28K of flash, 2K of RAM, 1K EEPROM, 16Mhz.

I would imagine if you are powering the thing with a 3.7v battery, you want to use the 3.3v version. If you are using USB power, you want 5v to avoid needing a level shifter.

I don't recall the limits of APA's, but for WS2812's, the leds could be powered with 3.5-5.5v. If you were powering the chip with a 3.7v lipo battery, you would not need a level shifter, but hook the leds directly to VIN. If you are using 5v power to the Teensy, you would likely need a level shifter for the data pins.
 
Last edited:
I think tbh I'm going to copy yours and go from there, feeling a little out of my depth here. I have a long wait until the apa102's arrive so I'm gonna swot up in the meantime.

Yes, the triangular construction idea was a way to get the batteries in and to up the voltage, I realise I would need a logic level converter with this too. It would up the weight but it would also free up space at the top and put the weight near the bottom which would be nicer for spinning. Although weight distribution with a single battery is probably a non issue.

And yes the ws2811 adapter was for the logic shifter. Again looks like I'll need to do some research.

As far as the images and coding, so far the adafruit process does seem to be the option I would go for, it may be a bit complicated but I think if my friend helps me the first few times I can get it.

Anyways thanks for your help so far, I'm gonna go and read some
 
@MichaelMeissner, I had two teensy 3.2's arrive today so I'm looking to make it work with them. I mentioned the adafruit projects more to get an idea of the brightness at 3.7v, which I assumed they were running at, although im not sure if they both are anymore. Both projects use the 5v version, the poi use the 5v trinket and the staffs the 5v trinket pro. Both are powered with a 3.7v battery but the trinket pro has:
•On-board 5.0V power regulator with 150mA output
Does this mean it has a level converter built in?



Gonna take another look at the apa's datasheet.
 
Back
Top