NeoPixel Rings different LED count same speed display

Maybe I am not searching correctly to find an answer in the forum. Wanting to hook up two or more NeoPixel rings of different LED counts but will display at the same speed. Example strand test start and finish on two different size rings at the same time.

Any help would be appreciated.



I don't recall seeing anything like that on the forum, so not surprised you found nothing.

Can you explain further what you want to do? Are both rings connected to same Arduino? If so, are the two rings daisy-chained to each other and back to the same Arduino pin, or are both connected to separate Arduino pins?

Cut down the strandtest sketch to include only one pattern which demonstrates what you want to do. When you have it working (on both rings separately), post it here, but make sure to use code tags as explained in the "read this first" post.


Thanks for the reply

Basically I want concentric rings that start and finish a pattern at the same time. Like a double circle. Yes prefer same arduino. My guess is two pins.

I have not even started to sketch this. I was hoping it would be as simple as adding a second pin and doubling the strand test. And yes I have paired down the strand test to one pattern. Although the pattern would not matter. The timing is what I was looking for help with.

My line of thinking is pin one drives a 12 LED circle at 100 percent speed and pin two would drive a 16 LED circle at say 120 percent speed. Thus starting and ending at the same time for both rings. It could go both ways I suppose with the larger at 100 and the smaller at say 75 or whatever the timing would work out to be.

BTW not looking for someone to do it for me. I just don't know what I am asking for in the program. Or if its even possible. I am sure that I could use a Pot to vary the speed but I was hoping to minimize components and for lack of better terms make it fool proof.

Thanks again for any help

Hi Ron

And yes I have paired down the strand test to one pattern.

I asked you to post it. Is there a reason you can’t?

You can run both rings off the same pin, as long as you have access to the “data out” connection on one of them.

There isn't any ready made code to do what you want. There are people who have written it using the FastLED library, but they weren't interested in sharing the code.

I don't know if this will work, but what I would do is measure the circumference of the two circles then figure out what the difference is percentage wise there is between the two circles and make the out ring take that percentage longer to refresh.

Edit: I actually think you potentiometer isn't a bad idea. after you figure out the right speed you can replay that value with the value from the pot and get rid of the pot.

To stay “in sync”, the LEDs in the outer ring advance at a rate of outerLEDs#/innerLEDs# times that of the inner ring.
With an inner ring of 7 LEDs and an outer ring of 24 LEDs:
24 / 7 = 3.43
If the inner ring is clicking at 100 Hz (every 19 msec) then the outer ring will have to click at 343 Hz (every 3 msec).

The display (effect) may look compromised absent a common factor.

Ron, post that code. Any pattern you like from strandtest. Connect the 2 rings in series and tell us what is wired to what. We will attempt to re-code the sketch so that both rings in sync. Then you can apply the same technique to other patterns

What helps is to write strictly time controlled code.

Have all your parameters based on millis() and everything works fine, no matter how many leds or which AVR/ARM you´re using. All that changes then are the fps the animation is running at.

Working with delays or increment counters every frame always leads to different animation running speeds on different setups.

It's actually a very simple problem. Your program must be time based, rather than step based.

Your main loop runs continuously, never waiting for anything to complete (other than a call to the NeoPixel update routine).

As it loops, it looks for "triggers" based on the millis() value increasing by a certain amount - a principle commonly described here as "Blink without delay()".

So each step in the pattern occurs at a given increase in the number of milliseconds. Your ring of 12 LEDs advances one step every 160 milliseconds, while your ring of 16 LEDs advances one step every 120 milliseconds,

Hey again all,

Sorry real life got in the way of my arduino.

Following is the paired down strand test for 16 pixel running on my uno.

I left all the lines in from the original code but remarked out all that did not apply. What is left is the slow rainbow portion of the strandtest. What I have not had time yet to do is to add a second pin and then create/duplicate for a 12 pixel strip/ring.

Several of you have said to write a time based code rather than a step based. As I am still learning what and how to program the arduino, can you point or show where I would change the following to a time rather than a step based?

Is this ( rainbowCycle(20); ) line where the steps are defined? I.E. the 20 in the parentheses?

Thanks again for all your help. I am learning in leaps and bounds.


#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h>

#define PIN 6

// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
//   NEO_RGBW    Pixels are wired for RGBW bitstream (NeoPixel RGBW products)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(144, PIN, NEO_GRB + NEO_KHZ800);

// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
// and minimize distance between Arduino and first pixel.  Avoid connecting
// on a live circuit...if you must, connect GND first.

void setup() {
 // This is for Trinket 5V 16MHz, you can remove these three lines if you are not using a Trinket
// #if defined (__AVR_ATtiny85__)
//   if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
// #endif
 // End of trinket special code

 strip.begin();; // Initialize all pixels to 'off'

void loop() {
 // Some example procedures showing how to display to the pixels:
// colorWipe(strip.Color(255, 0, 0), 50); // Red
// colorWipe(strip.Color(0, 255, 0), 50); // Green
//  colorWipe(strip.Color(0, 0, 255), 50); // Blue
//colorWipe(strip.Color(0, 0, 0, 255), 50); // White RGBW
 // Send a theater pixel chase in...
//  theaterChase(strip.Color(127, 127, 127), 50); // White
//  theaterChase(strip.Color(127, 0, 0), 50); // Red
//  theaterChase(strip.Color(0, 0, 127), 50); // Blue

//  rainbow(20);
//  theaterChaseRainbow(50);

// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
for(uint16_t i=0; i<strip.numPixels(); i++) {
   strip.setPixelColor(i, c);;

void rainbow(uint8_t wait) {
 uint16_t i, j;

 for(j=0; j<256; j++) {
   for(i=0; i<strip.numPixels(); i++) {
     strip.setPixelColor(i, Wheel((i+j) & 255));

// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
 uint16_t i, j;

 for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
   for(i=0; i< strip.numPixels(); i++) {
     strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));

//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
 for (int j=0; j<10; j++) {  //do 10 cycles of chasing
   for (int q=0; q < 3; q++) {
     for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
       strip.setPixelColor(i+q, c);    //turn every third pixel on


     for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
       strip.setPixelColor(i+q, 0);        //turn every third pixel off

//Theatre-style crawling lights with rainbow effect
void theaterChaseRainbow(uint8_t wait) {
 for (int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
   for (int q=0; q < 3; q++) {
     for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
      strip.setPixelColor(i+q, Wheel( (i+j) % 255));    //turn every third pixel on


     for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
       strip.setPixelColor(i+q, 0);        //turn every third pixel off

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
 WheelPos = 255 - WheelPos;
 if(WheelPos < 85) {
   return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
 if(WheelPos < 170) {
   WheelPos -= 85;
   return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
 WheelPos -= 170;
 return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);

Read the how to use the forum sticky post. Then edit that last post to put it in code tags, you use the </> icon in the reply button.

You need to rewrite this as a state machine. That is you must not have the delay function anywhere in your code. You have chosen a difficult problem for your first introduction to a state machine, start of with something easy. Modify the blink without delay example in the IDE to work with your neopixels first, then get more complex, work your way up to this.

Right, first things first.

Go and read the instructions, then go back and modify your post (use the "More --> Modify" option to the bottom right of the post) to mark up the code as such so we can examine it conveniently and accurately.

If you do not do this, the code you post could well be garbled and is certainly anything but easy to read.

Note: Also mark up any data in the same way. This includes error output that you get from the IDE.

And - before you post code, use "Auto Format" in the Tools menu to properly present the code.

For more on state machines see my
Or Robin2's several things at once

Sorry I did not see the code tags. Actually never intended to post the entire sketch as it is not my code.

As for my learning. I have gone through many of the "get to know" your arduino and how to change/modify sketches to make different things happen. So this is my first "real" challenge. My intent is to create a new code that will do what I want the rings to do and I thought that by starting with a working sketch I would have a little better luck with the new one. Examples of working code are IMHO always easier to work with than starting from scratch.

I am heading now to read the links provided and appreciate your help.