psieg / Lightpack

Lightpack and Prismatik open repository

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

best way to run SK6812's rgbww?

Volanaro opened this issue · comments

hey just a quick question, what would be the best way to rune the sk6812's i have a arduino uno, i was using before with wsb rgbs but they died and the white was yellow...

i also have a Raspberry pi4 sitting doing nothing, is it possible to run them from the pi? connected via usb like the arduino to the pc??? "using an exturning psu"

cheers

on your first question -
I haven't changed my code for my ambilight arduino in years but this is the snippet i use for converting the RGB signal from prismatik to RGBW, it has worked great and allows me to calibrate the LED "white" for my displays "white"

I hope this helps
(i am not the original creator of this code - However I do not know where it originated)

  uint8_t minVal = min(red, min(green, blue));
  uint8_t r = red - minVal;
  uint8_t g = green - minVal;
  uint8_t b = blue - minVal;

  //divisor must be above 3 (rgb(255,255,255) results in rgbw(0,0,0,255) then)
  //can be customized as the white LED tends to be brighter than the other channels, 4 is a sweet spot for me.
  uint8_t w = ((red - r) + (green - g) + (blue - b)) / 4;

  //most SK6812 RGBW strips aren't RGBNW (natural white), so a bit of compensation should be done.
  //this can either be done by using psieg's color temperature slider or on the microcontroller.
  //In device setup (when using psieg's fork), do not use any color correction (set r,g,b to 100) as that only really works for rgb LEDs.

  /*
    //a theory (not tested but pretty straightforward): to compensate cold or warm white (make it neutral), one could use the following (choose one line):
    //cold white:
    r += w / 10; //whatever divisor works best
    //warm white:
    b += w / 10; //whatever divisor works best
    //additionally, white should probably be turnt down a bit to not overbrighten the scene
    w -= w / 10; //use same divisor
  */

ok thanks, so where would i put this bit of code?, i found some Cold white strips im hoping to use, would a 5v 15A be enough for around 3m of strips? i would inject power from both sides using the same power supply?

Hey there @Volanaro
Im currently expirementing with sk6812RGBNW and use following code snipped and it works. On Ambibox only standard baudrate works. WIth prismatik you can go high baudrates.

Here is the code I found online. RUnning it on Arduino Uno at 4xxxxxx Baudrate no issues 110 leds. Will upgrade to 330 Leds on 3x 27 inch screen soon. Also experimenting on a teensy 4.1 right now with it.

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif

/**************************************
   S E T U P
   set following values to your needs
 **************************************/

#define INITIAL_LED_TEST_ENABLED true
#define INITIAL_LED_TEST_BRIGHTNESS 32  // 0..255
#define INITIAL_LED_TEST_TIME_MS 500  // 10..

#define MAX_LEDS 110

// type of your led controller, possible values, see below
#define LED_TYPE NEO_GRBW
#define LED_FREQUENCY NEO_KHZ800

#define LED_PINS 11        // 3 wire leds

#define OFF_TIMEOUT 15000    // ms to switch off after no data was received, set 0 to deactivate

#define BRIGHTNESS 255                      // maximum brightness 0-255

// Baudrate, higher rate allows faster refresh rate and more LEDs
//#define serialRate 230400      // use 115200 for ftdi based boards
//#define serialRate 460800      // use 115200 for ftdi based boards
#define serialRate 115200      // use 115200 for ftdi based boards
//#define serialRate 500000         // use 115200 for ftdi based boards


/**************************************
   A D A L I G H T   C O D E
   no user changes needed
 **************************************/

// Adalight sends a "Magic Word" (defined in /etc/boblight.conf) before sending the pixel data
uint8_t prefix[] = {'A', 'd', 'a'}, hi, lo, chk, i;

unsigned long endTime;

// Define the array of leds
Adafruit_NeoPixel leds(MAX_LEDS, LED_PINS, LED_TYPE + LED_FREQUENCY);

// set color to all leds
void showColor(uint8_t r, uint8_t g, uint8_t b) {
  #if MAX_LEDS > 1
    for (int led_pos=0; led_pos < MAX_LEDS; led_pos++) {
      leds.setPixelColor(led_pos, leds.Color(r, g, b));
    }
    leds.show();
  #endif
}

// switch of digital and analog leds
void switchOff() {
  #if MAX_LEDS > 1
    leds.clear();
    leds.show();
  #endif
}

// function to check if serial data is available
// if timeout occured leds switch of, if configured
bool checkIncomingData() {
  boolean dataAvailable = true;
  while (!Serial.available()) {
    if ( OFF_TIMEOUT > 0 && endTime < millis()) {
      switchOff();
      dataAvailable = false;
      endTime = millis() + OFF_TIMEOUT;
    }
  }

  return dataAvailable;
}

// main function that setups and runs the code
void setup() {
  Serial.begin(serialRate);

  int ledCount = MAX_LEDS;

  leds.begin();
  
  // color adjustments
  leds.setBrightness ( BRIGHTNESS );

  // initial RGB flash
  #if INITIAL_LED_TEST_ENABLED == true
  for (int v=0;v<INITIAL_LED_TEST_BRIGHTNESS;v++)
  {
    showColor(v,v,v);  
    delay(INITIAL_LED_TEST_TIME_MS/2/INITIAL_LED_TEST_BRIGHTNESS);
  }
 
  for (int v=0;v<INITIAL_LED_TEST_BRIGHTNESS;v++)
  {
    showColor(v,v,v);  
    delay(INITIAL_LED_TEST_TIME_MS/2/INITIAL_LED_TEST_BRIGHTNESS);
  }
  #endif
  showColor(0, 0, 0);

  Serial.print("Ada\n"); // Send "Magic Word" string to host
  Serial.println("Ada: LED num: " +  String(MAX_LEDS)); //Return number of LEDs configured

  boolean transmissionSuccess;
  unsigned long sum_r, sum_g, sum_b;

  // loop() is avoided as even that small bit of function overhead
  // has a measurable impact on this code's overall throughput.
  for(;;) {
    // wait for first byte of Magic Word
    for (i = 0; i < sizeof prefix; ++i) {
      // If next byte is not in Magic Word, the start over
      if (!checkIncomingData() || prefix[i] != Serial.read()) {
        i = 0;
      }
    }

    // Hi, Lo, Checksum
    if (!checkIncomingData()) continue;
    hi = Serial.read();
    if (!checkIncomingData()) continue;
    lo = Serial.read();
    if (!checkIncomingData()) continue;
    chk = Serial.read();

    // if checksum does not match go back to wait
    if (chk != (hi ^ lo ^ 0x55)) continue;

    leds.clear();
    transmissionSuccess = true;
    sum_r = 0;
    sum_g = 0;
    sum_b = 0;

    int num_leds = min ( MAX_LEDS, (hi<<8) + lo + 1 );

    // read the transmission data and set LED values
    for (int idx = 0; idx < num_leds; idx++) {
      byte r, g, b;
      if (!checkIncomingData()) {
        transmissionSuccess = false;
        break;
      }
      r = Serial.read();
      if (!checkIncomingData()) {
        transmissionSuccess = false;
        break;
      }
      g = Serial.read();
      if (!checkIncomingData()) {
        transmissionSuccess = false;
        break;
      }
      b = Serial.read();
      leds.setPixelColor(idx, leds.Color(r, g, b));
    }

    // shows new values
    if (transmissionSuccess) {
      endTime = millis() + OFF_TIMEOUT;
      #if MAX_LEDS > 1
      leds.show();
      #endif
    }
  }
} // end of setup

void loop() {
  // Not used. See note in setup() function.
}

``

Ohhh and I just now found another code by zomfg but yet have to try it

/*
 * Arduino interface for the use of WS2812 strip LEDs
 * Uses Adalight protocol and is compatible with Boblight, Prismatik etc...
 * "Magic Word" for synchronisation is 'Ada' followed by LED High, Low and Checksum
 * @author: Wifsimster <wifsimster@gmail.com> 
 * @date: 11/22/2015
 */

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif
const uint16_t NUMPIXELS = 110;
#define PIN 11

const long serialRate = 115200L;

const uint8_t PIXEL_TYPE = NEO_GRBW;

uint8_t prefix[] = {'A', 'd', 'a'}, hi, lo, chk;
uint16_t i = 0;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS, PIN, PIXEL_TYPE + NEO_KHZ800);
uint8_t *pixels = strip.getPixels();
const byte R_OFFSET = 1;
const byte G_OFFSET = 0;
const byte B_OFFSET = 2;
const byte W_OFFSET = 3;

const uint8_t pixelSize = PIXEL_TYPE == NEO_GRBW ? 4 : 3;
const uint16_t sizeofStrip = NUMPIXELS * pixelSize;

//defining a type makes passing the color easier
struct colorRgbw {
  uint8_t   red;
  uint8_t   green;
  uint8_t   blue;
  uint8_t   white;
};

//converts rgb to rgbw values
colorRgbw rgb2Rgbw(uint8_t red, uint8_t green, uint8_t blue) {
  uint8_t minVal = min(red, min(green, blue));
  uint8_t r = red - minVal;
  uint8_t g = green - minVal;
  uint8_t b = blue - minVal;

  //divisor must be above 3 (rgb(255,255,255) results in rgbw(0,0,0,255) then)
  //can be customized as the white LED tends to be brighter than the other channels, 4 is a sweet spot for me.
  uint8_t w = ((red - r) + (green - g) + (blue - b)) / 4;
  
  //most SK6812 RGBW strips aren't RGBNW (natural white), so a bit of compensation should be done.
  //this can either be done by using psieg's color temperature slider or on the microcontroller.
  //In device setup (when using psieg's fork), do not use any color correction (set r,g,b to 100) as that only really works for rgb LEDs.

/*
  //a theory (not tested but pretty straightforward): to compensate cold or warm white (make it neutral), one could use the following (choose one line):
  //cold white:
  r += w / 10; //whatever divisor works best
  //warm white:
  b += w / 10; //whatever divisor works best
  //additionally, white should probably be turnt down a bit to not overbrighten the scene
  w -= w / 10; //use same divisor
*/

  colorRgbw rgbw = {r, g, b, w};
  return rgbw;
}

colorRgbw rgbw; //global initialization as this doesn't have to be reinitialized for every loop

void setup() {
  strip.begin();

  // Initial GRB(W) flash
  for (byte offset = 0; offset < pixelSize; offset++) {
    if (offset > 0)
      pixels[0 + offset - 1] = 0;
    else
      pixels[0 + 3] = 0;
    pixels[0 + offset] = 255;
    strip.show();
    delay(500);
  }
  strip.clear();
  strip.show();
 
  Serial.begin(serialRate);
  // Send "Magic Word" string to host
  Serial.print("Ada\n");
}

void loop() {
  // Wait for first byte of Magic Word
  for(i = 0; i < sizeof prefix; ++i) {
    waitLoop: while (!Serial.available()) {
    }
    
    // Check next byte in Magic Word
    if(prefix[i] == Serial.read()) continue;
    // otherwise, start over
    i = 0;
    goto waitLoop;
  }
  // Hi, Lo, Checksum  
  while (!Serial.available()) ;;
  hi=Serial.read();
  while (!Serial.available()) ;;
  lo=Serial.read();
  while (!Serial.available()) ;;
  chk=Serial.read();
  
  // If checksum does not match go back to wait
  if (chk != (hi ^ lo ^ 0x55)) {
    i=0;
    goto waitLoop;
  }


  const uint16_t prismatikLedCount = (((hi << 8) | lo) + 1) * pixelSize;
  const uint16_t stripLimit = min(prismatikLedCount, sizeofStrip);
  //memset(leds, 0, NUM_LEDS * sizeof(struct CRGB));
  // Read the transmission data and set LED values
  for (i = 0; i < stripLimit; i += pixelSize) {
    byte r, g, b, w = 0;
    while(!Serial.available());
    r = Serial.read();
    while(!Serial.available());
    g = Serial.read();
    while(!Serial.available());
    b = Serial.read();

rgbw = rgb2Rgbw(r, g, b);
    
pixels[i + R_OFFSET] = rgbw.red;
pixels[i + G_OFFSET] = rgbw.green;
pixels[i + B_OFFSET] = rgbw.blue;
pixels[i + W_OFFSET] = rgbw.white;

  }
  for (; i < prismatikLedCount; i += pixelSize)
  {
    while(!Serial.available());
    Serial.read();
    while(!Serial.available());
    Serial.read();
    while(!Serial.available());
    Serial.read();
  }
  
  // Shows new values
  strip.show();
}