Teensy APA102 POV Poi / Pixel Poi Build. Tutorial

Finger loops with ring and swivel, with adjusted cord length. Swivel is important, I think. The sort that you can find in either Oddballs or Firetoys shops. leather or material loops, but leather gets grimey. For the attachment between the poi casing and the cord, I have a thermoplastic eye which is also an end cap. This is screwed into position through the polycarb tube by two self tapping screws.
 
Last edited:
Looking at this set up is pretty interesting. I've built POV systems in the past before all this great HW was available so it's kind of like a kid in a candy store. I'll have to build one...

A couple of observations - First, using an array of longs wastes a byte per pixel. A good rework would be to be declare 3 uchar arrays for R, G and B. A simple python program could do the transform. That will save 1/4 of your memory space with a pretty simple mode to the code. Secondly, there is a huge amount of redundancy in the data that I've seen so a simple run-length encoding could significantly reduce the amount of space required. This is more complex and takes some "decompress time" but the teensie has plenty of that. In the data I've seen, there are long runs of black (0x000000) which could compress into 4 bytes per long run. In the array of longs, the high byte could be used for repeat number. There would need to be a list of pointers/indexes to the start of each row.
 
@PhilB, thanks for the pointers. That Poi code really does need work, agreed. The only real thought that went into optimising was to avoid additional calculations impacting on speed, and maintaining simplicity to keep the logic of the code easily understandable. You are right about the speed issue, however, the Teensy has plenty, and I have to slow the pixel pushout rate down in order to obtain a well proportioned POV image. I haven't used run-length encoding before, I will have look into it when I get a bit of time. My main concern at the moment is to get it to work with the serialflash memory of the prop shield.
 
Hello everybody! I'm trying to make 3D led globe from APA102 with 35 leds.
Controller - arduino nano
Stripe was calibrated for right colour order (BGR)
Picture - 20 slices X 35 leds.

The form of the picture is right, (I see a hart), but colours are totaly wrong! I see BLACK instead of RED and BLUE instead of WHITE. Color codes in the array are right (0xffffff for white, for red 0xff0000).
Maybe Atmega328 is too slow? but colors are wrong even for 4X4 image =)

Please, help me.

#include "FastLED.h"
#define DATA_PIN 12//7 = second hardware spi data
#define CLOCK_PIN 13//14 = second hardware spi clock
#define BRIGHTNESS 50

#define NUM_LEDS 35 //leds
int numberOfSlices = 20; //coloumns

CRGB leds[NUM_LEDS];
void setup() {

delay(5000);
FastLED.addLeds<APA102, DATA_PIN, CLOCK_PIN, BGR>(leds, NUM_LEDS);
FastLED.setBrightness( BRIGHTNESS );
//DATA_RATE_KHZ(100)
}

//ARRAY

const unsigned int array1[] = { 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, 0xff0000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, }; //end of array

void loop() {PoiSonic(10000,array1);}


void PoiSonic(unsigned long time, const unsigned int array[]){
unsigned long currentTime = millis();
int f = numberOfSlices;
int z; //a counter
int j = NUM_LEDS;
while (millis()< currentTime + (time)) {
for (int x=0; x<f; x++){
for(z=NUM_LEDS; z>0; z--){
leds[z-1]= CRGB (array[x +((j-z)*f)]);}
FastLED.show();
// delayMicroseconds(1000); //may need to increase / decrease depending on spin rate
}
// delayMicroseconds(1000); //may need to increase / decrease depending on spin rate
}
}
 
Last edited:
It might be that the variable is declared as 'int' in 'const unsigned int array1[]' and should really be uint32_t instead. For nano, i think that int is 16bit data type. try replacing the segment above with 'const unsigned uint32_t array1[]' ??

MichaelMeissner has often reminded me to do the right thing about declaring data types, but I don't listen...
 
odeston said:
The form of the picture is right, (I see a hart), but colours are totaly wrong! I see BLACK instead of RED and BLUE instead of WHITE. Color codes in the array are right (0xffffff for white, for red 0xff0000).
Maybe Atmega328 is too slow? but colors are wrong even for 4X4 image =)

Please, help me.

You want to be explicit on the type. On an arm processor, int will be 32-bits and you can store a 24-bit value like 0xffffff, while on an AVR processor, int will be 16-bits, and the upper bits will be truncated to 0xffff.

Another issue is the AVR processors tend to have very little RAM, and you need to move such tables into the read-only flash memory holding the program. Because AVR chips use a Harvard architecture setup (code and data are in different address spaces), you need to decorate your code with PROGMEM and use the accessor macros to move the constant data from program memory to read/write memory to send to the lights. On the Arm systems like the Teensy 3.x/LC, you don't need to do this (Arm is a Von-Neumann architecture where the different memories are in the same address space).

It might be that the variable is declared as 'int' in 'const unsigned int array1[]' and should really be uint32_t instead. For nano, i think that int is 16bit data type. try replacing the segment above with 'const unsigned uint32_t array1[]' ??

MichaelMeissner has often reminded me to do the right thing about declaring data types, but I don't listen...
It is more that I've worked many different systems, and have had to port code between the systems (or setup the compiler to allow users to do the porting) that I've become sensitive to these issues.
 
Last edited:
It might be that the variable is declared as 'int' in 'const unsigned int array1[]' and should really be uint32_t instead. For nano, i think that int is 16bit data type. try replacing the segment above with 'const unsigned uint32_t array1[]' ??

MichaelMeissner has often reminded me to do the right thing about declaring data types, but I don't listen...
That was my 666th post on the forum... had to quickly post another....
beastly business
 
uint32_t helped! Thanks, I love you guys =) 328p is a baby, I am waiting for my ESP8266 WeMos with SD shield to try APA102 at 30 Mhz...
 
Hi I am wondering if you can help with something. I have been playing with the adafruit palette poi and want to again display the same image multiple times down the strip. So what you helped with before mortonkompf. The solution was to duplicate the statement of the array with a different start point and then have LED.Show following. Here is a piece of the code that is processing the image to display.

case PALETTE4: { // 4-bit (16 color) palette-based image
uint8_t pixelNum, p1, p2,
*ptr = (uint8_t *)&imagePixels[imageLine * NUM_LEDS / 2];
for(pixelNum = 0; pixelNum < NUM_LEDS; ) {
p2 = pgm_read_byte(ptr++); // Data for two pixels...
p1 = p2 >> 4; // Shift down 4 bits for first pixel
p2 &= 0x0F; // Mask out low 4 bits for second pixel
strip.setPixelColor(pixelNum++,
palette[p1][0], palette[p1][1], palette[p1][2]);
strip.setPixelColor(pixelNum++,
palette[p2][0], palette[p2][1], palette[p2][2]);
}
break;
}


Where it says:

strip.setPixelColor(pixelNum++,
palette[p1][0], palette[p1][1], palette[p1][2]);
strip.setPixelColor(pixelNum++,
palette[p2][0], palette[p2][1], palette[p2][2]);
It seems you would do additional palette[p1][20], etc with a different pixel start value. I tried that and it compiles but did not display images.

Here is my hack of an attempt. I wonder if you can help?

case PALETTE4: { // 4-bit (16 color) palette-based image
uint8_t pixelNum, p1, p2,
*ptr = (uint8_t *)&imagePixels[imageLine * NUM_LEDS / 2];
for(pixelNum = 0; pixelNum < 15; ) {
p2 = *ptr++; // Data for two pixels...
p1 = p2 >> 4; // Shift down 4 bits for first pixel
p2 &= 0x0F; // Mask out low 4 bits for second pixel
leds[pixelNum++]=CRGB(palette[p1][0], palette[p1][1], palette[p1][2]);
leds[pixelNum++]=CRGB(palette[p2][0], palette[p2][1], palette[p2][2]);
}




for(pixelNum = 16; pixelNum < 32; ) {
p2 = *ptr++; // Data for two pixels...
p1 = p2 >> 4; // Shift down 4 bits for first pixel
p2 &= 0x0F; // Mask out low 4 bits for second pixel
leds[pixelNum++]=CRGB(palette[p1][0], palette[p1][1], palette[p1][2]);
leds[pixelNum++]=CRGB(palette[p2][0], palette[p2][1], palette[p2][2]);
}
break;
}
 
It looks like you are setting the same pixels twice, rather than different pixels once. you will probably need to change one of your calls from "leds[pixelNum++]=..whatever" to "leds[pixelNum++(your offset goes here)]=..whatever"
 
Hi I am wondering if you can tell me what is going on and help diagnose a problem. I am making a staff with a single teensy 3.2 and 32 apa102 leds. There is a 4 foot section between staff led ends. The teensy is on one end and connects with about two inches of wire to the led strip on that same side. There is 4 feet of wire going from the teensy to the opposite side to connect to the other section of leds.

The leds on the side with the teensy closely connected acts strange and seems to be mixing up data or timing. The other side more distant from the teensy is working fine. When I unhook the long wire strands, the side close to the teensy works fine. Maybe because it is sending timing and data down the long strand and the short strand somehow it is getting messed up? I dont get what is going on. Using WS2812 leds this isnt a problem.
 
Also, when I send data from the clock output on the led strip closest to the teensy it makes the leds work better on both sides. It seems the clock signal, which is a square pulse I think, is going down the wire due to less resistance and the clock signal down the shorter line is weakened or changed due to the different wire lengths. Has anyone had this issue? I can fix it by connecting down stream of the led section closest to the teensy but it is a pain. I dont have access to various resistors to try out, will have to pick some up.
 
Hello,


Sorry for interrupting, I just wanted to share my creation inspired by mortonkopf








https://www.youtube.com/watch?v=crZ334qV-Gg


I changed a little bit the original project: I abandoned the idea of charging the battery through USB port. The OneHorse's charger is really fragile. Swapping batteries is much easier, faster and cheaper solution (maybe less sophisticated, but still). I extend also Teensy by adding 128 MB Flash memory board (also from OneHorse), which works great and is quite easy to program.

I can post more details (and the code), however I still building the second bar, and I want to program a IR reciever, so Teensy can be controlled remotely.

Thanks for all your help.
 
Hi
I have one idea,i don't know if its possible.
My idea is to put 2 parallel led strip in bout side to grow the resolution.
One strip can be with number of led- 1,3,5,7........ and second strip 2,4,6,8.....with around 5mm in distance
It is posible to change sketch and teensy addressing separate clock/data?
Led strip_0.jpg

Thanks
 
Last edited:
So this is my code for saving (5) pictures on the flash:

Code:
#include <SPI.h>
#include "SerialFlash.h"

const int FlashChipSelect = 10;


//1. kwiatek 1
const unsigned int array1[] = { 0x000000, 0x000000, 0x000000, x000000, 0x000000, ...}; //end of array 
const char filename1[]= "p11.bin";

//2. polish 1
const unsigned int array2[] = { 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,... }; //end of array 
const char filename2[]= "p12.bin";

//3. polish 2
const unsigned int array3[] = { 0x030102, 0x020204, 0x020403, 0x000200, 0x020204, ...}; //end of array 
const char filename3[]= "p13.bin";

 //4. polish 3
const unsigned int array4[] = { 0x000000, 0x000000, 0x000000, 0x000000, 0x0b0b0b,... }; //end of array 
const char filename4[]= "p14.bin";

//5. indian 1
const unsigned int array5[] = { 0x191f41, 0x141529, 0x100d16, 0x2a2b0c, 0x51530a,... }; //end of array 
const char filename5[]= "p15.bin";




void setup() {
  Serial.begin(9600);
  SerialFlash.begin(FlashChipSelect);
  unsigned long startMillis = millis();
  while (!Serial && (millis() - startMillis < 10000)) ;
  delay(100);
  Serial.println("START"); 

//TWORZENIE I ZAPISYWANIE

//////////////////////////////
SerialFlashFile file1;
  Serial.println(sizeof(array1));
  if (SerialFlash.exists(filename1))
    {
    Serial.println("Plik juz istnieje!!!"); 
    Serial.println(filename1);
    Serial.println("----------------------");
    }
  else{
    //twórz
    SerialFlash.create(filename1, sizeof(array1));
    //otwórz i zapisz
    file1 = SerialFlash.open(filename1);
    if (file1) {
      file1.write(array1, sizeof(array1));
      Serial.println("----zapisalo plik-----"); 
      Serial.println(filename1);
      Serial.println("rozmiar pliku");
      Serial.println(sizeof(array1));
      Serial.println("----------OK-----------");
    }
  file1.close();
  Serial.println(sizeof(array1));
  }
//////////////////////////////////////





//////////////////////////////
SerialFlashFile file2;
  Serial.println(sizeof(array2));
  if (SerialFlash.exists(filename2))
    {
    Serial.println("Plik juz istnieje!!!"); 
    Serial.println(filename2);
    Serial.println("----------------------");
    }
  else{
    //twórz
    SerialFlash.create(filename2, sizeof(array2));
    //otwórz i zapisz
    file2 = SerialFlash.open(filename2);
    if (file2) {
      file2.write(array2, sizeof(array2));
      Serial.println("----zapisalo plik-----"); 
      Serial.println(filename2);
      Serial.println("rozmiar pliku");
      Serial.println(sizeof(array2));
      Serial.println("----------OK-----------");
    }
  file2.close();
  Serial.println(sizeof(array2));
  }
//////////////////////////////////////


//////////////////////////////
SerialFlashFile file3;
  Serial.println(sizeof(array3));
  if (SerialFlash.exists(filename3))
    {
    Serial.println("Plik juz istnieje!!!"); 
    Serial.println(filename3);
    Serial.println("----------------------");
    }
  else{
    //twórz
    SerialFlash.create(filename3, sizeof(array3));
    //otwórz i zapisz
    file3 = SerialFlash.open(filename3);
    if (file3) {
      file3.write(array3, sizeof(array3));
      Serial.println("----zapisalo plik-----"); 
      Serial.println(filename3);
      Serial.println("rozmiar pliku");
      Serial.println(sizeof(array3));
      Serial.println("----------OK-----------");
    }
  file3.close();
  Serial.println(sizeof(array3));
  }
//////////////////////////////////////

//////////////////////////////
SerialFlashFile file4;
  Serial.println(sizeof(array4));
  if (SerialFlash.exists(filename4))
    {
    Serial.println("Plik juz istnieje!!!"); 
    Serial.println(filename4);
    Serial.println("----------------------");
    }
  else{
    //twórz
    SerialFlash.create(filename4, sizeof(array4));
    //otwórz i zapisz
    file4 = SerialFlash.open(filename4);
    if (file4) {
      file4.write(array4, sizeof(array4));
      Serial.println("----zapisalo plik-----"); 
      Serial.println(filename4);
      Serial.println("rozmiar pliku");
      Serial.println(sizeof(array4));
      Serial.println("----------OK-----------");
    }
  file4.close();
  Serial.println(sizeof(array4));
  }
//////////////////////////////////////

//////////////////////////////
SerialFlashFile file5;
  Serial.println(sizeof(array5));
  if (SerialFlash.exists(filename5))
    {
    Serial.println("Plik juz istnieje!!!"); 
    Serial.println(filename5);
    Serial.println("----------------------");
    }
  else{
    //twórz
    SerialFlash.create(filename5, sizeof(array5));
    //otwórz i zapisz
    file5 = SerialFlash.open(filename5);
    if (file5) {
      file5.write(array5, sizeof(array5));
      Serial.println("----zapisalo plik-----"); 
      Serial.println(filename5);
      Serial.println("rozmiar pliku");
      Serial.println(sizeof(array5));
      Serial.println("----------OK-----------");
    }
  file5.close();
  Serial.println(sizeof(array5));
  }
//////////////////////////////////////  

}



///////////////

void loop() {
}


and here is a code to play it. I added load function

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 <SPI.h>
#include "SerialFlash.h"
#include "FastLED.h"



#define FlashChipSelect 10
#define NUM_LEDS 56 //number of leds in strip length on one side
#define DATA_PIN 23//7 = second hardware spi data
#define CLOCK_PIN 21//14 = second hardware spi clock
CRGB leds[NUM_LEDS];

unsigned int array1[240*NUM_LEDS]; 
unsigned int pictureNumber = 11;
char filename[] = "pXX.bin";
const unsigned int arrBlack[] = { 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, };

int numberOfSlices = 1;

///////////////////////////////////////////////////////////////

void setup() {
  Serial.begin(9600);
  FastLED.addLeds<APA102, DATA_PIN, CLOCK_PIN>(leds, NUM_LEDS);
  SerialFlash.begin(FlashChipSelect);
  delay(100);
  Serial.println("setup"); 
 }

//////////////////////////////////////////////////////////////////

void loop() {

loadPicture(pictureNumber); //load picture number=pictureNumber to array 1
PoiSonic(8000,array1); //call method, with duration to show (8sec) and array name.
pictureNumber=pictureNumber+1;
 }

//////////////////////////////////////////////////////////////
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(1400); //may need to increase / decrease depending on spin rate
     }       
    delayMicroseconds(1000); //may need to increase / decrease depending on spin rate
   }
 }
/////////////////////////////////////////////////////////////


void loadPicture(int num){
  
  char XX[2];
  sprintf(XX, "%d", num);
  filename[1]=XX[0];
  filename[2]=XX[1];

  SerialFlashFile file;

  if (SerialFlash.exists(filename))
    {}
  else
    {
     pictureNumber = 11;
     filename[1]=1+'0';
     filename[2]=1+'0';
    }
  file = SerialFlash.open(filename);
      if (file)
        {
        file.read(array1, sizeof(array1));
        numberOfSlices = file.size()/4/NUM_LEDS;
        Serial.println("----sprawdzenie otwierania-----");
        Serial.println(numberOfSlices);
        Serial.println(filename);
        Serial.println(file.size());
        }
    file.close();
  
}



dzuljo, I this it may be possible. However, the strip are kind of wide, which may be a problem here.
 
@mortonkopf, I ran into the same problem in post #55. Moving the Loop() after PoiSonic() solved it for me. I'm using 1.6.9.

If I'm reading this right . . . The Arduino IDE tries to be helpful and - unlike standard "C" compilers - it will scan the sketch for functions and allow calling them before they are defined without a prior prototype. The same is true for global variables - and the IDE doesn't help with those. The IDE fails at times and unless you make a prototype for the function before it is called - this is done with .h Header files for library functions.

For instance to make this work - when the IDE gets confused:

// Add this prototype before the function is called
void PoiSonic(unsigned long time, const unsigned int array[]); // first line of function with a semi-colon not an open brace

loop() {
void PoiSonic( Xtime, Xarray );
}


void PoiSonic(unsigned long time, const unsigned int array[]){
// real function declared here
}

NOTE: I have a tendency to not type semi-colons - or edit code and mis-count braces. These are syntax errors that stop the IDE from parsing the file accurately and finding functions - often these typos are hidden by this same error where it complains about a missing prototype. In the IDE I use "Ctrl + T" Auto-Format to provide uniform spacing and indenting - it also chokes on miscounted braces and semi-colons - and this can make those typos stand out.
 
// Add this prototype before the function is called
void PoiSonic(unsigned long time, const unsigned int array[]); // first line of function with a semi-colon not an open brace

loop() {
void PoiSonic( Xtime, Xarray );
}


void PoiSonic(unsigned long time, const unsigned int array[]){
// real function declared here
}

@defragster, this also works. However I prefer moving the Loop(). Maintaining the prototype, as well as the function, is annoying. If I change from int to char in the function will I have to remember to do the same in the prototype? Why the change in the Arduino IDE?
 
@defragster, this also works. However I prefer moving the Loop(). Maintaining the prototype, as well as the function, is annoying. If I change from int to char in the function will I have to remember to do the same in the prototype? Why the change in the Arduino IDE?

AFAIK :: The change is a side affect of offering 'non standard C' feature of pre-parsing the sketch to allow this. The compiler rule is "I need to see what you are using before it is used", a Prototype of the function declaration does that. This pre-parsing by the IDE is subject to failure as it is not the compiler, but an evolving add on. At the point the IDE mis-parses the sketch it fails to find and create a valid prototype - which is why I added the NOTE about syntax errors throwing it off as it does the "Auto Format" when the language rules are not followed.

Indeed - maintaining a prototype and a function declaration can be annoying (as can be re-ordering the source in a long file) - but that is what happens in every #include <_HEADER_.h>. But when the code ever splits to multiple files or a 'library' - or if you leave the controlled environment of the Arduino IDE - it isn't an option.
 
I think about building a persistence-of-vision object that can receive new pictures/patterns over a serial-to-bluetooth adapter at run-time. From Fr1day's code in post #118 is see that even if I could store multiple patterns in SPI flash, the currently displayed pattern has to reside in ram, correct? So with Teensy's 64kBytes of RAM, how much will there be left (approximately) when the SPI and FastLED libraries are included? Or may it be possible to access an SPI flash memory in the delayMicroseconds()-pauses of the main update loop to only load parts of the images to ram and access the flash "on the fly" to load the next "frame"? That would allow for much higher resolution images and/or animations!
 
the currently displayed pattern has to reside in ram, correct?

Judging from my small knowledge of microcontrollers, I think that's correct. The patterns are stored in SPIFlash and than, at some point they are transferred to ram.

how much will there be left (approximately) when the SPI and FastLED libraries are included?

Max pattern I can display at one time is 56x240 pixels, which I think is more than enough for my build. Of course, when you are planing to double, for example, the amount of pixels in the row, the max width would be half of it, I guess.

It's fairly easy to write a program to play two/three or more picture in a row (one after another), however if you play my yt video frame by frame you can see that there is little delay in transmission between two patterns. You cannot even notice it in normal speed, but when there would be no repeated patterns it MAY be visible, but more test should be made.

With bluetooth there I see a lot of programming, but it could be possible. But again there may be some delay in the vision, because it's also SPI. I think that this guy https://www.youtube.com/watch?v=p9_Nv5Tiq-Q made something similar, see in the description.
 
because it's also SPI.

The speed of the SPI bus has been the bottleneck for me. I'd like to move four 288px X 512px images a second from an SD card to memory. It appears that the next version of the Teensy will have native SDIO, with that the speed bottleneck disappears, at least for my project. Bluetooth LE via SPI is too slow for what I'd like to do.
 
Back
Top