Neopixel is slowing down time reported by mills()

Hello all,

I am having a strange issue with the below code, it runs without any pixels connected. I would expect that every second I get one printout to serial if you run the code - and it does so if the ### line is in the code.
But if the line is disabled the times reported by mills() is less than half.

What is going on and how can I get mills() to be accurate again ?

Thanks for reading,

#include <Adafruit_NeoPixel.h>

#define LED_PIN     8
Adafruit_NeoPixel strip(120, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup() {

int last;

void loop()
  unsigned long now = millis() / 1000;
  if (now > last)
    last = now;

  for (int i = 0; i < 120; i++)
    strip.setPixelColor(i, i < now ? 0x101010 : 0);

  if (strip.canShow());
  delay(100); // ### disable this line and millis() is not correct

You are spending about 99.99% of your time updating the neoPixels. When that is going on the “clock thing” is turned off.

-jim lee

Well, it is a well known problem. Neopixels need careful timing, so interrupts are disabled while the strip is being updated, and this can cause problems with millis(). That said, your code might also be a cause. Try changing it like this:

unsigned long last;

void loop()
  unsigned long now = millis();
  if (now - last >= 1000)
    Serial.println(now / 1000);
    last += 1000;


I think 99.99% of the time is delay(100), Jim.

This is an extreme example of course and my real code does many more things but I still need to be able to measure time accurately. Is there another library that circumvents this issue?

N0… He said it failed when he DIDN"T put in the delay thing. IE the 100 (year) delay masked the problem.

-jim lee

No, I don’t think any library can fix the problem, it’s the nature of Neopixels like ws2812.

The trick to neoPixels is… The human eye can’t really see better than 15 fps. So I’ll always put a timer on mine to only only update maybe every 50 ms or so.

-jim lee

Oops, sorry, you’re right Jim.

If you move to an APA102 type led strip (more expensive) then the timing requirements are gone and you have more cpu for your code

Yeah, but then I can’t use my nifty neoPixel library. And that just makes me sad.

-jim lee

I’m FINALLY right on something. :slight_smile:
-jim lee

I am assuming the time spent in the Neopixel lib is constant, is there a way to measure that without mills()?

Or use a processor that supports DMA. PJRC has a couple libraries that blast out data for NeoPixel-type strips over DMA on Teensy boards. Interrupts (and hence millis()) remain functional.

I think there are also libraries to do something similar on ESP boards.

Even if you do the timing correction for the neoPixels. The timing on an Arduino is not all that great. And it varies from Arduino to Arduino. What are you needing this fancy timing for?

-jim lee

I also work with audio input and measure BPM on the music to drive the LED animations → timing is key…

You may want to add a second Arduino to do the Neopixel stuff. Or try one of the ESPxxx range that is multi-threaded. You will need one of the ESP experts to weigh in on the latter though - I’ve never used one.

1 Like

Not sure the timing errors caused by the Neopixels would be noticeable over such short periods (e.g. 0.5 ~ 1 second). The errors would build up over hours or days if you were comparing elapsed time to an accurate clock or something. But for animating pixels in time to music, you can re-synchonise regularly with the input signal, so the errors would not grow much beyond a few milliseconds, I think.

Did you try my suggested change? And Jim’s suggestion about limiting the update rate?

As an example which triggered the whole thing: I was measuring a 120 bpm metronome and got measured 155. So only options is to offset the time in mills() by an error correction value

Hook the metronome to an input pin and drive it all from that? Have a look at Teensys. The group that ,does them are really really into sound and music processing.

I’d totalaly go for adding a processor for the light display.

-jim lee