OctoWS2811 POV reading BMP from SD card

Status
Not open for further replies.

mortonkopf

Well-known member
Hi all, thanks to ZTiK.nl for pointers to using SD card buffers, I have now finished the Pixel Poi POV that reads BMP from the SD card and displays on 60 WS2811 leds (from a 144led/m strip). I have posted the full code over on a blog, as its a bit long to put up here.

here are some photos of images being displayed on the POV. Each image is 60 x 150 pixels, and is read in about 300ms. The code repeats the display of the images for a given number of secs then moves on to the next image file named in the loop. If anyone can see how performance can be improved, please let me know.

Oh, and thanks to everyone on this forum for your help.

blueflower.jpgpattern2.jpg

The code uses the buffer set up that ZTiK.nl highlighted for the tft screen output:
Code:
     for (row=0; row<h; row++) {       
         if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
            pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
          else     // Bitmap is stored top-to-bottom
            pos = bmpImageoffset + row * rowSize;
          if(bmpFile.curPosition() != pos) { // Need seek?
            bmpFile.seekSet(pos);
            buffidx = sizeof(sdbuffer); // Force buffer reload
          }

          for (col=0; col<w; col++) { // For each column...
            // read more pixel data
           if (buffidx >= sizeof(sdbuffer)) { 
             povidx = 0;         
              bmpFile.read(sdbuffer, sizeof(sdbuffer));
              buffidx = 0; // Set index to beginning
           }
            // set pixel
            b = sdbuffer[buffidx++];
            g = sdbuffer[buffidx++];
            r = sdbuffer[buffidx++];

            povbuffer[povidx++] = Color(b,r,g);//octo colour, but you might need to change this
          }
        for(int i=0;i<ledsPerStrip;i++){
   leds.setPixel(i, povbuffer[i]); }
 
        leds.show();
      //  delay(1);// change the delay time depending effect required
          delayMicroseconds(220);
    } // end scanline

The Color() function is a helper function that puts the separate colour bits together in the right way.
The full code is at: http://orchardelica.com/wp/displaying-led-graphic-poi-bmp-from-sd-card
 
Last edited:
Hey Morton and Paul, thanks for responding to my thread earlier; very helpful tips and information.

Was wondering though: is there any wireless protocol that would be able to do this fast enough, without an SD card? As in, rather than having a sketch on the Teensy that brings in a .bmp from the SD, then play the pattern line by line, is the following possible?
- Assuming I have a functional Android/iOS app of some sort that can download images, then prepare them as 1pix wide slices
- The app then sends this data via bluetooth (or some other wireless method), slice by slice to a receiver on the teensy end
- The teensy then outputs this into the LEDs, allowing for a similar light painting effect.

I realize it's far more complicated to do it this way and doesn't add too much value to the project, but was just wondering if it could be done. Thanks :)
 
It probably gets down to data amount, and whether the sender can actually prepare the stream in real-time. I would imagine you would need Wifi speeds at least. It probably would make sense to do a back of envelope calculation of how many bytes need to be sent out in what period of time, adding in some fudge factors. For example, I believe the ws2812's need 3 bytes per pixel (plus some control information). These days you may have to worry about congrestion in the spectrum, and it may lower the amount of data you can push through.
 
thanks Michael.

Found these (https://www.sparkfun.com/products/9034), and at up to 2Mbps I imagine they could do the job. Probably isn't compatible with any android/iOS hardware though, which kind of defeats the purpose. I suppose the best way is, as you suggested before, to have an onboard SD storage, and maybe use bluetooth to load images if needed, or do very simple, non animation based color changes.
 
That is about the same speed as bluetooth (wifi is faster than either of those, which is why I speculated you might need it). The bps is mega-bits, which means you need to divide by 10 to get the number of bytes per second (roughly 200,000 bytes). Assuming you want a refresh rate of 30 times a second, and you need to send out 3 bytes, the absolute maximum you could support is maybe 1,5000 pixels. However, in terms of radio, like with gas mileage, you rarely receive the theoretical maximum. So it might be possible to send out 500 pixels 30 times a second if you are near enough and nobody else is congesting the 2.4Ghz band, but I wouldn't bet the ranch on it, until I actually measured it. You still need to do the calculation whether the thing sending the bytes of data is fast enough to do the processing in real time (assuming you aren't reading it from a disk or SD card).
 
An alternative is to load up an on board sd card with images (they can hold a lot) and use:
1) bluetooth signal from android to teensy loop that triggers the selection of the bmp you want (there are free phone apps that talk to Teensy through a bluetooth module)
2) a simple push button on the device that selects the next image and then scroll through to the one you want
3) an onboard physical device that provides menu such as buttons and lcd
4) an RF device that Teensy listens to select the bmp via one of the signal patterns produced by the device? (although someone else would have to confirm the process for this as I have no direct experience of using it)
 
Last edited:
@wasaler, using this code for light painting: I did a quick light staff build to test the code and setup, and yes, it can easily be used for a light painting project. The below image (a very poor one, out of focus and in bright daylight) shows that a bmp can be read from the sd card and shown over 147 ws2811 pixels to light paint an image. The code does need tweaking, but I'm sure you sort that out. If not, I can post changes.
jem2.jpg

teensy_staff.jpg

space_invader.jpg

mortonkopf
 
Last edited:
Can the code be changed to work with 30LED/m?
Still trying to get this working just ordered some 60LED/m strips.
Does the SD have to be hooked up to turn on the strip? (I connected it with out the SD nothing happened)
Do I put the .bmp in root dir on sd?
Sorry Im new to Teensy any info would help.
I have a 3.1 also.
Thanks :)
 
If you're just getting started, please at least run the simpler examples that come with OctoWS2811 (in Arduino, use File > Examples > OctoWS2811). At least run those to make sure your LEDs work, before you venture on to more complex stuff!
 
Yes, it should work with 30 led strip so long as you save your BMP to that size pixel number. As Paul says go though the building block basic sketches to test each component first. It will save a lot of pain later. First, do a basic led test, then do the basic SD card test sketch. You should save the bitmap as 24bit in the root,or change the sketch to suit.
 
Last edited:
Ok thanks. You guys are right im sure im just missing a few things. Im going to go back through it and install the sd too. I will update if I get things going :) THANKS so much for putting the code up. Im a POI spinner and a tek guy and would love to save some $ and build my own. They dont need to be super high res so I was hoping I could use 30 or 60 leds per meter strips instead of the 144/m strips.

In the code what is 147?

//fixed values for octoWS2811
const int ledsPerStrip = 147;//60;

60 is the Num of leds right?
 
yes, ledsPerStrip in the number of leds on the poi / light painting stick. For the poi this is the length of one side, as the same led data for the pattern will be sent to each side at the same time. i think that you should consider apa102 leds and changing the code to run these. i have not used theseleds, but they seem to have a much higher refresh rate and so will be really good for poi spinning speeds. After all, you only want to build these poi once!

Also, try the basic sd card sketch on its own to make sure that the connections are all good.
 
So the 60 is commented out in that example?

//fixed values for octoWS2811
const int ledsPerStrip = 147;//60; (just wondering why there is two)

I will give the apa102 a try if you think it will work better :)
WS2811 work with apa102?

I got the next 2 days off so im going to put in some work on this project :::D
 
yes, commented out as a left over from some testing and to show that it can be changed to suit.

Hmm, no, i think you will need a different library for the apa102, the octows2811 library probably does not drive these. Like I said, have not used them, just read about them. You might have do some more research before a purchase...
 
Yes will do some research on them but want to give what you have here a shot first. It doesnt have to look great to me just cool :)
 
Got it up and running but still not able to get a .bmp to work. The patterns work great though :)

upDown(5000);
bmpDraw("Test_1.bmp"),5000;
bmpDraw("Test_2.bmp"),5000;
Chaser(5000,1);
bmpDraw("Test_2.bmp");//,5000);

//Blue_flower(5000,2);
 
Good news that you got it working for the patterns. RE the bmpDraw, have you uploaded and tested the simple SDfat file sketch that prints to the serial? You can use that to test that you have the sd card connections set up correctly. Perhaps try the openNext sketch in the SDfat library, it will be in the examples drop down to ensure that all is working with the card.

The bitmap will need to saved as a 24bit bitmap, and the bitmap height will need to be your pixel length / number. The bitmap can be as wide as you like, as the sketch will just play out the file contents until no more data is read.
 
:::D YAY!!! Got it working!!! Had to set the #define BUFFPIXEL size. Im only using 30led/m stripes so its not very detailed but its working so thats cool. Just ordered so 60led/m strips to do more testing and will be getting some 144led/m strips soon as I get some more cash (they are not very cheap).

BIG THANKS TO *>>mortonkopf<<*

How can I set each .bmp to loop a few times?
I would like it to loop the .bmp 5-10x before going to the next.
 
Thats great, another glowy poi spinner soon! I would set the drawBMP() function differently, so that it had a time element in it, or a count element such as bmpDraw(bmp file, count); this would pass to the method bmpDraw(). Where count can equal a value for time or a value for the number of times to be repeated.

Or, a cheap and easy way to get a piece of code to happen a few times is to put it in a "for loop()". This is a simple counter that counts up a set amount for each time something happens. It might work. The other way is to use a "while" statement, and that sets your piece of code to do something for a set amount of time. There are probably other ways, but these are simple ones.

Using the for loop, you might be able to do something like:

int count;
int number = 5;//where number is the number of times you want to repeat, or the maximum you want to count to

for (count=0;count<number;count++){
bmpDraw(filename);//or whatever you want to do here
}

this has some problems associated with it, and is probably not a very safe way to run things from you main loop(). I would set the drawBMP() function differently, as above with the count within the call to the method, and then ensure that this goes through the cycle the wanted number of times, or for the time required.

I think that I have a version of the sketch with this included, but for a set time rather than a set number of repeats of the bmp. I will see if i can dig it out.
 
Last edited:
To get the bmp file to play again and again for set time change the call to use millis:
Code:
  bmpDraw("ball.bmp",2000);//filename and time in ms to keep displaying

Change the front end of the bmpDraw method to:
Code:
void bmpDraw(char* filename, unsigned long time) {
 unsigned long currentTime = millis();
 
 //so that the image continues to be displayed again for a set time
   while (millis()< currentTime + (time)) {
and don't forget to add the additional closing curly }
 
So I changed the code to what you have up here ^^ But seems to just slow down the speed of displaying the BMP when i adjust (( bmpDraw("ball.bmp",-->2000<---); ))
 
Status
Not open for further replies.
Back
Top