Neopixel LED Count flickering

Probably a dumb question but I have a problem with the Demo100 sketch under Examples>FastLED.

I have:

Arduino Due.
Two strings of 60 count LEDs in series, each LED has its own bypass cap.
A single 5V, 5A DC supply powering the strings.

At 69 LEDs operating, all goes well, so 9 LEDs into the second string, all ok.
At 70 LEDs operating, the animation still works but all the smoothness is gone and all LEDs now blink in transition.

I have tried varying the brightness and FPS with the flickering observed still the same.
The connection to the 70th and onwards LEDs tests fine, verified by running Adafruit_Neopixel>Strandtest.

Am I missing something? Ram?

Thank you.

#include <FastLED.h>

FASTLED_USING_NAMESPACE

// FastLED "100-lines-of-code" demo reel, showing just a few 
// of the kinds of animation patterns you can quickly and easily 
// compose using FastLED.  
//
// This example also shows one easy way to define multiple 
// animations patterns and have them automatically rotate.
//
// -Mark Kriegsman, December 2014


#define DATA_PIN    2
//#define CLK_PIN   4
#define LED_TYPE    WS2811
#define COLOR_ORDER GRB
#define NUM_LEDS    69
CRGB leds[NUM_LEDS];

#define BRIGHTNESS          32
#define FRAMES_PER_SECOND  120

void setup() {
  delay(3000); // 3 second delay for recovery
  
  // tell FastLED about the LED strip configuration
  FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  //FastLED.addLeds<LED_TYPE,DATA_PIN,CLK_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);

  // set master brightness control
  FastLED.setBrightness(BRIGHTNESS);
}


// List of patterns to cycle through.  Each is defined as a separate function below.
typedef void (*SimplePatternList[])();
SimplePatternList gPatterns = { rainbow, rainbowWithGlitter, confetti, sinelon, juggle, bpm };

uint8_t gCurrentPatternNumber = 0; // Index number of which pattern is current
uint8_t gHue = 0; // rotating "base color" used by many of the patterns
  
void loop()
{
  // Call the current pattern function once, updating the 'leds' array
  gPatterns[gCurrentPatternNumber]();

  // send the 'leds' array out to the actual LED strip
  FastLED.show();  
  // insert a delay to keep the framerate modest
  FastLED.delay(1000/FRAMES_PER_SECOND); 

  // do some periodic updates
  EVERY_N_MILLISECONDS( 40 ) { gHue++; } // slowly cycle the "base color" through the rainbow
  EVERY_N_SECONDS( 10 ) { nextPattern(); } // change patterns periodically
}

#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))

void nextPattern()
{
  // add one to the current pattern number, and wrap around at the end
  gCurrentPatternNumber = (gCurrentPatternNumber + 1) % ARRAY_SIZE( gPatterns);
}

void rainbow() 
{
  // FastLED's built-in rainbow generator
  fill_rainbow( leds, NUM_LEDS, gHue, 7);
}

void rainbowWithGlitter() 
{
  // built-in FastLED rainbow, plus some random sparkly glitter
  rainbow();
  addGlitter(80);
}

void addGlitter( fract8 chanceOfGlitter) 
{
  if( random8() < chanceOfGlitter) {
    leds[ random16(NUM_LEDS) ] += CRGB::White;
  }
}

void confetti() 
{
  // random colored speckles that blink in and fade smoothly
  fadeToBlackBy( leds, NUM_LEDS, 10);
  int pos = random16(NUM_LEDS);
  leds[pos] += CHSV( gHue + random8(64), 200, 255);
}

void sinelon()
{
  // a colored dot sweeping back and forth, with fading trails
  fadeToBlackBy( leds, NUM_LEDS, 20);
  int pos = beatsin16( 13, 0, NUM_LEDS-1 );
  leds[pos] += CHSV( gHue, 255, 192);
}

void bpm()
{
  // colored stripes pulsing at a defined Beats-Per-Minute (BPM)
  uint8_t BeatsPerMinute = 62;
  CRGBPalette16 palette = PartyColors_p;
  uint8_t beat = beatsin8( BeatsPerMinute, 64, 255);
  for( int i = 0; i < NUM_LEDS; i++) { //9948
    leds[i] = ColorFromPalette(palette, gHue+(i*2), beat-gHue+(i*10));
  }
}

void juggle() {
  // eight colored dots, weaving in and out of sync with each other
  fadeToBlackBy( leds, NUM_LEDS, 20);
  uint8_t dothue = 0;
  for( int i = 0; i < 8; i++) {
    leds[beatsin16( i+7, 0, NUM_LEDS-1 )] |= CHSV(dothue, 200, 255);
    dothue += 32;
  }
}

You might have "power problems"... A voltage drop through the thin power conductors in the LED strip. Adafruit recommends "injecting" power about every meter (or powering both ends of a 2-meter strip). Of course, data only goes into the input-end.

What happens if you just turn-on one (or a few) LEDs at the far-end? If you have a voltage drop problem, that should work OK because the voltage drop is related to the wire resistance and total current.

Also, 5 Amps might not be enough under "worst case conditions" with all LEDs full-brightness-white. (Usually 60mA per RGB LED.)

I have tried varying the brightness and FPS with the flickering observed still the same i.e. the LEDs not able to drive to anywhere near to full brightness e.g. 256/8 = 1/32 of full power.

The connection to the 70th and onwards LEDs tests fine, verified by running Adafruit_Neopixel>Strandtest.

I will try adding additional power lines in parallel at another point, either mid-way or at the end.

Thanks.

Yes what you forget is that the LEDs still take the same peak current no matter what the brightness because the brightness is achieved by PWM, that is switching the LEDs rapidly on and off.

Does that mean on the strip or in front of each strip? To smooth out the peak brightness peaks you need at least 1000uF capacitors on each strip. Also have you got a series resistor from the Due to the first strip?

Well SRAM actually. Your code only shows you are using 69 LEDs, how many are you actually hoping to use?
The Due has 96K of SRAM so that is approximately enough for 3000 LEDs so I doubt you are running out of memory.

Virtually all problems like this are caused by an inadequate power supply, lack of decoupling, or poor physical wiring layout.

1 Like

Noted. I am working on getting a lab sorted out so I can measure and capture transients, and I totally forgot about PWM averaging the brightness over time to our perception.

Bypass caps are fitted to the strips, behind each LED position, across +5 and GND.
No, I don't have an overall cap on each strip, I shall do so.
I do have a 330Ω resistor in series, from D2 to Din of the first string.

Plenty RAM then.

There are 120 LED in total, depending on the animation being ran, they may well all be on for an instant. 0.06 * 120 = 7.2A Peak, but that will depend on duty cycle?

This is all very good info, thanks Mike, I will add-in the caps, add extra parallel power wiring, plus an extra PSU if the results are the same with the single PSU.

No, the duty cycle controls the average current, the peak current is just that, the peak at any time. The large capacitors immediately before the strip, that is on the power and ground connection to the strips, are designed to average out the peak current by supplying this extra very short surge.

Don't forget what others have said about applying power and ground via separate wires to both ends of each strip you have.

The Due is a 3.3v device, and to my surprise nobody has mentioned this yet. The WS2812's expect a 5v logic level, so recommend that you use a TTL logic IC like the 74HCT04 (or 74HCT14) , powered with 5v between the Due and the resistor and pass the signal through 2 gates inverting it twice. Since you actually are getting OK results,, this may not change much, but still it should be mentioned.

But although the the PWM frequency of the LEDs will be roughly the same, chances are they will not be in sync, so those peaks will not all occur at the same time. Of course a 1000uF capacitor is better than no capacitor, but don't expect any miracles.

Now there is one more thing.

// insert a delay to keep the framerate modest
  FastLED.delay(1000/FRAMES_PER_SECOND); 

This does not actually do what the comment claims it does.
FastLED.delay() actually calls .show() repeatedly until the time has expired, and as the authors of the library claim, do a calculation with the brightness setting, that will result in calculated levels resulting in fractional outcome to be displayed by the use of 'dithering' that's what they call it anyway.
If the color value is 127 and brightness is 128, a value of 63 & 64 are sent alternatingly to achieve a brightness of 63.5
It also means that during that time interrupts are turned of nearly all the time, and frame reset time is at the 50us minimum.
I am no fan of FastLED for several reasons, but humor me and change it into a standard delay()

// insert a delay to keep the framerate modest
  delay(1000/FRAMES_PER_SECOND); 

and see if that changes anything.

1 Like

First rule of hardware / software design.
If it is possible for something to happen, it will happen.

I keep saying that to people that say that nuclear power is safe and that the failsafes are automatic.
Regardless one should always provide sufficient power for all leds at full brightness. Mind you, coil PSU's will just break when you draw more than they can provide, modern PSU's will just not provide what you demand and drop the voltage.
From experience i have never fixed a glitch in LED strip by adding a Capacitor, but there is a first time for everything.

This is a very good idea. It would separate Power Problems (getting enough current down the line) from Signal Integrity Problems (getting the control signal down the line in good shape).

This is a good idea too. I use 74AHCT125 as it non-inverting.

@negativ3, have you tried these suggestions?

Going to an Arduino Micro cured the issue. Good catch!

So a logic voltage level issue. And the edge is so close. I still stand by my surprise at no one else saying anything before. Usually something is mentioned about it in the first couple of replies.

Yea, I thought each LED would act as a buffer for the signal, and no real degradation would be seen, but the limit for me was 69 LEDs then the signal goes haywire. It would be interesting to scope it just to see... something about assumptions...

I will of course implement, as others have suggested, sufficient peak PSU(s), parallel wiring and a cap for each string, these seem to form "best practice". Thanks all.

By going to a different processor you have not definitely proved that it was the logic levels that were the cause of the problem. To do that you have to go back to the original Due, with the original code and add buffers to the output. Only then can you say that the signal levels were the problem.

Yes it does, which is what is strange.

Perhaps the buffering is not ideal? Combine that with the wrong drive level from the processor to begin with, and maybe some power problems ..... could cause issues.

Also, @negativ3 never reported on the results from this test:

If that were to be the case then no matter what the drive level into the first LED was you would still get this error.

I'm sure it's not that simply clear-cut. I'd bet on a combination of factors .... start with the incorrect drive voltage from the processor ... add less-than-perfect signal replication in the buffers ... add decreasing supply voltage level near end of the LED strip (which further degrades buffering quality and signal integrity). Things will eventually go south.

Remove one of those factors and the maximum strip length you can go might just increase to what you need .... or maybe not.

Totally agree with you on that. It could even be a timing issue within the ARM core specific code within the FastLED library.

Well it sort of does. It is not that the whole signal is received and recreated and transmitted. The first 3 bytes received are 'muted' for the transmission, but logic levels will be corrected to near Vcc, which is actually a sign that the logic levels may not be at fault.
As stated before, the 3.3v logic level is very close to the minimum level for logic HIGH, and if the PSU puts out 5.2v it may lift it above the threshold. It is even possible that the PSU switches to a higher voltage level when there is more demand. It shouldn't but switching PSU's may not always do what one expects.
Another option can be to try the Due without the buffer but using a different library like adafruit_neopixel or Makuna Neopixelbus.

From earlier, I had tested trailing LEDs and they seem fine.

Breaking out the scope to do some mythbusting :face_with_monocle: :grinning: tonight.