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.

Revision:
25:751c89f7e654
Parent:
23:33df42ff2541
Child:
26:ac5d0e18c7b6
--- 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