Syncing strands of 2812s

I have two 1 meter strands of 2812s wired in series. I'm trying to treat them as 2 different strands instead of one long one. I'm trying to make the lights chase from center to ends.

I am trying to get them to start at the same time. The further part of the strand starts first, then about 1/4 of a second later, the closer strand starts its light chase towards the data in side.

I started with an example program and I'm slowly adding things one part at a time to work my project up to the end goal. So, I'll post the code, everyone should recognize the basic parts. The extra parts are parts I've added to make the different parts "stand alone".

My end goal is to have 6-8 strands total that sequence together so I REALLY need to figure out how to fix the timing issues from one strand to the next. I'm also going to have 20-30' of distance between strands that I think will also cause timing issues. Currently the data line is about 4" from the Arduino, with no physical break in the strands. Its actually one continuous strand that I'm trying to treat as 2 strands. So distance should not be an issue at this point.

Thanks for any help.

#include <PololuLedStrip.h>

// Create an ledStrip object and specify the pin it will use.
PololuLedStrip<12> ledStrip;

// Create a buffer for holding the colors (3 bytes per color).

rgb_color colors[60];

byte time = millis() >> 2;
byte x = 0;
byte y = 0;
rgb_color LEDupdate1(rgb_color colors);
rgb_color LEDupdate2(rgb_color colors);

void setup()
{
}

void loop()
{
time = millis() >> 2;

colors[60] = LEDupdate1(colors);
colors[60] = LEDupdate2(colors);

// Write the colors to the LED strip.
ledStrip.write(colors, 60);

delay(10);
}

rgb_color LEDupdate1(rgb_color colors[60])
{

// Update the colors.

for(uint16_t i = 0; i < 30; i++)
{
x = time + 8*i;
colors = (rgb_color){ x, 255 - x, x };

  • }*

  • return colors[60];*

}
rgb_color LEDupdate2(rgb_color colors[60])
{

  • // Update the colors.*

  • for(uint16_t i = 30; i < 60; i++)*

  • {*
    _ y = time - 8i;_
    colors = (rgb_color){ y, 255 - y, y };
    _
    }*_

* return colors[60];*

}

Learning learning learning...

So I figured out that the delay is caused by the math to generate the sequence. One is time+8i, the other is time-8i.

This seems to be my problem. Now to figure out how to sync it.......

Since I asked, and there were 34 views so far and no other responses....

I wrote the math out on paper (for several clock cycles, and calculated for each LED position i) to understand what was going on. One strand does "time + 8i" while the other one does "time - 8i", so there is an offset in numbers where I need them to be the same.

The solution was correcting the offset as follows for only one of the function folders:

rgb_color LEDupdate1(rgb_color colors[60])
{

// Update the colors.

for(int i = 0; i < 30; i++)
{
x = (time + 8*i)+32;
colors = (rgb_color){ (.5*x), 255 - x, x };

When I look at speeding software up and making it more efficient, I often look at maths that are common with in the program, if there is the same bit of maths that I can do once instead of twice I will do it.

I have also found mutiplication to be quite slow, maybe use bitshift instead
for example instead of 8*i, use i<<3

Thats good to know. Thanks for the info. I'll try that.

helicopterjockey:
colors = (rgb_color){ (.5*x), 255 - x, x };
[/quote]
If you're worried about speed then floating point math is the last thing you should be using...

instead of 0.5 *x, use x>>1 (this just halves it by shifting x right by one !)

mcnobby:
instead of 0.5 *x, use x>>1 (this just halves it by shifting x right by one !)

The thing is.... when x is a byte the compiler will promote that to 16 bit math:

  // x = x>>1
  ac: 80 91 00 01   lds	r24, 0x0100
  b0: 90 e0         ldi	r25, 0x00	; 0
  b2: 95 95         asr	r25
  b4: 87 95         ror	r24
  ba: 80 93 00 01   sts	0x0100, r24

So in this case it's actually better to use less clever tricks:

  // x = x/2
  ac: 80 91 00 01   lds	r24, 0x0100
  b8: 86 95         lsr	r24
  ba: 80 93 00 01   sts	0x0100, r24

mcnobby:
I have also found mutiplication to be quite slow, maybe use bitshift instead
for example instead of 8*i, use i<<3

Not always true. The Mega328 has a hardware multiply instruction that can multiply two 8 bit numbers in 2 clock cycles. The trick is to check your code and make sure the compiler is using it (the compiler can produce some head-slappingly bad code sometimes)

For the simple case of multiplying by 8 though, you're probably safe assuming "<<" will be faster, especially when the compiler does stuff like this.

byte c = 8;
byte x = 12;
volatile byte z;
void loop()
{
  z = x<<3;
  z = x*c;
  z = x*8;
}

This produces:

  // z = x<<3;   // Shift 3 times can be done in 3 instructions
  ac:  80 91 01 01   lds  r24, 0x0101
  b0:  88 0f         add  r24, r24
  b2:  88 0f         add  r24, r24
  b4:  88 0f         add  r24, r24
  b6:  80 93 02 01   sts  0x0102, r24

  // z = x*c;   This uses the MUL instruction and is 2 cycles slower than "<<" for the number '8'
  ce:  80 91 01 01   lds  r24, 0x0101
  d2:  90 91 00 01   lds  r25, 0x0100
  d6:  89 9f         mul  r24, r25
  d8:  80 2d         mov  r24, r0
  da:  11 24         eor  r1, r1
  dc:  80 93 02 01   sts  0x0102, r24

  //  z = x*8;  This actually produces a loop and goes around it 3 times (!)
  ba:  80 91 01 01   lds  r24, 0x0101
  be:  90 e0         ldi  r25, 0x00  ; 0
  c0:  23 e0         ldi  r18, 0x03  ; 3
  c2:  88 0f         add  r24, r24
  c4:  99 1f         adc  r25, r25
  c6:  2a 95         dec  r18
  c8:  e1 f7         brne  .-8        ; 0xc2 <loop+0x16>
  ca:  80 93 02 01   sts  0x0102, r24

For numbers more complicated than '8' the MUL instruction can often beat bit-twiddling.

The real secret to optimizing is to know your compiler....