Driving a HL1606 RGB LED strip with the new mbed m0 LPC11U24: first version, without the use of the SI wire, software-PWM only.

Files at this revision

API Documentation at this revision

Comitter:
uski
Date:
Fri Dec 23 19:48:46 2011 +0000
Commit message:

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri Dec 23 19:48:46 2011 +0000
@@ -0,0 +1,358 @@
+#include "mbed.h"
+
+DigitalOut mbedLED1(LED1);
+DigitalOut mbedLED2(LED2);
+DigitalOut mbedLED3(LED3);
+DigitalOut mbedLED4(LED4);
+
+Ticker tkrHL1606_update;
+
+#define HL1606_LEDcnt 160 //Depends of your particular strip, here 5meters=80 HL1606=160 LEDs
+int HL1606_pwmCounter; //Used in HL1606_update, PWM counter
+
+unsigned char HL1606_redPWM[2][HL1606_LEDcnt];
+unsigned char HL1606_greenPWM[2][HL1606_LEDcnt];
+unsigned char HL1606_bluePWM[2][HL1606_LEDcnt];
+unsigned char HL1606_curFrame;
+unsigned char HL1606_lastFrameDisplayed;
+
+DigitalOut HL1606_latchPin(p8);
+SPI HL1606_SPI(p5, p6, p7); // mosi, miso, sclk
+
+// Send updated RGB values to the strip
+void HL1606_update()
+{
+  unsigned char i, d, curFrameLatched;
+  
+  // Remember which frame we're showing, in case the background code changes it while we run
+  curFrameLatched=HL1606_curFrame;
+  
+  //Duty cycle of the led = cpu usage of this func
+  mbedLED4 = 1;
+  
+  // write out data to strip 
+  for (i=0; i < HL1606_LEDcnt; i++) {
+    d = 0x80;          // set the latch bit
+    // calculate the next LED's byte
+    if (HL1606_pwmCounter < HL1606_redPWM[curFrameLatched][i]) {
+      d |= 0x04;
+    } 
+    if (HL1606_pwmCounter < HL1606_bluePWM[curFrameLatched][i]) {
+      d |= 0x10;
+    } 
+    if (HL1606_pwmCounter < HL1606_greenPWM[curFrameLatched][i]) {
+      d |= 0x01;
+    } 
+
+    // send new data
+    HL1606_SPI.write(d); 
+  }
+
+  // increment our PWM counter
+  HL1606_pwmCounter += 1;
+  // 2 bits per pixel, max value 3 (0 1 2 3)
+  if (HL1606_pwmCounter > 3) HL1606_pwmCounter = 0;
+
+  // latch
+  HL1606_latchPin = 1;
+  wait_us(2);
+  HL1606_latchPin = 0;
+  
+  mbedLED4 = 0;
+}
+
+// LOW LEVEL
+unsigned int lfsr_stat;
+unsigned int lfsr()
+{
+  unsigned int bit;
+  /* taps: 16 14 13 11; characteristic polynomial: x^16 + x^14 + x^13 + x^11 + 1 */
+  bit  = ((lfsr_stat >> 0) ^ (lfsr_stat >> 2) ^ (lfsr_stat >> 3) ^ (lfsr_stat >> 5) ) & 1;
+  lfsr_stat = (lfsr_stat >> 1) | (bit << 15);
+  return lfsr_stat;
+}
+
+void HL1606_fillRGB(unsigned char red,unsigned char green,unsigned char blue)
+{
+    unsigned char workBuf = HL1606_curFrame ^ 1; //work with the frame buffer not displayed
+    
+    for (int i = 0; i < HL1606_LEDcnt; i++)
+    {
+        HL1606_redPWM[workBuf][i] = red;
+        HL1606_greenPWM[workBuf][i] = green;
+        HL1606_bluePWM[workBuf][i] = blue;
+    }
+    HL1606_curFrame = workBuf;
+}
+
+//HIGH LEVEL
+
+void HL1606_doBlueWhiteFading(float delayDuringFading, float delayBetweenFadings)
+{
+    //Start white
+    HL1606_fillRGB(3,3,2);
+    wait(delayBetweenFadings);
+    //Fade to blue
+    for (int i = 0; i <= 3; i++)
+    {
+        HL1606_fillRGB(3-i,3-i,2);
+        wait(delayDuringFading);
+    }
+    //Stay blue for a while
+    HL1606_fillRGB(0,0,2);
+    wait(delayBetweenFadings);
+    //Go back to white
+    for (int i = 0; i <= 3; i++)
+    {
+        HL1606_fillRGB(i,i,2);
+        wait(delayDuringFading);
+    }    
+}
+
+//Simulate a old-school christmas light
+void HL1606_simulateOldSchoolRGBY(float delay)
+{
+    unsigned char workBuf;
+    unsigned char curBrightness = 3;
+    unsigned char curColor = 0;
+    
+    //Each color after the other
+    for (curColor = 0; curColor < 4; curColor++)
+    {
+        workBuf = HL1606_curFrame ^ 1; //work with the frame buffer not displayed
+        //Draw the LEDs
+        for (int i = 0; i < HL1606_LEDcnt; i++)
+        {
+            unsigned int color = i & 3; //get LSB 2 bits : tells the current color
+            if (color == curColor)
+            {
+                if (color == 0)
+                {
+                    HL1606_redPWM[workBuf][i] = curBrightness;
+                    HL1606_greenPWM[workBuf][i] = 0;
+                    HL1606_bluePWM[workBuf][i] = 0;
+                }
+                else if (color == 1)
+                {
+                    HL1606_redPWM[workBuf][i] = 0;
+                    HL1606_greenPWM[workBuf][i] = curBrightness;
+                    HL1606_bluePWM[workBuf][i] = 0;
+                }
+                else if (color == 2)
+                {
+                    HL1606_redPWM[workBuf][i] = 0;
+                    HL1606_greenPWM[workBuf][i] = 0;
+                    HL1606_bluePWM[workBuf][i] = curBrightness;
+                }
+                else
+                {
+                    HL1606_redPWM[workBuf][i] = curBrightness;
+                    HL1606_greenPWM[workBuf][i] = curBrightness;
+                    HL1606_bluePWM[workBuf][i] = 0;
+                }
+            }
+            else
+            {
+                HL1606_redPWM[workBuf][i] = 0;
+                HL1606_greenPWM[workBuf][i] = 0;
+                HL1606_bluePWM[workBuf][i] = 0;
+            }
+        }
+        HL1606_curFrame = workBuf;
+        wait(delay);
+    }
+}
+
+void HL1606_doSparkle()
+{
+    unsigned char workBuf = HL1606_curFrame ^ 1; //work with the frame buffer not displayed
+    
+    for (int i = 0; i < HL1606_LEDcnt; i++)
+    {
+        HL1606_redPWM[workBuf][i] =  HL1606_greenPWM[workBuf][i] = HL1606_bluePWM[workBuf][i] = ((lfsr() & 63) == 0)?3:0;
+    }
+    HL1606_curFrame = workBuf;
+}
+
+void HL1606_doRainbow(float delay)
+{
+        //now: 3,0,0 (red)
+        for (int i = 0; i<4; i++)
+        {
+            HL1606_fillRGB(0x3,i,0x0);
+            wait(delay);
+        }
+        //now: 3,3,0 (yellow)
+        for (int i = 0; i<4; i++)
+        {
+            HL1606_fillRGB(0x3-i,0x3,0x0);
+            wait(delay);
+        }
+        //now: 0,3,0 (green)
+        for (int i = 0; i<4; i++)
+        {
+            HL1606_fillRGB(0x0,0x3,i);
+            wait(delay);
+        }
+        //now: 0,3,3 (cyan)
+        for (int i = 0; i<4; i++)
+        {
+            HL1606_fillRGB(0x0,0x3-i,0x3);
+            wait(delay);
+        }
+        //now: 0,0,3 (blue)
+        for (int i = 0; i<4; i++)
+        {
+            HL1606_fillRGB(i,0x0,0x3);
+            wait(delay);
+        }        
+        //now: 3,0,3 (purple)
+        for (int i = 0; i<4; i++)
+        {
+            HL1606_fillRGB(0x3,0x0,0x3-i);
+            wait(delay);
+        }        
+        //now: 3,0,0 (red)
+}
+
+void HL1606_doK2000(float delay, unsigned char speed, unsigned char length)
+{
+    unsigned char workBuf = HL1606_curFrame ^ 1; //work with the frame buffer not displayed
+    
+    //end stores the position of the end of the light line (it can be higher than HL1606_LEDcnt because
+    //the led line can go completely off the display
+    for (int end = 0; end <  HL1606_LEDcnt + length; end += speed)
+    {    
+        for (int i = 0; i < HL1606_LEDcnt; i++)
+        {
+            HL1606_redPWM[workBuf][i] = ((i<end)&&(i>(end-length)))?3:0;
+            HL1606_greenPWM[workBuf][i] = ((i<end)&&(i>(end-length)))?1:0;
+            HL1606_bluePWM[workBuf][i] = 0;
+        }
+        HL1606_curFrame = workBuf;    
+        wait(delay);
+    }
+
+    //reverse
+    for (int end = HL1606_LEDcnt + length - 1; end >= 0; end -= speed)
+    {    
+        for (int i = 0; i < HL1606_LEDcnt; i++)
+        {
+            HL1606_redPWM[workBuf][i] = ((i<end)&&(i>(end-length)))?3:0;
+            HL1606_greenPWM[workBuf][i] = ((i<end)&&(i>(end-length)))?1:0;;
+            HL1606_bluePWM[workBuf][i] = 0;
+        }
+        HL1606_curFrame = workBuf;    
+        wait(delay);
+    }
+    
+}
+
+void HL1606_doXmas(float delay, unsigned char speed, unsigned char length)
+{
+    unsigned char workBuf = HL1606_curFrame ^ 1; //work with the frame buffer not displayed
+    
+    //display red/green alternating bars, moving together
+    for (int shift = 0; shift < length*2; shift += speed)
+    {    
+        unsigned char countSameColor = shift%length;
+        unsigned char state;
+        if (shift>=length) state = 0;
+        else state = 1;
+        for (int i = 0; i < HL1606_LEDcnt; i++)
+        {
+
+            countSameColor++;
+            if (countSameColor == length)
+            {
+                state = state ^ 1;
+                countSameColor = 0;            
+            }
+            
+            HL1606_redPWM[workBuf][i] = state?3:0;
+            HL1606_greenPWM[workBuf][i] = state?0:1;
+            HL1606_bluePWM[workBuf][i] = 0;
+        }
+        HL1606_curFrame = workBuf;    
+        wait(delay);
+    }
+    
+}
+
+void HL1606_doFrenchFlag()
+{
+    unsigned char workBuf = HL1606_curFrame ^ 1; //work with the frame buffer not displayed
+    //This wasn't meant to be very patriotic, just wanted to do a quick test
+    //Blue, white, red (reverse because of the order of the LEDs)
+    for (int i = 0; i < HL1606_LEDcnt/3; i++)
+    {
+        HL1606_redPWM[workBuf][i] = 0;
+        HL1606_greenPWM[workBuf][i] = 0;
+        HL1606_bluePWM[workBuf][i] = 3;
+    }
+    for (int i = HL1606_LEDcnt/3; i < (HL1606_LEDcnt/3)*2; i++)
+    {
+        HL1606_redPWM[workBuf][i] = 2;
+        HL1606_greenPWM[workBuf][i] = 2;
+        HL1606_bluePWM[workBuf][i] = 3;
+    }
+    for (int i = (HL1606_LEDcnt/3)*2; i < HL1606_LEDcnt; i++)
+    {
+        HL1606_redPWM[workBuf][i] = 3;
+        HL1606_greenPWM[workBuf][i] = 0;
+        HL1606_bluePWM[workBuf][i] = 0;
+    }
+
+    HL1606_curFrame = workBuf;
+}
+
+int main() {
+
+    HL1606_SPI.format(8,3); // 8 bits per frame, SPI mode 3
+    HL1606_SPI.frequency(450000); // 450kHz freq; higher speed = draw errors
+    
+    lfsr_stat = 0xACE1; //LFSR init
+    
+    mbedLED1 = 0;
+    mbedLED2 = 0;
+    mbedLED3 = 0;
+    mbedLED4 = 0;
+    
+    HL1606_curFrame = 0; //init double-buffer cur frame pointer
+    
+    for (int i = 0; i < 160; i++)
+    {
+        HL1606_redPWM[0][i] = i & 0x03;
+        HL1606_greenPWM[0][i] = (i & 0x0C) >> 2;
+        HL1606_bluePWM[0][i] = (i & 0x30) >> 4;
+    }
+
+    // Update LEDs every 4.5ms
+    tkrHL1606_update.attach(&HL1606_update, 0.0045);
+
+    // Main effect loop
+    while(1) {
+        //Sparkle
+        for (int i = 0; i < 900; i++)
+        {
+            HL1606_doSparkle();
+            wait(0.025);
+        }
+        //Xmas banner
+        for (int i = 0; i < 20; i++) HL1606_doXmas(0.04,1,25);
+        //French flag :)
+        HL1606_doFrenchFlag();
+        wait(8);
+        //Blue and white fading
+        for (int i = 0; i < 5; i++) HL1606_doBlueWhiteFading(0.3,1.5);
+        //Chase like K2000
+        for (int i = 0; i < 5; i++) HL1606_doK2000(0.01,1,25);
+        //Rainbow: red->yellow->green->cyan->blue->purple...
+        HL1606_doRainbow(0.3);
+        HL1606_doRainbow(0.3);
+        HL1606_doRainbow(0.3);
+        HL1606_doRainbow(0.3);
+        //Old school RGBY light
+        for (int i = 0; i < 15; i++) HL1606_simulateOldSchoolRGBY(0.4);
+    }
+}