Skip to content

Latest commit

 

History

History
321 lines (236 loc) · 67.7 KB

tinyNeoPixel.md

File metadata and controls

321 lines (236 loc) · 67.7 KB

tinyNeoPixel - a library for WS2812 "NeoPixel" and similar at full range of supported clock speeds

Outputting data to WS2812 and compatible LEDs requires carefully tuned assembly to get correct output. This means a separate implementation must be provided for several ranges of clock speeds to support the full range of clock speeds that ATTinyCore supports; the readily available WS2812 libraries do not support this. These included libraries support all speeds that ATTinyCore does from 7.3728MHz and up. It is not possible to drive neopixels at speeds much below that: 8 MHz has only 10 clock cycles per bit if we are aspiring to meet the standards that this library always has. If the no-dead-time requirement is relaxed, and you were willing to drag a menu option or port-specific code back in, it could be done potentially at as low as 4 MHz but then you will be worrying about the pixels latching between bytes. 2812-alikes latch within just 6-7 us, not the 50 us that the datasheet claims - though some that require 250 us (!!) exist. It is difficult to know which ones you have without careful testing.

tinyNeoPixel Port menu option REMOVED from ATTinyCore 2.0.0

There assembly has been refactored and now uses ST and works on all pins with neither multiplication of flash use nor the user having to supply an appropriate menu option. At less than 15.4MHz, the hand-tuned assembly code used to send the data to the LEDs requires the port to be set at compile time. The original Adafruit_NeoPixel library used if/then statements to allow it to work with different ports - however this requires multiple copies of the assembly code in the compiled binary which increases flash usage. Since the pin that the NeoPixel is on is known when the sketch is written, a submenu is provided to select the port to be used with the NeoPixel library - this is used only at speeds below 15.4MHz (and only on parts with more than 8 I/O pins - the x5-series only has one port, and hence there is no menu for the port); at 16MHz and higher, this option is ignored and any pin will work regardless of the menu setting.

Library name

While this library was initially created in order to both ensure compatibility with, and through the Static version, fit within the flash and memory constraints of the tinyAVR line of parts, now with the removal of dependence on a tools menu option in ATTinyCore 2.0.0 (tinyNeoPixel 1.5.0) this library is entirely suitable for non-tiny devices - this version (1.5.x) is suitable for all classic AVR devices, and the version distributed with megaTinyCore and DxCore (2.0.x) is suitable for all modern (AVRxt) parts; It offers all the functionality of the Adafruit version on the library, with the addition of the Static mode. This library is code compatible with the version distributed with megaTinyCore and DxCore. Only show() has non-trivial changes: On AVRxt, several instructions, crucially including ST, execute 1 clock faster; that had to be accounted for. Plus AVR Dx-series parts can be overclocked at high as 48 MHz, requiring the addition of new "speed buckets" with appropriate implementations of show(). .

Like the normal Adafruit_NeoPixel library, this supports WS2811/WS2812/SK6812 and all the nominally compatible single-wire individually addressable LEDs. Unlike that library, support for the really old first generation ones that use the 400 kHz data rate was dropped. I have not seen those for sale in ages, but they do make the library larger. It is also not compatible with the ones that use both data and clock linea, like the APA102 or the even more numerous (global dimming and competition on the basis of pwm frequency for POV systems added more ways to differentiate copycat devices) knockoffs thereof; libraries for those do not pose special compatibility issues with either classic ATtiny or modern AVRxt parts

Version numbers

The version numbering may be confusing if encountered without warning. There are two active "branches" of this library.

  • Version 1.5.x - (released 2022) These versions are included with ATTinyCore 2.0.0 and are the first versions to not require the tools submenu to select the port on classic AVRs. They also include correcting a number of silent problems also fixed in 2.0.4.
  • Version 2.0.x - (released 2018-2019) These versions support the modern AVRs (those released in 2016 and later) with the improved instruction timing. The assembly that actually outouts data is not the same. Almost everything else is, and the two branches will track eachother's changes.
  • Version 1.0.x - This version predates either of those. It is obsolete and contains significant defects. It should not be used.

tinyNeoPixel and tinyNeoPixel_Static

There are two versions of this library provided. tinyNeoPixel implements the entire API that Adafruit_NeoPixel does, including setting the length and type of LEDs (color order and whether it's RGB or RGBW) of the string at runtime. This provides maximum portability between code written for use with Adafruit_NeoPixel and tinyNeoPixel (only the constructor and library name need to be changed) - however, the memory used to store the "frame buffer" (the color of every pixel) is not included in the SRAM usage displayed when compiling a sketch because it is "dynamically allocated". This can be a large portion of the memory available on smaller parts (I have seen support inquiries from people trying to control a string of LEDs which would require several times the total memory of the part for this alone); trying to allocate a larger array than will fit in RAM does not generate any sort of error - it just fails to allocate anything at runtime, nothing gets sent to the light string, and no LEDs turn on. This dynamic memory allocation also requires compiling in malloc(), free(), and associated functions; on parts with small flash (ie, tinyAVR), this can be significant. Finally, dynamic memory allocation is arguably bad practice on small embedded systems like the AVR devices.

tinyNeoPixel_Static is slightly cutdown, removing the option to change the length or type of pixels at runtime (which relies on dynamic memory allocation). Instead it requires the user to manually declare the pixel array and pass it to the tinyNeoPixel constructor. Additionally, it does not set the pinMode of the pin (the sketch must set this as OUTPUT); - the reason for this was that it is a no-holds-barred attempt to cut the flash consumption as much as possible, Removing that last pinMode cuts out over 100 bytes, which is nothing to sneeze at on the tiniest of tinies! Note that the savings requires eliminating all calls to pinMode and replacing them with writes toVPORTx.DIR registers (if you have to set only a small number of bits in one of those, and everything is known at compile time, you're often better with several consecutive |= operators each setting one bit, because those end up as a single-word SBI or CBI - while |= for more than 1 bit requires a read/modify/write (IN, ORI, OUT, which must be done with interrupts disabled if any interrupts modify the same register. Finally, no call to begin() should be made, nor can it be made. These changes reduce sketch size and provide greater visibility on the memory usage. Unless you need to change string length or type at runtime, it is recommended that tinyNeoPixel_Static be used - it uses less flash, particularly if you don't use malloc elsewhere (I try to avoid it - the core certainly doesn't, nor, to my knowledge, do any of the included libraries!

Constructors

The constructor is the declaration that you call outside of any function, to create the global tinyNeoPixel object. The example sizes were recorded on megaTinyCore 2.4.3 on an ATtiny1624 @ 16 MHz

tinyNeoPixel(uint16_t n, uint8_t p, neoPixelType t=NEO_GRB) - for tinyNeoPixel only.

#include <tinyNeoPixel.h>
#define NUMLEDS 100
tinyNeoPixel leds = tinyNeoPixel(NUMLEDS, PIN_PA6, NEO_GRB);
void setup() {
  leds.begin();
  leds.setPixelColor(0,255,0,0); // first LED full RED
  leds.show();                   // LED turns on.
}
void loop() {/* empty loop */}

This example uses 1946 bytes of flash, and reports using only 34 bytes of RAM (it actually uses 334!). If you didn't have enough free memory the call to leds.begin() would fail and the LEDs would not be enabled. No facility is provided detect that begin() didn't.

tinyNeoPixel(uint16_t n, uint8_t p, neoPixelType t=NEO_GRB, uint8_t *pxl) - for tinyNeoPixel_static only - note that the class name is the same, only the library name changes. Also notice how the pixels array is handled: It is declared as an array. But it is passed without subscripting, thus passing a pointer to the start of the array. Take care to ensure that the number of leds you pass times the number of channels (3 or 4) match what you pass to the constructor. This is C++, it doesn't check array bounds. I strongly recommend

#include <tinyNeoPixel_Static.h>
#define NUMLEDS 100
byte pixels[NUMLEDS * 3];
tinyNeoPixel leds = tinyNeoPixel(NUMLEDS, PIN_PA6, NEO_GRB, pixels);
void setup() {
  pinMode(PIN_PA6, OUTPUT);
  leds.setPixelColor(0, 255, 0, 0); // first LED full RED
  leds.show();                   // LED turns on.
}
void loop() {/* empty loop */}

The equivalent example with the Static version uses only 894 bytes and reports (accurately) that it uses 323 bytes of RAM. While you can't run many leds with them, you can still cram in the basics on 2k parts.

tinyNeoPixel() - Empty constructor for tinyNeoPixel only - for when you won't even know the type of LEDs, or how many of them, until your sketch starts running. You set pin and length later with setPin(), updateLength(), and updateType(), which must be set before you can control any LEDs.

#include <tinyNeoPixel.h>
volatile uint16_t numleds=100;        // Declaring these volatile prevents the constants from being optimized.
volatile neoPixelType led_type;       // This is the easiest way to simulate not knowing what you're driving until runtime.
volatile uint8_t neopin = PIN_PA6;    // Maybe you read from EEPROM, maybe you have jumpers or switches, etc.
tinyNeoPixel leds = tinyNeoPixel();   // empty constructor...
void setup() {
  leds.updateLength(numleds);         // Set the length
  leds.updateType(led_type);          // Set the type
  leds.setPin(neopin);                // set the pin

  leds.setPixelColor(0, 255, 0, 0);      // first LED full RED
  leds.show();                        // LED turns on.
}

void loop() {/* empty loop */}

This compiles to 2204 bytes and reports 39 bytes of RAM used as well (actually uses 339).

API Summary

begin() Enable the LEDs, on tinyNeoPixel, must be called before show() - not applicable for tinyNeoPixel_Static.

show() Output the contents of the pixel buffer to the LEDs

setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b) set the color of pixel n to the color r,g,b (for RGB LEDs)

setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w) set the color of pixel n to the color r,g,b,w (for RGBW LEDs)

setPixelColor(uint16_t n, uint32_t c) set the color of pixel n to color c (expressed as a uint_32 - as returned from getColor())

getPixelColor(uint16_t n) Returns the color of pin n as a uint_32

fill(uint32_t c, uint16_t first, uint16_t count) set count pixels, starting from first to color c which is a 32-bit "packed color". If first is unspecified, the first LED on the string is assumed. If count is unspecified, or if 0 is passed to it, all the LEDs from first to the end of the strip will be set. And if c is not specified, it is assumed to be 0 (off) - so fill() with no arguments is equivalent to clear().

setBrightness(uint8_t) set the brightness for the whole string (0-255). Adjusting the brightness is implemented as multiplying each channel by the given brightness to get a uint16_t, and then taking only the high byte; once brightness has been set, this is done every time pixel(s) are set. Because this process is lossy, frequently adjusting the brightness will lead to quantization errors. At least the modern AVR devices have hardware multiply (note - this adjustment is performed on the whole pixel array when setBrightness() is called, and on specific pixels any time something changes their brightness)

clear() clear the pixel buffer (set all colors on all LEDs to 0).

setPin(uint8_t p) Set the pin for output; in tinyNeoPixel_Static, it is your responsibility to ensure that this pin is set OUTPUT. tinyNeoPixel copies the Adafruit behavior, and called pinMode() on it. Be aware

updateLength(uint16_t n) Set the length of the string of LEDs. Not available on tinyNeoPixel_Static.

updateType(neoPixelType_t) Set the color order and number of colors per pixel. Not available on tinyNeoPixel_Static.

getPixels() Returns a pointer to the pixel buffer (a uint_8 array); note that this is the same pointer that you passed the constructor if using tinyNeoPixel_Static.

getBrightness() Returns the current brightness setting (per setBrightness())

getPin() Returns the current pin number.

numPixels() Returns the number of LEDs in the string

sine8(uint8_t angle) Returns the sine of the angle (angle in 256's of a circle, that is, 128 = 180 degrees), from 0 to 255. Used for some animation effects. Because this makes use of a lookup table

gamma8(uint8_t input_brightness) Performs basic gamma correction for smoother color transitions, returns a gamma corrected brightness that can be passed to setPixelColor().

gamma32(uint_32 input_color) As gamma8, only acts on and returns a 32-bit "packed" color (uint32_t).

Color(uint8_t r, uint8_t g, uint8_t b) Return the color r,g,b as a "packed" color, which is a uint32_t (For RGB leds)

Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w) Return the color r,g,b,w as a uint_32 as a "packed" color, which is a uint32_t (For RGBW leds)

ColorHSV(uint16_t hue, uint8_t sat, uint8_t val) Return the color described by the given Hue, Saturation and Value numbers as a uint32_t

Pixel order constants

In order to specify the order of the colors on each LED, the third argument passed to the constructor should be one of these constants; a define is provided for every possible permutation, however only a small subset of those are widespread in the wild. GRB is by FAR the most common. No, I don't know why either, but I wager there was a reason for it; the human visual system does some surprising things with light and color, and mankind has been figuring out how to make the most of those unexpected factors since we first started painting on cave walls.

For RGB LEDs

    NEO_RGB /* Less common than you'd think */
    NEO_RBG
    NEO_GRB /* Very common */
    NEO_GBR
    NEO_BRG
    NEO_BGR

For RGBW LEDs

    NEO_WRGB
    NEO_WRBG
    NEO_WGRB
    NEO_WGBR
    NEO_WBRG
    NEO_WBGR
    NEO_RWGB
    NEO_RWBG
    NEO_RGWB
    NEO_RGBW
    NEO_RBWG
    NEO_RBGW
    NEO_GWRB
    NEO_GWBR
    NEO_GRWB
    NEO_GRBW
    NEO_GBWR
    NEO_GBRW
    NEO_BWRG
    NEO_BWGR
    NEO_BRWG
    NEO_BRGW
    NEO_BGWR
    NEO_BGRW

Other color orders

You may be thinking - how is that possible? The above list covers every possible permutation! But that is only true when we restrict ourselves to the two most common sets of colors. There are two others (both believed to be based on SK6812) in circulation, both directed towards similar ends. "WWA" is White, Warm White, and Amber (all generated through a phosphor - so it's basically neutral white, warm white, and VERY warm, white). The order, in the ones I have at least, is Cool White, Amber, Warm White. Use a different color order; then you need only make note in comments something like "GRB order gives red = Amber, green = CW, and blue = WW for WWA"

The other oddball I've seen is WW ("warm white"? "white/warm white?"). I have not actually mounted those onto a PCB to test out yet, however examination under UV implies that there is only one color of white - a uniform warm-ish white. If anyone has played with them, I'd love to hear how they work - that is, do they have multiple warm white LEDs? Do they take fewer data bytes (potentially only one)? Or is it something else?); until such a time as I get more information, making this library control those shall remain an exercise for the user. If there are a full 3 emitters, it's straightforward to just set colors where all three channels are equal. If they take fewer than 3 bytes, that gets a bit trickier.

Refresh Rate

Data is sent at 800 kbit/s, or 100k byte/s - 33,333 LEDs/s. Latching takes 50us of idle time, which is pretty small (only long enough for 5 LEDs of data). Note: Although show() guarantees that it can't be called for 50 us after it last returned. This check relies on micros() and is disabled when millis timekeeping is not used or is based on the RTC (hence no micros() is available) as well as on chips with less than 8k of flash (since micros() is painfully large to pull in). A warning is issued in these cases, and it's up to you to ensure that there's a brief pause between calls to show() if you aren't doing something else, like updating the colors of the pixels you're going to send (and if you aren't doing that, why are you sending data again?!). There do exist a few "WS2812" leds with some other chip in them that waits 200us to latch. These are rare, but if you end up using them for some reason, you may need to add a brief delay between calls to show(). On the other hand, apparently most WS2812's will latch the colors after only a few microseconds, so this issue may be largely academic.

Supported LEDs and LED asssemblies

All individually addressable LEDs marketed as WS2811/2812/SK6812 or SK6805, as well as those claimed to be compatible with such strips are expected to work (supposedly P943S, P9411, SM16703, UCS1903, TM1804 are some examples; they are almost always mis-sold as WS2811/2812 or SK6812). I am aware of no comprehensive list - as soon as the WS281x's got popular, everyone started cloning them, abd there are in excess of a dozen (not counting examples of the identical die mounted in a different shaped package). Most of these have no english datasheet. Usually the only English on the datasheet is the timing diagram, which is an exact copy of the one WorldSemi used. Clones that are WS2811-like (that is, it is a standard IC which must be connected to discrete LEDs constitute the majority by number of models - though it appears that WS2812-like (integrated) constitute a large majority by total quantity produced. Integrating the IC die with the LED poses some technical challenges, which caused problems when these first came out.

These clones sometimes vary in thresholds of their timing (I have, for example, seen cases where a controller would only drive one of the two types, particularly if the oscillator is not exactly on the frequency target. I have never seen one that couldn't use the output of other "2812-alikes"). They also sometimes vary in the maximum voltage that can be seen at their outputs (12V units like the 2811 can be used to drive 3 LEDs of each color in series, at a lower current). However, with the exception of the SK6812/6805 and WS281x (as well as the APA102 and it's clones), none have achieved significant name recognition in the western world. I'm sure we're buying plenty of them - but not under their real names/part numbers. The WS2812 and SK6812 names are used almost interchangibly when finished devices are sold - regardless of which one is used (be it SK68xx, WS2812B, or some random no-name clone).

One thing that is worh noting is that although competent people, over time, have debated whether SK6812 or WS2812B's (the B is rarely seen in marketing material now, and I don't think non-B WS2812's are made anymore) are better, there has been no consensus. The non-B's were clearly inferior, being failure prone and requiring additional connections, and the WS2813 and WS2815 are clearly superior, with the additional backup data line and (on the '15s) 12v operation - but cost significantly more. While WorldSemi deserves some credit for originality, having been the first to make such a device, and have addressed the "old school christmas light problem" where one light goes out and the whole string after it does with the WS2813/15, the SK6812's have a much greater variety of LEDs available: They now come in in RGBW and RGBWW (warm white) 4-color versions, a WWA (Cool White, Warm White, Amber) version, and have been shrunken down to package sizes as small as 1.5mm square, and are available in side facing packages. Note that these are guesses based on the catalogs of vendors who openly sell both SK6812's and WS2812's in the same listing, which makes it unlikely that they'd be lying about the model of the IC.

I think the only way one could really find out would be to depot them and examine the die under a microscope, and even that isn't foolproof, because in the time that they've existed, there have most certainly been die-shrinks. In any event, mostly sold as SK6812's, they are available in nearly every plausible component package: 5050, 3535, at least two drastically different packages both called 2020 by the merchant selling them, 1515 (that's 1.5mm on a side), 2427 (these I am told are what are under the surface of COB led strip), 3216 (in english units, 1206 - the same size as the resistors), and more. In the other direction, there are 3mm and 5mm through-hole diffused ones (though they are less common - those strings of "christmas light" style lights are almost universally made with a little circuit board with a WS2811 or clone thereof and a standard 8mm RGB led, as opposed to an 8mm addressable through-hole LED. There are even a few PCBs that pair a WS2811 and a trio of beefy MOSFET drivers designed to drive MONSTER leds, in the 10-50 watt range. The intended use case remains unclear to me - and even at Direct-from-China prices, the costs would add up quickly. Plus LEDs of that size would need considerable heatsinks...

Key differences

There are a very small number of significant differences between the 2812-alikes, other than package and who made them:

  • The 5050 package with 6 pins was used by the original WS2812, the WS2813 and WS2815, and a small number of compatible clones. It is also used by a very large number of incompetible leds. If you see leds with a 6-pin package and were considering buying them, you need to do a bit of further investigation. There are three possibilitis, and only one of them is appropriate if you wanted 2812-alikes. The pinout chart will hold the answers; if it's strip, you can probably get the key information from the markings on the strip:
    • If they have two power pins per LED, or (for strip) if there is only one data line, they are actual WS2812-not-B's. Pass, these burned out easily and had no particular advantage.
    • If they have a DI/DO and BI/BO - these are WS2813/WS2815 LEDs! These are the top of the line from World Semi. DI/DO is the normal date line, while BI/BO is a backup data line. If one LED in the strip fails for any reason, in theory, the BI signal should pass through unaltered to BO, while in a working LED the DO signal will be output on both DO and BO. If the next LED sees no signal on DI, but sees a signal on BI, it will use that, and the rest of the strip after it will not fail too. The difference between the '13 and '15 is that WS2813's are 5v, and behave much the same as typical 2812-alikes except for the redundant data lines. WS2815's run at 12v, drawing only 1/3rd the current for the same brightness (my understanding is that they have three tiny LED dies in series). Since the voltage drop along a conductor is proportional to the current, you have to inject power less frequently. Knowing that power is defined as P = V * I, and that V = 12, and I is one third that of the WS2812, we can see that the overall power ends up as: (12/5 * 1/3) or 4/5ths that if a 2812. As noted, they're of similar brightness; the operating forward voltage of a blue LED is around 3.2V. With perfect drivers (assuming no minimum dropout - this isn't the case, but they're quite good), there is 1.8v or so of margin on the blue. Once the blue hits it's limit, every 0.1V below that lowers the voltage applied to the LED by 0.1V, causing color rendition failure. The 12V ones have around 2.4V of margin for blue, and once you do hit that limit, the the voltage seen by each LED will only drop by one third that much. The disdvantages of the the WS2815's are the higher cost, the lack of RGBW options, and the fact that they need a different voltage power supply than the controller. They also supposedly will wait longer before latching (250uS according to some source, though those may instead be a clone).
      • Update: As of Q2 2023, the WS2813 has been knocked off, with the creatively named SK6813.
    • If they have DI/DO and CI/CO, they aren't 2812-alikes. They are APA102-alikes. They use a two-wire non-timing-critical control scheme, cost more, PWM at a higher frequency for less weird and undesirable persistence of vision effects, and use 4 bytes per LED, including a 5-bit global dimming field. The two wire control allows data to be pushed through them far faster, increasing the effective maximum frame rate by more than an order of magnitude (depending on the clone, the maximum ranges from 10 MHz to 40 MHz). These are excellent LEDs. The added finesse of global diming makes low brightness colors look great. They are also significantly more expensive, have no RGBW or WWA versions, and as noted, have a different control scheme. This library does not support APA102 or APA102-alikes. See note below.
  • For other sizes of LEDs, since WS2813 and WS2815 seem to be made exclusively in 5050 packages, you can simply count pins.
    • If the individual LED has 4 pins, it could only be a '2812-alike.
    • If a strip or other grouping has 1 input pin and 1 (or sometimes zero) output pins, it's also gotta be '2812-like
    • If there are 6 pins on the individual leds, or two inputs in addition to power, they are very likely APA-102-like. The input-end of an APA102-like LED string will likely have one pin marked with one or more letters including a "D" and one marked with letters including a "C" - Data and Clock.
    • A string of non-5050 size LEDs, but where the inputs are marked with abbreviations including "D" and "B" suggests a WS2813/WS2815-like scheme.

No, we do not support APA 102's nor will we ever

The reason that this library exists is that a classic AVR WS2812-driver library (since the timing is critical and not all that many times the clock speed) will typically have the code that actually sends out the data written in assembly. That requires a separate implementation for each clock speed, and (in the original version) for every possible port. To reduce the size of the resulting code, only the most common ports were supported by adafruitNeoPixel; but within the heterogeneous population that is the classic AVRs, that meant that only some pins worked on some of the parts. Particularly before we introduced the PIN_Pxn-notation to refer to pins, it caused great confusion.

Additionally, the adafruitNeoPixel library allows for changing the size of the LEDs at runtime. That sounds great, except that implementing that requires using malloc(). The problem with malloc() and free() (which it inevitably brings in) is that these take take 1k or so of flash, which the tinyAVRs can ill-afford. This has another more subtle problem too: When you 'verify' the sketch, you are told the amount of flash and RAM the sketch uses but this does not include dynamically allocated RAM. This can be the majority of the RAM usage on a LED controller. I have had people show me code which tried to control 250 LEDs on a tinyAVR with 512b of SRAM. Since the buffer to fit the pixel data would take 750 bytes, there was no hope of that working. But as far as the user could tell, there was tons of RAM available, because that almost-150%-of-total-RAM was not counted.

Finally, starting in 2016, Microchip began selling a new generation of AVRs. They haven't come up with a name to refer to these parts as a whole, despite having had 7 years to do so. I refer to them as Modern AVRs (in contrast with Classic AVRs). ATTinyCore supports the classic tinyAVR parts; I also maintain megaTinyCore and DxCore to handle the modern tinyAVR and full-size devices, which at the time that I ported this library to them had no WS2812 libraries available. The relevant difference between the two lineages comes down to a change in the AVR instruction timing: Classic AVRs require 2 system clocks to execute an "indirect" ST instruction (STore 1 byte to a location pointed to by the X, Y, or Z pointer); the author of the asm in the Adafruit version was unable to come up with a way to meet the timing constraints of these LEDs using 2-clock ST at 8 MHz, so they instead used the 1 clock OUT instruction, which required that the port be known at compile time (OUT can address only 64 locations, and the instruction itself encodes which location this is. While the opcode for ST says "Store the contents of working register [0-31] to the location pointed to by [X, Y, or Z] and [do nothing, postincrement the pointer, or predecrement the pointer]". On the other hand, the opcode for OUT says "Store the contents of working register [0-31] to [0-63] in the low I/O space.").

Now, as it turns out, with more effort and finesse, the small number of clock cycles worth of slack in 8 MHz implementation could be cleverly used to meet the timing requirements (well - they almost meet the ideal timing requirements - it's like 1-2 clocks longer than it should be per 8 bits, with the extra time at the least sensitive time (between bytes) - that does not cause problems; sending the data too fast can cause problems, but not sending it too slow unless it is WAY too slow). This technique is used to allow tinyNeoPixel for Classic AVRs to work down to slightly below 8 MHz without a separate routine for each port.

On the Modern AVRs, the problem was much more acute, because when ST became a 1-cycle instruction, the data would be sent too fast, such that the minimum time per bit was not observed, and the signal reshaping mechanism in the LED controllers would end up dropping data; Thus, the version of this library provided with DxCore and megaTinyCore had to slow down the LED sending routines a touch in order to make sure all LEDs would work.

Additionally, both modern and classic AVRs can be run at speeds other than 8, 12, and 16 MHz, which was all that the Adafruit library supported (I wouldn't support frequencies I didn't sell boards at either). On the classic AVRs, speeds of 20 MHz (for performance) are possible. And then there is a menagerie of oddball speeds that are not an integer number of MHz, which ATTinyCore supports. These are USART clocks, and are used to get the USART standard baud rates with much greater accuracy than is otherwise possible (see the Hardware USART reference). ATTinyCore supports these on all parts (though they are only of particular use on the few parts with hardware serial ports). These are different enough from the "standard" speeds that many of them need a separate routine to output '2812 data.

Library Version 7.3-8 MHz 8 MHz 9.21 MHz 10 MHz 11.06 MHz 12 MHz 14.74 MHz 16 MHz 18.43 MHz 20 MHz 24 MHz 28 MHz 30 MHz 32 MHz 40 MHz 48 MHz
Classic AVR --------> Yes Yes Yes --------> Yes Yes Yes ------> Yes No No No No No No
Modern AVR --------> Yes No Yes No Yes No Yes No Yes Yes No
Yes Yes Yes Yes

The arrows for some speeds indicate that the higher speed pointed to is used instead In practice, we will typically use the next highest speed (though I think 25 MHz uses the 24 MHz timing), so a modern AVR clocked from, say, a 18.43 MHz crystal will use the 20 MHz timing. It will run slow, but will be close enough to be within the constraints - however, they are marked as "No" in an attempt to make clear that those are not speeds that these parts should be run at, because they come with many disadvantages, and the new USART baud rate generator has eliminated the advantages that they had, and also the make clear that they are not considered "supported" speeds - users running at those speeds are on their own.

Modern tinyAVRs are commonly run at 4, 5, 8, 10, 16 and 20 MHz (8 and up is supported), and can be overclocked through tuning as high as 30 MHz (0/1-series, some specimens only - others can only reach 24 or 25). The 2-series can reach speeds as high as 32 MHz (most specimens, but not all) again, just by tuning. Running at 5V, with a very solid power supply and an external clock will enable some (but not all) 0/1-series specimens to run at 32 as well. There's no analogy for that on the 2-series, since the internal oscillator there generally works at 32, and the next convenient frequency is 40 MHz, which a tinyAVR 2-series isn't going to hit even with an external clock. The modern tinyAVR series does not support using a crystal, relying upon a much better internal oscillator instead/

The AVR Dx-series can be run at 4, 8, 10 (20/2), 12, 16, 20, or 24 MHz while remaining in spec, and the internal oscillator has "secret" 28 and 32 MHz settings. Additionally, with the exception of the DD, they support an external crystal. 40 MHz works on most specimens, and on some E-spec parts, even 48 MHz works! While the assembly starts to get a little silly at the high end of these speeds (a great deal of time is spent in space-optimized "no-op" instructions), even in the absence of other tricks for outputting WS2812 data (we believe a background method is possible by abusing the SPI and CCL subsystems) raising the clock speed allows allows longer LED strings or faster frame rates by making it possible to calculate more pixel colors between sending the buffer.

Common types of Light Strip

This section lists the types of light strip that I have seen marketed. They

Flexible PCB strip

Typically made with sticky tape on one side, and 5050 LEDs on the other. Sometimes it is covered in a silicone waterproofing layer for outdoor use (this should be expected to keep a light drizzle off of the LEDs. They should not be submerged or anything, especially while operating - even with a light drizzle, it's up to you to figure out how to protect the connectors from water ingress). This stuff is incredibly common, and can often be seen in the wild decorating storefronts, and is the least expensive of these options. It looks pretty lousy if you don't use some sort of diffuser, use some other means to ensure that the light doesn't reach the viewers' eye directly (such as locating it in a recessed fixture on the ceiling, or at the top of a glass-fronted display case that is below eye level). The points are just too bright for the tiny area of the visual field that they come from. This complaint is apparently widespread, since there are a number of off-the-shelf solutions to this: There are little diffuser caps you're supposed to put over 5050 LEDs, individually (these don't do the trick) A much more effective method essentially places the strip within a rubber sleeve. One side is translucent, the others opaque on the outside and white on the inside. These actually work pretty well, though the added expense is not negligible and the result is bulkier. These sleeves are available in many crossections, and it may not be clear which is ideal for a given use case.

SK6805 COB LED strip

These are, in many ways, the logical integration of the diffuser and normal light strip described above; they use what are called "COB" LED strip. "COB" LEDs are those LEDs where the emitter is embedded in some sort of soft rubber, and feature large numbers of smaller LEDs (which is more efficient, and looks better *). In this case, there is a row of incredibly high density (332/m) of SK6805 LEDs in a very small packages, hidden under a white rubbery diffuser that leaves the total strip barely thicker than a standard 5050-strip. While it doesn't throw off as much light because of the lower power LEDs, the tight packing of the pattern makes it appear almost continuous. Vendors claim (though I find that claim dubious) that they only need power injected every 3m (at both ends). 1M with power into 1 end does work, though, so maybe the claim holds up. It certainly shouldn't be hard to avoid voltage droop browning if it doesn't actually hold up by limiting brightness in software. COB LED strip is incredibly beautiful - and eye-wateringly expensive - $30/m or so.

* you can also get non-addressable COB LEDs as either flexible strip (often fairly pricey, and usually CW/WW, with a common positive, so you can PWM an N-channel MOSFET on the two negative sides to achieve adjustable color temperature. I haven't tried these, so I can't comment on how nice or not-nice these look), as well as aluminum-backed panels, which are much more affordable, but generally only a single variety of white. These are preferred for general illumination; search aliexpress for "COB LED panel" (or strip). Panels up to 900 mA can be powered from an inexpensive LD24ADJT buck driver DC supply (like a laptop power brick, my favorite source of 18V DC) and s

Individually addressable 12v or 24v LED strip

There are now three similar kinds of LED strip of this sort:

  • WS2815 LEDs with DI and BI/DO and BO control scheme (primary and backup to bypass burned out controllers); these have 3 tiny dies in series in each color for each package, allowing 1/3rd the current per LED at 12V (no 24V ones)
  • Versions with an IC for every 3 (12V) or 6 (24V) LEDs, typically a WS2811 or clone thereof. These are less exciting, as they're only addressable in groups of three. Sometimes this is fine, or even preferable. Usually it's worse. Depends on your application.
  • Versions with no IC's, only a single data line, but somehow claiming 12 or even 24v operation. These often use the SK6812 P8 LEDs, which exist in RGB and RGBW versions. This strip is easily identified on close visual examination (often impossible online): every third or sixth LED will look different. That LED is the addressable one, and 3 (RGB) or 4 (RGBW) pins are connected to 2 or 5 non-addressable LEDs - they work like a WS2811 as described above, except that the IC is itself integrated into the LED.

Warning There exist 12v and 24v LED strips that are not addressable. They use the same trick, 3 or 6 LEDs in series at a time. These have no relation to this library, they are controlled using beefy mosfets, and all the LEDs on the strip must be the same color. They can be recognized by having one common (usually the positive), and a negative connection point for the three colors, and by the presence of physically large, but low resistance resistors every 3 or 6 LEDs. They're boring and further discussion of these is beyond the scope of this document; I don't write about boring stuff like that.

12V and 24V COB addressable LED strip

Much like the "Individually addressable 12V LED strip above: This has the LEDs controlled in groups, and while the number of LEDs sounds very exciting, you don't actually get as much control over the pattern as you might think. It is however considerably simpler to power.

Rigid PCBs amd panels

Pre-populated PCBs full of addressable LEDs are readily available. They are commonly shaped like rings, bars, or squares. These also almost universally use 5050 package LEDs (with the exception of some panels, which use smaller packages to more effectivelty make a display). The refresh rate quickly becomes problematic on larger displays. While the LEDs are still not terribly comfortable to look at, the smaller number of them and their confinement to a small part of ones visual field on small panels, or distance and the larger number involved in a truly massve display on the wall of a building or something isn't unpleasant to look at in the same way. Many panels sold use an entirely different control scheme, however, on account of the limited frame rate achievable as the number of LEDs increases.

"String Lights"

Name in quotes because I don't think this is an official name; I don't know that they have one, but I have to call them something. These are the only type that is essentially always based on the WS2811: Each module has a single large RGB LED with the fogged plastic for light diffusion, connected to the '2811 driver IC (this is in spite of the existence of LEDs of the same size with 2812-alike controllers inside - I guess it's cheaper to do it this way, and the folks going . Each of those LED assemblies, with 6 wires from one the end opposite the LED, then has plastic surrounding it (it looks to me like they got pushed into a housing that fit tightly around the bulb and epoxy was then poured in). You should inject power at the start (or end) of each string of 50. You should use the additional power wires they provide for this; JST-SM connectors like they use can barely handle 3A (the maximum current from 50 LEDs), and you never want to push something right to it's limit. So should have power coming into one or both of the pairs of power wires on every section.

"Cursed" String Lights - mystery has been solved

I was recently made aware of (as in was wondering what the heck was wrong with my lights) a type of light string which to all outward appearances, looks almost identical to normal string lights. Side-by-side, tiny differences like the exact tint of the potting compound may be visible. However, even though the data rate coming out is correct, many LEDs will not work when down-stream from them. It is nearly impossible to confirm this behavior without a 'scope - but on the 'scope it was very clear that something was up: the signal was only going up to like 3.something volts! These apparently use a different controller which also comes in a SOIC8 package... but this one outputs 3V logic levels? I didn't think it makes much sense either... Several weeks later, I was checking light strips and came upon them again - only this time the LED that was in my hand happened to have a smoother surface to the epoxy-filled case near the bottom, so I cold read the silkscreen inside. Gnd. Dat. 12v. This was twelve volt LED string! Likely the logic voltage was going through an internal regulator. If it was expecting 7 volts of headroom, they wouldn't think twice about using cheaper regulator technology, resulting in 7805-like minimum dropouts, which from 5v would yield right around 3.3v. So these are not actually cursed, but are likely better. The only thing that gives me pause is that the brightness wasn't obviously "way too dim". There are no inductors inside for buck or boost conversion, implying linear voltage regulation, so they'd be dissipating considerably more power as heat.

Diffused "String Lights"

These diffusers are almost always hemispheres, affixed to a round PCB, with two sets of wires coming out opposite sides (imagine taking a round PCB with LED(s) and maybe an IC on it, cutting a pingpong ball in half, and putting that over it. The flat side is usually equipped with adhesive tape for mounting against the wall. Sometimes, each module has a WS2811 and 3 LEDs. These are likely the least common of the types listed here. (I actually did the pingpong ball thing, with cheapo knockoff pingpong ball. That was back before such strings were easy to buy; besides I wanted APA102's for that project, and I've only seen those on panels and plain strip. It took two halves stacked to get enough diffusing, for the one led in the middle. While they came out beautifully, the process was was a ton of work, and I can't recommend that to others - besides, I used the apparently extinct "APA102TW", which has a distinctly better red).

Warning: Real pingpong balls are insanely flammable - for reasons I've never understood, they are still made from 50% nitrocellulose (one of the active components of smokeless gunpowder). It was widely used as a plastic (it was the original material that film for movies was made from, too) before less flammable ones were invented. But it is still almost universally used in real pingpong balls (maybe competition rules dictate that any other material is not legal?). Never, ever tape them to your wall or put heat generating electronics in them (they can be recognized by scratching with your fingernail - real ones also contain camphor, which has a distinct smell. You can also always cut off a small piece, take it outdoors away dry grass or other highly flammable material, and set it aight.Don't hold it in your hand while you light it, you cannot drop it fast enough. Normal plastic will burn with a small flame, melting, maybe dripping molten plastic on the ground, take tens of seconds or more to burn, and will leave behind some unburned crud. Nitrocellulose will burn completely. leaving just a thin wisp of ash in a second or two.

Fairy Lights

These are, as far as I know, a fairly recent innovation. These use thinner wires and MUCH smaller leds (looks like a single LED, with wires soldered directly onto it, covered in a blob of diffusing plastic. They come in strings of (typically) 50, 100, and 200. Some of the 50's can be daisy-chained (and include wires to inject power). The longer strings generally can't, and most have an integral USB power connector and controller (which generates impressively ugly patterns - I don't think I could design worse patterns if I tried). It can be desoldered where it meets the LEDs, though I'd recommend cutting the wire, or desoldering it at the USB end, as their wire looks more attractive that the wire most of us have kicking around, and the LED wire itself is is a bit tricky to work with. These strings use lower current SK6805 LEDs, which allows the existence of 100 and 200 LED strings with such thin wire and with USB power. Even so, in the case of 200-LED strings, running one next to a same-brand 50-LED or 100-LED string, you can see that the controller is throttling the brightness to keep the power usage low enough for the limits , you'll realize that the the controller is limiting the brightness in software to stay within a power budget and keep the ones at the end from going ofg-color. Note also that there are (or at least were) two kinds of these; in both cases, the wire looks fragile, but through totally different mechanisms. The currently dominant version has solid (not stranded) wire. On the one hand, this holds its shape very well and can easily be bent into a desired shape. On the downside, this bending action makes it more likely to break via fatigue, and the wires are also more visible. In the past, I have received a few sets made with a very different wire - incredibly flexible; I think there were other fibers woven in with the copper for improved flexibility; it looked great, but it was eager to knot itself if you did anything suboptimal to it (like putting it onto a reel without spinning the reel on it's axis - if the reel does not rotate on it's axis during rolling and unrolling each wrap introduces a 360 degree twist!). Wire in general is eager to knot itself (see Spontaneous Knotting of Agitated String - it won an Ignobel Prize a while back for a proof of this tendency to knot itself.)

SK6805 vs SK6812

There exists a very similar led to the SK6812, called the SK6805. There are, as far as I can tell, two key differences. Physically, SK6805 is typically smaller (though there is some overlap in available packages) - the smallest I have seen is 1.5 x 1.5mm (yes, you read that right, you can fit a 3x3 array of them in the footprint of a standard 5050 LED), while 3.5x3.5 is very common, and 2427 is supposedly used in "COB" led strips. These are the ones used in most fairy lights. The second difference is that, because of their smaller size, they need to use less power and dissipate less heat, so the current drive is reduced to 5 mA per channel.

Notable LEDs that are NOT compatible

  • Anything that is not addressable, such as standard (single color or RGB) LED strip. As far as I have seen, every listing for a WS2812 compatible device has either WS2811, WS2812, or SK6812, and usually all three, in the title of the listing on marketplace sites like EBay, AliExpress, and Amazon. A dead giveaway is the presence of resistors on the strip every few LEDs. They can also be spotted by close examination - you'll see that none of the LEDs have that larger, dark square thing visible in the transparent window (that's the controller itself).
  • Anything with a data AND a clock line - APA102, APA107 SK9822, HD107 and similar. These are all great LEDs - they implement 5-bit of global diming dimming, in some cases using actual constant current sources instead of a superimposing a second PWM frequency! Because of that, and because they generate PWM at a higher frequency, some of them are suited for persistance-of-vision dependent art without looking like dashed lines (though not all are). They all do do a far better job of rendering dim colors. Since there is both a clock and data line the transfer rate is governed by the controller and the maximum specified by the LEDs. These maximums are often high enough that in practice, the limit of the wiring and the chip itself will be encountered before the limits of the LED. There exist multiple other libraries for these, since they operate via SPI (be it software or hardware SPI), no special measures are required to make those libraries compatible with AVRxt. More care and research is needed when buying these, too, since the specific LED, in some applications, actually makes a big difference, even though there is a control scheme which works for all of them.

The HD108

This is a LED from the makers of some of the best APA-102-alikes, but it's a weird one indeed. The control scheme is different, and I have neither read any work by native english speakers who have used them, nor ordered any myself (min order is 100 of something I am unlikely to use. So kind of a tough sell.

Bad pixels

They do exist, and travel in groups. Apparently when these were relatively new there were a LOT of bad batches of them making the rounds; the root cause, apparently, was that the transparent material atop the die and LEDs was not making an airtight seal. Once air reached the dies and bond wire, the life of the LED was very short indeed. Some people reported that it was possible to test for it with a black magic marker, by drawing a circle around the perimiter of the LED, if you saw any black seeping down, the LED was no good. But if you do that, then you have black ink on your good LEDs too, and it's not clear how to remove it without causing the problem you were testing to avoid. Thankfully, the manufacturers seem to have gotten their process sorted out and bad LEDs are now fairly rare. At the peak of the pixel plague (as in a plague that afflicts pixels, not a plague of pixels; the latter is ongoing with no sign of slowing), the "wisdom of the internet" was that the SK6812 LEDs (which are the knockoff - the WS2812 is the original) were in fact more reliable than WS2812's of that era. But LEDs with that sort of issue are very rare now, no matter which major LED manufacturer is producing them.

Fairy Light control IC (may apply to some other LED controllers)

The fairy lights appear to use an LED that has slightly different timing from the standard ones - or at least, one that tolerates slightly different timing than the standard. It's not clear to me exactly what is different, but something is. They work with this library, but the controllers don't work with other other LEDs. So if you were thinking you could chop off the controller, and wire the lights up to an Arduino, you can. But if you were expecting to use it as a known good controller ("goddamnit why is nothing working? Is my arduino bad? Are all the strings of leds broken? Did I do something stupid in my code and am still not seeing it?"), this won't help you, at least in it's stock state. It runs at only 6/10ths of the speed that it is supposed to, and this presumably causes LEDs to be misinterpreted. Intriguingly, it has a crystal on it. The crystal had no markings whatsoever on it. Removing the crystal and replacing it with a slow MHz crystal results in no output. So I tried a 32.768k crystal. That seems to be what it's using to derive it's timebase. I've got some faster crystals on order to see if that's all it takes to make these into proper LED controllers. Or at least, ones that can be used for tests - they patterns they generate are the "ugly christmas sweater" of illumination.

Safety Notice

Large LED lighting projects can pose safety hazards when connected improperly (generally fire, though the exposed mains terminals on the backs of some power supplies commonly used for this should also be covered, along with other exposed wires). While these concerns are by no means unique to LED lighting projects, such projects often combine high current, shoddy components, inexperienced designers/programmers and operation for prolonged periods of time with little or no supervision - so particular care is warranted.

Large LED light strips can draw a surprising amount of current (60mA per LED and up to 144 LEDs/m with some strip = 8.6A/m), and a great deal of discussion has been devoted how and how often power should be injected. What I rarely see mentioned is the limit of the ubiquitous JST-SM connectors that these strips usually use. Those are rated at a MAXIMUM of 3A, when used with 22 gauge wire (It doesn't matter what size the wire says on it, either, because some wire makers over there lie) and when the terminals involved are actual JST terminals (we can rest assured that the guys using fraudulently marked wire aren't using terminals or housings from JST). I have seen wires supplying power to light strings get so hot (without any sign of failure of the string) that the red positive wire had darkened to the same color as the black ground wire. How could this have happened? I used pre-wired connectors with 22 AWG wire to bring in power! Examination revealed that the "22 AWG" (printed right on it), was actually between 29 and 30 AWG, with the difference in outside diameter made up with thicker insulation. This is much worse than usual undersized wire from China, but wire that's 4 AWG undersize is extremely common (curiously, it's rarely 3, 5, or 6 AWG undersized).

In addition to following all the usual safety guidelines, pay particular attention to these:

  • Do not overload connectors; check the maximum current rating for any type of connector you're using, and make sure that the worst case scenario remains comfortably below it. Surprisingly few people show much concern about overloading their connectors, but a connector - particularly one that has corroded, leading to higher resistance and heance heat - is a frequent point of failure in electrical systems, and can even start a fire.
  • Always measure the gauge of the wire in a batch of wire or pre-wired connectors; intentionally mismarked wire is very common on the Chinese market, with thicker insulation to make it look like what it is sold as. Hence, the specifications printed on the outside of the wire are not trustworthy.
    • PVC wire is almost universally afflicted with this. It is rare to purchase PVC wire from chinese suppliersand get what was advertised; I have found in the wild that the wire is typically 4 AWG thinner, but it may be as little as 1 AWG undersized to as much as 8. This does not apply western wire makers who subcontract manufacture to China - they weren't born yesterday, and are keenly aware of this trick, and keep their manufacturing partners in line. I try to avoid PVC insulated wire from China entirely.
      • This is particularly troublesome when you were planning to crimp on connectors, as the insulation thickness no longer matches what the crimper and terminals expect. You can think "Okay, I need 24 AWG wire, so I'll order 20 AWG wire" to maximize your chance of getting 24 AWG wire". But to conceal their fraud, they made the insulation as thick as it would be on to 20 AWG wire: Your terminals won't fit over it!
      • You know those "christmas light" style WS2811 strings? You know how you need to inject power stupidly often? The wire says 20 AWG on the side, so you really shouldn't need to inject power that often... So is it really 20 AWG? I counted 19 wires, measured each strand as 0.08mm, so it's 19/0.08, or in AWG... around 27 AWG. No wonder we have to feed power in every 50 LEDs! That wire is the second least honestly spec'ed wire I have encountered, being beaten by less than 1 AWG by a particularly horrible batch of prewired JST-SM connectors (the ones I mentioned above where red wire was cooked black)
    • FEP (Flourinated ethylene-propylene, a copolymer of perflouroethylene and perflouropropylene) is a much tougher, stronger, more heat resistant material used as insulation. It is considerably harder to manufacture, but can be made thinner while having superior mechanical properties. Like PVC, however, it can still be removed with thermal wire strippers, and is not terribly hard to remove with hand strippers either. It is, unsurprisingly, more expensive. What is surprising is that it doesn't seem to have the undersizing problem that PVC insulated wire does. I don't know if this is just because it's harder to make and that keeps the riff-raff out of the market, or if they consider people who would buy FEP wire to be more likely to notice their bogus wire, or what the full reason is, but I've never had PVC-insulated wire arrive from China that wasn't at least 1 AWG undersized, while no FEP insulated wire has been undersized by even 1 AWG. The thinner insulation ensures that crimp connectors will fit over the wire, even when you're pushing the upper limits of the size of wire that can fit a given type of terminal. This wire is often mis-sold as PTFE (teflon) insulated wire. Luckily they are lying about this: you don't want actual PTFE insulated wire. That stuff is tough as nails. It laughs at a normal thermal wire stripper, and is very challenging to strip with hand strippers as well. Stripping it easily needs a fancy thermal-wirestripper (and my chemical background struggles to come up with potential compounds which might make up odd-smelling fumes which wouldn't be noxious). Thankfully, little if any of the "PTFE" wire you would get buying from China is PTFE - it's all FEP.
  • Always pull-test a few samples from a batch of prewired connectors (most commercial dupont line fails the pull test, and even some JST-SM prewired connector fails. Hopefully if you crimp your own, you're already pull testing them).
  • When using pre-wired connectors, use a pin extractor to pull out a male and female pin from a given batch and compare them to a pin on the "same" connectors you already have. Proceed only with great caution and testing if you discover that the existing connectors and the ones you just got do not look identical - some terminals are made in several versions with different mating force or for different wire gauges. These both matter, but are generally designed to be compatible. On the other hand there are horror stories of incompatible male and female pins from different suppliers that would fail over time when used together, or male pins that were ever so slightly too large and would damage female terminals from other manufacturers - both could result in a poor (high resistance) connection which might get hot without causing visible symptoms until you start a fire, or notice that the wires have been discolored from heat..
  • Make sure that any power supply you use will turn itself off in the event of overcurrent, instead of changing to constant current mode. Folding back to constant current mode is great for a benchtop supply in your workshop, but in the field, all it does is waste power while generating a bunch of heat wherever the fault is, until either someone notices, something burns out, or it starts a fire.
  • Be certain that the system will deal gracefully with all pixels being written white. Malfunctioning code result in this, for example if code is compiled for the wrong speed. "Graceful" in this case means that either the supply will be able to supply all of the LEDs, or will detect the overcurrent and shut down. Relying on the resistance of the wire in this condition is not acceptable.
  • Consider the use of a resettable circuit breaker (these aren't that expensive) or even a fuse if you are not fully satisfied with the safety of the supply you are using when you attempt to draw excessive current. Make sure your wiring precludes a short before this mechanism.
  • Consider implementing an automatic shutoff in software the lights are left on for a certain length of time without the settings being changed (or on other criteria depending on what sensors it may have and the intended use case). Cases where the LEDs are at nearly maximum brightness are of greatest concern, which is why I advocated testing behavior under "full white" conditions.
  • Cover all splices with shrink tube around each conductor, and another larger one around the whole splice. The double-wall glue-lined shrink tube is recommended - thicker shrink tube is naturally more durable, and the glue acts as a moisture barrier.
  • Are you using a buck or boost converter anywhere? I often use laptop power bricks (approx 3A at 19-20V, in a nice consumer-proof form, which can usually be obtained for free if you don't need them to match any laptop that's still useful), carried by a second pair of wires ziptied along the length of the string, combined with a high efficiency buck converter at each point where power is injected. Buck converters can only pull the voltage upwards, not downwards, so they can't "fight" like some power supplies can. Under the no-load condition, whichever converter has the highest set point due to variation between units will carry most of the current - but as soon as the lights are on and there's a load, the same wire resistance that forces us to use power injectors in the first place will distribute the load more or less evenly.
    • If at all possible, use DC-DC converters with "synchronous rectification". This replaces the schottky diode with another low Rds(on) MOSFET (this may be external, or integrated with the chip). This greatly reduces the power dissipated in heat within the converter, by replacing the fixed 0.3-0.7V schottky diode drop with a much smaller resistive drop. The downside is just cost - the controller now needs to control two FETs, instead of one, and the must absolutely never both be on at once (a condition called "shoot-through" where there is a short circuit through the two MOSFETs between power and ground).
    • In all projects, use buck converters that are capable of handling a significantly larger load than you are asking of them (particularly if buying them from no-name companies in You-Know-Where). Counterfeit chips are sometimes used, system specifications may be inflated (how else does a buck converter with a chip rated for 2A get sold with a rating of 3A?), and other parts used may be insufficient.
    • Test how your DC-DC converters react to a short circuit. Don't use the ones that make a "pop" noise and emit a puff of smoke as the die vaporizes and the main chip cracks open.
  • Whatever scheme you go with for connectors, you should heed Murphy's Law of Connectors: Any connector that physically can be plugged in wrong will be. Make sure you can't plug them in in such a way that polarity is reversed: doing so will result in you discovering how much hardware you can burn out before the overcurrent in the power supply trips. Be warned that knockoffs of polarized connectors sometimes can be plugged in backwards, when the real ones cannot (this is a problem with some of the knockoff MX 3.0 connectors, for example).
    • Be sure, in your design notes, to clearly specify the polarity of connectors, not just the order of the conductors (speaking from experience). If drawing a sketch of it, make sure it's unambiguous which direction you're looking at the connector from. Some connectors have a marker for pin 1, or even number all the pins. Most don't - in that case, consider using a connector with more pins than you need, leaving one or more unpopulated - if reversed, the power pin should go to an unused one. If you look at both the FTDI 1x6 header and the ISP 2x3 header, and considerwhat wouldhappen if you connected it backwards, you'll find that the wire order used was the one least likely to be harmful.
    • The connector which supplies the power should, whenever possible (if one connector is on a PCB, it often isn't possible, because the PCB connectors are rarely available in both genders), be the side where it is harder for something to short pins together when the connector isn't connected to anything.
    • If you are thinking of using the same connector, with the same number of pins. for two different purposes - STOP. Don't do that, especially not if making the wrong connection could damage anything (if it will simply not work - you still shouldn't do that, but it's a usability issue instead of a safety one. Either use a different connector, or use a connector with more pins, leaving some pins intentionally unpopulated. For added safety, you can even fill in the unused hole in the female connector with glue (some connector systems have special plastic inserts for this purpose, called "keying", however they seem to be surprisingly uncommon and unreasonably expensive, considering what they are).
  • If you've got a large lighting system and it's going to be set up with the help of others, be sure to be on-site to oversee setup and (if temporary) teardown. If it was temporary, be sure to examine the hardware for any signs of damage afterwards - either from mechanical mishandling or excessive heat. Check for partally melted connectors, brittle insulation on wire (a sign that the wire was overheating) and of course failed parts.

Comparison with other WS2812 libraries

Both FastLED and Adafruit libraries have the buffered design which - while expensive in terms of RAM, you need it for arbitrary control over the colors of each pixel. Other schemes can be used for cases where the patterns are simple, at substantal memory savings (an example that supports these parts is FAB_LED), and while those are very valuable in applicable situations, I wanted something that could take the place of a buffered, full-service LED copntrol library. That meant that I should be modifying either FastLED or AdafruitNeoPixel (ideally keeping the API nearly identical); Opening the source code for the libraries, I found the Adafruit one to be readily understood, simple, with one purpose that it handles capably, and extensively commented, especially the assembly. Meanwhile FastLED was largely unreadable. I felt that the code suffered from "kitchen-sinkism" - when the author throws feature after feature, up to and including the kitchen sink, into a gigantic omnibus library. I had yet to locate the code that actually generated the output in the FastLED source within the length of time it took to modify the Adafruit library to achieve what I needed in the first tinyNeoPixel release.

New Adafruit additions

If Adafruit has added new methods to their library, please report via an issue in one of my cores that ships with this library so that I can pull in the changes.

Changelog - V1.5.x (AVRe/AVRe+) version

  • 1.5.0 - Remove memu options for port and adapt assembly to output with valid timing with ST. Correct insufficiently constraining constraints in operands passed to inline asm. Should now be up to date with Adafruit version in terms of accessory functions.

License

Unlike the core itself (as noted within the library files), tinyNeoPixel is licensed under LGPL 3, not LGPL 2.1, since the Adafruit library was always LGPL 3.

* - C++ predates the invention of names like "properties" and "methods" (as well as countless programming concepts that we take for granted on more modern languages, if you haven't noticed). Strictly speaking, they are called "member variables" and "member functions" - however when you call them those names, nobody without exposure to C++ outside Arduino who didn't learn programming 25+ years ago will have any idea what you're talking about.