running into minimum delay on colorWipe on OctoWS2811 example

RenMan

Member
Hey gang!

I soldered together my teensy 4.1 with the audio shield and the OctoWS2811 board, hooked up my LED strip to the data and power, and was delighted to find that it all worked right out of the box! The correct colors are coming up in the right order and the colorWipe (from the Teensy4_PinList example) looks great.

Only thing is, when I change the delay (first line in the loop function) by adding 0s, I can slow down the animation, but if I remove 0s I can't speed it up much. The quickest wipe time (per color) that I can get is about 2.7 seconds for the 300 RGB LEDs in my strip (https://www.amazon.com/dp/B018X04ES2).

I'm wondering if this is a ceiling I'm running into because of my hardware or if I've done something odd in my code. It's not a big deal, I've tried running the Fire and Plasma examples and they look great, I just want to understand why I can't get the colorWipe to run at some blazing fast speed.

Code:
/*  OctoWS2811 Teensy4_PinList.ino - Demonstrate use of any pins
    http://www.pjrc.com/teensy/td_libs_OctoWS2811.html

  With Teensy 4.x, you can use any group of pins.  You are not limited
  to only 8 fixed pins as with Teensy 3.x.  This example shows how to
  use only 4 pins, which are the 4 pins of the Octo28 shield which do
  not conflict with the Audio shield.

  Required Connections
  --------------------
    pin 2:  LED Strip #1
    pin 14: LED strip #2
    pin 6:  LED strip #5
    pin 5:  LED strip #8
*/

#include <OctoWS2811.h>

// Any group of digital pins may be used

/* original 
const int numPins = 4;
byte pinList[numPins] = {2, 14, 6, 5};
*/

const int numPins = 1;
byte pinList[numPins] = {2};

const int ledsPerStrip = 300;


// These buffers need to be large enough for all the pixels.
// The total number of pixels is "ledsPerStrip * numPins".
// Each pixel needs 3 bytes, so multiply by 3.  An "int" is
// 4 bytes, so divide by 4.  The array is created using "int"
// so the compiler will align it to 32 bit memory.
const int bytesPerLED = 3;  // change to 4 if using RGBW
DMAMEM int displayMemory[ledsPerStrip * numPins * bytesPerLED / 4];
int drawingMemory[ledsPerStrip * numPins * bytesPerLED / 4];

const int config = WS2811_GRB | WS2811_800kHz;

OctoWS2811 leds(ledsPerStrip, displayMemory, drawingMemory, config, numPins, pinList);

void setup() {
  //Serial.begin(9600);
  leds.begin();
  leds.show();
}
/*
#define RED    0xFF0000
#define GREEN  0x00FF00
#define BLUE   0x0000FF
#define YELLOW 0xFFFF00
#define PINK   0xFF1088
#define ORANGE 0xE05800
#define WHITE  0xFFFFFF
*/
// Less intense...

#define RED    0x160000
#define GREEN  0x001600
#define BLUE   0x000016
#define YELLOW 0x101400
#define PINK   0x120009
#define ORANGE 0x100400
#define WHITE  0x101010


void loop() {
  int microsec = 2000000 / leds.numPixels();  // change them all in 2 seconds
  //Serial.print(microsec);
  //Serial.println();

  // uncomment for voltage controlled speed
  // millisec = analogRead(A9) / 40;

  colorWipe(RED, microsec);
  colorWipe(GREEN, microsec);
  colorWipe(BLUE, microsec);
  colorWipe(YELLOW, microsec);
  colorWipe(PINK, microsec);
  colorWipe(ORANGE, microsec);
  colorWipe(WHITE, microsec);
}

void colorWipe(int color, int wait)
{
  for (int i=0; i < leds.numPixels(); i++) {
    leds.setPixel(i, color);
    leds.show();
    delayMicroseconds(wait);
  }
}
 
Speed is limited at 800 kbps. RGB has 24 bits, so each LED on the strip takes 30 us. With a strip length of 300, you need 9 ms to update (plus a short time between frames). All 4 in this case (pinlist) are transmitted simultaneously, so it's 4 times faster than if you had them all in 1 long strip of 1200.

So no matter how short you make the delay, sending the data still takes approx 9000 microseconds.

To complete an animation that requires 1200 updates (changing the LEDs 1 at a time across 4 strips of 300) will require 1200 * 9ms = 10.8 seconds.

If you want it to animate faster, you'll need to change the code to "draw" more than 1 per update, since you're limited to 9ms per update by the communication speed. For example, changing 2 LEDs at a time will perform a visually similar animation at twice the speed.

Code:
  for (int i=0; i < leds.numPixels(); i += 2) {
    leds.setPixel(i, color);
    leds.setPixel(i + 1, color);
    leds.show();
    delayMicroseconds(wait);
  }

You can change as many LEDs are you like on every update. The other more complicated examples like plasma and fire change all the LEDs on every update.
 
Sorry I have not played with a lot of that code for a long time and don't have your setup. Mostly only did some simple testing...

But if it were me, I would probably try changing the colorWipe code to take into effect that the leds.show() will take time...

Maybe something like:
Code:
void colorWipe(int color, int wait)
{
  elapsedMicros em; 
  for (int i=0; i < leds.numPixels(); i++) {
    leds.setPixel(i, color);
    leds.show();
    while (em < wait) ; // wait at least that long before next loop.
    em -= wait;        // try to keep it for each loop ... Alternative just set it to 0 (em = 0;) 
  }
}

Note, I typed on the fly so could have issues.
 
Fascinating. Thanks for the replies!!

Since your youtube video example and the other flashy examples evoke such speed I assumed that the framerate that was possible was arbitrarily high. I love how your calculation, Paul, perfectly fits the 2.7 seconds that I was getting for one 300 LED strip to finish.

OK, I don't need a color wipe anywhere, but I'll keep your advice in mind and now I know why it was happening! Thanks!
 
Yep, 300 updates over 2.7 seconds is ~111 frames/sec. That does indeed match 9 ms to communicate 300 RGB pixels of 24 bits at 800 kbps.

The BasicTest example and colorWipe() are meant to be very simple code for testing the hardware.

For normal visual effects, on LEDs or video or other media, you would design your animation for a particular frame rate. If your animation is to achieve a color wipe over 1/4 second, and you have 111 frames per second, then the normal way to create that animation is to divide it into 28 steps, since you will display 28 frames over 1/4 second. Each frame would add another 10 or 11 LEDs, or maybe add 10 and the 11th at a lower intensity, so you get to all 300 by the 28th frame. Or you might prefer to change the speed, maybe faster in the middle and slower at the beginning and end. Normally with animations you keep the frame rate at a fixed speed and draw the image differently within each frame to affect changes to the visually perceived speed.
 
Back
Top