Go Down

Topic: [HELP] Using Jinx! for SK6812 RGBW Matrix  (Read 444 times) previous topic - next topic

Rufuz

Jul 17, 2017, 10:58 pm Last Edit: Jul 17, 2017, 11:04 pm by Rufuz
Hi Guys,
I built a 10x20 LED Matrix with SK6812 RGBW LED´s and an Arduino Uno clone as controller.
First tests with several test scripts worked fine. https://forum.arduino.cc/index.php?topic=364208.0
Fully motivated after the first success I configured Jinx! as it is done for the WS2811/12.

I found a sketch which uses FastLED to transmit the data to the LED´s:
Code: [Select]
#include <FastLED.h>
#define NUM_LEDS 200 // the last 4th didn´t light up, setting it to 267 = 200/3*4 worked
#define DATA_PIN 6
#define CMD_NEW_DATA 1
#define BAUD_RATE 500000

CRGB leds[NUM_LEDS];

void setup() {
  FastLED.addLeds<WS2811, DATA_PIN, GRB>(leds, NUM_LEDS);
  Serial.begin(BAUD_RATE);
}
int serialGlediator () {
  while (!Serial.available()) {}
  return Serial.read();
}
void loop() {
  while (serialGlediator () != CMD_NEW_DATA) {}
  Serial.readBytes((char*)leds, NUM_LEDS*3);
  FastLED.show();
}


The result of the first test with Jinx! can be seen in the first attached picture. I selected the mode "Simple Color" and chose plain green.
The first pixel is in the top right corner. Leds light up in the order: red, green+white,  blue+white. But the last 50 (one 4th) stay off.
So I set the Number of LEDs to 267 and all light up (picture 2) but still in the wrong colors.

My question is: How can i read the glediator protocoll (GRB) - 24 bit - and put it out as 32 bit with "0" for the white part to get the right color for every pixel?

I also found a sketch which sets a CRGBW struct in FastLED. Trying this didn´t help either:
Code: [Select]
/* 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 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

and the code where i tried using it:
Code: [Select]
#include <FastLED.h>
#include "FastLED_RGBW.h"
#define NUM_LEDS 200
#define NUM_LEDS_adj 267
#define DATA_PIN 6
#define CMD_NEW_DATA 1
#define BAUD_RATE 500000

// FastLED with RGBW
CRGBW leds[NUM_LEDS];
CRGB *ledsRGB = (CRGB *) &leds[0];

void setup() {
FastLED.addLeds<WS2812, DATA_PIN, RGB>(ledsRGB, NUM_LEDS_adj);
  Serial.begin(BAUD_RATE);
}
int serialGlediator () {
  while (!Serial.available()) {}
  return Serial.read();
}
void loop() {
  while (serialGlediator () != CMD_NEW_DATA) {}
  Serial.readBytes((char*)leds, NUM_LEDS_adj*3);
 
 
  FastLED.show();
}

I hope you can help me get the matrix going!
PS English is not my mother tongue, spelling errors can be kept.

Grumpy_Mike

You are going to have to write code that fills a buffer with four bytes per pixel instead of the normal three.
So you have an array that holds the state of each LED and then use the fast LED library to send out that buffer. I don't think the Adafruit library can do this. You have to write the equivalent of the set LED colour function and not use the librarie's built in ones. You use the built in show when you want to transfer the buffer into the LEDs.

mcnobby

Rufuz

I have the same problem about two years ago, I contacted the writer of Jinx! to see if he had any plans to make the application RGBW (since that is the way LEDs are going...) but he wasnt interested at that time

Then I decided to look for information on how to extrapolate the White data and found this white paper

http://www.research.ed.ac.uk/portal/files/17162678/published_paper.pdf

I didnt get round to implementing it in code, but I am sure a rough version could be done on the fly, using lookup tables and assembler, calculating the required byte values at the time of outputting

Its no easy task
http://www.youtube.com/user/Recovered
http://www.smartshow.lighting

Grumpy_Mike

Ah ah, that is exactly the way I came up with last night thinking about it. It is expressed in a typically opaque way in that paper.

Basically get the smallest of the three RGB quantities and assign it to the white value. Then subtract the white value from the three RGB values. One of them, the smallest will go to zero.

However that is not exactly the OP's problem he wants to send a 4 byte stream per LED and not a three byte stream. That is addressed in reply #1.

Grumpy_Mike

This is the sort of thing I meant for your own set colour function.

Code: [Select]

void setColour(int pixelNumber, byte R, byte G, byte B, byte W){
arrayPos = pixelNumber << 2; // find position in array
// now write the values into an array called LEDs in an GRBW format
LEDs[arrayPos] = G;
LEDs[arrayPos+1] = R;
LEDs[arrayPos+2] = B;
LEDs[arrayPos+3] = W;
}

Just swap the colours around to use any other colour order.

Rufuz

#5
Jul 18, 2017, 02:54 pm Last Edit: Jul 19, 2017, 08:17 pm by Rufuz
Thank you @Grumpy_Mike for the idea with the buffer array and @mcnobby for the color subtraction idea.
I edited the code a bit, still using the CRGB and CRGBW structs. It is now working as it is supposed to.
Code: [Select]
#include <FastLED.h>
#include "FastLED_RGBW.h"
#define NUM_LEDS 200
#define DATA_PIN 6
#define CMD_NEW_DATA 1
#define BAUD_RATE 1000000

// FastLED with RGBW
CRGB ledsJinx[NUM_LEDS];
CRGBW leds[NUM_LEDS];
CRGB *ledsRGB = (CRGB *) &leds[0];

void setup() {
FastLED.addLeds<WS2811, DATA_PIN, RGB>(ledsRGB, getRGBWsize(NUM_LEDS));
  Serial.begin(BAUD_RATE);

//  FastLED.show();
}
int serialGlediator () {
  while (!Serial.available()) {}
  return Serial.read();
}
uint8_t MINIMUM(int i) {
  uint8_t MIN = ledsJinx[i].r;
  if(ledsJinx[i].g < MIN)
    MIN = ledsJinx[i].g;
  else if(ledsJinx[i].b < MIN)
    MIN = ledsJinx[i].b;
  return MIN;
}
void loop() {
  while (serialGlediator () != CMD_NEW_DATA) {}
    Serial.readBytes((char*)ledsJinx, NUM_LEDS*3);
 
  for( int i = 0; i< NUM_LEDS; i++) {
    uint8_t MIN = MINIMUM(i);
    leds[i] = CRGBW(ledsJinx[i].r - MIN,ledsJinx[i].g - MIN,ledsJinx[i].b - MIN, MIN);
  }
 
  FastLED.show();
}


Things that can be improved:
1. The buffer array is eating a lot of memory and the ram is getting tight.
How can i handle this? I don´t really know how to get rid of the buffer...
2. In the posted paper they improve their color values by setting a parameter "W":
       MIN_out = MIN * W.
I am using the warm white SK6812´s -> more red light. So there has to be a differnet W for each color set. I will post my parameters later.

Grumpy_Mike

Quote
I don´t really know how to get rid of the buffer...
Basically you can't, you need a buffer with 4 bytes per LED.


Go Up