Driving a HL1606 RGB LED strip with the new mbed m0 LPC11U24: first version, without the use of the SI wire, software-PWM only.
main.cpp
- Committer:
- uski
- Date:
- 2011-12-23
- Revision:
- 0:5ebdba8c620f
File content as of revision 0:5ebdba8c620f:
#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); } }