Update: I did some more testing, and it’s definitely better than it was before-- maybe the drift is in the range of 1% now, down from drift as bad as 20%(!) before.
So on the one hand, that’s good news.
On the other hand, 1% time drift can be off by one second every two minutes, or 30 seconds each hour.
I wish we could get more precise, but these $&#% WS2811/WS2812 pixels are so finicky that we have to disable interrupts to communicate with the pixels, and when we do that, the Arduino timer doesn’t run. We do a great job of calculating how many millionths of a second we took, and adjusting the millis() timer accordingly, but there’s some basically unavoidable loss of precision, and when you’re repeating this operation hundreds of times per second, even tiny tiny drifts adds up.
As we’ve said before, you cannot have all three of these things at once:
- Code running on an AVR Arduino board,
- WS2811/WS2812 pixels lit correctly, and
- Interrupts working normally.
It has nothing to do with FastLED; it’s just the physics of the situation. (And as far as I know, FastLED is the only library that comes even close to fixing up the millis() timer-- the others just let it be horribly off.)
Ultimately you have three choices if you want much more accurate tracking of the passage of real time, and each corresponds to changing your reliance on the three items listed above:
- Use an ARM-based board,
- Use APA102 or LPD8806 pixels, or
- Use a hardware realtime clock to track time, instead of the interrupt-based AVR millis() timer.
You can, of course, combine these! You just need at least one of them if you want to track the passage of real time more accurately than “within 1%”.
The standard AVR Arduino millis() timer is typically accurate to within about 0.01%, meaning that it drifts about on the order of a second per hour, or about 10 seconds per day, or about a minute per week, or five minutes per month. If you use LED pixels such as APA102 or LPD8806 that don’t require disabling interrupts, that’s about the clock accuracy you’ll probably see. (Temperature affects the speed of the clock, too!)
If you use an ARM-based board like the Teensy3 etc, you can drive WS2811/WS2812 pixels without millis() going so far off, just due to architectural differences and how time is tracked there.
Adding a (temperature-adjusted) realtime clock is a great way to track the passage of time. I’ve found that for “clock” projects, it’s an absolute must. (I’ve had good success with the Chronodot.)
So there you have it. We’re continuing to make things as awesome as possible, given all the crazy constraints of the hardware. The millis() timer on AVR is better now than it was, and as for me, I can’t wait to switch all my new projects over to APA102 LEDs.