Driving a HL1606 RGB LED strip with the new mbed m0 LPC11U24: first version, without the use of the SI wire, software-PWM only.
Diff: main.cpp
- Revision:
- 0:5ebdba8c620f
--- /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); + } +}