You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The copies on DxCore and here had diverged significantly. Also, the way that the presence/absence of a valid pin was handled here was nonsensical... t was checled for.... in places where it did not matter. But in the one place where it did, show, the same check was not performed. The null pointer would be treated as the pointer to the port struct of the pin (port struct address + 4 gives PORTx.OUT -so null pointer + 4 gives 0x0004. That's VPORTB.DIR... And because the bitmask was coming back NOT_A_PIN, in the event that it wound up getting an invalid pin iot would merrily toggle the hell out of the direction register for PORTB. Also, in some places the pin was an int8_t, in others uint8_t. Now is uint8_t everywhere in the library, consistent with conventions elsewhere. If pin is set to something that couldn't be a digital pin number. we now refuse to output signals.
The change in architecture from the classic AVR to the "modern AVR" of the tinyAVR 0-series and 1-series parts (and megaAVR 0-series parts) causes many of the existing WS2812 libraries to not work on the these parts. This library adapts the Adafruit_NeoPixel library to work with the improved architecture, and adds support for 10MHz and 20MHz clock speeds. Unlike in ATTinyCore, where slower clock speeds require a separate implementation (chosen via a menu option in that case) depending on which PORT the pin being used is on, these parts do not need this, because the indirect ST instruction executes in a single clock cycle instead of 2. Prior to version 2.0.2, this was not realized, and there were issues with real WS2812B LEDs (as opposed to SK6812 clones) in addition to a requirement for awkward port-dependant methods of calling the library.
4
+
The change in architecture from the classic AVRs (which use the AVRe or AVRe+ variant of the AVR instruction set) to "modern" AVRs (which use AVRxt) causes many of the existing WS2812 libraries to not work on the new parts. This library adapts the Adafruit_NeoPixel library to work with AVRxt version; this has slightly improved execution times, among other things, and adds support for additional clock speeds: 10 and 20 MHz because of it's use on the tinyAVR 0/1/2-series and megaAVR 0-series, and faster speeds all the way up to 48 MHz (I have yet to try overclocking them quite that hard, but while rated at 24 MHz, the Dx-series seems to be able to do 32 MHz off the internal oscillator (that's without touching the calibration). Unlike the version for classic AVR (AVRe/AVRe+), one of the benefits of the improved timing is that ST (indirect store) executes in 1 clock cycle, rather than 2, so there is no need for multiple versions of the library.
4
5
5
-
### tinyNeoPixel and tinyNeoPixel_Static
6
-
There are two versions of this library provided. `tinyNeoPixel` implements the entire API that Adafruit_NeoPixel does, including setting the pin and length 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).
6
+
Like the normal Adafruit_NeoPixel library, this supports WS2811/WS2812/SK6812 and all the nominally compatible single-wire individually addressable LEDs. It does not support two-wire ones like the APA102 or the countless knockoffs thereof; libraries for those do not pose special compatibility issues with AVRxt because they are not timing critical in the same way.
7
7
8
-
`tinyNeoPixel_Static` is slightly cutdown, removing the option to change the length at runtime, and instead of using malloc() to dynamically allocate the pixel buffer, the user must declare the pixel buffer and pass it to the constructor. Additionally, it does not set the pinMode of the pin (the sketch must set this as OUTPUT). Finally, no call to begin() need be made - begin() is removed entirely. These changes reduce flash use (by eliminating malloc() and free(), and because the pixel buffer is statically declared, the memory used for it is included in count of used SRAM output when the sketch is compiled. Removal of the pinMode() call within the library, while it requires an additional line of code in the sketch, opens the option of eliminating all calls to pinMode() from a sketch (replacing with direct port manipulation) when maximum flash savings is required.
8
+
### tinyNeoPixel and tinyNeoPixel_Static
9
+
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 pratice on small embedded systems like the AVR devices.
10
+
11
+
`tinyNeoPixel_Static` is slightly cutdown, removing the option to change the length or type of pixels at runtime (which relies on dynamic memory allocation), and 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); this allows severely flash-constrained applications to save a small amount of flash by eliminating calls to pinMode and replacing them with writes to the `PORTx.DIR` or `VPORTx.DIR` registers. Finally, no call to begin() need be made - begin() is removed entirely. 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.
12
+
13
+
14
+
### Constructors
15
+
The constructor is the declaration that you call outside of any function, to create the global tinyNeoPixel object.
leds.setPixelColor(0,255,0,0); // first LED full RED
40
+
leds.show(); // LED turns on.
41
+
}
42
+
```
43
+
This non-static tinyNeoPixel example uses 2236 bytes of flash, and reports using only 40 bytes of RAM (it actually uses 340 - and if you didn't have enough free memory the call to leds.begin() would fail, the LEDs would not be enabled, bnut the rest of the sketch would continue to run, which could be confusing to debug.
44
+
45
+
`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. You might have the same code running a number of lighting displays, and store the specifics in EEPROM, as shown below:
46
+
```
47
+
#include <tinyNeoPixel.h>
48
+
#include <EEPROM.h>
49
+
tinyNeoPixel leds = tinyNeoPixel();
50
+
void setup() {
51
+
uint16_t numleds=EEPROM.read(0)*50; // see how many 50-LED strips we're driving.
52
+
leds.updateLength(numleds); //
53
+
leds.updateType(EEPROM.read(1)); // and read what type of LEDs
54
+
leds.setPin(5); // Maybe I don't need to get everything from the EEPROM
55
+
leds.setPixelColor(0,255,0,0); // first LED full RED
56
+
leds.show(); // LED turns on.
57
+
}
58
+
59
+
```
60
+
This compiles to 2256 bytes and reports 40 bytes of RAM used as well (but, it is using an additional 150 bytes times whatever number was read from tyhe EEPROM)
9
61
10
62
### API Summary
11
63
12
-
13
-
`tinyNeoPixel(uint16_t n, uint8_t p=6, neoPixelType t=NEO_GRB)` constructor for tinyNeoPixel - the first argument is is the number of LEDs in the string, the second is the pin, and the final argument is the color order of the LEDs in use; the library provides #defines for every possible color order for RGB and RGBW LEDs (full list below).
14
-
15
-
`tinyNeoPixel()` - empty constructor, set pin and length later with setPin(), updateLength(), and updateType().
16
-
17
-
`tinyNeoPixel(uint16_t n, uint8_t p, neoPixelType t,uint8_t *pxl);` constructor for tinyNeoPixel_Static - the final argument is a uint_8 (byte) array sized to accommodate the data to be sent to the LED. For example:
18
-
19
-
20
-
#include <"tinyNeoPixel_Static.h">
21
-
#define NUMLEDS 10
22
-
byte pixels[NUMLEDS*3];
23
-
tinyNeoPixel(NUMPIXELS, 5, NEO_GRB, pixels); //pin 5 is on PORT B on all parts except the 8-pin ones
24
-
void setup() {
25
-
pinMode(5,OUTPUT);
26
-
}
27
-
28
-
29
64
`begin()` Enable the LEDs, on tinyNeoPixel, must be called before show() - not applicable for tinyNeoPixel_Static
30
65
31
66
`show()` Output the contents of the pixel buffer to the LEDs
@@ -36,15 +71,21 @@ There are two versions of this library provided. `tinyNeoPixel` implements the e
36
71
37
72
`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())
38
73
39
-
`setBrightness(uint8_t)` set the brightness for the whole string (0~255)
74
+
`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())
75
+
76
+
`getPixelColor(uint16_t n)` Returns the color of pin `n` as a uint_32
77
+
78
+
`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()`.
79
+
80
+
`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.
40
81
41
-
`clear()` clear the pixel buffer (set all colors on all LEDs to 0)
82
+
`clear()` clear the pixel buffer (set all colors on all LEDs to 0).
42
83
43
-
`setPin(uint8_t p)` Set the pin for output. At 8 or 10MHz, this must be on the port selected from the tools -> tinyNeoPixel Port submenu. Note that in tinyNeoPixel, the old pin is set as input, and the new pin is set as OUTPUT and written LOW. This is not done on tinyNeoPixel_Static for the reasons described above.
84
+
`setPin(uint8_t p)` Set the pin for output; in `tinyNeoPixel_Static`, it is your responsability to ensure that this pin is set OUTPUT. `tinyNeoPixel` copies the Adafruit behavior, and called pinMode() on it. Be aware
44
85
45
86
`updateLength(uint16_t n)` Set the length of the string of LEDs. Not available on tinyNeoPixel_Static.
46
87
47
-
`updateType(neoPixelType t)` Set the color order. Not available on tinyNeoPixel_Static.
88
+
`updateType(neoPixelType_t)` Set the color order and number of colors per pixel. Not available on tinyNeoPixel_Static.
48
89
49
90
`getPixels()` Returns a pointer to the pixel buffer (a uint_8 array).
50
91
@@ -54,24 +95,32 @@ There are two versions of this library provided. `tinyNeoPixel` implements the e
54
95
55
96
`numPixels()` Returns the number of LEDs in the string
56
97
57
-
`Color(uint8_t r, uint8_t g, uint8_t b)` Return the color `r,g,b` as a uint_32 (For RGB leds)
98
+
`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, uses a lookup table kept in PROGMEM.
58
99
59
-
`Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w)` Return the color `r,g,b,w` as a uint_32 (For RGBW leds)
100
+
`gamma8(uint8_t input_brightness)` Performs basic gamma correction for smoother color transitions, returns a gamma corrected brightness that can be passed to setPixelColor().
60
101
61
-
`getPixelColor(uint16_t n)` Returns the color of pin `n` as a uint_32
102
+
`gamma32(uint_32 input_color)` As gamma8, only acts on and returns a 32-bit "packed" color (uint32_t).
103
+
104
+
`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)
105
+
106
+
`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)
62
107
63
-
### Pixel order #defines
64
-
These are the same names for the #defines used by Adafruit_NeoPixel; these are used for the third argument to tinyNeoPixel().
108
+
`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
109
+
110
+
### Pixel order constants
111
+
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 and
65
112
66
113
#### For RGB LEDs
114
+
```
67
115
NEO_RGB
68
116
NEO_RBG
69
117
NEO_GRB
70
118
NEO_GBR
71
119
NEO_BRG
72
120
NEO_BGR
73
-
121
+
```
74
122
#### For RGBW LEDs
123
+
```
75
124
NEO_WRGB
76
125
NEO_WRBG
77
126
NEO_WGRB
@@ -96,3 +145,14 @@ These are the same names for the #defines used by Adafruit_NeoPixel; these are u
96
145
NEO_BRGW
97
146
NEO_BGWR
98
147
NEO_BGRW
148
+
```
149
+
### The name
150
+
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, this library is entirely suitable for non-tiny devices; It offers all the functionality of the Adafruit version on the library, with the addition of the Static mode - and has been ported to the AVRxt core, and where appropriate, core-specific matters are accounted for. Frankly, dynamic allocation has no place on an 8-bit microcontroller. Since almost all of the other pixel libraries *dont* work, considering the populkarity of WS2812 LEDs, I decided it would be improve the UX with the core to distribute a known working '2812 library with a standard API along with the cores.
151
+
152
+
Why did I start from the Adafruit library, and not FASTLed? Because I can't make sense of that code - it also sort of exemplifies how I do not like libraries written or architected.
153
+
154
+
### New Adafruit additions
155
+
If Adafruit has added new methods to their library, please report via an issue in one of my cores that ships with this library, and I will go pull them in!
156
+
157
+
### License
158
+
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 LGPL3.
0 commit comments