From 4f09d0a3c39b883a7e948f90fc2baf93693b2afe Mon Sep 17 00:00:00 2001 From: Clinton Ebadi Date: Sun, 23 Nov 2014 23:48:40 -0500 Subject: [PATCH] arduino rgb led strip driver A few iterations in, time for version control. led-controller.scm interfaces with this. This supports driving an arbitrary number of rgb led strips. All currently are set to the same color. You just wire up the pins, and send it three bytes (r, g, b) and read the response line to keep in sync. Originally read r g b using Serial.parseInt(). Returning to that soon as I am porting it to Teensy 3.1 and it has fast buffered communication making the current approach unsuitable. It uses a basic intensity correction table from another project (generated by gamma.py). This is most likely wrong... each color needs its own table, I think. --- README | 4 +- arduino-rgb-led/arduino-rgb-led.ino | 100 ++++++++++++++++++++++ arduino-rgb-led/gamma.h | 7 ++ arduino-rgb-led/gamma.py | 69 +++++++++++++++ arduino-rgb-led/pwm_rgb_led_corrected.ino | 100 ++++++++++++++++++++++ 5 files changed, 279 insertions(+), 1 deletion(-) create mode 100644 arduino-rgb-led/arduino-rgb-led.ino create mode 100644 arduino-rgb-led/gamma.h create mode 100644 arduino-rgb-led/gamma.py create mode 100644 arduino-rgb-led/pwm_rgb_led_corrected.ino diff --git a/README b/README index 3c7d6c6..afcd2d1 100644 --- a/README +++ b/README @@ -4,4 +4,6 @@ Miscellaneous (often broken) bits of code that may have been worth recording in version control, but are not large enough to need a dedicated project. -Code is public domain unless another license is noted in the file. \ No newline at end of file +Code is public domain unless another license is noted in the +file. Some files are from third parties and are noted as such. All are +under Free licenses. \ No newline at end of file diff --git a/arduino-rgb-led/arduino-rgb-led.ino b/arduino-rgb-led/arduino-rgb-led.ino new file mode 100644 index 0000000..e9b3c5a --- /dev/null +++ b/arduino-rgb-led/arduino-rgb-led.ino @@ -0,0 +1,100 @@ +/* -*- c -*- */ +/* Arduino rgb led driver */ +/* Copyright (c) 2014 Clinton Ebadi */ +/* This program is free software: you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, either version 3 of the License, or */ +/* (at your option) any later version. */ + +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ + +/* You should have received a copy of the GNU General Public License */ +/* along with this program. If not, see . */ + +#include +#include "gamma.h" + +const int dither_steps = pow (2, DITHER_BITS); + +typedef struct rgb_pins +{ + int red; + int green; + int blue; +} rgb_pins; + +const int rgb_banks = 2; + +const rgb_pins pins[rgb_banks] = { {10, 9, 11}, + {5, 6, 3} }; + +static int led_colors[rgb_banks * 3]; + +void set_color_x (int r, int g, int b, int dither_step = 0) +{ + int offset = dither_step * 256; + + for (int bank = 0; bank < rgb_banks; bank++) + { + analogWrite (pins[bank].red, pgm_read_byte_near (gammaTable + (r >= 0 ? offset : 0) + r)); + analogWrite (pins[bank].green, pgm_read_byte_near (gammaTable + (g >= 0 ? offset : 0) + g)); + analogWrite (pins[bank].blue, pgm_read_byte_near (gammaTable + (b >= 0 ? offset : 0) + b)); + } +} + +void setup () +{ + Serial.begin (115200); + Serial.setTimeout (100000); + + for (int bank = 0; bank < rgb_banks; bank++) + { + pinMode (pins[bank].red, OUTPUT); + pinMode (pins[bank].green, OUTPUT); + pinMode (pins[bank].blue, OUTPUT); + } + + // Test sequence to confirm wiring + set_color_x (255, 255, 255); + delay(500); + set_color_x (255, 0, 0); + delay (500); + set_color_x (0, 255, 0); + delay (500); + set_color_x (0, 0, 255); + delay (500); +} + +void loop () +{ + static int r = 192; + static int g = 192; + static int b = 192; + static int step = -1; + + //step = (step + 1) % dither_steps; + step = 0; // dithering is bogus/i'm-not-doing-it-right + + if (Serial.available () >= 3) + { + r = Serial.read (); + g = Serial.read (); + b = Serial.read (); + + Serial.print ("set color "); + Serial.print (r); + Serial.print (" "); + Serial.print (g); + Serial.print (" "); + Serial.print (b); + Serial.println (); + + set_color_x (r, g, b); + } + + set_color_x (r, g, b, step); + +} diff --git a/arduino-rgb-led/gamma.h b/arduino-rgb-led/gamma.h new file mode 100644 index 0000000..4021a21 --- /dev/null +++ b/arduino-rgb-led/gamma.h @@ -0,0 +1,7 @@ +/* Dithered luminance correction table - autogenerated by gamma.py */ +#define DITHER_BITS 1 +const prog_uchar PROGMEM gammaTable[]={ + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x5,0x5,0x5,0x5,0x6,0x6,0x6,0x6,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x8,0x9,0x9,0x9,0xa,0xa,0xa,0xa,0xb,0xb,0xb,0xc,0xc,0xc,0xd,0xd,0xe,0xe,0xe,0xf,0xf,0x10,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x18,0x18,0x19,0x19,0x1a,0x1a,0x1b,0x1b,0x1c,0x1d,0x1d,0x1e,0x1f,0x1f,0x20,0x20,0x21,0x22,0x22,0x23,0x24,0x25,0x25,0x26,0x27,0x28,0x28,0x29,0x2a,0x2b,0x2b,0x2c,0x2d,0x2e,0x2f,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4e,0x4f,0x50,0x51,0x52,0x54,0x55,0x56,0x57,0x59,0x5a,0x5b,0x5d,0x5e,0x5f,0x61,0x62,0x63,0x65,0x66,0x68,0x69,0x6a,0x6c,0x6d,0x6f,0x70,0x72,0x73,0x75,0x76,0x78,0x7a,0x7b,0x7d,0x7e,0x80,0x82,0x83,0x85,0x87,0x88,0x8a,0x8c,0x8d,0x8f,0x91,0x93,0x95,0x96,0x98,0x9a,0x9c,0x9e,0xa0,0xa2,0xa3,0xa5,0xa7,0xa9,0xab,0xad,0xaf,0xb1,0xb3,0xb5,0xb7,0xb9,0xbc,0xbe,0xc0,0xc2,0xc4,0xc6,0xc9,0xcb,0xcd,0xcf,0xd1,0xd4,0xd6,0xd8,0xdb,0xdd,0xdf,0xe2,0xe4,0xe6,0xe9,0xeb,0xee,0xf0,0xf3,0xf5,0xf8,0xfa,0xfd, + 0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x5,0x5,0x5,0x5,0x6,0x6,0x6,0x6,0x6,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x8,0x9,0x9,0x9,0x9,0xa,0xa,0xa,0xb,0xb,0xb,0xc,0xc,0xc,0xd,0xd,0xd,0xe,0xe,0xe,0xf,0xf,0x10,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x18,0x18,0x19,0x19,0x1a,0x1a,0x1b,0x1b,0x1c,0x1d,0x1d,0x1e,0x1e,0x1f,0x20,0x20,0x21,0x22,0x22,0x23,0x24,0x24,0x25,0x26,0x27,0x27,0x28,0x29,0x2a,0x2a,0x2b,0x2c,0x2d,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x51,0x52,0x53,0x54,0x55,0x57,0x58,0x59,0x5a,0x5c,0x5d,0x5e,0x60,0x61,0x62,0x64,0x65,0x67,0x68,0x69,0x6b,0x6c,0x6e,0x6f,0x71,0x72,0x74,0x75,0x77,0x78,0x7a,0x7c,0x7d,0x7f,0x80,0x82,0x84,0x85,0x87,0x89,0x8a,0x8c,0x8e,0x90,0x91,0x93,0x95,0x97,0x99,0x9b,0x9c,0x9e,0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae,0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe,0xc0,0xc2,0xc5,0xc7,0xc9,0xcb,0xcd,0xd0,0xd2,0xd4,0xd7,0xd9,0xdb,0xdd,0xe0,0xe2,0xe5,0xe7,0xe9,0xec,0xee,0xf1,0xf3,0xf6,0xf8,0xfb,0xfd + }; + diff --git a/arduino-rgb-led/gamma.py b/arduino-rgb-led/gamma.py new file mode 100644 index 0000000..405b8b4 --- /dev/null +++ b/arduino-rgb-led/gamma.py @@ -0,0 +1,69 @@ +# https://github.com/raplin/HexaWS2811/blob/master/gamma.py +# Lookup table generator +# +# Really it's correcting for the eye's luminance response, it's not actually gamma correction (it's misnamed!) +# +# We're generating a set of 256-entry lookup tables which you use to (separately) convert the 8-bit R, G and B components of your color +# into something you output, typically with an intelligent RGB LED such as a WS2812B; but a simple CPU-based PWM will give the same results (and benefit from this correction) +# +# We generate several sets (2,4,8...) of 256-entry tables so you can cycle through them, using a successive 8-bit lookup table each successive output frame. +# This is 'temporal dithering', which aims to give you better color resolution at the dark end of the scale. +# If you update at e.g. 100hz, try using two or three 'ditherBits' (i.e. 2^^2 or 2^^3=8 tables. The faster your update the more tables you can use +# and you get better color resolution. More than 5 ditherbits is probably excessive, even 2 will help somewhat. +# +# If you get objectionable flickering when displaying low-intensity pixels, you should either update your leds faster or reduce ditherBits +# +# +# +fout=open("gamma.h","wt") + +#adjust me! Each extra bit doubles the table size +ditherBits=1 + +ditherMSB=1<<(ditherBits-1) + +res="/* Dithered luminance correction table - autogenerated by gamma.py */\n#define DITHER_BITS %d\nconst prog_uchar PROGMEM gammaTable[]={" % ditherBits + +useRealLuminanceCalcuation=True # CIE 1931 formula + +finalAdjust=0 #set this to 1 if you want your values to start at one (1..255). This is a quirky request for FastLED users only + +for dither in range(1<>=1 + if dither & dread: + ditherValue|=dout + dout<<=1; + + ditherValue=(ditherValue<<(8-ditherBits)) + + for n in range(256): + if useRealLuminanceCalcuation: + # CIE 1931 + brightness=n/2.56 + if brightness > 8: + pwmValue= pow( ((brightness + 16) / 116) , 3 ) + else: + pwmValue = brightness / 903.3 + pwmValue*=256 + else: + #use simple power + pwmValue=pow(255,(n/256.0))-1 + pwmValue=int(pwmValue*256) + pwmValue+=ditherValue + pwmValue=min(255, (pwmValue>>8)+finalAdjust) + out.append( pwmValue ) + if dither: + res+="," + res+="\n\t"+(",".join([ "0x%x"%n for n in out])) + +res+="\n\t};\n" + +print >>fout,res +fout.close() diff --git a/arduino-rgb-led/pwm_rgb_led_corrected.ino b/arduino-rgb-led/pwm_rgb_led_corrected.ino new file mode 100644 index 0000000..e9b3c5a --- /dev/null +++ b/arduino-rgb-led/pwm_rgb_led_corrected.ino @@ -0,0 +1,100 @@ +/* -*- c -*- */ +/* Arduino rgb led driver */ +/* Copyright (c) 2014 Clinton Ebadi */ +/* This program is free software: you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, either version 3 of the License, or */ +/* (at your option) any later version. */ + +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ + +/* You should have received a copy of the GNU General Public License */ +/* along with this program. If not, see . */ + +#include +#include "gamma.h" + +const int dither_steps = pow (2, DITHER_BITS); + +typedef struct rgb_pins +{ + int red; + int green; + int blue; +} rgb_pins; + +const int rgb_banks = 2; + +const rgb_pins pins[rgb_banks] = { {10, 9, 11}, + {5, 6, 3} }; + +static int led_colors[rgb_banks * 3]; + +void set_color_x (int r, int g, int b, int dither_step = 0) +{ + int offset = dither_step * 256; + + for (int bank = 0; bank < rgb_banks; bank++) + { + analogWrite (pins[bank].red, pgm_read_byte_near (gammaTable + (r >= 0 ? offset : 0) + r)); + analogWrite (pins[bank].green, pgm_read_byte_near (gammaTable + (g >= 0 ? offset : 0) + g)); + analogWrite (pins[bank].blue, pgm_read_byte_near (gammaTable + (b >= 0 ? offset : 0) + b)); + } +} + +void setup () +{ + Serial.begin (115200); + Serial.setTimeout (100000); + + for (int bank = 0; bank < rgb_banks; bank++) + { + pinMode (pins[bank].red, OUTPUT); + pinMode (pins[bank].green, OUTPUT); + pinMode (pins[bank].blue, OUTPUT); + } + + // Test sequence to confirm wiring + set_color_x (255, 255, 255); + delay(500); + set_color_x (255, 0, 0); + delay (500); + set_color_x (0, 255, 0); + delay (500); + set_color_x (0, 0, 255); + delay (500); +} + +void loop () +{ + static int r = 192; + static int g = 192; + static int b = 192; + static int step = -1; + + //step = (step + 1) % dither_steps; + step = 0; // dithering is bogus/i'm-not-doing-it-right + + if (Serial.available () >= 3) + { + r = Serial.read (); + g = Serial.read (); + b = Serial.read (); + + Serial.print ("set color "); + Serial.print (r); + Serial.print (" "); + Serial.print (g); + Serial.print (" "); + Serial.print (b); + Serial.println (); + + set_color_x (r, g, b); + } + + set_color_x (r, g, b, step); + +} -- 2.20.1