Test program for my Multi_WS2811 library that started out as a fork of heroic/WS2811. My library uses hardware DMA on the FRDM-KL25Z to drive up to 16 strings of WS2811 or WS2812 LEDs in parallel.

Dependencies:   Multi_WS2811 mbed MMA8451Q

Fork of WS2811 by Heroic Robotics

NOTE: I have accidentally pushed changes for another fork of this program that I used in the recent Georgetown Carnival Power Tool Races. When I get some time, I will restore the test program to its original glory.

You can see my power tool racer (Nevermore's Revenge) here

/media/uploads/bikeNomad/img_0482.jpg

This tests my FRDM-KL25Z multi-string WS2811/WS2812 library. It uses the accelerometer to change the rainbow phase on two strings of LEDs as well as the touch sense to change brightness.

A video of this program in operation is here.

Here is the library that I developed to run the LEDs:

Import libraryMulti_WS2811

Library allowing up to 16 strings of 60 WS2811 or WS2812 LEDs to be driven from a single FRDM-KL25Z board. Uses hardware DMA to do a full 800 KHz rate without much CPU burden.

Files at this revision

API Documentation at this revision

Comitter:
heroic
Date:
Sat Nov 10 05:58:14 2012 +0000
Parent:
7:3025f0e0d70a
Child:
9:dd524af149e6
Commit message:
Initial commit for first cut of WS2811 driver. These are one-wire style devices, so we do some timing mojo.

Changed in this revision

WS2801.cpp Show diff for this revision Revisions of this file
WS2801.h 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
--- a/WS2801.cpp	Fri Oct 12 04:16:40 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +0,0 @@
-// Mbed library to control LPD8806-based RGB LED Strips
-// (c) 2011 Jelmer Tiete
-// This library is ported from the Arduino implementation of Adafruit Industries
-// found at: http://github.com/adafruit/LPD8806
-// and their strips: http://www.adafruit.com/products/306
-// Released under the MIT License: http://mbed.org/license/mit
-//
-// Parameterized and modified to use soft SPI.
-// Jas Strong <jasmine@electronpusher.org>
-/*****************************************************************************/
-
-#include "LedStrip.h"
-#include "WS2801.h"
-
-WS2801::WS2801(PinName dataPin, PinName clockPin, int n) :
-    dat(dataPin),
-    clk(clockPin) {
-    // Allocate 3 bytes per pixel:
-    numLEDs = n;
-    if ((pixels = (uint8_t *)malloc(numLEDs * 3))) {
-        memset(pixels, 0x00, numLEDs * 3); // Init to RGB 'off' state
-    }
-    guardtime.start();
-}
-
-/*
- *  Soft SPI clock-out implementation (CPOL = 0, CPHA = 0).
- *  Certainly not the fastest in the world but it'll do.
- *  Gets about 3.6 MHz;  could get several times as much
- *  using the bitbands directly  - jas.
- */
- 
-void WS2801::write(uint8_t byte) {
-    for (int i=0; i<8; i++) {
-        clk = 0;
-        wait_us(WS2801_DELAY);
-        dat = (byte & 0x80);
-        clk = 1;
-        wait_us(WS2801_DELAY);
-        byte <<= 1;
-    }
-    clk = 0;
-}
-
-void WS2801::begin(void) {
-    blank();
-    show();
-}
-
-uint16_t WS2801::numPixels(void) {
-    return numLEDs;
-}
-
-void WS2801::blank(void) {
-    memset(pixels, 0x00, numLEDs * 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
-// 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 WS2801::show(void) {
-    uint16_t i, nl3 = numLEDs * 3; // 3 bytes per LED
-    while (guardtime.read_us() < 500)
-        /* spin */;
-    for (i=0; i<nl3; i++ ) {
-        write(pixels[i]);
-    }
-
-    guardtime.reset();
-}
-
-
-uint32_t WS2801::total_luminance(void) {
-    uint32_t running_total;
-    running_total = 0;
-    for (int i=0; i<numLEDs*3; i++)
-        running_total += pixels[i];
-    return running_total;
-}
-
-// Convert R,G,B to combined 32-bit color
-uint32_t WS2801::Color(uint8_t r, uint8_t g, uint8_t b) {
-    // 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;
-}
-
-// store the rgb component in our array
-void WS2801::setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b) {
-    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
-
-    pixels[n*3  ] = g;
-    pixels[n*3+1] = r;
-    pixels[n*3+2] = b;
-}
-
-void WS2801::setPixelR(uint16_t n, uint8_t r) {
-    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
-
-    pixels[n*3+1] = r;
-}
-
-void WS2801::setPixelG(uint16_t n, uint8_t g) {
-    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
-
-    pixels[n*3] = g;
-}
-
-void WS2801::setPixelB(uint16_t n, uint8_t b) {
-    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
-
-    pixels[n*3+2] = b;
-}
-
-void WS2801::setPixelColor(uint16_t n, uint32_t c) {
-    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;
-}
--- a/WS2801.h	Fri Oct 12 04:16:40 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-// Mbed library to control WS2801-based RGB LED Strips
-// some portions (c) 2011 Jelmer Tiete
-// This library is ported from the Arduino implementation of Adafruit Industries
-// found at: http://github.com/adafruit/LPD8806
-// and their strips: http://www.adafruit.com/products/306
-// Released under the MIT License: http://mbed.org/license/mit
-//
-/*****************************************************************************/
-
-// Heavily modified by Jas Strong, 2012-10-04
-// Changed to use a virtual base class and to use software SPI.
-
-#include "mbed.h"
-#include "LedStrip.h"
-#ifndef MBED_WS2801_H
-#define MBED_WS2801_H
-
-#define WS2801_DELAY 1
-
-class WS2801 : public LedStrip {
-
- public:
-
-  WS2801(PinName dataPin, PinName clockPin, int n);
-  virtual void begin(void);
-  virtual void show(void);
-  virtual void blank(void);
-  virtual void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b);
-  virtual void setPixelB(uint16_t n, uint8_t b);
-  virtual void setPixelG(uint16_t n, uint8_t g);
-  virtual void setPixelR(uint16_t n, uint8_t r);
-  virtual void setPixelColor(uint16_t n, uint32_t c);
-  virtual uint16_t numPixels(void);
-  virtual uint32_t Color(uint8_t, uint8_t, uint8_t);
-  virtual uint32_t total_luminance(void);
-
- private:
-  DigitalOut dat;
-  DigitalOut clk;
-  void write(uint8_t byte);
-  uint8_t *pixels;     // Holds LED color values
-  uint16_t numLEDs;     // Number of RGB LEDs in strand
-  Timer guardtime;
-    
-};
-#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WS2811.cpp	Sat Nov 10 05:58:14 2012 +0000
@@ -0,0 +1,137 @@
+// WS2811 driver, kinda.
+//
+// Parameterized and modified to use soft SPI.
+// Jas Strong <jasmine@electronpusher.org>
+/*****************************************************************************/
+
+#include "LedStrip.h"
+#include "WS2811.h"
+
+WS2811::WS2811(PinName dataPin, PinName clockPin, int n) :
+    dat(dataPin),
+    clk(clockPin) {
+    // Allocate 3 bytes per pixel:
+    numLEDs = n;
+    if ((pixels = (uint8_t *)malloc(numLEDs * 3))) {
+        memset(pixels, 0x00, numLEDs * 3); // Init to RGB 'off' state
+    }
+    // calibrate delay loops for NRZ 
+    int i;
+    guardtime.start();
+    for (i=0; i<1000; i++)
+        /* do nothing */;
+    i=guardtime.read_us();
+    printf("ws2811:  1000 iters took %d usec.\n", i);
+    bogocal = (1000 / (i*2.4)); // iterations per bitcell (417 nsec)
+    printf("ws2811:  calibrating to %d bogojiffies.\n", bogocal);
+}
+
+/*
+ *  These chips use a one-wire protocol based on a sort of NRZ signalling- jas.
+ */
+ 
+void WS2811::write(uint8_t byte) {
+    for (int i=0; i<8; i++) {
+        if (byte & 0x80)
+            writebit(1);
+        else
+            writebit(0);
+        byte <<= 1;
+    }
+}
+
+inline void WS2811::celldelay(void) {
+    for (int i = 0; i<bogocal; i++)
+        /* do nothing */ ;
+}
+
+void WS2811::writebit(bool bit) {
+    // first cell is always 1
+    dat = 1;
+    celldelay();
+    if (bit) {
+        celldelay();
+    } else {
+        dat=0;
+        celldelay();
+    }
+    // last cell is always 0
+    dat=0;
+    celldelay();
+}
+
+void WS2811::begin(void) {
+    blank();
+    show();
+}
+
+uint16_t WS2811::numPixels(void) {
+    return numLEDs;
+}
+
+void WS2811::blank(void) {
+    memset(pixels, 0x00, numLEDs * 3);
+}
+
+void WS2811::show(void) {
+    uint16_t i, nl3 = numLEDs * 3; // 3 bytes per LED
+    while (guardtime.read_us() < 50)
+        /* spin */;
+    for (i=0; i<nl3; i++ ) {
+        write(pixels[i]);
+    }
+
+    guardtime.reset();
+}
+
+
+uint32_t WS2811::total_luminance(void) {
+    uint32_t running_total;
+    running_total = 0;
+    for (int i=0; i<numLEDs*3; i++)
+        running_total += pixels[i];
+    return running_total;
+}
+
+// Convert R,G,B to combined 32-bit color
+uint32_t WS2811::Color(uint8_t r, uint8_t g, uint8_t b) {
+    // 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;
+}
+
+// store the rgb component in our array
+void WS2811::setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b) {
+    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
+
+    pixels[n*3  ] = g;
+    pixels[n*3+1] = r;
+    pixels[n*3+2] = b;
+}
+
+void WS2811::setPixelR(uint16_t n, uint8_t r) {
+    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
+
+    pixels[n*3+1] = r;
+}
+
+void WS2811::setPixelG(uint16_t n, uint8_t g) {
+    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
+
+    pixels[n*3] = g;
+}
+
+void WS2811::setPixelB(uint16_t n, uint8_t b) {
+    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
+
+    pixels[n*3+2] = b;
+}
+
+void WS2811::setPixelColor(uint16_t n, uint32_t c) {
+    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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WS2811.h	Sat Nov 10 05:58:14 2012 +0000
@@ -0,0 +1,48 @@
+// Mbed library to control WS2801-based RGB LED Strips
+// some portions (c) 2011 Jelmer Tiete
+// This library is ported from the Arduino implementation of Adafruit Industries
+// found at: http://github.com/adafruit/LPD8806
+// and their strips: http://www.adafruit.com/products/306
+// Released under the MIT License: http://mbed.org/license/mit
+//
+/*****************************************************************************/
+
+// Heavily modified by Jas Strong, 2012-10-04
+// Changed to use a virtual base class and to use software SPI.
+
+#include "mbed.h"
+#include "LedStrip.h"
+#ifndef MBED_WS2811_H
+#define MBED_WS2811_H
+
+
+class WS2811 : public LedStrip {
+
+ public:
+
+  WS2811(PinName dataPin, PinName clockPin, int n);
+  virtual void begin(void);
+  virtual void show(void);
+  virtual void blank(void);
+  virtual void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b);
+  virtual void setPixelB(uint16_t n, uint8_t b);
+  virtual void setPixelG(uint16_t n, uint8_t g);
+  virtual void setPixelR(uint16_t n, uint8_t r);
+  virtual void setPixelColor(uint16_t n, uint32_t c);
+  virtual uint16_t numPixels(void);
+  virtual uint32_t Color(uint8_t, uint8_t, uint8_t);
+  virtual uint32_t total_luminance(void);
+
+ private:
+  DigitalOut dat;
+  DigitalOut clk;
+  void write(uint8_t byte);
+  void writebit(bool bit);
+  void celldelay(void);
+  uint8_t *pixels;     // Holds LED color values
+  uint16_t numLEDs;     // Number of RGB LEDs in strand
+  Timer guardtime;
+  uint32_t bogocal;
+    
+};
+#endif
\ No newline at end of file