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 Jan 02 19:42:14 2014 +0000
Parent:
24:feb1dae0403a
Child:
26:ac5d0e18c7b6
Commit message:
added second light strip to demo.

Changed in this revision

WS2811.cpp 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
--- a/WS2811.cpp	Thu Jan 02 11:26:44 2014 +0000
+++ b/WS2811.cpp	Thu Jan 02 19:42:14 2014 +0000
@@ -54,15 +54,13 @@
 static const uint32_t tpm_p0_period = NSEC_TO_TICKS(CLK_NSEC / 3);
 static const uint32_t tpm_p1_period = NSEC_TO_TICKS(CLK_NSEC * 2 / 3);
 
-enum DMA_MUX_SRC
-{
+enum DMA_MUX_SRC {
     DMA_MUX_SRC_TPM0_CH_0     = 24,
     DMA_MUX_SRC_TPM0_CH_1,
     DMA_MUX_SRC_TPM0_Overflow = 54,
 };
 
-enum DMA_CHAN
-{
+enum DMA_CHAN {
     DMA_CHAN_START = 0,
     DMA_CHAN_0_LOW = 1,
     DMA_CHAN_1_LOW = 2,
@@ -86,8 +84,7 @@
 #define BITS_PER_RGB       24
 #define DMA_TRAILING_ZEROS 1
 
-static struct
-{
+static struct {
     uint32_t start_t1_low[ DMA_LEADING_ZEROS ];
     uint32_t dmaWords[ BITS_PER_RGB * MAX_LEDS_PER_STRIP ];
     uint32_t trailing_zeros_1[ DMA_TRAILING_ZEROS ];
@@ -97,7 +94,7 @@
     uint32_t trailing_zeros_2[ DMA_TRAILING_ZEROS + 1 ];
 } dmaData WORD_ALIGNED;
 
-// class static 
+// class static
 bool WS2811::is_dma_done()
 {
     return dma_done;
@@ -148,11 +145,9 @@
 void WS2811::io_init()
 {
     uint32_t m = 1;
-    for (uint32_t i = 0; i < 32; i++)
-    {
+    for (uint32_t i = 0; i < 32; i++) {
         // set up each pin
-        if (m & enabledPins)
-        {
+        if (m & enabledPins) {
             IO_PORT->PCR[i] = PORT_PCR_MUX(1) // GPIO
                               | PORT_PCR_DSE_MASK; // high drive strength
         }
@@ -235,11 +230,13 @@
 // class static
 void WS2811::startDMA()
 {
+    hw_init();
+
     DMA_Type volatile * dma   = DMA0;
     TPM_Type volatile *tpm   = TPM0;
     uint32_t nBytes = sizeof(dmaData.start_t1_low)
-        + sizeof(dmaData.dmaWords)
-        + sizeof(dmaData.trailing_zeros_1);
+                      + sizeof(dmaData.dmaWords)
+                      + sizeof(dmaData.trailing_zeros_1);
 
     tpm->SC &= ~TPM_SC_CMOD_MASK; // disable internal clocking
     tpm->CNT = tpm_p0_period - 2 ;
@@ -267,20 +264,18 @@
     dma->DMA[DMA_CHAN_1_LOW].SAR     = (uint32_t)(void*)dmaData.start_t1_low; // set source address
     dma->DMA[DMA_CHAN_1_LOW].DSR_BCR = DMA_DSR_BCR_BCR_MASK & nBytes; // length of transfer in bytes
 
-    dma->DMA[DMA_CHAN_0_LOW].DAR 
-        = dma->DMA[DMA_CHAN_1_LOW].DAR 
-        = dma->DMA[DMA_CHAN_START].DAR 
+    dma->DMA[DMA_CHAN_0_LOW].DAR
+    = dma->DMA[DMA_CHAN_1_LOW].DAR
+      = dma->DMA[DMA_CHAN_START].DAR
         = (uint32_t)(void*)&IO_GPIO->PDOR;
 
     // wait until done
-    while (!is_dma_done())
-    {
+    while (!is_dma_done()) {
         __WFI();
     }
-    
+
     // ensure sufficient guard time
-    while (guardtime.read_us() < 50)
-    {
+    while (guardtime.read_us() < 50) {
         __NOP();
     }
 
@@ -324,8 +319,7 @@
 // class static
 void WS2811::writeByte(uint8_t byte, uint32_t mask, uint32_t *dest)
 {
-    for (uint8_t bm = 0x80; bm; bm >>= 1)
-    {
+    for (uint8_t bm = 0x80; bm; bm >>= 1) {
         // MSBit first
         if (byte & bm)
             *dest |= mask;
@@ -347,7 +341,7 @@
 
 #if DEBUG
     for (unsigned i = DMA_LEADING_ZEROS; i < DMA_LEADING_ZEROS + BITS_PER_RGB; i++)
-            dmaData.dmaWords[i] = DEBUG_MASK;
+        dmaData.dmaWords[i] = DEBUG_MASK;
 #else
     memset(dmaData.dmaWords, 0x00, sizeof(dmaData.dmaWords));
 #endif
@@ -355,18 +349,14 @@
 
 void WS2811::show()
 {
-    hw_init();
 
     uint16_t i, n = numPixels(); // 3 bytes per LED
     uint8_t *p = pixels;
 
-    for (i=0; i<n; i++ )
-    {
+    for (i=0; i<n; i++ ) {
         writePixel(i, p);
         p += 3;
     }
-
-    startDMA();
 }
 
 extern "C" void DMA0_IRQHandler()
@@ -375,20 +365,17 @@
     TPM_Type volatile *tpm   = TPM0;
 
     uint32_t db = dma->DMA[DMA_CHAN_START].DSR_BCR;
-    if (db & DMA_DSR_BCR_DONE_MASK)
-    {
+    if (db & DMA_DSR_BCR_DONE_MASK) {
         dma->DMA[DMA_CHAN_START].DSR_BCR = DMA_DSR_BCR_DONE_MASK;  // clear/reset DMA status
     }
 
     db = dma->DMA[DMA_CHAN_0_LOW].DSR_BCR;
-    if (db & DMA_DSR_BCR_DONE_MASK)
-    {
+    if (db & DMA_DSR_BCR_DONE_MASK) {
         dma->DMA[DMA_CHAN_0_LOW].DSR_BCR = DMA_DSR_BCR_DONE_MASK;  // clear/reset DMA status
     }
 
     db = dma->DMA[DMA_CHAN_1_LOW].DSR_BCR;
-    if (db & DMA_DSR_BCR_DONE_MASK)
-    {
+    if (db & DMA_DSR_BCR_DONE_MASK) {
         dma->DMA[DMA_CHAN_1_LOW].DSR_BCR = DMA_DSR_BCR_DONE_MASK; // clear/reset DMA status
         dma_done                         = true;
         tpm->SC &= ~TPM_SC_CMOD_MASK; // disable internal clocking
--- a/main.cpp	Thu Jan 02 11:26:44 2014 +0000
+++ b/main.cpp	Thu Jan 02 19:42:14 2014 +0000
@@ -5,6 +5,7 @@
 
 // per LED: 3 * 20 mA = 60mA max
 // 60 LEDs: 60 * 60mA = 3600 mA max
+// 120 LEDs: 7200 mA max
 unsigned const nLEDs = MAX_LEDS_PER_STRIP;
 
 // I/O pin usage
@@ -13,24 +14,26 @@
 // PTD2 data output
 // PTD3 debug output
 
-unsigned const DATA_OUT_PIN = 2; // PTD2
+unsigned const DATA_OUT_PIN1 = 2; // PTD2
+unsigned const DATA_OUT_PIN2 = 3; // PTD3
 
 Serial pc(USBTX, USBRX);
+Timer timeRunning;
 
 TSISensor touchSensor;
 Ticker touchTicker;
 float touchPercentage;
-float const minBrite = 0.1;
-float const maxBrite = 0.7;
+unsigned frames;
+
+float const minBrite = 0.2;
+float const maxBrite = 0.5;
 float brite;
 
 void readTouchSensor()
 {
     touchPercentage *= 0.9;
     touchPercentage += touchSensor.readPercentage() * 0.1;
-    brite = maxBrite * touchPercentage;
-    if (brite < minBrite)
-        brite = minBrite;
+    brite = minBrite + (maxBrite - minBrite) * touchPercentage;
 }
 
 // @brief sets different colors in each of the LEDs of a strip
@@ -62,28 +65,28 @@
 int main(void)
 {
     pc.baud(115200);
-    WS2811 lightStrip(nLEDs, DATA_OUT_PIN);
+    WS2811 lightStrip1(nLEDs, DATA_OUT_PIN1);
+    WS2811 lightStrip2(nLEDs, DATA_OUT_PIN2);
 
     touchTicker.attach(&readTouchSensor, 0.1);
-    lightStrip.begin();
+    lightStrip1.begin();
+    lightStrip2.begin();
 
     float rainbowPeriod = 1 * 1.0e6; // usec
     float sat = 1.0;
 
-    Timer timeRunning;
     timeRunning.start();
     bool printed = false;
-    unsigned frames = 0;
 
     uint8_t r =0;
     uint8_t g =0;
     uint8_t b =0;
     for (;;) {
-        if (r < 255)
+        if (r < 40)
             r++;
-        else if (g < 255)
+        else if (g < 40)
             g++;
-        else if (b < 255)
+        else if (b < 40)
             b++;
         else {
             unsigned running = timeRunning.read_us();
@@ -92,7 +95,10 @@
         }
 
         wait(0.1);
-        showSolidColor(lightStrip, r, g, b);
+        showSolidColor(lightStrip1, r, g, b);
+        showSolidColor(lightStrip2, r, g, b);
+        WS2811::startDMA();
+
         frames++;
     }
 
@@ -106,7 +112,10 @@
             pc.printf("%u frames in %u usec = %u frames / sec\r\n", frames, running, frames * 1000000 / running);
             printed = true;
         }
-        showRainbow(lightStrip, sat, brite, hueShift);
+        showRainbow(lightStrip1, sat, brite, hueShift);
+        showRainbow(lightStrip2, sat, brite, hueShift + 0.5);
+        WS2811::startDMA();
+
         frames ++;
     }
 }