Permalink
Browse files

Incorporated mtbf0's optimizations, tested on Leonardo

  • Loading branch information...
1 parent 882b4fa commit 1d0eba667c9e84fc6d1fa587772fda7e450cab42 @PaintYourDragon PaintYourDragon committed Jul 23, 2012
Showing with 64 additions and 89 deletions.
  1. +18 −38 LPD8806.cpp
  2. +1 −7 LPD8806.h
  3. +1 −1 examples/longstrandtest/longstrandtest.pde
  4. +44 −43 examples/strandtest/strandtest.pde
View
@@ -26,8 +26,7 @@ void LPD8806::alloc(uint16_t n) {
memset(pixels, 0x80, n * 3); // Init to RGB 'off' state
numLEDs = n;
} else numLEDs = 0;
- begun = slowmo = false;
- pause = 3;
+ begun = false;
}
// via Michael Vogt/neophob: empty constructor is used when strip length
@@ -38,8 +37,7 @@ void LPD8806::alloc(uint16_t n) {
LPD8806::LPD8806(void) {
numLEDs = 0;
pixels = NULL;
- begun = slowmo = false;
- pause = 3;
+ begun = false;
updatePins(); // Must assume hardware SPI until pins are set
}
@@ -50,7 +48,7 @@ void LPD8806::begin(void) {
} else {
pinMode(datapin, OUTPUT);
pinMode(clkpin , OUTPUT);
- writeLatch(numLEDs);
+ writeLatch();
}
begun = true;
}
@@ -76,7 +74,7 @@ void LPD8806::updatePins(uint8_t dpin, uint8_t cpin) {
// Regardless, now enable output on 'soft' SPI pins:
pinMode(dpin, OUTPUT);
pinMode(cpin, OUTPUT);
- writeLatch(numLEDs);
+ writeLatch();
} // Otherwise, pins are not set to outputs until begin() is called.
// Note: any prior clock/data pin directions are left as-is and are
@@ -101,7 +99,7 @@ void LPD8806::startSPI(void) {
// work up to 20MHz, the unshielded wiring from the Arduino is more
// susceptible to interference. Experiment and see what you get.
- writeLatch(numLEDs);
+ SPDR = 0; // 'Prime' the SPI bus with initial latch (no wait)
}
uint16_t LPD8806::numPixels(void) {
@@ -117,34 +115,29 @@ void LPD8806::updateLength(uint16_t n) {
} else numLEDs = 0;
// 'begun' state does not change -- pins retain prior modes
- if(begun == true) writeLatch(n); // Write zeros for new length
+ if(begun == true) writeLatch();
}
-// Issue latch of appropriate length; pass # LEDs, *not* latch length
-void LPD8806::writeLatch(uint16_t n) {
-
- // Latch length varies with the number of LEDs:
- n = ((n + 63) / 64) * 3;
+void LPD8806::writeLatch(void) {
if (hardwareSPI) {
- while(n--) SPI.transfer(0);
- } else if(slowmo) {
- digitalWrite(datapin, LOW);
- for(uint16_t i = 8 * n; i>0; i--) {
- digitalWrite(clkpin, HIGH);
- digitalWrite(clkpin, LOW);
- }
+ while(!(SPSR & (1<<SPIF))); // Wait for prior byte out to complete
+ SPDR = 0; // Issue new byte
} else {
*dataport &= ~datapinmask; // Data is held low throughout
- for(uint16_t i = 8 * n; i>0; i--) {
+ for(uint8_t i = 8; i>0; i--) {
*clkport |= clkpinmask;
*clkport &= ~clkpinmask;
}
}
+
+ // Might need a slight delay here, on the order of a few milliseconds.
+ // Or maybe not. Commented out for the time being.
+ // delay(3);
}
// This is how data is pushed to the strip. Unfortunately, the company
-// that makes the chip didnt release the protocol document or you need
+// that makes the chip didnt release the protocol document or you need
// to sign an NDA or something stupid like that, but we reverse engineered
// this from a strip controller and it seems to work very nicely!
void LPD8806::show(void) {
@@ -153,17 +146,8 @@ void LPD8806::show(void) {
// write 24 bits per pixel
if (hardwareSPI) {
for (i=0; i<nl3; i++ ) {
- SPDR = pixels[i];
- while(!(SPSR & (1<<SPIF)));
- }
- } else if(slowmo) {
- for (i=0; i<nl3; i++ ) {
- for (uint8_t bit=0x80; bit; bit >>= 1) {
- if(pixels[i] & bit) digitalWrite(datapin, HIGH);
- else digitalWrite(datapin, LOW);
- digitalWrite(clkpin, HIGH);
- digitalWrite(clkpin, LOW);
- }
+ while(!(SPSR & (1<<SPIF))); // Wait for prior byte out
+ SPDR = pixels[i]; // Issue new byte
}
} else {
for (i=0; i<nl3; i++ ) {
@@ -175,12 +159,8 @@ void LPD8806::show(void) {
}
}
}
-
- writeLatch(numLEDs); // Write latch at end of data
- // We need to have a delay here, a few ms seems to do the job
- // shorter may be OK as well - need to experiment :(
- delay(pause);
+ writeLatch(); // Write latch at end of data
}
// Convert separate R,G,B into combined 32-bit GRB color:
View
@@ -26,12 +26,6 @@ class LPD8806 {
Color(byte, byte, byte),
getPixelColor(uint16_t n);
- // These primarily exist for debugging and will likely come out later:
- boolean
- slowmo; // If true, use digitalWrite instead of direct PORT writes
- uint8_t
- pause; // Delay (in milliseconds) after latch
-
private:
uint16_t
@@ -45,7 +39,7 @@ class LPD8806 {
void
alloc(uint16_t n),
startSPI(void),
- writeLatch(uint16_t n);
+ writeLatch(void);
boolean
hardwareSPI, // If 'true', using hardware SPI
begun; // If 'true', begin() method was previously invoked
@@ -22,7 +22,7 @@ LPD8806 strip = LPD8806(nLEDs, dataPin, clockPin);
// specific pins on the Arduino. For "classic" Arduinos (Uno, Duemilanove,
// etc.), data = pin 11, clock = pin 13. For Arduino Mega, data = pin 51,
// clock = pin 52. For 32u4 Breakout Board+ and Teensy, data = pin B2,
-// clock = pin B1.
+// clock = pin B1. For Leonardo, this can ONLY be done on the ICSP pins.
//LPD8806 strip = LPD8806(nLEDs);
void setup() {
@@ -5,20 +5,25 @@
/*****************************************************************************/
-// Choose which 2 pins you will use for output.
-// Can be any valid output pins.
-int dataPin = 2;
-int clockPin = 3;
+// Number of RGB LEDs in strand:
+int nLEDs = 32;
-// Set the first variable to the NUMBER of pixels. 32 = 32 pixels in a row
-// The LED strips are 32 LEDs per meter but you can extend/cut the strip
+// Chose 2 pins for output; can be any valid output pins:
+int dataPin = 2;
+int clockPin = 3;
+
+// First parameter is the number of LEDs in the strand. The LED strips
+// are 32 LEDs per meter but you can extend or cut the strip. Next two
+// parameters are SPI data and clock pins:
LPD8806 strip = LPD8806(32, dataPin, clockPin);
-// you can also use hardware SPI, for ultra fast writes by leaving out the
-// data and clock pin arguments. This will 'fix' the pins to the following:
-// on Arduino 168/328 thats data = 11, and clock = pin 13
-// on Megas thats data = 51, and clock = 52
-//LPD8806 strip = LPD8806(32);
+// You can optionally use hardware SPI for faster writes, just leave out
+// the data and clock pin parameters. But this does limit use to very
+// specific pins on the Arduino. For "classic" Arduinos (Uno, Duemilanove,
+// etc.), data = pin 11, clock = pin 13. For Arduino Mega, data = pin 51,
+// clock = pin 52. For 32u4 Breakout Board+ and Teensy, data = pin B2,
+// clock = pin B1. For Leonardo, this can ONLY be done on the ICSP pins.
+//LPD8806 strip = LPD8806(nLEDs);
void setup() {
// Start up the LED strip
@@ -30,20 +35,20 @@ void setup() {
void loop() {
- colorChase(strip.Color(127,127,127), 10);
// Send a simple pixel chase in...
- colorChase(strip.Color(127,0,0), 10); // full brightness red
- colorChase(strip.Color(127,127,0), 10); // orange
- colorChase(strip.Color(0,127,0), 10); // green
- colorChase(strip.Color(0,127,127), 10); // teal
- colorChase(strip.Color(0,0,127), 10); // blue
- colorChase(strip.Color(127,0,127), 10); // violet
-
- // fill the entire strip with...
- colorWipe(strip.Color(127,0,0), 10); // red
- colorWipe(strip.Color(0, 127,0), 10); // green
- colorWipe(strip.Color(0,0,127), 10); // blue
+ colorChase(strip.Color(127, 127, 127), 50); // White
+ colorChase(strip.Color(127, 0, 0), 50); // Red
+ colorChase(strip.Color(127, 127, 0), 50); // Yellow
+ colorChase(strip.Color( 0, 127, 0), 50); // Green
+ colorChase(strip.Color( 0, 127, 127), 50); // Cyan
+ colorChase(strip.Color( 0, 0, 127), 50); // Blue
+ colorChase(strip.Color(127, 0, 127), 50); // Violet
+
+ // Fill the entire strip with...
+ colorWipe(strip.Color(127, 0, 0), 50); // Red
+ colorWipe(strip.Color( 0, 127, 0), 50); // Green
+ colorWipe(strip.Color( 0, 0, 127), 50); // Blue
rainbow(10);
rainbowCycle(0); // make it go through the cycle fairly fast
@@ -79,37 +84,33 @@ void rainbowCycle(uint8_t wait) {
}
}
-// fill the dots one after the other with said color
-// good for testing purposes
+// Fill the dots progressively along the strip.
void colorWipe(uint32_t c, uint8_t wait) {
int i;
-
+
for (i=0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, c);
strip.show();
delay(wait);
}
}
-// Chase a dot down the strip
-// good for testing purposes
+// Chase one dot down the full strip.
void colorChase(uint32_t c, uint8_t wait) {
int i;
-
- for (i=0; i < strip.numPixels(); i++) {
- strip.setPixelColor(i, 0); // turn all pixels off
- }
-
- for (i=0; i < strip.numPixels(); i++) {
- strip.setPixelColor(i, c);
- if (i == 0) {
- strip.setPixelColor(strip.numPixels()-1, 0);
- } else {
- strip.setPixelColor(i-1, 0);
- }
- strip.show();
- delay(wait);
+
+ // Start by turning all pixels off:
+ for(i=0; i<strip.numPixels(); i++) strip.setPixelColor(i, 0);
+
+ // Then display one pixel at a time:
+ for(i=0; i<strip.numPixels(); i++) {
+ strip.setPixelColor(i, c); // Set new pixel 'on'
+ strip.show(); // Refresh LED states
+ strip.setPixelColor(i, 0); // Erase pixel, but don't refresh!
+ delay(wait);
}
+
+ strip.show(); // Refresh to turn off last pixel
}
/* Helper functions */
@@ -139,4 +140,4 @@ uint32_t Wheel(uint16_t WheelPos)
break;
}
return(strip.Color(r,g,b));
-}
+}

0 comments on commit 1d0eba6

Please sign in to comment.