Optimised fork of bikeNomad's WS2811 LED control library. Supports KL25Z and KL46Z

Dependents:   CubicHand

Fork of Multi_WS2811 by Ned Konz

Optimised to use far less RAM than the original.

Capable of running up to 8 strings of 240 LEDs each with plenty of RAM to spare on the KL46Z.

Should run at least three strings of 240 LEDs on the KL25Z (RAM limited)

Files at this revision

API Documentation at this revision

Comitter:
Tomo2k
Date:
Wed Apr 02 13:22:25 2014 +0000
Parent:
6:3b5b8a367f40
Commit message:
Updated comments, parameter names and added example usage

Changed in this revision

LedStrip.cpp Show annotated file Show diff for this revision Revisions of this file
LedStrip.h Show annotated file Show diff for this revision Revisions of this file
WS2811.cpp Show annotated file Show diff for this revision Revisions of this file
WS2811.h Show annotated file Show diff for this revision Revisions of this file
diff -r 3b5b8a367f40 -r 58623ad7f310 LedStrip.cpp
--- a/LedStrip.cpp	Wed Apr 02 12:16:42 2014 +0000
+++ b/LedStrip.cpp	Wed Apr 02 13:22:25 2014 +0000
@@ -1,9 +1,9 @@
 #include "LedStrip.h"
 
-LedStrip::LedStrip(int n)
+LedStrip::LedStrip(uint16_t pixelCount) :
+    numLEDs(pixelCount)
 {
-   // Allocate 3 bytes per pixel:
-    numLEDs = n;
+    // Allocate 3 bytes per pixel:
     pixels = (uint8_t *)malloc(numPixelBytes());
     if (pixels) {
         memset(pixels, 0x00, numPixelBytes()); // Init to RGB 'off' state
@@ -14,8 +14,8 @@
 {
     free(pixels);
 }
- 
-uint32_t LedStrip::total_luminance(void)
+
+uint32_t LedStrip::total_luminance()
 {
     uint32_t running_total;
     running_total = 0;
@@ -25,56 +25,53 @@
 }
 
 // Convert R,G,B to combined 32-bit color
-uint32_t LedStrip::Color(uint8_t r, uint8_t g, uint8_t b)
+uint32_t LedStrip::Color(uint8_t red, uint8_t green, uint8_t blue)
 {
-    // Take the lowest 7 bits of each value and append them end to end
-    // We have the top bit set high (its a 'parity-like' bit in the protocol
-    // and must be set!)
-    return ((uint32_t)g << 16) | ((uint32_t)r << 8) | (uint32_t)b;
+    return ((uint32_t)green << 16) | ((uint32_t)red << 8) | (uint32_t)blue;
 }
 
-// store the rgb component in our array
-void LedStrip::setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b)
+// Store the rgb component in our array
+void LedStrip::setPixelColor(uint16_t pixNum, uint8_t red, uint8_t green, uint8_t blue)
 {
-    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
-
-    pixels[n*3  ] = g;
-    pixels[n*3+1] = r;
-    pixels[n*3+2] = b;
+    if (pixNum < numLEDs) {
+        pixels[pixNum*3  ] = green;
+        pixels[pixNum*3+1] = red;
+        pixels[pixNum*3+2] = blue;
+    }
 }
 
-void LedStrip::setPixelR(uint16_t n, uint8_t r)
+void LedStrip::setPixelR(uint16_t pixNum, uint8_t red)
 {
-    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
-
-    pixels[n*3+1] = r;
+    if (pixNum < numLEDs) {
+        pixels[pixNum*3+1] = red;
+    }
 }
 
-void LedStrip::setPixelG(uint16_t n, uint8_t g)
+void LedStrip::setPixelG(uint16_t pixNum, uint8_t green)
 {
-    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
-
-    pixels[n*3] = g;
+    if (pixNum < numLEDs) {
+        pixels[pixNum*3] = green;
+    }
 }
 
-void LedStrip::setPixelB(uint16_t n, uint8_t b)
+void LedStrip::setPixelB(uint16_t pixNum, uint8_t blue)
 {
-    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
-
-    pixels[n*3+2] = b;
+    if (pixNum < numLEDs) {
+        pixels[pixNum*3+2] = blue;
+    }
 }
 
-void LedStrip::setPackedPixels(uint8_t * buffer, uint32_t n)
+void LedStrip::setPackedPixels(uint8_t * buffer, uint32_t count)
 {
-    if (n >= numLEDs) return;
-    memcpy(pixels, buffer, (size_t) (n*3));
+    if (count > numLEDs) return;
+    memcpy(pixels, buffer, (size_t) (count*3));
 }
 
-void LedStrip::setPixelColor(uint16_t n, uint32_t c)
+void LedStrip::setPixelColor(uint16_t pixNum, uint32_t color)
 {
-    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
-
-    pixels[n*3  ] = (c >> 16);
-    pixels[n*3+1] = (c >>  8);
-    pixels[n*3+2] =  c;
+    if (pixNum < numLEDs) {
+        pixels[pixNum*3  ] = (color >> 16);
+        pixels[pixNum*3+1] = (color >>  8);
+        pixels[pixNum*3+2] =  color;
+    }
 }
diff -r 3b5b8a367f40 -r 58623ad7f310 LedStrip.h
--- a/LedStrip.h	Wed Apr 02 12:16:42 2014 +0000
+++ b/LedStrip.h	Wed Apr 02 13:22:25 2014 +0000
@@ -20,66 +20,73 @@
 {
 public:
     /** Create an LED strip
-    @param n Number of RGB LEDs on the strip
+    @param pixelCount Number of RGB LEDs on the strip
     */
-    LedStrip(int n);
+    LedStrip(uint16_t pixelCount);
     ~LedStrip();
 
     //! Initialise the LED strip
     virtual void begin(void)=0;
-    //! Display the LED strip
+    //! Apply the new LED strip values
     virtual void show(void)=0;
     //! Blank the LED strip
     virtual void blank(void)=0;
 
     /** Pack RGB Color data
-    @param r Amount of Red
-    @param g Amount of Green
-    @param b Amount of Blue
+    @param red Amount of Red
+    @param green Amount of Green
+    @param blue Amount of Blue
+    @returns Packed RGB color data for one pixel
     */
-    static uint32_t Color(uint8_t r, uint8_t g, uint8_t b);
+    static uint32_t Color(uint8_t red, uint8_t green, uint8_t blue);
 
     //! Number of RGB pixels
-    uint16_t numPixels(void) { return numLEDs; }
+    uint16_t numPixels() {
+        return numLEDs;
+    }
     //! Number of bytes used for pixel colour data
-    uint16_t numPixelBytes(void) { return numLEDs * 3; }
-    //! Total brightness of all diodes\n
-    //! Use to check power budget
-    uint32_t total_luminance(void);
+    uint16_t numPixelBytes() {
+        return numLEDs * 3;
+    }
+    /** Total brightness of all diodes\n
+    * Use to check power budget
+    @returns Sum total of all diodes (red + green + blue)
+    */
+    uint32_t total_luminance();
 
     /** Set Blue level of pixel
-    @param n Pixel Number
-    @param b Amount of Blue
+    @param pixNum Pixel Number
+    @param blue Amount of Blue
     */
-    void setPixelB(uint16_t n, uint8_t b);
+    void setPixelB(uint16_t pixNum, uint8_t blue);
     /** Set Green level of pixel
-    @param n Pixel Number
-    @param g Amount of Green
+    @param pixNum Pixel Number
+    @param green Amount of Green
     */
-    void setPixelG(uint16_t n, uint8_t g);
+    void setPixelG(uint16_t pixNum, uint8_t green);
     /** Set Red level of pixel
-    @param n Pixel Number
-    @param r Amount of Red
+    @param pixNum Pixel Number
+    @param red Amount of Red
     */
-    void setPixelR(uint16_t n, uint8_t r);
-    
+    void setPixelR(uint16_t pixNum, uint8_t red);
+
     /** Set color of pixel
-    @param n Pixel Number
-    @param c Packed RGB color data
+    @param pixNum Pixel Number
+    @param color Packed RGB color data
     */
-    void setPixelColor(uint16_t n, uint32_t c);
+    void setPixelColor(uint16_t pixNum, uint32_t color);
     /** Set color of pixel
-    @param n Pixel Number
-    @param r Amount of Red
-    @param g Amount of Green
-    @param b Amount of Blue
+    @param pixNum Pixel Number
+    @param red Amount of Red
+    @param green Amount of Green
+    @param blue Amount of Blue
     */
-    void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b);
+    void setPixelColor(uint16_t pixNum, uint8_t red, uint8_t green, uint8_t blue);
     /** Set color of all pixels
     @param *buffer Packed pixel data
-    @param n number of pixels
-    */    
-    void setPackedPixels(uint8_t * buffer, uint32_t n);
+    @param count Number of pixels
+    */
+    void setPackedPixels(uint8_t * buffer, uint32_t count);
 
 protected:
     uint8_t *pixels;     // Holds LED color values
diff -r 3b5b8a367f40 -r 58623ad7f310 WS2811.cpp
--- a/WS2811.cpp	Wed Apr 02 12:16:42 2014 +0000
+++ b/WS2811.cpp	Wed Apr 02 13:22:25 2014 +0000
@@ -212,8 +212,8 @@
     NVIC_EnableIRQ(TPM0_IRQn);
 }
 
-WS2811::WS2811(unsigned n, unsigned pinNumber)
-    : LedStrip(n)
+WS2811::WS2811(uint16_t pixelCount, uint8_t pinNumber)
+    : LedStrip(pixelCount)
     , pinMask(1U << pinNumber)
 {
     enabledPins |= pinMask;
@@ -224,7 +224,7 @@
 void WS2811::startDMA()
 {
     hw_init();
-    
+
     wait_for_dma_done();
     dma_done = false;
 
@@ -386,7 +386,7 @@
 extern "C" void TPM0_IRQHandler()
 {
     TPM0->SC = 0; // disable internal clocking
-    TPM0->SC = TPM_SC_TOF_MASK;        
+    TPM0->SC = TPM_SC_TOF_MASK;
     RESET_DEBUG;
     WS2811::dma_done = true;
 }
diff -r 3b5b8a367f40 -r 58623ad7f310 WS2811.h
--- a/WS2811.h	Wed Apr 02 12:16:42 2014 +0000
+++ b/WS2811.h	Wed Apr 02 13:22:25 2014 +0000
@@ -13,8 +13,8 @@
 // Modified by Ned Konz, December 2013.
 // Using three-phase DMA ala Paul Stoffegren's version.
 //
-// Modified by richard Thompson, Marhc 2014.
-// Uses 8-bit DMA transfers instead of 32-bit, uses 1/4 of the RAM.
+// Modified by richard Thompson, March 2014.
+// Uses 8-bit DMA transfers instead of 32-bit, uses 1/4 of the RAM (static)
 // Now capable of running 240 LEDs on one pin
 
 #ifndef MBED_WS2811_H
@@ -29,7 +29,7 @@
 extern "C" void DMA0_IRQHandler();
 extern "C" void TPM0_IRQHandler();
 
-/** 
+/**
 * WS2811/WS2812/WS2812B
 * LED Strip controller\n
 * For FRDM-KL25Z and FRDM-KL46Z
@@ -49,22 +49,101 @@
 
       Eight strings:\n
         240*8 LEDs: 11520 + (240*3) * 8 = 17,280 bytes
+
+Example usage:
+@code
+#include "mbed.h"
+#include "WS2811.h"
+#include "Colors.h"
+
+static void showRainbow(WS2811 &strip, float startHue, float sat, float brite, float hueShift)
+{
+    unsigned nLEDs = strip.numPixels();
+    float hue = startHue;
+    for (unsigned i = 0; i < nLEDs; i++) {
+        uint8_t r, g, b;
+        Colors::HSBtoRGB(hue, sat, brite, &r, &g, &b);
+        strip.setPixelColor(i, r, g, b);
+        hue += hueShift;
+        if (hue > 1.0) hue = 0.0;
+    }
+    strip.show();
+}
+
+static void showSolidColor(WS2811 &strip, uint8_t r, uint8_t g, uint8_t b)
+{
+    unsigned nLEDs = strip.numPixels();
+    for (unsigned i = 0; i < nLEDs; i++) {
+        strip.setPixelColor(i, r, g, b);
+    }
+    strip.show();
+}
+
+int main(void)
+{
+    WS2811 lightStrip1(nLEDs, 2);
+    WS2811 lightStrip2(nLEDs, 3);
+    WS2811 lightStrip3(nLEDs, 4);
+
+    lightStrip1.begin();
+    lightStrip2.begin();
+    lightStrip3.begin();
+
+    uint8_t r =0;
+    uint8_t g =0;
+    uint8_t b =0;
+
+    bool fadeUp = true;
+
+    float startHue = 0.0;
+    for (;;) {
+        startHue += 0.01;
+        if (startHue > 1.0) startHue = 0.0;
+        if (fadeUp) {
+            if (r == 255) fadeUp = false;
+            else {
+                ++r;
+                ++g;
+                ++b;
+            }
+        } else {
+            if (r == 0) fadeUp = true;
+            else {
+                --r;
+                --g;
+                --b;
+            }
+        }
+
+        // Solid fading white
+        showSolidColor(lightStrip1, r, g, b);
+        // Maximum saturation rainbow
+        showRainbow(lightStrip2, startHue, 1.0, 1.0, 1.0/nLEDs);
+        // Pastel rainbow
+        showRainbow(lightStrip3, startHue, 0.5, 1.0, 1.0/nLEDs);
+
+        WS2811::startDMA();
+        wait_ms(25);
+        frames++;
+    }
+}
+@endcode
 */
 class WS2811 : public LedStrip
 {
 public:
     /** Set up the LED strip
-    @param n Number of LEDs on the strip. Must be less than MAX_LEDS_PER_STRIP
+    @param pixelCount Number of RGB LEDs on the strip. No more than MAX_LEDS_PER_STRIP (240)
     @param pinNumber Pin number on PORTD. 0-7.
     */
-    WS2811(unsigned n, unsigned pinNumber);
+    WS2811(uint16_t pixelCount, uint8_t pinNumber);
 
     virtual void begin();
     virtual void show();
     virtual void blank();
 
-    /** Send a level update to all the WS2811 LED strips
-    * All updates happen in parallel, ensure all (max. 8) strips have complete data before calling this.
+    /** Send a level update to all the WS2811 LED strips\n
+    * All updates happen in parallel, ensure all (max 8) strips have complete data before calling this.
     */
     static void startDMA();
 
@@ -78,17 +157,19 @@
     static bool initialized;
     static uint32_t enabledPins;
     static volatile bool dma_done;
-    static void wait_for_dma_done() { while (!dma_done) __WFI(); }
+    static void wait_for_dma_done() {
+        while (!dma_done) __WFI();
+    }
 
     static void writeByte(uint8_t byte, uint32_t mask, uint8_t *dest);
 
     static void hw_init();
-        static void io_init();
-        static void clock_init();
-        static void dma_init();
-        static void tpm_init();
-        static void dma_data_init();
-        
+    static void io_init();
+    static void clock_init();
+    static void dma_init();
+    static void tpm_init();
+    static void dma_data_init();
+
     friend void TPM0_IRQHandler();
 };