Not a week goes by in the Adafruit Forums that someone isn’t heartbroken to discover that the NeoPixel and Servo libraries won’t work together in the same Arduino sketch. Fear not, help is on the way!
Rather than just leave you with a “mysterious black box” workaround (an Arduino library), it also seemed a good opportunity to introduce some advanced Arduino programming concepts. If you just want a fix and aren’t interested in a lengthy technical explanation, that’s totally fine! You can skip ahead to the third page, “The TiCoServo Library” and get started.
The Root of the Problem
The single-wire control protocol used by NeoPixels requires a very steady data stream at 800 kilobits per second. There’s a tiny margin for error, but not very much. Bits must be issued at a precisely controlled rate…the Adafruit_NeoPixel library handles all this behind the scenes, carefully counting the time of each machine code instruction. For every pixel, there’s 24 of these:
Meanwhile, the Arduino is normally using small fractions of time here and there to process interrupts…certain events and situations that need to be handled immediately. You usually don’t see it, but interrupts are occurring all the time behind the scenes. Your regular sketch code stops, an interrupt service routine is called, and your code then resumes right where it left off. Interrupts help the Arduino’s delay() and millis() functions work, as well as Serial.read(), all manner of things!
These two concepts cannot coexist. Even a very short and simple interrupt routine will throw off the delicate NeoPixel timing. Therefore, the NeoPixel library temporarily disables all interrupts when issuing data, then re-enables them when done.
This is rarely a problem. You might have noticed that millis() and micros() lose time in NeoPixel sketches (the timekeeping interrupt stops whenever we write to the strip), that’s usually the extent of it.
The issue arises that servos also have very specific timing requirements of their own, and the Arduino Servo library uses interrupts to achieve this. So every time the NeoPixel library turns off interrupts, even for a moment, the servos will lose track of time (and therefore position) and shake unpredictably. How sad!
One way to address this is to use other features of the AVR microcontroller at the heart of the Arduino to control the servos without using interrupts, as we’ll explain on the next page. This is an advanced topic, but a good thing to learn about at some point. If the explanation is too technical for your current skill level, or if you’d rather use our library instead, it’s okay to skip ahead.
There are hardware-based workarounds as well that are much more flexible. Our 16-channel 12-bit PWM/Servo Driver (in both shield and breakout formats) offloads the servo control task to a special-purpose chip, so NeoPixels can’t interfere. These boards can “stack” to control dozens (potentially even hundreds) of servos! For complex projects that’s probably the way to go. If you just need a couple servos, a little software might be all that’s needed…
Using a Different Board?
This guide is specific to 8-bit AVR-based microcontroller boards like the Arduino Uno. If using a newer 32-bit board with an ARM Cortex-M0 or M4 processor (such as the Adafruit Feather M0, Circuit Playground Express or Arduino Zero), we have a different guide using a different approach. Still others, like ESP32 or nRF, may require different tactics or just might not exhibit the problem at all. This guide focuses on the mainstream AVR boards where it’s a big issue.
Text editor powered by tinymce.