Wall's Corners Wall's Corners Author
Title: Adafruit NeoPixel Überguide (Part II)
Author: Wall's Corners
Rating 5 of 5 Des:
Why not just use the rotation feature in Adafruit_GFX? Adafruit_GFX only handles rotation. Though it would handle our example above, it doe...

Why not just use the rotation feature in Adafruit_GFX?

Adafruit_GFX only handles rotation. Though it would handle our example above, it doesn’t cover every permutation of rotation and mirroring that may occur with certain matrix layouts, not to mention the zig-zag capability, or this next bit…

Tiled Matrices

A tiled matrix is comprised of multiple smaller NeoPixel matrices. This is sometimes easier for assembly or for distributing power. All of the sub-matrices need to be the same size, and must be ordered in a predictable manner. The Adafruit_NeoMatrix() constructor then receives some additional arguments:

Copy Code

Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(

matrixWidth, matrixHeight, tilesX, tilesY, pin, matrixType, ledType);

  1. Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(
  2.  matrixWidth, matrixHeight, tilesX, tilesY, pin, matrixType, ledType);Tiles don’t need to be square! The above is just one possible layout. The display shown at the top of this page is three 10×8 tiles assembled from NeoPixel strip. Once the matrix is defined, the remainder of the project is similar to Adafruit_NeoPixel. Remember to use matrix.begin() in the setup() function and matrix.show() to update the display after drawing. The setBrightness() function is also available. The library includes a couple of example sketches for reference. For any other cases that are not uniformly tiled, you can provide your own function to remap X/Y coordinates to NeoPixel strip indices. This function should accept two unsigned 16-bit arguments (pixel X, Y coordinates) and return an unsigned 16-bit value (corresponding strip index). The simplest row-major progressive function might resemble this: uint16_t myRemapFn(uint16_t x, uint16_t y) {}
  3. return WIDTH * y + x;
  4. Copy Code
  5. Other Layouts
  6. The first two arguments are the width and height, in pixels, of each tiled sub-matrix, not the entire display. The next two arguments are the number of tiles, in the horizontal and vertical direction. The dimensions of the overall display then will always be a multiple of the sub-matrix dimensions. The fifth argument is the pin number, same as before and as with the NeoPixel library. The last argument also follows prior behaviors, and in most cases can be left off. The second-to-last argument though…this gets complicated… With a single matrix, there was a starting corner, a major axis (rows or columns) and a line sequence (progressive or zigzag). This is now doubled — similar information is needed both for the pixel order within the individual tiles, and the overall arrangement of tiles in the display. As before, we add up a list of symbols to produce a single argument describing the display format. The NEO_MATRIX_* symbols work the same as in the prior single-matrix case, and now refer to the individual sub-matrices within the overall display. All tiles must follow the same format. An additional set of symbols work similarly to then describe the tile order. The first tile must be located at one of the four corners. Add either NEO_TILE_TOP or NEO_TILE_BOTTOM and NEO_TILE_LEFT or NEO_TILE_RIGHT to indicate the position of the first tile. This is independent of the position of the first pixel within the tiles; they can be different corners. Tiles can be arranged in horizontal rows or vertical columns. Again this is independent of the pixel order within the tiles. Add either NEO_TILE_ROWS or NEO_TILE_COLUMNS. Finally, rows or columns of tiles may be arranged in progressive or zigzag order; that is, every row or column proceeds in the same order, or alternating rows/columns switch direction. Add either NEO_TILE_PROGRESSIVE or NEO_TILE_ZIGZAG to indicate the order. BUT…if NEO_TILE_ZIGZAG order is selected, alternate lines of tiles must be rotated 180 degrees. This is intentional and by design; it keeps the tile-to-tile wiring more consistent and simple. This rotation is not required for NEO_TILE_PROGRESSIVE.
  1. uint16_t myRemapFn(uint16_t x, uint16_t y) {
  2.  return WIDTH * y + x;
  3. }Copy Code
  4. matrix.setRemapFunction(myRemapFn);
  5. That’s a crude example. Yours might be designed for pixels arranged in a spiral (easy wiring), or a Hilbert curve. The function is then enabled using setRemapFunction():
  1. matrix.setRemapFunction(myRemapFn);On a per-pixel basis, Adafruit_NeoMatrix is no more memory-hungry than Adafruit_NeoPixel, requiring 3 bytes of RAM per pixel. But the number of pixels in a two-dimensional display takes off exponentially…a 16×16 display requires four times the memory of an 8×8 display, or about 768 bytes of RAM (nearly half the available space on an Uno). It can be anywhere from tricky to impossible to combine large displays with memory-hungry libraries such as SD or ffft. Because the Adafruit_GFX library was originally designed for LCDs (having limited color fidelity), it handles colors as 16-bit values (rather than the full 24 bits that NeoPixels are capable of). This is not the big loss it might seem. A quirk of human vision makes bright colors less discernible than dim ones. The Adafruit_NeoMatrix library uses gamma correction to select brightness levels that are visually (though not numerically) equidistant. There are 32 levels for red and blue, 64 levels for green. The Color() function performs the necessary conversion; you don’t need to do any math. It accepts 8-bit red, green and blue values, and returns a gamma-corrected 16-bit color that can then be passed to other drawing functions. by Technology If looking to boost your NeoPixel prowess, you may find everything you need in the FastLED library. It’s an alternative to the Adafruit_NeoPixel library, providing more advanced features like HSV color support, nondestructive brightness setting and high-speed mathematical operations. (It works with other types too, such as DotStars!)Note: FastLED currently works only with RGB NeoPixels; RGBW pixels are not yet supported. At all. You will get incorrect and unpredictable colors.Visit the FastLED web site to get started.Help! My Arduino servo code stops working when combined with NeoPixels!
  2. Unfortunately the NeoPixel and Servo libraries don’t play nice together; one is dependent on periodically disabling interrupts, the other absolutely requires interrupts. There are a couple of options here:
  3. FAQ and Further Insights
  4. We don’t write or maintain FastLED, and can’t provide software troubleshooting advice. If requesting help with a FastLED NeoPixel project in the forums, we’ll usually ask that you try one of the known-working Adafruit_NeoPixel example sketches to narrow down whether it’s a hardware or software issue.
  5. FastLED works altogether differently; it’s not a drop-in replacement for Adafruit_NeoPixel, and existing sketches will require some rewriting.
  6. FastLED
  7. Advanced Coding
  8. Gamma Correction
  9. RAM Again
  • Use a dedicated servo control shield or breakout board, offloading that task from the processor so interrupts are a non-issue.
  • Use a hardware-PWM-based servo library rather than the stock Arduino Servo library. This can provide rock-steady servo timing without interrupts, but can only control a very limited number of servos (2-3), and only on very specific pins.

How fast can I refresh a string of (N) pixels?

NeoPixels receive data from a fixed-frequency 800 KHz datastream (except for “V1” Flora pixels, which use 400 KHz). Each bit of data therefore requires 1/800,000 sec — 1.25 microseconds. One pixel requires 24 bits (8 bits each for red, green blue) — 30 microseconds. After the last pixel’s worth of data is issued, the stream must stop for at least 50 microseconds for the new colors to “latch.” For a strip of 100 pixels, that’s (100 * 30) + 50, or 3,050 microseconds. 1,000,000 / 3,050 = 328 updates per second, approximately. However… That’s only the time needed to push the bits down the wire. The actual refresh rate will be something less than this, and can’t be estimated as a single number for all cases. It takes time to process each “frame” of animation. How much time depends on the complexity of the math and the efficiency of the code (for example, floating-point calculations can be relatively slow). The formula above gives a maximum theoretical rate, but that’s just a starting point. Reality in some cases could fall an order of magnitude (or more) below this. For exploratory benchmarking, you can always write code as if a large number of pixels were present, and time the result. The extra output bits will simply be ignored by the strip (or you can even test with no NeoPixels connected at all).

That won’t do. Now what?

Because NeoPixels use a fixed-frequency clock, options are limited. You can’t switch out for a faster microcontroller and expect substantially different results. One option is to use a different type, such as our DotStar or LPD8806 strips, or WS2801 pixels. These can be driven at higher data rates, though they do have some other tradeoffs with respect to NeoPixels (cost, color resolution and/or pixel density). Another is to develop your own code on a more capable microcontroller or an FPGA that drives multiple NeoPixel strips in parallel. One such project — OctoWS2811 for the Teensy 3 microcontroller — is shown later. This sort of thing is a complex undertaking and not recommended for beginners. And even among more experienced programmers, there’s often an unreasonable over-emphasis on data rates when the real bottlenecks lie elsewhere…don’t dwell on this too much unless you can confirm it’s the root of the problem.

Can I control NeoPixels using (Board X)?

We currently only offer an Arduino library. See the links later for other devices. For anything beyond this, if considering writing your own library, understand that some processors are better suited to the task than others. Read through the timing requirements shown below and determine if the chip in question can synthesize a signal meeting those specifications. An 8 MHz AVR can just barely keep up…anything slower may have trouble, though some hardware-specific hacks (like clever use of SPI) might make it possible. In many cases, assembly language is required.

Why not Pi?

The Raspberry Pi running Linux is a multitasking system, and control may switch among multiple running programs at any time. As such, it’s impossible to guarantee the strict 800 KHz signal required by NeoPixels. You may be able to fudge it for short intervals, but it’s not something that can be counted upon. This is why we use DotStar LEDs for the Raspberry Pi light painting project.

Third-Party Libraries

In addition to the previously-mentioned FastLED library, NeoPixel-compatible libraries have been developed for devices beyond Arduino. Please keep in mind that Adafruit did not develop any of this code and can’t fix bugs or offer technical help. This is Wild West stuff.

  • OctoWS2811: specifically for the PJRC Teensy 3.0 microcontroller board. Uses DMA to drive up to 8 NeoPixel strips concurrently with minimal processor load. Multiple boards can be cascaded for still larger displays.
  • FadeCandy: also for Teensy 3.0. Doesn’t support as many pixels as OctoWS2811, but adds dithering and smooth interpolation for color purists.
  • LEDscape: specifically for BeagleBone Black. Although the BeagleBone is a multitasking Linux system like the not-NeoPixel-compatible Raspberry Pi, this code exploits hardware features specific to the BeagleBone Black to drive hundreds of meters of NeoPixel strip with virtually no processor load.
  • WS2812 LED Driver for Parallax Propeller.
  • xCORE NeoPixel test code for the XMOS xCORE startKIT.

Some of these are 3.3V devices. See the “Powering NeoPixel” page for notes on controlling 5V NeoPixels from 3.3V microcontrollers.

WS2811? WS2812? Why do I see two different names mentioned?

The WS2811 is an earlier driver chip separate from the RGB LED. The data signal is similar, but runs at half the speed. By the time the WS2812 (with integrated LED) was released, a lot of code and projects had already built up around the WS2811 name. Sometimes code “for the WS2811” might actually be for the newer chip, or for either type. The Adafruit_NeoPixel library supports both.

Writing Your Own Library

The WS2812 datasheet explains the data transmission protocol. This is a self-clocking signal — there’s only one wire, not separate data and clock lines. “1” and “0” bits are indicated by varying the duty cycle of a fixed-frequency square wave.

There’s a math goof in the datasheet’s timing values. Use these figures instead:

Note that there’s nearly 25% “wiggle room” in the timing. So if your code can’t match the recommended times exactly, it’s usually okay, as long as it’s close. There are three bytes of data for each pixel. These should be issued in green, red, blue order, with the most-significant bit first.

The data for pixel #0 (nearest the microcontroller) is issued first, then pixel #1, and so forth to the furthest pixel. This does not operate like a traditional shift register! After all the color data is sent, the data line must be held low for a minimum of 50 microseconds for the new colors to “latch.” You may want to dig through our Arduino library for insights. The timing-critial parts are written in AVR assembly language, but it’s extensively commented with C-like pseudocode.

My Microcontroller Isn’t Fast Enough to Do That

The WS2812 appears to be backwardly-compatible with the 400 KHz WS2811 signal. If you can precisely match the latter chip’s timing, either type will respond. The WS2811 protocol is not simply a half-speed WS2812. The duty cycle for the “0” and “1” bits is slightly different. From the WS2811 datasheet:

 

Share This:

View more at: http://yoursmart.mobi

About Author

Advertisement

Post a Comment

 
Top