Last fall when I was working on the now-defunct ‘Footwell NeoPixels’ project I wrote a short post talking about how you cannot use the FastLED library with RGBW leds, and have to deal with the clunkier Adafruit NeoPixels library.
Well last week a man named Jim Bumgardner commented on that post and shared his method for doing just that: using the FastLED library with RGBW leds.
Preface
Before we get started, you should know one thing: this is a hack. It is not a supported part of the library, it only works with SK6812 leds (that I’m aware of), and it does not work perfectly. But, it does work!
Daniel Garcia and the rest of the FastLED team have said that they are working on an RGBW upgrade behind the scenes, but they have no time table for when it will be completed. In the meantime, this is a quick and dirty fix.
The Hack
This hack works by exploiting the fact that WS2812B LEDs and SK6812 LEDs have similar data timing. It’s not identical, but it’s close enough to make this work. The trick is to tell FastLED that we’re writing to a WS2812B strip, but insert an extra ‘white’ byte between each RGB group.
To do this, we create a special ‘CRGBW’ struct that adds the extra byte, and a few helper functions to integrate with FastLED. I rewrote Jim’s code a bit so the assignment methods more closely match their FastLED counterparts, and I also added an operator overwrite so you can assign CRGB colors directly. Here’s the code, in full:
/* FastLED_RGBW * * Hack to enable SK6812 RGBW strips to work with FastLED. * * Original code by Jim Bumgardner (http://krazydad.com). * Modified by David Madison (http://partsnotincluded.com). * */ #ifndef FastLED_RGBW_h #define FastLED_RGBW_h struct CRGBW { union { struct { union { uint8_t g; uint8_t green; }; union { uint8_t r; uint8_t red; }; union { uint8_t b; uint8_t blue; }; union { uint8_t w; uint8_t white; }; }; uint8_t raw[4]; }; CRGBW(){} CRGBW(uint8_t rd, uint8_t grn, uint8_t blu, uint8_t wht){ r = rd; g = grn; b = blu; w = wht; } inline void operator = (const CRGB c) __attribute__((always_inline)){ this->r = c.r; this->g = c.g; this->b = c.b; this->white = 0; } }; inline uint16_t getRGBWsize(uint16_t nleds){ uint16_t nbytes = nleds * 4; if(nbytes % 3 > 0) return nbytes / 3 + 1; else return nbytes / 3; } #endif
Download and save this file as “FastLED_RGBW.h”, and place it the same folder as your sketch. Then include it in your sketch by typing:
#include "FastLED_RGBW.h"
When defining the LED array, we also need a CRGB pointer to send to the addLEDs
function. We do this like so:
#define NUM_LEDS 60 // FastLED CRGB leds[NUM_LEDS]; // FastLED with RGBW CRGBW leds[NUM_LEDS]; CRGB *ledsRGB = (CRGB *) &leds[0];
Lastly, when we create the FastLED controller we need to inflate the number of LEDs to account for the extra bytes. The header file has a helper function for this, named getRGBWsize
. The function takes the number of RGBW LEDs as an argument and returns the number of CRGB elements that cover that many bytes.
Now when we create the FastLED controller in the setup
function, we use both the CRGB pointer and the size function:
#define DATA_PIN 6 //FastLED FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS); //FastLED with RGBW FastLED.addLeds<WS2812B, DATA_PIN, RGB>(ledsRGB, getRGBWsize(NUM_LEDS));
Once the strip is set up, you can set LED colors just like you would normally:
// Set Standard FastLED Color leds[0] = CRGB::Red; // Set Individual Colors leds[0].r = 255; leds[0].g = 128; leds[0].b = 64; leds[0].w = 32; // Specific to RGBW leds[0] = CRGB(255, 128, 64); leds[0] = CRGBW(255, 128, 64, 32); // Set HSV Color leds[0] = CHSV(hue, sat, val);
Example Sketch
Here is a basic example sketch that works with SK6812 strips. It does a color wipe for each channel (red, green, blue, and white), then does a rainbow pattern for a 5 seconds and repeats.
/* FastLED RGBW Example Sketch * * Example sketch using FastLED for RGBW strips (SK6812). Includes * color wipes and rainbow pattern. * * Written by David Madison * http://partsnotincluded.com */ #include "FastLED.h" #include "FastLED_RGBW.h" #define NUM_LEDS 60 #define DATA_PIN 6 CRGBW leds[NUM_LEDS]; CRGB *ledsRGB = (CRGB *) &leds[0]; const uint8_t brightness = 128; void setup() { FastLED.addLeds<WS2812B, DATA_PIN, RGB>(ledsRGB, getRGBWsize(NUM_LEDS)); FastLED.setBrightness(brightness); FastLED.show(); } void loop(){ colorFill(CRGB::Red); colorFill(CRGB::Green); colorFill(CRGB::Blue); fillWhite(); rainbowLoop(); } void colorFill(CRGB c){ for(int i = 0; i < NUM_LEDS; i++){ leds[i] = c; FastLED.show(); delay(50); } delay(500); } void fillWhite(){ for(int i = 0; i < NUM_LEDS; i++){ leds[i] = CRGBW(0, 0, 0, 255); FastLED.show(); delay(50); } delay(500); } void rainbow(){ static uint8_t hue; for(int i = 0; i < NUM_LEDS; i++){ leds[i] = CHSV((i * 256 / NUM_LEDS) + hue, 255, 255); } FastLED.show(); hue++; } void rainbowLoop(){ long millisIn = millis(); long loopTime = 5000; // 5 seconds while(millis() < millisIn + loopTime){ rainbow(); delay(5); } }
Limitations
FastLED is a huge library, and unfortunately not all of its helper functions work with this hack. From my testing, while the basic features of the library work the more advanced ones do not. For instance – while non-destructive brightness works perfectly, the color temperature functions do not work at all.
These problems come down to the additional bytes added by the CRGBW struct, in combination with the hard-coded color order. Any function that references the raw array members will be cyclically referencing the wrong color channels.
The other obvious limitation is that this only works with RGBW strips that share protocols already in the FastLED library. SK6812 strips (RGBW NeoPixels) work fine using the WS2812B protocol, but you may need to write your own protocol class if you cannot find one already supported.
Lastly, a not-so-obvious limitation is that for LED byte counts that are not factors of 12, junk data is sent past the defined LED array, causing stray colors to show up on the next LED. This is only an issue if the number of LEDs in the code is less than the number of physical LEDs. You can also get around this by defining the CRGBW array as one element larger than necessary, and leaving those last four bytes at 0.
Conclusion
This is mostly a proof of concept, rather than a turn-key solution. But if you have some color patterns generated using the FastLED library, this will let you use those patterns with RGBW strips until the library properly supports RGBW strips.
A huge thanks to Jim Bumgardner for sharing his method. If you found this post useful, please check out his website at http://krazydad.com/.
66 Comments
Joel · August 14, 2017 at 10:28 pm
Thanks for this. Just setup a whole FastLED project with these not realizing I bought the RGBW. Hope I can get this working!
Dave · August 15, 2017 at 12:26 am
Best of luck!
Niklas · October 17, 2017 at 8:39 am
Thanks a lot for your article!
However the script doesn’t compile and gives me that error:
sketch\FastLED_RGBW.h:45:64: error: ISO C++ forbids declaration of ‘operator=’ with no type [-fpermissive]
What could cause the issue?
Dave · October 17, 2017 at 9:22 am
What compiler are you using? This compiles fine for me using the Arduino IDE (1.8.2).
Trying adding the keyword ‘void’ between ‘inline’ and ‘operator’ in the header file. That might be an oversight on my part.
Niklas · October 17, 2017 at 10:15 am
I’m using the IDEversion 1.8.5. Declaring it as void helped.
Now I tried running your demo script, but the LEDs (SK6812 RGBW) do nothing.
Everything works fine with the Neopixel Library.
What else could have gone wrong?
Thanks in advance!
Dave · October 17, 2017 at 10:32 am
I’m not sure. I just tried using the code above and it works perfectly for me.
Make sure you have the latest version of FastLED installed, and then check the hardware. My hardware setup for the RGBW strips is an Arduino Uno connected through a 470 Ω resistor, with everything powered directly by USB (only 8 LEDs on my demo board). Check that the voltages are as expected and if you have a logic analyzer or oscilloscope, check the output of the data pin.
As I said in the post – this is a hack, and the timings between the two strip types are at their min/max limits. If your hardware is different the timings may be off enough to not work at all.
Manne Danneman · July 12, 2018 at 4:45 pm
Hi.
Impressive work!
I did get the example sketch to run all RGBW. Do you have any idea how to get this to work with Ambibox or Prismatik?
note: I know very little about this stuff. Just trying to learn and to get some ambilight up and running. 🙂
Dave · July 22, 2018 at 9:55 am
I wouldn’t use RGBW leds if you’re getting started, because none of the ambilight software I know of uses RGBW either. You’d just be using an RGBW strip as RGB, and going through quite a bit of hassle to get it to work.
That being said, you could use my ambilight code as a foundation. Though you’d need to add some extra code to keep track of the channel index to insert a ‘0’ byte at each white address.
Manne Danneman Lundkvist · September 9, 2018 at 12:09 pm
Hey! Thanks for the answer! Didn’t notice it until now.
Yes I noticed it was way harder to figure it out with RGBW. So much I actually put it on hold for now. Haha. I just figured that eventually I will find more time to learn more about this or that someone would put up a working template that I could use. I was looking for a challenge but soon realised it was above my head.
One thought I had was to just buy a ordinary RGB strip and use that. But it feels like such a shame when I have 3 m of this amazing looking (and expensive) strip. 🙂
Thank you again for the answer!
Manne Danneman Lundkvist · July 18, 2018 at 2:51 pm
Hi.
I did manage to get the example sketch to work with a 144leds/m SK6812. But got no connection with prismatik or ambibox. Any idea why not? 🙂
Pete · December 1, 2018 at 6:10 am
awesome stuff, up and running in no time 🙂
Daniel Stelzer · December 3, 2018 at 5:51 pm
This saved my project! I made a couple enhancements, having it auto-calculate the white value instead of leaving at zero if it’s not specified. Add this constructor in addition to the given one, and overwrite operator= as follows:
CRGBW(uint8_t rd, uint8_t grn, uint8_t blu){ // If we pass in three values, correct for white
w = min(rd, grn);
w = min(w, blu); // Now w is the smallest of the three values
r = rd – w;
g = grn – w;
b = blu – w;
}
inline void operator = (const CRGB c) __attribute__((always_inline)){ // Turn RGB into RGBW with automatic white correction
uint8_t w = min(c.r, c.g);
w = min(w, c.b); // Now w is the smallest of the three values
this->r = c.r – w;
this->g = c.g – w;
this->b = c.b – w;
this->w = w;
}
Dave · December 3, 2018 at 6:25 pm
I’m glad you found it useful! Those look like useful changes as well.
John · March 7, 2019 at 9:49 pm
Nice, but this transform will lead to unsaturated colors shifting as you bring up the brightness. This leads to colors that appear pastel. Correcting for this requires a little bit of calibration, but the results are worth it.
What we need to do is to find what values of RGB correspond to the white LED’s output. The good news is SK6812s appear to be using linear PWM. This actually makes it much easier as the apparent lumens will be linear as well. This lets us keep all the calculations in luminosity and avoid that nasty cube-root that lightness calculations would bring in – and a single point of reference will be enough to figure this out.
The trick is to find the brightest RGB-only value that is the closest match to a White-only value. I am using the warm white version of the LEDs. With the batch I have, RGBW of 255,128,34,0 is a very close match to 0,0,0,100, both in color and in brightness.
Here the ratio of red to white is 255/100, green to white is 128/100, and blue to white is 34/100. We use these weights to figure out the maximum amount of output we can use from the white LED without altering the color. Just as in your example we can then subtract the white LEDs contribution from the other colors.
This is completely unoptimized with floats and lots of divisions:
//Calibrated values
const float RC = 255;
const float GC = 128;
const float BC = 34;
const float WC = 100;
CRGBW(uint8_t rd, uint8_t grn, uint8_t blu) {
//Normalized red, green, and blue
float rn = rd * WC / RC;
float gn = grn * WC / GC;
float bn = blu * WC / BC;
//Find maximum white value that won’t desaturate
float wn = min( rn, gn );
wn = min( wn, bn );
//Remove red, green, and blue contributions to be supplied by the white LED
r = rd – wn * RC / WC;
g = grn – wn * GC / WC;
b = blu – wn * BC / WC;
w = wn;
}
With a few overflow checks, some values with RGB components greater than 255 are possible:
CRGBW(uint16_t rd, uint16_t grn, uint16_t blu) {
//Normalized red, green, and blue
float rn = rd * WC / RC;
float gn = grn * WC / GC;
float bn = blu * WC / BC;
//Find maximum white value that won’t desaturate
float wn = min( rn, gn );
wn = min( wn, bn );
wn = min( wn, 255 ); //maximum white contribution reached.
//Remove red, green, and blue contributions supplied by the white LED
rn = rd – wn * RC / WC;
gn = grn – wn * GC / WC;
bn = blu – wn * BC / WC;
//Cap red, green, and blue values at 255.
r = max( rn, 255 );
g = max( gn, 255 );
b = max( bn, 255 );
w = wn;
}
cyberponk · March 15, 2019 at 1:14 am
If anyone is trying to modify the code with the enhancements above, and is getting compiling errors, I had do re-type the “-” chars because the copied ones were not read as subtraction by the compiler.
Daniel Stelzer · March 23, 2019 at 6:01 pm
Very nice! I’m adding these modifications to my version. But, in the last assignments, don’t you want `min` instead of `max`?
John · March 24, 2019 at 1:44 pm
Quite right. I was doing on the logic on the PC side, sending the rgbw values across the serial port. When rewritting it inside the CRGBW ctor, I replaced the ternary operator to attempt make it clear why it was being done… oops. At some point I’ll probably revisit it to make it more 8-bit friendly unless someone else does it first.
For anyone cutting and pasting, this is probably what you want to start with:
//Calibrated values
const float RC = 255;
const float GC = 128;
const float BC = 34;
const float WC = 100;
void CRGBW(uint16_t rd, uint16_t grn, uint16_t blu) {
//Normalized red, green, and blue
float rn = rd * WC / RC;
float gn = grn * WC / GC;
float bn = blu * WC / BC;
//Find maximum white value that won’t desaturate
float wn = min( rn, gn );
wn = min( wn, bn );
wn = min( wn, 255 ); //maximum white contribution reached.
//Remove red, green, and blue contributions supplied by the white LED
rn = rd - wn * RC / WC;
gn = grn - wn * GC / WC;
bn = blu - wn * BC / WC;
//Cap red, green, and blue values at 255.
r = min( rn, 255 );
g = min( gn, 255 );
b = min( bn, 255 );
w = wn;
}
Raineer · June 9, 2019 at 6:48 pm
Does someone perhaps have a similar code also for RGBWW? (Rgb + WarmWhite + Coldwhite).
Got a TM1812 5 in 1 Strip, red and green are working properly, but when I set the pixels to Blue, they turn to WarmWhite…. ColdWhite is working fine with your little hack (leds[0].w = 255 gives me perfect WarmWhite).
Daniel · June 11, 2019 at 3:59 pm
I don’t have a TM1812 to test this with, but: try making an array of two CRGBs (just normal RGB, not RGBW), telling FastLED to use WS2812s, then turn on each of the six channels in sequence and see what happens? If each channel corresponds to one of your colors, then it would only take a small modification to make this code work for you.
Jonas Andersson · July 2, 2019 at 2:49 am
Hi thank you for sharing this awesome hack 🙂 I have been struggling with my SK6812 LED strips and getting it to work with a proper driver library. I have been playing around with “marcmerlin”‘s FAST_LED library combined with the NEO_MATRIX librray for easy matrix text and GFX handeling.
Here—-> https://github.com/marcmerlin/FastLED_NeoMatrix
But i am straggling to get it working even tho I follow you setup and include the RGBW header file like you show.
Code:
// Adafruit_NeoMatrix example for single NeoPixel Shield.
// Scrolls ‘Howdy’ across the matrix in a portrait (vertical) orientation.
#include
#include
#include
#include
#define PIN 6
// MATRIX DECLARATION:
// Parameter 1 = width of NeoPixel matrix
// Parameter 2 = height of matrix
// Parameter 3 = pin number (most are valid)
// Parameter 4 = matrix layout flags, add together as needed:
// NEO_MATRIX_TOP, NEO_MATRIX_BOTTOM, NEO_MATRIX_LEFT, NEO_MATRIX_RIGHT:
// Position of the FIRST LED in the matrix; pick two, e.g.
// NEO_MATRIX_TOP + NEO_MATRIX_LEFT for the top-left corner.
// NEO_MATRIX_ROWS, NEO_MATRIX_COLUMNS: LEDs are arranged in horizontal
// rows or in vertical columns, respectively; pick one or the other.
// NEO_MATRIX_PROGRESSIVE, NEO_MATRIX_ZIGZAG: all rows/columns proceed
// in the same order, or alternate lines reverse direction; pick one.
// See example below for these values in action.
// Parameter 5 = pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic ‘v1’ (not v2) FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
// Example for NeoPixel Shield. In this application we’d like to use it
// as a 5×8 tall matrix, with the USB port positioned at the top of the
// Arduino. When held that way, the first pixel is at the top right, and
// lines are arranged in columns, progressive order. The shield uses
// 800 KHz (v2) pixels that expect GRB color data.
#define mw 8
#define mh 32
#define NUMMATRIX (mw*mh)
CRGBW leds[NUMMATRIX];
CRGB *ledsRGB = (CRGB *) & leds[0];
//CRGB matrixleds[NUMMATRIX];
FastLED_NeoMatrix *matrix = new FastLED_NeoMatrix(ledsRGB, mw, mh, mw/8, 1,
NEO_MATRIX_TOP + NEO_MATRIX_RIGHT +
NEO_MATRIX_ROWS + NEO_MATRIX_ZIGZAG );
const uint16_t colors[] = {
matrix->Color(255, 0, 0), matrix->Color(0, 255, 0), matrix->Color(0, 0, 255) };
void setup() {
FastLED.addLeds(ledsRGB, getRGBWsize(NUMMATRIX));
matrix->begin();
matrix->setTextWrap(false);
matrix->setBrightness(40);
matrix->setTextColor(colors[0]);
}
int x = mw;
int pass = 0;
void loop() {
matrix->fillScreen(0);
matrix->setCursor(x, 0);
matrix->print(F(“Howdy”));
if(–x width();
if(++pass >= 3) pass = 0;
matrix->setTextColor(colors[pass]);
}
matrix->show();
delay(100);
}
Dave · July 2, 2019 at 5:53 pm
My guess is that the matrix library is incompatible. This is a good example of how adding an additional byte per pixel throws off a lot of code. The matrix library likely sees each LED as a group of 3 bytes and not as a struct, so when you treat it like a matrix everything goes sideways.
I’d recommend trying to modify the matrix library or write your own implementation that accounts for 4 bytes per pixel.
Manu · September 26, 2019 at 12:08 am
Hi Dave,
i want to try your Code to make the Adalightsketch working for Prismatic… but it doesnt work … only your example is working fine … It is possible that you post the complete working Code that i can load them to my arduino nano and make my sk8612 working with prismatik again ? if i understand all of them here correctly than your code will change rgb into rgbw … in my head it worked … but not on my PC … please help me … THX a lot
Dave · September 26, 2019 at 2:26 am
There’s no real benefit to using an RGBW strip with Prismatik because Prismatik only outputs RGB colors. You would also need to modify whatever Arduino code you’re using for Prismatik to take the different color channels into account – most of them (mine included) just increment the pointer address.
Mark Kriegsman · January 20, 2020 at 4:14 pm
Hi, FastLED maintainer Mark Kriegsman here — Nice hack! Nice way to get some data going out pin, using the built-in data transfer functions! We were working on RGBW support when we lost Dan Garcia in a tragic accident last fall, and then I took some time off. But we’re now starting to get back up and running, and full-on support for RGBW is definitely one of our top topics. Thanks for sharing this great hack in the meantime!
-Mark
Dave · January 20, 2020 at 10:17 pm
Hi Mark!
Those are some very kind words, although I can’t take all the credit. It was Jim Bumgardner (https://krazydad.com/) who discovered and shared this method, I was just the one who wrote it down.
I was so sorry to hear about Dan. I didn’t interact with him much but he always struck me as a helpful and friendly guy. I’m glad you guys are finding a way to keep the library alive in his absence. Good luck with the RGBW conversion – I’m eager to see how it turns out!
Alex · May 4, 2020 at 6:06 am
Hi ! Thanks a lot for sharing this GREAT hack ! It’s been really helpful to me ! I wanted to improve it be adding the ability of using fadeLightBy function in order to dim a CRGBW color without using setBRightness().
I tried to copy/paste the code from FastLED library into fastLED_rgbw.h but it gives me an error when compiling.
inline CRGBW& fadeLightBy (uint8_t fadefactor )
{
nscale8x3( r, g, b, 255 – fadefactor);
return *this;
}
It gave me :
Sketch/FastLED_RGBW.h: In function ‘CRGBW& fadeLightBy(uint8_t)’:
FastLED_RGBW.h:71:20: error: ‘r’ was not declared in this scope
nscale8x3( r, g, b, 255 – fadefactor);
^
FastLED_RGBW.h:71:23: error: ‘g’ was not declared in this scope
nscale8x3( r, g, b, 255 – fadefactor);
^
FastLED_RGBW.h:71:26: error: ‘b’ was not declared in this scope
nscale8x3( r, g, b, 255 – fadefactor);
^
FastLED_RGBW.h:72:17: error: invalid use of ‘this’ in non-member function
return *this;
^~~~
exit status 1
‘r’ was not declared in this scope
What should I do to make it work ???
Thanks !!!
Alex
Dave · May 4, 2020 at 7:42 am
Hi Alex. Two things:
First, you have to paste that snippet into the CRGBW struct definition itself (before the last curly brace). The header in the post includes a
getRGBWsize
function that is outside of the struct definition, which is why you see those errors.Second, remember that the function as-written will only scale the red, green, and blue channels and not white. You would have to scale the white channel yourself. Look at the FastLED source code for reference on how to do it.
I hope that helps.
Koepel · June 27, 2020 at 11:31 am
Thank you. I use the led[i]=CRGBW(r,g,b,w) and make my own colors and patterns and it works very well. I bought a SK6812 RGBWW (RGB with Warm White) ledstrip to be able to make subtle changes to the warm white by mixing the RGB colors into it, and the result is beautiful.
Rosa Wurtz · June 29, 2020 at 1:31 am
Just my two cents. I have a 2,400 piece RGBW SK6812 LED installation for home automation. I am currently driving it with my own library based on the Adafruit Neopixel RGBW library. My current library is blocking so I rarely play around with animations. I am thinking of rewriting my entire library to be non-blocking, but I would really rather use FastLED. I am just a hobbyist so I am pretty sure I can’t write production quality code, but FastLED RGBW support would be a great birthday present 😉 If there is anything I can contribute to let me know.
Jesse · July 11, 2020 at 6:36 pm
Wow, thank you so much! I love the Pacifica effect. I’ll be working on it for SK6812, though I can settle for the WS/B. Thank you SOOO much 😀
Christoph · November 8, 2020 at 6:22 pm
Thanks for this hack.
I just treid to implement this for my existing project.
But I cannot get real colors.
The result is always a pattern of thre leds with different colros.
For example this `fill_solid(ledsRGB, NUM_LEDS, CRGB::Red);` does not show red.
But only every third led is red.
I guess this would be the result without the hack, too.
Same for `fill_rainbow()`.
Are functions like “fill_solid” part of the limitations of this hack?
This would be really unfortunate, because my project uses many of these functions. 🙁
I used `CRGBArray leds;` until now.
I am no expert, bus maybe this be a hint I am using features the hack does not support?!
Thanks
I cannot wait for official RGBW support from FastLED. 🙂
Dave · November 8, 2020 at 6:59 pm
Hi Christoph, sorry to hear you’re having issues.
Unfortunately the built-in ‘fill’ functions do not work with this hack. The hack works by inserting an extra ‘white’ channel byte for each LED. The built-in functions do not do this, so the color channel mapping gets messed up.
Hope is not lost, though! You can create your own
CRGBW
versions of the functions you need and include them in theFastLED_RGBW.h
header. You can even use the built-in functions, just run a ‘for’ loop for the number of LEDs: fill one LED at a time, set the white byte to 0, and continue. If you pass the CRBGW array the new version of the function will be used and everything should work swimmingly. It will be a little extra work, but you shouldn’t have to rewrite the rest of your animation code.Christoph · November 11, 2020 at 2:45 pm
Thanks, Dave.
It was really not that hard to customize the FastLED functions to work with CRGBW.
I did not knew I could have two functions with the same name but different parameter types. Cool.
If anyone is interested, here is my FastLED_RGBW.h with the customized functions I needed for my project.
https://gist.github.com/CWempe/2369aa8b1ca2a2ae8e63be8e2f7694aa
And I replaced this command (which I used many times):
“`
leds(0, NUM_LEDS – 1) = CRGB::Black;
“`
with this:
“`
fill_part(leds, 0, NUM_LEDS, CRGB::Black);
“`
I created this function for this:
“`
#ifdef FastLED_RGBW_h
void fill_part( struct CRGBW * leds, int numFromFill, int numToFill, CRGB color)
{
if ( numFromFill <= numToFill ) {
for( int i = numFromFill; i < numToFill; i++) {
leds[i] = color;
}
}
}
#else
void fill_part( struct CRGB * leds, int numFromFill, int numToFill, CRGB color)
{
if ( numFromFill <= numToFill ) {
for( int i = numFromFill; i < numToFill; i++) {
leds[i] = color;
}
}
}
#endif
“`
This still does irgnore the "white" part of the RGBW leds.
But at least I can install and use the better stripes and take care of the "W" part later. 🙂
Areeb Khan · November 4, 2022 at 10:35 pm
Hey Christoph,
I was facing the same problem when using the following code: fill_solid(ledsRGB, NUM_LEDS, CHSV(huevalue,255,255));
**I’m using MQTT to send different values for hue to get different colors.
I got so excited to see that you had solved this issue but I am not succesfull even after using your customized FastLED_RGBW.h file.
I’m a beginner at coding so I might be doing something wrong. I just replaced Dave’s FastLED_RGBW.h file with yours. Is there something else that I’m supposed to do as well to get the fill_Solid function i referenced above to work?
Thank you so much for your help.
Dave · November 4, 2022 at 10:49 pm
Hi Areeb. You need to pass the CRGBW version of the array to use the CRGBW version of the function. That’s presumably called `leds` in your code. You’re using `ledsRGB`, which I’m guessing is the CRGB pointer.
Andrea · March 23, 2021 at 2:04 pm
That’s amazing thanks… I was wondering if there’s a chance to use it with analog RGBW strip. The “showAnalogRGB” do not accept the forth value…
Dave · March 23, 2021 at 2:07 pm
Sure, you just need to write a function that takes a `CRGBW` struct as a parameter and writes to the relevant pins.
Andrea · March 23, 2021 at 4:34 pm
Yes, it took me a while but in the end I’ve got it. Thanks!!!
Justin · June 1, 2021 at 1:45 am
Hi Dave,
Thanks SO much for your hack. It helped me to make my SK6812s work with the famous tweaking4all fastled toggle sketch, but I have been trying to get it to work with another sketch I’ve been using successfully on WS2812Bs. Unfortunately, no matter what I do, even I change anything randomly in the sketch it makes error colors and random flashing. I uploaded my code on Pastbin https://pastebin.com/raw/4RnVGi1j
I’ve spent hours trying to figure out the problem, any help would be very much appreciated!
Thanks
Dave · June 1, 2021 at 3:01 am
Hi Justin! I’m glad you’ve found the hack helpful. Although unless I’m missing something it looks like the code you linked doesn’t use it?
Justin · June 5, 2021 at 6:37 pm
Oops sorry Dave, didn’t get a notification you responded. My apologies. Also, apologies for the old pastebin. That’s where I kept the code, but when I used it, I did reference your code with #include “FastLED_RGBW.h”
Kolala · June 21, 2021 at 12:17 pm
Thanks you for this awesome hack but I have a problem, I don’t know how to make like Multiple Arrays exemple of FastLED library with this one.
Can you please help me
Dave · June 21, 2021 at 3:37 pm
You can use multiple strips the same way you do in vanilla FastLED. Look at the library examples for reference.
Kolala · June 22, 2021 at 11:39 am
Ok thanks but I want to do it with an array like this one : CRGBW leds[NUM_STRIPS][NUM_LEDS_PER_STRIP];
Kolala · June 22, 2021 at 12:00 pm
And if I try to make like your example it can’t display blue
Kolala · July 15, 2021 at 12:13 pm
Ohhh, I’m so stupid I don’t used the getRGBWsize() function.
Now if I use it it’s working perfectly
Daniel · July 16, 2021 at 9:45 am
You’re a genious
Many thanks, you safed my project.
Mark Wallis · October 2, 2021 at 7:34 am
Hi Dave.
I have just tried to modify the Arduino ‘DemoReel100’ sketch (pasted below)
but get an error; conflicting declaration ‘CRGBW leds [16]’
What have I missed? (Your example sketch built & ran okay.)
Regards, Mark Wallis.
England
Dave · October 2, 2021 at 8:11 am
Hi Mark,
I’ve removed your code snippet to keep the comment size down. The error is because you declared both a `CRGB` version of the ‘leds’ array as well as a `CRGBW` version. Unfortunately there will be other errors as well, as the DemoReel100 example makes liberal use of FastLED functions not supported by this hack.
Oscar · December 28, 2021 at 7:56 am
Hi,
I’m using the code and it’s working, though I have encountered a problem. One LED after the defined amount (if I define 10 —-> number 11) always flickers. Usually, it’s green but I’ve also had that it glows green and flickers red. When using a rainbow effect the LED’s brightness goes up and down but doesn’t change color. As I said it’s a LED outside the definition so it’s just supposed to be off.
The led strip is an SK6812, I have a 1000 uf capacitor, a 390-ohm resistor, Arduino Uno, and no extra power cuz it’s so few LEDs now.
Does anyone nows how to fix it?
Dave · December 28, 2021 at 9:59 am
Hi Oscar. This issue is explained in the “Limitations” section. If your physical strip is longer than your array, the array length must be either a factor of 12 or 1 element larger than needed.
Michel · August 24, 2022 at 9:21 am
Hi, I have been using this hack for a long time and very happy. Thanks for the work. But now I found some SK6812 RGBWW ledstrips running on 12 Volt. They use a different color order though. Red and Green are swapped. So GRBW in stead of RGBW
I tried this:
CRGBW leds_RGBW_1[MAX_LEDS];
CRGB *leds_RGBW_RGB_1 = (CRGB *) &leds_RGBW_1[0];
FastLED.addLeds(leds_RGBW_RGB_1, getRGBWsize(NUM_LEDS));
And then I expected only Green and Blue to be swapped, but it looks like the whole order swapped and I get weird results. Any idea how I could fix this?
Dave · August 24, 2022 at 9:39 am
Hi Michel. If you want to change the color order you will need to change the declaration order in the struct itself, which in turn changes the layout of the color data in memory. The color order enum (like the rest of the FastLED library) is only designed for 3 channels, so it doesn’t work properly when reshuffling the 4 channel data.
Michel · August 30, 2022 at 4:04 am
Hi Dave, thank you very much for your answer. I will have a look. The problem is though that I need both definitions at the same time, so I guess I have to make a separate struct then.
James · November 22, 2022 at 3:00 pm
Hi Dave,
Just thought I’d say thanks for this tutorial, which still seems to be the best way to get RGBW working in FastLED. I’d forgotten I’d got RGBW LEDs and couldn’t figure out why I was asking for 16 LEDs and it was only showing 11……
Cheers
Sam · January 22, 2023 at 6:55 pm
Useful post!
I was wondering if you’d be able to publish your fork of the fastLED library so that it could be easily used?
Thanks,
Dave · January 23, 2023 at 12:41 am
Hi Sam. I don’t have a private fork of the library. All of the work for RGBW support is a part of this post.
Johan · May 1, 2023 at 11:57 am
Hi!
I’m trying to use this with multiple strips, like this:
#define NUM_ROWS (5)
#define NUM_COLUMNS (7)
#define NUM_LEDS_PER_STRIP (64 * NUM_ROWS)
#define NUM_LEDS (NUM_LEDS_PER_STRIP * NUM_COLUMNS)
CRGBW _leds[NUM_LEDS];
CRGB *_ledsRGB = (CRGB *)&_leds[0];
void setup() {
auto rbgw_size = getRGBWsize(NUM_LEDS_PER_STRIP);
FastLED.addLeds(_ledsRGB, 0 * rbgw_size, rbgw_size);
FastLED.addLeds(_ledsRGB, 1 * rbgw_size, rbgw_size);
FastLED.addLeds(_ledsRGB, 2 * rbgw_size, rbgw_size);
FastLED.addLeds(_ledsRGB, 3 * rbgw_size, rbgw_size);
FastLED.addLeds(_ledsRGB, 4 * rbgw_size, rbgw_size);
FastLED.addLeds(_ledsRGB, 5 * rbgw_size, rbgw_size);
FastLED.addLeds(_ledsRGB, 6 * rbgw_size, rbgw_size);
FastLED.setBrightness(80);
for (uint32_t i = 0; i < NUM_LEDS; ++i) {
_leds[i] = CRGBW(255, 0, 0, 0);
}
FastLED.show();
}
The first strip is red, the second one is green, then blue and white. So I assume there is some offset issue here that I'm missing.
Regards,
Johan
Dave · May 1, 2023 at 1:14 pm
Hi Johan. The error is caused by the mismatch in data sizes. FastLED requires everything to be CRGB which is 3 bytes, and the RGBW hack works with 4 byte data. The strip offsets are calculated in 3-byte space and because your number of LEDs per strip is not evenly divisible, it creates a channel offset for each strip.
I see two possible fixes.
First, you could modify the strip size to be evenly divisible by 3. You should be able to add 1 to your `NUM_LEDS_PER_STRIP` define and then compensate for the missing LED in your animation code (e.g. with an `XY()` function).
Second, you could modify the controller creation to calculate the memory addresses in RGBW space instead, e.g. `FastLED.addLeds<>((CRGB*)&_leds[NUM_LEDS_PER_STRIP*N], rgbw_size);`; That would require no modifications to your animation code, but each controller would be reading into other LEDs’ memory on write. You would have to test to see if that’s an issue in practice.
Johan · May 1, 2023 at 1:31 pm
Thanks for the quick reply!
I tried the first approach and that worked fine (and adding an offset by one for each column/strip traversed).
Jonathan · September 13, 2023 at 5:00 am
Hello, I have a similar issue that I get the Compilation error: conflicting declaration ‘CRGBW leds [60]’. It also comes up when I just copy paste the example code that you posted. Not sure whats happening as I didn’t change anything. Is there an extra step which im missing?
Also, this is the code that I’m trying to run for my own project, and Im getting the same error as when I try to run your example code.
#include “FastLED.h”
#include “FastLED_RGBW.h”
#define NUM_LEDS 60
#define DATA_PIN 7
#define BRIGHTNESS 50
// FastLED with RGBW
CRGBW leds[NUM_LEDS];
CRGB *ledsRGB = (CRGB *) &leds[0];
void setup() {
FastLED.addLeds(ledsRGB, getRGBWsize(NUM_LEDS));
FastLED.setBrightness(BRIGHTNESS);
FastLED.show();
}
void loop() {
leds[0] = CRGBW(0, 0, 0, 255);
FastLED.show();
delay(500);
}
Dave · September 13, 2023 at 1:46 pm
Hi Jonathan. I can’t replicate your error, but I do see that you’re missing the template arguments on the `addLeds` call.
roman · November 16, 2023 at 2:57 am
Thanks, worked perfectly 🙂
relwin · March 8, 2024 at 1:37 am
FYI on the newer FastLED lib and new Arduino 2.3.0 IDE: Using this hack I’m having issues with Arduino IDE 2.3.0 and FastLED 3.6 on ESP8266 NodeMCU, where the LEDs operate sporadically.
I don’t have problems with FastLED 3.4, other than many compiler warnings associated with IDE 2.3.0.
Also the ESP’s output pin used is important as some pins don’t work reliably as LED data, specifically the SPI pins, even though they’re not used.
Thanks for supplying this code as I’ve used it successfully for other projects.
–Randy
relwin · March 9, 2024 at 3:08 pm
Ignore previous comments please! Turns out I was using analogWrite() which has known problems on ESP8266. In my case it didn’t appear until using FastLED 3.6.
-r
JMRGB · July 9, 2024 at 6:52 pm
I try to verify the code (i’m realy a newby in programing) and i get that error
#error “No implementation for nscale8x3 available.”
What did I do wrong ?
Thanks