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:
bikeNomad
Date:
Thu Dec 05 15:12:47 2013 +0000
Parent:
14:c97261a9a282
Commit message:
inlined bit writes

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 diff for this revision Revisions of this file
WS2811.h Show diff for this revision Revisions of this file
WS2812.cpp Show annotated file Show diff for this revision Revisions of this file
WS2812.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LedStrip.cpp	Thu Dec 05 15:12:47 2013 +0000
@@ -0,0 +1,80 @@
+#include "LedStrip.h"
+
+LedStrip::LedStrip(int n)
+{
+   // Allocate 3 bytes per pixel:
+    numLEDs = n;
+    pixels = (uint8_t *)malloc(numPixelBytes());
+    if (pixels) {
+        memset(pixels, 0x00, numPixelBytes()); // Init to RGB 'off' state
+    }
+}
+
+LedStrip::~LedStrip()
+{
+    free(pixels);
+}
+ 
+uint32_t LedStrip::total_luminance(void)
+{
+    uint32_t running_total;
+    running_total = 0;
+    for (int i=0; i< numPixelBytes(); i++)
+        running_total += pixels[i];
+    return running_total;
+}
+
+// Convert R,G,B to combined 32-bit color
+uint32_t LedStrip::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 LedStrip::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 LedStrip::setPixelR(uint16_t n, uint8_t r)
+{
+    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
+
+    pixels[n*3+1] = r;
+}
+
+void LedStrip::setPixelG(uint16_t n, uint8_t g)
+{
+    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
+
+    pixels[n*3] = g;
+}
+
+void LedStrip::setPixelB(uint16_t n, uint8_t b)
+{
+    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed
+
+    pixels[n*3+2] = b;
+}
+
+void LedStrip::setPackedPixels(uint8_t * buffer, uint32_t n)
+{
+    if (n >= numLEDs) return;
+    memcpy(pixels, buffer, (size_t) (n*3));
+}
+
+void LedStrip::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/LedStrip.h	Sun Jul 28 08:38:18 2013 +0000
+++ b/LedStrip.h	Thu Dec 05 15:12:47 2013 +0000
@@ -9,22 +9,33 @@
 // of strip may be used in a single array or container.
 
 #include "mbed.h"
+
 #ifndef LEDSTRIP_H
 #define LEDSTRIP_H
 
-class LedStrip {
- public:
-  virtual void begin(void)=0;
-  virtual void show(void)=0;
-  virtual void blank(void)=0;
-  virtual void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b)=0;
-  virtual void setPackedPixels(uint8_t * buffer, uint32_t n)=0;
-  virtual void setPixelB(uint16_t n, uint8_t b)=0;
-  virtual void setPixelG(uint16_t n, uint8_t g)=0;
-  virtual void setPixelR(uint16_t n, uint8_t r)=0;
-  virtual void setPixelColor(uint16_t n, uint32_t c)=0;
-  virtual uint16_t numPixels(void)=0;
-  virtual uint32_t Color(uint8_t, uint8_t, uint8_t)=0;
-  virtual uint32_t total_luminance(void);
+class LedStrip
+{
+public:
+    LedStrip(int n);
+    ~LedStrip();
+
+    virtual void begin(void)=0;
+    virtual void show(void)=0;
+    virtual void blank(void)=0;
+
+    uint16_t numPixels(void) { return numLEDs; }
+    uint16_t numPixelBytes(void) { return numLEDs * 3; }
+    virtual uint32_t Color(uint8_t, uint8_t, uint8_t);
+    virtual uint32_t total_luminance(void);
+    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 void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b);
+    virtual void setPackedPixels(uint8_t * buffer, uint32_t n);
+
+protected:
+    uint8_t *pixels;     // Holds LED color values
+    uint16_t numLEDs;     // Number of RGB LEDs in strand
 };
 #endif
\ No newline at end of file
--- a/WS2811.cpp	Sun Jul 28 08:38:18 2013 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,157 +0,0 @@
-// 800 KHz WS2811 driver, kinda.
-//
-// Parameterized and modified to use soft SPI.
-// Jas Strong <jasmine@electronpusher.org>
-/*****************************************************************************/
-
-#include "LedStrip.h"
-#include "WS2811.h"
-
-extern int onewire_speed_multiplier;   // speed setting for ws2811 et al.
-
-
-WS2811::WS2811(PinName dataPin, PinName clockPin, int n) :
-    dat(dataPin),
-    clk(clockPin) {
-    // Allocate 3 bytes per pixel:
-    numLEDs = n;
-    pixels = (uint8_t *)malloc(numLEDs * 3);
-    if (pixels) {
-        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 / (onewire_speed_multiplier * i * 4.2)); // iterations per bitcell (417 nsec)
-    printf("ws2811:  calibrating to %d bogojiffies.\n", bogocal);
-    
-    data_mask = dat.get_mask();
-    clock_mask = clk.get_mask();
-    data_set = dat.get_set();
-    data_clr = dat.get_clr();
-    clock_set = clk.get_set();
-    clock_clr = clk.get_clr();
-    
-}
-
-/*
- *  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 (volatile int i = 0; i<bogocal; i++)
-        /* do nothing */ ;
-}
-
-inline void WS2811::writebit(bool bit) {
-    // first cell is always 1
-    (*data_set) = data_mask;
-    celldelay();
-    if (bit) {
-        (*clock_set) = data_mask; // dummy, we don't care but must take constant time
-        celldelay();
-    } else {
-        (*data_clr) = data_mask;
-        celldelay();
-    }
-    // last cell is always 0
-    (*data_clr) = data_mask;
-    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 */;
-    __disable_irq();
-    for (i=0; i<nl3; i++ ) {
-        write(pixels[i]);
-    }
-    __enable_irq();
-    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::setPackedPixels(uint8_t * buffer, uint32_t n) {
-    if (n >= numLEDs) return;
-    memcpy(pixels, buffer, (size_t) (n*3));
-}
-
-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;
-}
--- a/WS2811.h	Sun Jul 28 08:38:18 2013 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +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_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 setPackedPixels(uint8_t * buffer, uint32_t n);
-  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;
-  __IO uint32_t *data_set;
-  __IO uint32_t *clock_set;
-  __IO uint32_t *data_clr;
-  __IO uint32_t *clock_clr;
-  uint32_t clock_mask;
-  uint32_t data_mask;
-  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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WS2812.cpp	Thu Dec 05 15:12:47 2013 +0000
@@ -0,0 +1,82 @@
+// 800 KHz WS2812 driver, kinda.
+//
+// Parameterized and modified to use soft SPI.
+// Jas Strong <jasmine@electronpusher.org>
+// Modified to use hard SPI by Ned Konz <ned@bike-nomad.com>
+/*****************************************************************************/
+
+#include "LedStrip.h"
+#include "WS2812.h"
+
+WS2812::WS2812(int n, PinName mosi, PinName sclk) :
+    LedStrip(n),
+    spi(mosi, NC, sclk)
+{
+#ifdef TARGET_KL25Z
+    spi.format(8, 3);
+#else
+    spi.format(16, 3);
+#endif
+    spi.frequency(800e3 * 16);  // 12.8 MHz => 800KHz bit rate
+}
+
+/*
+ *  These chips use a one-wire protocol based on a sort of NRZ signalling- jas.
+ */
+
+inline void WS2812::writebit(bool bit)
+{
+    if (bit) {
+#ifdef TARGET_KL25Z
+        spi.write(0xff);    // 8 high
+        spi.write(0x00);    // 8 low
+#else
+        spi.write(0xff00);
+#endif
+    } else {
+#ifdef TARGET_KL25Z
+        spi.write(0xe0);    // 3 high, 5 low
+        spi.write(0x00);    // +8 low
+#else
+        spi.write(0xe000);
+#endif
+    }
+}
+
+void WS2812::write(uint8_t byte)
+{
+    writebit(byte & 0x80);
+    writebit(byte & 0x40);
+    writebit(byte & 0x20);
+    writebit(byte & 0x10);
+    writebit(byte & 0x08);
+    writebit(byte & 0x04);
+    writebit(byte & 0x02);
+    writebit(byte & 0x01);
+}
+
+void WS2812::begin(void)
+{
+    blank();
+    show();
+}
+
+void WS2812::blank(void)
+{
+    memset(pixels, 0x00, numPixelBytes());
+}
+
+void WS2812::show(void)
+{
+    uint16_t i, nl3 = numPixelBytes(); // 3 bytes per LED
+    while (guardtime.read_us() < 50)
+        /* spin */;
+    __disable_irq();
+    for (i=0; i<nl3; i++ ) {
+        write(pixels[i]);
+    }
+    __enable_irq();
+    guardtime.reset();
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WS2812.h	Thu Dec 05 15:12:47 2013 +0000
@@ -0,0 +1,42 @@
+// 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
+
+#ifdef TARGET_KL25Z
+#define MOSI_DEFAULT PTD2
+#define SCLK_DEFAULT PTC5
+#else
+#endif
+
+class WS2812 : public LedStrip
+{
+public:
+    WS2812(int n, PinName mosi = MOSI_DEFAULT, PinName sclk = SCLK_DEFAULT);
+    virtual void begin(void);
+    virtual void show(void);
+    virtual void blank(void);
+
+private:
+    SPI spi;            // to do actual communication
+
+    Timer guardtime;
+    uint32_t bogocal;
+
+    void write(uint8_t byte);
+    void writebit(bool bit);
+    void celldelay(void);
+};
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Dec 05 15:12:47 2013 +0000
@@ -0,0 +1,7 @@
+#include "mbed.h"
+#include "WS2812.h"
+
+int main(void)
+{
+    WS2812 lightStrip(60*4, PTD2, PTD3);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Thu Dec 05 15:12:47 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/9c8f0e3462fb
\ No newline at end of file