NeoPixels are magical things. It couldn’t be simpler…a single data wire from the microcontroller, linking pixel to pixel for as long as you need. When NeoPixel projects get really large though…hundreds of pixels or more…this simplicity starts to become a bottleneck

  • The standard NeoPixel data rate is a fixed 800 KHz, or 30 microseconds per 24-bit pixel. As projects scale into the hundreds or thousands of pixels, the time spent issuing all that data reaches progressively larger fractions of a second; animation becomes less smooth.
  • While this data is being transmitted, all other processing on the microcontroller stops, including interrupts which keep track of time. This is why the millis() and micros() functions gradually drift in NeoPixel projects.

NeoPXL8 (pronounced “NeoPixelate”) is a hardware-and-software combo that works around these limitations to bring buttery smooth animation to large-scale NeoPixel projects.

NeoPXL8 splits the problem 8 ways: rather than one long strand of, say, 1,000 pixels*, eight strands of 125 pixels can operate concurrently in perfect sync. It’s like shoving two whole Kit Kats® in your mouth “the illegal way” instead of nibbling one bar at a time. Data transmission times are greatly reduced and animation can remain smooth.

* Hypothetical situation, not an imposed limit. Depends on available RAM, but most “M0” (SAMD21) boards might handle upwards of 2,500 pixels, with “M4” (SAMD51) potentially up to 15,000…but in reality, you’ll want some fraction of that, so your code has time to compute those pixels.

Additionally, NeoPXL8 uses direct memory access (DMA) to allow the CPU to continue with other tasks while these data transfers take place in the background. Your code could start processing the next frame of animation, or load data from an SD card. All interrupts and timekeeping functions operate normally, no drift.

The NeoPXL8 code relies on features unique to the SAMD21 and SAMD51 microcontrollers — it should work on any Adafruit “M0” or “M4” board, plus the Arduino Zero. It will not work on other architectures.

The NeoPXL8 FeatherWing adapters provide 8 NeoPixel outputs with 5-Volt logic level shifting, and it stacks directly atop any of our M0 or M4 Feather boards — Basic Proto, Adalogger and so forth. (Note there are different versions for Feather M0 vs M4, they are not interchangeable!)

The NeoPXL8 Friend breakout board provides similar functionality in a non-FeatherWing format, making it handy for use with boards like the Metro Express or ItsyBitsy M0 Express (and their respective M4 variants).

For NeoPixel projects starting with one of our Feather M0 or M4 board variants, a NeoPXL8 FeatherWing can simplify and make sense of the wiring…the boards are designed to be stacked. Some soldering and “maker skills” are required.

There are two distinct versions of the NeoPXL8 FeatherWing: one for M0 boards, the other for M4. The two are not interchangeable.

You can use any Feather M0 or M4…however, some NeoPXL8 outputs get configured to take over I2C or SPI pins. In particular, if an SPI pin is used for NeoPXL8, the Adalogger, WiFi, Bluefruit will not be able to use the built in SD/WiFi/BTLE chips! If I2C is used, most FeatherWings with I2C sensors/devices won't work!
The M0 and M4 versions of the NeoPXL8 FeatherWing are NOT interchangeable — get the correct type to match your Feather board!

Connections: Two Types

The NeoPXL8 FeatherWing can be assembled one of two ways depending on your preferences and needs. You must choose beforehand what kind of connectors your project needs, as there’s not enough room for both at once…

Populating the 8x2 row header at the center of the board (16 pins total) provides a “Fadecandy-style” connection.

Fadecandy is a USB NeoPixel controller popular in large-scale LED installations. The 8x2 connector is fairly compact and low-profile. Assembled this way, the NeoPXL8 Feather-and-Wing combo could, with suitable Arduino code, function as a swap-in replacement in an existing Fadecandy project, or could make use of NeoPixels already wired for such.

Populating the two RJ45 connectors at the board ends provides an “OctoWS2011-style” connection.

OctoWS2811 is a similar hardware-and-software combo for large NeoPixel setups using the PJRC Teensy 3.2 microcontroller. These connections are bulkier but latch into place and ensure a specific polarity. Assembled this way, the NeoPXL8 Feather-and-Wing combo could, with suitable Arduino code, function as a swap-in replacement in an existing OctoWS2811 project, or could make use of NeoPixels already wired for such.

In either case, the NeoPixel headers mount on the FLAT SIDE of the NeoPXL8 FeatherWing — the side with NO COMPONENTS — and are soldered on the component side. The Feather-stacking pins are done the OPPOSITE way — install from the component side, solder on the flat side. See the photos above for reference.

Additionally, you still need to build a wiring harness between these connectors and your NeoPixel LEDs. The above is just a starting point.

Adopting these two wiring schemes mean that any existing tutorials for wiring up Fadecandy or OctoWS2811 projects are applicable to NeoPXL8 as well — it’s not starting over with a third incompatible standard.

This tutorial shows some Fadecandy-style wiring harnesses being made, using a ribbon cable and 8x2 IDC header, plus lots of soldering and heat-shrink. A multimeter with continuity beep is helpful in keeping track of data wires and grounds!

The OctoWS2811 product page on the PJRC web site shows RJ45 wiring harnesses being made by cutting open Ethernet cables.

You will also need to safely distribute 5 Volt power to all of your NeoPixels. This is not done through the NeoPXL8 board — it needs to be part of your wiring harness. This tutorial explains some of the issues in powering large-scale NeoPixel installations.

Pin Selection

Because we’re using hardware tricks, NeoPXL8 output works only on specific pins. Some are set in stone, others give some control in that you can select an alternate pin. This may be helpful if using a Feather or Wing with its own peripheral pin constraints (wireless, perhaps)…sometimes you can re-route some signals and keep full functionality.

Depending on what additional hardware you’re interfacing, it’s possible that neither selection will work…one peripheral or another absolutely requires that pin. In such cases, you can use NeoPXL8 with fewer than 8 outputs. We’ll elaborate further on the “Library” page.

Keep track of your selections. Write it down somewhere. You’ll need this information when writing Arduino sketches using the NeoPXL8 library.

The pin selection is a little different between the M0 and M4 FeatherWings…

For M0 NeoPXL8 FeatherWing only…

Let’s refer to NeoPXL8’s eight outputs as “0” through “7,” sequentially. Outputs 3, 6 and 7 are fixed to specific Feather pins (13, A4, A3) and cannot be changed, period. Outputs 0, 1, 2, 4 and 5 offer a “this” or “that” choice.

On the component side of the FeatherWing you’ll see several solder pad groups, labeled “N0”, “N1”, “N2”, “N5” and “N4”. Pay careful attention to those numbers…they are neither sequential nor contiguous (partly because three pins are fixed, partly because it was more practical to route the board this way).

Each of these five pins has a default assignment. To change a pin to an alternate setting, use a hobby knife or file to cut the trace between the center and default pads, then apply a solder bridge between the center and alternate pad.

Output Number

Default Pin

Alternate Pin

N0

RX

12

N1

TX

10

N2

MISO

11

N5

SDA

MOSI

N4

D5 (digital pin 5, not A5)

SCK

For M4 NeoPXL8 FeatherWing only…

Let’s refer to NeoPXL8’s eight outputs as “0” through “7,” sequentially. Outputs 4, 5, 6 and 7 are fixed to specific Feather pins (13, 12, 11 and 10) and cannot be changed, period. Outputs 0, 1, 2, and 3 offer a “this” or “that” choice.

On the component side of the FeatherWing you’ll see several solder pad groups, labeled “n0”, “n1”, “n2” and “n3”.

Each of these four pins has a default assignment. To change a pin to an alternate setting, use a hobby knife or file to cut the trace between the center and default pads, then apply a solder bridge between the center and alternate pad.

Output Number

Default Pin

Alternate Pin

n0

SCK

RX

n1

D5

TX

n2

D9

SCL

n3

D6

SDA

If you’re working on a solderless breadboard or aren’t using a Feather form-factor microcontroller, the Adafruit NeoPXL8 Friend provides similar utility to the NeoPXL8 FeatherWing but in a non-FeatherWing package.

The NeoPXL8 Friend breakout board provides logic level shifting from 3V devices to as many as eight NeoPixel strips, which can be connected one of two ways:

The 8x2 row header (16 pins total) provides a “Fadecandy-style” connection.

Fadecandy is a USB NeoPixel controller popular in large-scale LED installations. The 8x2 connector is fairly compact and low-profile. Assembled this way, the NeoPXL8 Friend could, with suitable Arduino code, function as a swap-in replacement in an existing Fadecandy project, or could make use of NeoPixels already wired for such.

The two RJ45 connectors provide an “OctoWS2011-style” connection.

OctoWS2811 is a similar hardware-and-software combo for large NeoPixel setups using the PJRC Teensy 3.2 microcontroller. These connections are bulkier but latch into place and ensure a specific polarity. Assembled this way, the NeoPXL8 Friend could, with suitable Arduino code, function as a swap-in replacement in an existing OctoWS2811 project, or could make use of NeoPixels already wired for such.

In either case, the NeoPixel headers mount on the FLAT SIDE of the NeoPXL8 Friend — the side with NO COMPONENTS — and are soldered on the component side. The breadboarding pins are done the OPPOSITE way — install from the component side, solder on the flat side.

Additionally, you still need to build a wiring harness between these connectors and your NeoPixel LEDs. The above is just a starting point.

Adopting these two wiring schemes mean that any existing tutorials for wiring up Fadecandy or OctoWS2811 projects are applicable to NeoPXL8 as well — it’s not starting over with a third incompatible standard.

This tutorial shows some Fadecandy-style wiring harnesses being made, using a ribbon cable and 8x2 IDC header, plus lots of soldering and heat-shrink. A multimeter with continuity beep is helpful in keeping track of data wires and grounds!

The OctoWS2811 product page on the PJRC web site shows RJ45 wiring harnesses being made by cutting open Ethernet cables.

You will also need to safely distribute 5 Volt power to all of your NeoPixels. This is not done through the NeoPXL8 board — it needs to be part of your wiring harness. This tutorial explains some of the issues in powering large-scale NeoPixel installations.

A third option is to install header pins on the NeoPixel outputs, so both the “ins” and “outs” are breadboardable…this may be useful for certain prototyping tasks.

There isn’t clearance for the outputs on a regular-size breadboard, but linking two breadboards side-by-side is often done with wider devices like this.

Unlike the FeatherWing, the NeoPXL8 Friend has space for both an 8x2 row header and two RJ45 connectors at the same time.

HOWEVER, if using the 8x2 connector, depending how one’s ribbon cable is crimped and strain-relieved, the RJ45 connectors may still be in the way…so you may want to leave those two connectors off unless you’re certain to need them.

Because we’re using hardware tricks, NeoPXL8 output works only on specific microcontroller pins. The Arduino library examples explain in more detail. On boards like the Adafruit Metro Express or Arduino Zero, it’s conveniently on digital pins 0 through 7, so you can use an 8-pin ribbon cable to link directly to the NeoPXL8 Friend’s 8 inputs. In other situations, the pins may be strewn in different places around the board.

The Adafruit_NeoPXL8 library can be installed using the Arduino Library Manager. You will also need the Adafruit_NeoPixel and Adafruit_ZeroDMA libraries.

Don't forget to add SAMD board support installed through the Boards Manager (Adafruit SAMD or Arduino SAMD depending which board you’re using). See the Feather M0 guide for an example

Example Code

There is a single Adafruit_NeoPXL8 example sketch called “strandtest,” and it’s pretty minimal. There’s no need for a whole graphics demo, because most NeoPXL8 functions are identical to their NeoPixel counterparts, and there are plenty of NeoPixel examples around already. The differences mostly relate to pin assignments.

First, include Adafruit_NeoPXL8.h instead of Adafruit_NeoPixel.h:

Download: file
#include <Adafruit_NeoPXL8.h>

Then declare an Adafruit_NeoPXL8 object (instead of an Adafruit_NeoPixel object) — we’ll call our object “leds” in the example — passing up to three arguments:

Download: file
Adafruit_NeoPXL8 leds(LENGTH, PINS, FORMAT);

The constructor’s first argument is the number of NeoPixels in each of the eight strands. In other words, the total number of NeoPixels will be 8 times this value. If this value is set at 60, then the total number of NeoPixels is 480 (60 × 8).

The strands don’t all need to be the same length. In that case, give the length of the longest strand. But from the software’s point of view there’s still 8 times this many pixels…it’s going to require that much memory regardless and there will be gaps in how pixels are addressed. It’s best and optimal if all 8 strands are in use and the same length, but not required.

NeoPXL8 is a RAM hog, but on most M0 boards, depending on your code’s other needs, you can often get 250 RGB pixels per strand (2,000 pixels total). 300 (2,400 total) is starting to push things. Scale back for RGBW pixels, which require about 33% more RAM.

M4 boards have six times the RAM and can handle absurd thousands of pixels…but in reality, you might not want more than a couple thousand, tops, just to allow the CPU enough time to compute all those pixels at a good frame rate. For an M0 project, maybe a few hundred to a thousand or so. There’s no hard limit, you just need to experiment what’s practical to compute.

The second argument is an 8-element int8_t array indicating which pins to use for outputs 0 through 7.

This is extremely hardware-dependent, and you’ll see in the strandtest sketch there are several different arrays given for different situations. For example, using a Feather M0, NeoPXL8 FeatherWing with the default pin assignments and the Fadecandy-style connector, it’s:

Download: file
int8_t pins[8] = { PIN_SERIAL1_RX, PIN_SERIAL1_TX, MISO, 13, 5, SDA, A4, A3 };
Adafruit_NeoPXL8 leds(NUM_LED, pins, NEO_GRB);

As explained on the prior page, on the Feather M0, outputs 3, 6 and 7 are not negotiable — they must go to pins 13, A4 and A3 (these can be reordered — you can change which is considered output 3, 6 or 7 — but you cannot select completely different pins). For the remaining 5 outputs, there’s a limited ability to reassign things:

Output Number

Default Pin

Alternate Pin

0

PIN_SERIAL1_RX

12

1

PIN_SERIAL1_TX

10

2

MISO

11

4

5

SCK

5

SDA

MOSI

Feather M4 is a little different. There, outputs 4 through 7 are not negotiable — they must go to pins 13 through 10 (though they can be reordered within that series). For the other four outputs, there’s a limited ability to reassign things:

Output Number

Default Pin

Alternate Pin

0

SCK

RX

1

3

TX

2

9

SCL

3

6

SDA

Changing these assignments requires cutting and bridging pads on the component side of the FeatherWing board, plus matching changes to the pins[] array.

If neither pin choice will work for your application, use a value of -1 for that element of the pins[] array, as many as required. You will lose the corresponding NeoPixel output, and it will still take up RAM and pixel indices as if it were there, but the pin can then be used for normal GPIO.

Different boards will have different pinouts, you’ll see this in the example code. The Metro M4 uses an entirely different set of pins. And on the Metro M0 (or Arduino Zero), things are super easy…if you want to use digital pins 0-7 as the eight NeoPixel outputs, just pass NULL instead of a pins[] array, or leave this argument off entirely.

The third argument to the constructor is the NeoPixel data format or color order. Different manufacturers of “NeoPixel compatible” LEDs may use a different R/G/B (and sometimes W) byte order…and even among single manufacturers, different production runs may change the order as required for big customers or if they find it can economize the design. This is very similar to the last argument to the Adafruit_NeoPixel constructor, except any NEO_KHZ800 or NEO_KHZ400 values are ignored (only 800 KHz is supported). You can leave this argument off to use the default NEO_GRB color order.

All 8 strands must be the same type and color order; e.g. you cannot mix RGB and RGBW NeoPixels.

From a coding perspective, the rest appears nearly identical to a regular NeoPixel sketch.

Call the object’s begin() function to allocate memory and initialize the pin outputs:

Download: file
  leds.begin();

You can check for a return value of “true” to confirm the allocation was successful.

Then setPixelColor() to modify individual pixel values and show() to issue data to the strands, just like a regular NeoPixel sketch.

For functions that take a pixel index (e.g. setPixelColor(), getPixelColor()), all the pixels are treated as if one long continuous strand. For example:

If the strand length was declared as 60…that’s 480 pixels total…

  • Pixels 0 – 59 are on strand 0
  • Pixels 60 – 119 are on strand 1
  • Pixels 120 – 179 are on strand 2
  • Pixels 180 – 239 are on strand 3
  • Pixels 240 – 299 are on strand 4
  • Pixels 300 – 359 are on strand 5
  • Pixels 360 – 419 are on strand 6
  • Pixels 420 – 479 are on strand 7

This is true even if some strands are physically shorter, or if an element in the pins[] array is -1. The unused bits just vanish into the unknown, like that one light switch that doesn’t seem to control anything in the house.

One small difference from Adafruit_NeoPixel is that the setBrightness() function, in combination with setPixelColor() and getPixelColor(), work better here. The original color value assigned to a pixel using setPixelColor() will always be accurately returned by getPixelColor(), regardless of the current brightness setting. In Adafruit_NeoPixel this is a “destructive” operation and only an approximation is returned.

That’s the vital stuff to know.

Arduino Libraries

Datasheets and Technical Information

Schematics & Fab Prints

EagleCAD PCB files on GitHub

NeoPXL8 FeatherWing M0 (click to embiggen):

NeoPXL8 FeatherWing M4 (click to embiggen):

NeoPXL8 Friend (click to embiggen):

Components for Fritzing App:

This guide was first published on May 30, 2018. It was last updated on May 30, 2018.