HSI to RGB/RGBW conversion library with optional direct PWM output

Dependents:   KL25Z_HSI2RGBW_PWM KL25Z_HSI2RGBW_PWM_local KL25Z_FFT_Demo FFT_BUENA ... more

HSI to RGB / RGBW with optional PWM output

Library for converting HSI color space values to RGB or RGBW and, optionally, directly send the converted values to PWM outputs.

Code ported from http://saikoled.com - Copyright 2013, Brian Neltner
http://blog.saikoled.com/post/44677718712/how-to-convert-from-hsi-to-rgb-white

Info on the HSI color space can be found here and here.

KL25Z PTA4 as PWM output

By default, PTA4 is defined as the NMI input in the the mbed library. When PTA4 is to be used as a PWM output, we MUST disable the NMI assignment, otherwise the system will lock-up when this pin is pulled low. Read this page for more information.
The easiest way (without changing mbed-src) to disable the NMI input is by adding following code at the start of your main program (this is present in the demo program mentioned below):

// Dummy ISR for disabling NMI on PTA4 - !! DO NOT REMOVE THIS !!
extern "C" void NMI_Handler() {
    DigitalIn test(PTA4);
}

Demo code using the KL25Z-FRDM board:

Import programKL25Z_HSI2RGBW_PWM

SaikoLED fade demo using the HSI2RGBW_PWM libary


Constructor & conversion function
When 3 PWM ouptuts are declared, the library automatically selects RGB mode.
When 4 PWM ouptuts are declared, the library automatically selects RGBW mode.
When no PWM outputs are declared, the library defaults to RGBW mode. Use .colorMode(RGB) to switch to RGB mode.
depending on the way you want to use this library, you can call the conversion function in different ways

// Assign 4 PWM outputs and also allow to return the converted RGBW value.
hsi2rgbw_pwm led(PTD4, PTA12, PTA4, PTA5);
// Call to the conversion function
float H, S, I;
float rgbw[4];
led.hsi2rgbw(H, S, I, rgbw);

// Assign 4 PWM outputs, no converted RGBW value will be returned.
hsi2rgbw_pwm led(PTD4, PTA12, PTA4, PTA5);
// Call to the conversion function
float H, S, I;
led.hsi2rgbw(H, S, I);

// No PWM outputs are assigned, only the converted RGBW value will be returned.
hsi2rgbw_pwm led(NC);
// Call to the conversion function
float H, S, I;
float rgbw[4];
led.hsi2rgbw(H, S, I, rgbw);

// Assign 3 PWM outputs and also allow to return the converted RGB value.
hsi2rgbw_pwm led(PTD4, PTA12, PTA4);
// Call to the conversion function
float H, S, I;
float rgb[4];
led.hsi2rgbw(H, S, I, rgbw);

// Assign 3 PWM outputs, no converted RGB value will be returned.
hsi2rgbw_pwm led(PTD4, PTA12, PTA4);
// Call to the conversion function
float H, S, I;
led.hsi2rgbw(H, S, I);

// No PWM outputs are assigned, only the converted RGB value will be returned.
hsi2rgbw_pwm led(NC);
//Set RGB mode
led.colorMode(RGB);
// Call to the conversion function
float H, S, I;
float rgb[4];
led.hsi2rgbw(H, S, I, rgb);


Hue, Saturation and Intesity range

Hue0...360Color value : 0 or 360 = red, 120 = green, 240 = blue, 60 = yellow, 300 = magenta, ...
Saturation0...1Color saturation : 0 = white, 1 = max. color, 0.7 is a nice pastel
Intensity0...1Color intensity : 0 = off, 1 = full intensity


RGB(W) return value
In your main program, declare an array of 4 float values and pass the pointer to this array to the function:
Even when RGB is used, do declare an array of 4 float values.

float rgbw[4];

Upon exit, the function will return the values in rgbw[], representing the red, green, blue and white component that corresponds to the chosen HSI values. Range : 0...1 where 0 = minimum and 1 = maximum.

rgbw[0]RED
rgbw[1]GREEN
rgbw[2]BLUE
rgbw[3]WHITENote : this value has no significance when RGB mode is used.


parabolic mode
By default, each component of the RGB(W) return value is mapped to a parabolic scale.
Call led.parabolic(0); to disable the parabolic mapping.

Choose RGB or RGBW mode
By default, the conversion return value is set to RGBW.
Call led.colorMode(RGB); to change to RGB mode.
Call led.colorMode(RGBW); to go back to RGBW mode.

Change PWM period
By default, the PWM period is set to 4ms (250Hz).
Call led.period(n); to change the PWM period (replace n with a value in ms).

Change PWM values
We can alter the PWM outputs directly, without passing through the HSI to RGB(W) conversion.
declare float rgbw[4]; and set each value of this array.
Call led.pwm(rgbw); to write the values directly to the PWM outputs.

Invert PWM channels
When common anode LEDs are used, we need to invert the PWM signal..
Call led.invertpwm(1); to use the inverted PWM signal.

NOTES
period() and pwm() will not change any value if no PWM pins are declared.
Do not forget to replace led. with the declared function name.

Files at this revision

API Documentation at this revision

Comitter:
frankvnk
Date:
Sun Feb 02 14:41:29 2014 +0000
Parent:
3:dda6914d713f
Child:
5:68daa710ba3f
Commit message:
Fixed runtime error (RGB mode).
; Added invertpwm.

Changed in this revision

hsi2rgbw_pwm.cpp Show annotated file Show diff for this revision Revisions of this file
hsi2rgbw_pwm.h Show annotated file Show diff for this revision Revisions of this file
--- a/hsi2rgbw_pwm.cpp	Mon Dec 30 11:22:53 2013 +0000
+++ b/hsi2rgbw_pwm.cpp	Sun Feb 02 14:41:29 2014 +0000
@@ -28,11 +28,23 @@
 
 #define PI 3.14159265
 
-hsi2rgbw_pwm::hsi2rgbw_pwm(PinName red, PinName green, PinName blue, PinName white) : _red(red), _green(green), _blue(blue), _white(white)
+PwmOut *_red;
+PwmOut *_green;
+PwmOut *_blue;
+PwmOut *_white;
+
+hsi2rgbw_pwm::hsi2rgbw_pwm(PinName pred, PinName pgreen, PinName pblue, PinName pwhite)
 {
     parabol = 1;
+    use_invpwm = 0;
     use_rgbw = RGBW;
-    if(_red == NC && _green == NC && _blue == NC)
+    if(pred != NC) _red = new PwmOut (pred);
+    if(pgreen != NC) _green = new PwmOut (pgreen);
+    if(pblue != NC) _blue = new PwmOut (pblue);
+    if(pwhite != NC) _white = new PwmOut (pwhite);
+    if((pred != NC) && (pgreen != NC) && (pblue != NC) && (pwhite == NC))
+        use_rgbw = RGB;
+    if((pred == NC) && (pgreen == NC) && (pblue == NC) && (pwhite == NC))
     {
         use_pwm = 0;
     }
@@ -40,18 +52,18 @@
     {
         use_pwm = 1;
         //Setup PWM channels - default period = 4 ms (250Hz) 
-        _red.period_ms(4);
-        _green.period_ms(4);
-        _blue.period_ms(4);
-        if(_white != NC)
-            _white.period_ms(4);
+        _red->period_ms(4);
+        _green->period_ms(4);
+        _blue->period_ms(4);
+        if(pwhite != NC)
+            _white->period_ms(4);
 
         // Initial RGB values.
-        _red   = 0.0f;
-        _green = 0.0f;
-        _blue  = 0.0f;
-        if(_white != NC)
-            _white = 0.0f;
+        _red->write(0.0f);
+        _green->write(0.0f);
+        _blue->write(0.0f);
+        if(pwhite != NC)
+            _white->write(0.0f);
     }
 }
 
@@ -64,7 +76,7 @@
     H = PI*H/(float)180; // Convert to radians.
     S = S>0?(S<1?S:1):0; // clamp S and I to interval [0,1]
     I = I>0?(I<1?I:1):0;
-    if(use_rgbw)
+    if(use_rgbw == RGBW)
         Srgb = 1;
     else
     {
@@ -88,7 +100,7 @@
         cos_h = cos(H) / cos(1.047196667-H);
         rgbw[0] = S*I/3*(1+Srgb*cos_h);
         rgbw[1] = S*I/3*(1+Srgb*(1-cos_h));
-        if(use_rgbw)
+        if(use_rgbw == RGBW)
         {
             rgbw[2] = 0;
             rgbw[3] = (1-S)*I;
@@ -100,7 +112,7 @@
         cos_h = cos(H) / cos(1.047196667-H);
         rgbw[1] = S*I/3*(1+Srgb*cos_h);
         rgbw[2] = S*I/3*(1+Srgb*(1-cos_h));
-        if(use_rgbw)
+        if(use_rgbw == RGBW)
         {
             rgbw[0] = 0;
             rgbw[3] = (1-S)*I;
@@ -112,7 +124,7 @@
         cos_h = cos(H) / cos(1.047196667-H);
         rgbw[2] = S*I/3*(1+Srgb*cos_h);
         rgbw[0] = S*I/3*(1+Srgb*(1-cos_h));
-        if(use_rgbw)
+        if(use_rgbw == RGBW)
         {
             rgbw[1] = 0;
             rgbw[3] = (1-S)*I;
@@ -120,22 +132,32 @@
         else
             rgbw[1] = I/3*(1-Srgb);
     }
-  
+
+    if(use_invpwm)
+    {
+        rgbw[0] = (1.0f - rgbw[0]);
+        rgbw[1] = (1.0f - rgbw[1]);
+        rgbw[2] = (1.0f - rgbw[2]);
+        if(use_rgbw == RGBW)
+            rgbw[3] = (1.0f - rgbw[3]);
+    }
+
     // parabolic mapping.
     if(parabol) {
         rgbw[0] *= rgbw[0];     // RED
         rgbw[1] *= rgbw[1];     // GREEN
         rgbw[2] *= rgbw[2];     // BLUE
-        if(use_rgbw)
+        if(use_rgbw == RGBW)
             rgbw[3] *= rgbw[3]; // WHITE
     }
+
     if(use_pwm)
     {
-        _red = rgbw[0];
-        _green = rgbw[1];
-        _blue = rgbw[2];
-        if(_white != NC)
-            _white = rgbw[3];
+        _red->write(rgbw[0]);
+        _green->write(rgbw[1]);
+        _blue->write(rgbw[2]);
+        if(use_rgbw == RGBW)
+            _white->write(rgbw[3]);
     }
 }
 
@@ -143,11 +165,11 @@
 {
     if(use_pwm)
     {
-        _red.period_us(per);
-        _green.period_us(per);
-        _blue.period_us(per);
-        if(_white != NC)
-            _white.period_us(per);
+        _red->period_us(per);
+        _green->period_us(per);
+        _blue->period_us(per);
+        if(use_rgbw == RGBW)
+            _white->period_us(per);
     }
 }
     
@@ -155,11 +177,22 @@
 {
     if(use_pwm)
     {
-        _red = rgbw[0];
-        _green = rgbw[1];
-        _blue = rgbw[2];
-        if(_white != NC)
-            _white = rgbw[3];
+        if(!use_invpwm)
+        {
+            _red->write(rgbw[0]);
+            _green->write(rgbw[1]);
+            _blue->write(rgbw[2]);
+            if(use_rgbw == RGBW)
+                _white->write(rgbw[3]);
+        }
+        else
+        {
+            _red->write(1.0f - rgbw[0]);
+            _green->write(1.0f - rgbw[1]);
+            _blue->write(1.0f - rgbw[2]);
+            if(use_rgbw == RGBW)
+                _white->write(1.0f - rgbw[3]);
+        }
     }
 }
 
@@ -173,3 +206,7 @@
     use_rgbw = como;
 }
 
+void hsi2rgbw_pwm::invertpwm(bool invpwm)
+{
+    use_invpwm = invpwm;
+}
--- a/hsi2rgbw_pwm.h	Mon Dec 30 11:22:53 2013 +0000
+++ b/hsi2rgbw_pwm.h	Sun Feb 02 14:41:29 2014 +0000
@@ -46,20 +46,22 @@
     * @param white = WHITE PWM pin\n
     * @return none\n
     * When you want to use hsi2rgbw standalone (no PWMout), use following initializer:\n
-    *   hsi2rgbw_pwm led;  OR  hsi2rgbw_pwm led(NC, NC, NC, NC);\n
+    *   hsi2rgbw_pwm led(NC);\n
     *   Create a float array in your program to return the rgbw values, eg : float rgbw[4]\n
     *   Call hsi2rgbw with the rgbw pointer : hsi2rgbw(H, S, I, rgbw)\n
+    * When PWM ouptuts are used, RGB or RGBW mode is automatically set.\n
+    * When no PWM outputs are used, the default output is RGBW.\n
     */
-    hsi2rgbw_pwm(PinName red = NC, PinName green = NC, PinName blue = NC, PinName white = NC);
+    hsi2rgbw_pwm(PinName pred = NC, PinName pgreen = NC, PinName pblue = NC, PinName pwhite = NC);
 
     /** Convert HSI to RGBW or RGB.
     *
     * @param Hue         = float (0..1)\n
     * @param Saturation  = float (0..1)\n
     * @param Intensity   = float (0..1)\n
-    * @param rgbw        = Optional pointer to float array[4]\n
-    *                      This parameter can be omitted when PWM output is enabled:\n
-    *                      hsi2rgbw(H, S, I)\n
+    * @param rgbw        Optional pointer to float array[4]\n
+    *                    This parameter can be omitted when PWM output is enabled:\n
+    *                    hsi2rgbw(H, S, I)\n
     *
     * This function can be used to convert HSI to RGBW or RGB:\n
     *   call colorMode(RGBW) to enable HSI->RGBW\n
@@ -100,19 +102,26 @@
     
     /** Set color conversion mode.
     *
-    * @param Colormode   RGBW (1) = convert HSI to RGBW (default).\n
+    * @param Colormode   RGBW (1) = convert HSI to RGBW.\n
     *                    RGB  (0) = convert HSI to RGB.\n
     * @return none\n
     */
     void colorMode(bool como);
 
+    /** Invert PWM output.
+    *
+    * @param InvertPWM   0 : Normal PWM output.\n
+    *                    1 : PWM output is inverted.\n
+    * @return none\n
+    *
+    * Enable (1) when common anode LEDs are used.\n
+    */
+    void invertpwm(bool invpwm);
+
 private:
-    PwmOut _red;
-    PwmOut _green;
-    PwmOut _blue;
-    PwmOut _white;
     bool parabol;
     bool use_pwm;
     bool use_rgbw;
+    bool use_invpwm;
 }; 
 #endif