Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 11 of 11

Thread: Teensy 3 WS2811 POV (144led/m)

  1. #1
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    London, uk

    Teensy 3 WS2811 POV (144led/m)

    Hello all,

    I have been working on a POV baton using Teensy 3 and OctoWS2811. I currently have a set of POV batons using LPD6803 leds and Teensy 2++, but these had to be soldered individually, and my soldering was not too good. Anyhow, I wanted to get a higher density, and the 144led/m strips looked like a good idea. I have used the Octows2811 lib for scrolling text displays, but thought that it might be fast enough for a POV - and it is (great stuff Paul).

    I bought a couple of strips of the144led per meter ws2811 led strips from china, but the build quality was terrible, and in the end i had to do a fair bit of cutting of the strip and resoldering. anyhow, here is pic of first attempt, hope you like it. Like Neep (we must get in touch), I think that POV toys are fun, and seem to be spending too much time thinking about them. I think that the teensy 3 and octo lib are the way to go. How about a thread on Led twirly things?

    Happy to share code if anyone wants it. Just working on figuring out the sd code from (your work is also much appreciated).

    Also, Neep, I have some maths code patterns that you might like. Let me know.


    Click image for larger version. 

Name:	teensy3_1.jpg 
Views:	1169 
Size:	129.6 KB 
ID:	1077Click image for larger version. 

Name:	holly.jpg 
Views:	593 
Size:	121.2 KB 
ID:	1078
    Last edited by mortonkopf; 11-07-2013 at 09:19 PM.

  2. #2
    Senior Member
    Join Date
    Jan 2013
    Now THAT looks awesome!
    Last edited by Headroom; 11-08-2013 at 01:56 AM.

  3. #3
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Oh yes, that is awesome.

  4. #4
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    London, uk
    I have a question about how the ws2811 colour is reset using octows2811. There appears to be a 'gap' in the colour when refreshing. Is this because the 50us low switches the ws2811 led off momentarily, or perhaps something in my code. When using the ldp6803, the colour could remain until a new colour was set, so no gaps, just a continuous flow, as it were. A pic below shows this. These were driven with Fast_SPI lib.

    Any pointers appreciated, as the continuous changes looks smoother to my mind.

    kind regards
    Click image for larger version. 

Name:	centre.jpg 
Views:	450 
Size:	85.0 KB 
ID:	1079
    Last edited by mortonkopf; 11-08-2013 at 06:36 AM.

  5. #5
    Junior Member
    Join Date
    Nov 2013
    The gaps are a function of the slow PWM rate on the WS281X chips (about 400 Hz). Fine for animation on a static thing, good enough for light painting, not so good for POV. For the latter I recommend...well, almost anything else (e.g. LPD8806), downside being the coarser pixel density. Tradeoffs!

  6. #6
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    London, uk
    @pburgess. thanks for the info. Is a shame that this is so, but there you go. Now on the search for high density strips without this issue.

    I have tested these strips for slower refresh work for a light painting staff, and they work reasonably well.

  7. #7
    Junior Member
    Join Date
    Dec 2013
    Dear Mortonkopf,

    i'm working on a project similar to yours and i can see that you got a great result so far.

    Can you please share the code and picture of your project or schematic ?

    Thanks in advance.

  8. #8
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    London, uk
    @e3d. I have not made a schematic for this project, but it simply follows the set up of two other wiring schemes, one for the SD Card and one for the WS2811 led strip. The SD card pins are described in posts on this forum, and also included in the code below.

    This forum post by describes the sd card use:

    For the wiring of the leds, look at the Octows2811 page on the pjrc site for a good description of the set up, better than me going through it here. I use 4 x AAA rechargeable batteries that run the Teensy3, Leds, and the sd card a the same time. I found that I needed to use a common GND pin for the Leds and the Teensy.

    the code is available at:

  9. #9
    Junior Member
    Join Date
    Dec 2013
    Thanks Mortonkopf,

    I Just added slight modification on your code to try to work it out on 16 LEDs NeoPixel strip using Arduino 1.0.5 environment & Teensduino loader v.1.17

    however, i'm unable to compile the code due to the following error message, what could be the problem ?

    Please note that i'm using Teensy 2.0

    ----error message-----

    This report would have more information with
    "Show verbose output during compilation"
    enabled in File > Preferences.
    Arduino: 1.0.5 (Mac OS X), Board: "Teensy 2.0"
    pov_2_0:18: error: expected constructor, destructor, or type conversion before 'int'
    pov_2_0.ino: In function 'void bmpDraw(char*, long unsigned int)':
    pov_2_0:96: error: initializer fails to determine size of '__c'


    //#include <OctoWS2811.h>// ensure you are on PIN 2 + PINS 15 and 16 bridge
    #include <Adafruit_NeoPixel.h>
    #include <SdFat.h>
    #include <SdFatUtil.h>

    //OCtoWS2811 library from the good folk at PJRC
    //SDfat library from this brilliant person
    // most of the code for the buffer workings come from (many thanks)

    //for SD card wiring
    //MOSI goes to pin 11
    //MISO goes to pin 12
    //SCLK goes to pin 13
    //SS goes to pin 10

    //fixed values for octoWS2811
    const int ledsPerStrip = 16;
    DMAMEM int displayMemory[ledsPerStrip*6];
    int drawingMemory[ledsPerStrip*6];
    //const int config = WS2811_GRB | WS2811_800kHz;
    //OctoWS2811 leds(ledsPerStrip, displayMemory, drawingMemory, config);
    Adafruit_NeoPixel leds = Adafruit_NeoPixel(16, 6, NEO_GRB + NEO_KHZ800);

    //for SD_Fat
    SdFile myFile;
    #define SD_CS SS // Set the chip select line to whatever you use (10 doesnt conflict with the library)
    SdFat sd; // set filesystem
    SdFile bmpFile; // set filesystem

    //for image processing
    #define BUF_SIZE 180//10240
    #define BUFFPIXEL 60//20

    // because the BMP is read from the bottom first, and we are displaying this using a POV wand,
    // the BMP needs to be saved on its side to display correctly when the POV is waved, that is
    // turned by 90 degrees, then saved as a 24bit bmp to the SD card

    // BMP needs to be NUM_LEDS high when saving a version to the BMP.

    // In the SD card, place 24 bit color BMP files (be sure they are 24-bit!)

    ArduinoOutStream cout(Serial);
    // store error strings in flash to save RAM
    #define error(s) sd.errorHalt_P(PSTR(s))

    void setup()
    // Serial.begin(9600); //for bug testing and speed checking using serial
    // while(!Serial){};
    // delay(100);
    progmemPrint(PSTR("Initializing SD card..."));
    if (!sd.begin(SD_CS, SPI_FULL_SPEED)) {

    //begin for Octows2811

    void loop()
    bmpDraw("star.bmp",2000);//filename and time in ms to keep displaying


    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)) {

    SdFile bmpFile;
    int bmpWidth, bmpHeight; // W+H in pixels
    uint8_t bmpDepth; // Bit depth (currently must be 24)
    uint32_t bmpImageoffset; // Start of image data in file
    uint32_t rowSize; // Not always = bmpWidth; may have padding
    uint8_t sdbuffer[3*BUFFPIXEL]; // pixel in buffer (R+G+B per pixel)
    /*uint16_t*/uint32_t povbuffer[BUFFPIXEL]; // pixel out buffer (16-bit per pixel)//////mg/////this needs to be 24bit per pixel////////
    uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer
    boolean goodBmp = false; // Set to true on valid header parse
    boolean flip = true; // BMP is stored bottom-to-top
    int w, h, row, col;
    uint8_t r, g, b;
    uint32_t pos = 0, startTime = millis();
    uint8_t povidx = 0;
    boolean first = true;

    // Open requested file on SD card, O_READ);
    // Parse BMP header
    if(read16(bmpFile) == 0x4D42) { // BMP signature
    progmemPrint(PSTR("File size: "));
    (void)read32(bmpFile); // Read & ignore creator bytes
    bmpImageoffset = read32(bmpFile); // Start of image data
    progmemPrint(PSTR("Image Offset: "));
    Serial.println(bmpImageoffset, DEC);
    // Read DIB header
    progmemPrint(PSTR("Header size: "));
    bmpWidth = read32(bmpFile);
    bmpHeight = read32(bmpFile);
    if(read16(bmpFile) == 1) { // # planes -- must be '1'
    bmpDepth = read16(bmpFile); // bits per pixel
    progmemPrint(PSTR("Bit Depth: ")); //Serial.println(bmpDepth);
    if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed

    goodBmp = true; // Supported BMP format -- proceed!

    // BMP rows are padded (if needed) to 4-byte boundary
    rowSize = (bmpWidth * 3 + 3) & ~3;

    // If bmpHeight is negative, image is in top-down order.
    // This is not canon but has been observed in the wild.
    if(bmpHeight < 0) {
    bmpHeight = -bmpHeight;
    flip = false;

    w = bmpWidth;
    h = bmpHeight;

    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?
    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;, 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.setPixelColor(i, povbuffer[i]); };
    // delay(1);// change the delay time depending effect required
    } // end scanline

    // progmemPrint(PSTR("Loaded in ")); //for bug testing using serial output
    // Serial.print(millis() - startTime);
    // Serial.println(" ms");
    } // end goodBmp
    // Serial.println(read16(bmpFile), HEX);

    //------- HELPER FUNCTION------//
    // Create a 24 bit color value from R,G,B ////these strips are BRG, but you might need to change this
    unsigned int Color(byte b/*r*/, byte g, byte /*b*/r)
    //Take the lowest 8 bits of each value and append them end to end
    return( ((unsigned int)g & 0xFF )<<16 | ((unsigned int)r & 0xFF)<<8 | (unsigned int)b & 0xFF);
    //end of helper function

    // These read 16- and 32-bit types from the SD card file.
    // BMP data is stored little-endian, Arduino is little-endian too.
    // May need to reverse subscript order if porting elsewhere.

    uint16_t read16(SdFile& f) {
    uint16_t result;
    ((uint8_t *)&result)[0] =; // LSB
    ((uint8_t *)&result)[1] =; // MSB
    return result;

    uint32_t read32(SdFile& f) {
    uint32_t result;
    ((uint8_t *)&result)[0] =; // LSB
    ((uint8_t *)&result)[1] =;
    ((uint8_t *)&result)[2] =;
    ((uint8_t *)&result)[3] =; // MSB
    return result;

    // Copy string from flash to serial port
    // Source string MUST be inside a PSTR() declaration!
    void progmemPrint(const char *str) {
    char c;
    while(c = pgm_read_byte(str++)) Serial.print(c);

    // Same as above, with trailing newline
    void progmemPrintln(const char *str) {
    Last edited by e3d; 12-21-2013 at 09:30 AM.

  10. #10
    Junior Member
    Join Date
    Jul 2013
    Now this is great and inspiring use of leds for sure

  11. #11
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    London, uk
    @e3d, THis was written for the octows2811 lib, but should be easily transferred over to another lib. You probably need to comment out the line:
    //DMAMEM int displayMemory[ledsPerStrip*6]; or, as it says that there is an issue in the draw method, it might be to do with the progmemPrint calls. but I don't have a teensy 2 to test this at the moment.

    You will also need to change the calls to show() the pixels and to set up the pixel driver. for example, octows2811 lib uses leds.begin() whereas it looks like neopixel lib uses strip.begin(); and; you will need to change this in setup.

    Also, octows2811 lib uses leds.setPixel to set the pixel colour, whereas it looks as though neopixel lib uses strip.setPixelColor(); I think that you may well need to go through the sketch to firstly initialise the strip in setup with strip.begin, and chagnes the other calls to set the pixels.

    I have not used the neopixel library so don't know where to look. The fastspi lib may also be a useful alternative.
    Last edited by mortonkopf; 12-21-2013 at 09:46 PM.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts