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.

Dependents:   Multi_WS2811_test

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers WS2811.h Source File

WS2811.h

Go to the documentation of this file.
00001 //! @file WS2811.h
00002 // Mbed library to control WS2801-based RGB LED Strips
00003 // some portions (c) 2011 Jelmer Tiete
00004 // This library is ported from the Arduino implementation of Adafruit Industries
00005 // found at: http://github.com/adafruit/LPD8806
00006 // and their strips: http://www.adafruit.com/products/306
00007 // Released under the MIT License: http://mbed.org/license/mit
00008 //
00009 /*****************************************************************************/
00010 
00011 // Heavily modified by Jas Strong, 2012-10-04
00012 // Changed to use a virtual base class and to use software SPI.
00013 //
00014 // Modified by Ned Konz, December 2013.
00015 // Using three-phase DMA ala Paul Stoffegren's version.
00016 // Example:
00017 // @code
00018 // #include <mbed.h>
00019 // // In one file that includes this one,
00020 // // #define INSTANTIATE_TEMPLATES as non-zero before including this file:
00021 // #define INSTANTIATE_TEMPLATES 1
00022 // #include "WS2811.h"
00023 // // Then declare a template class with the maximum number of LEDs per strip that you will need:
00024 // unsigned const maxLEDs = 30;
00025 // template class WS2811<maxLEDs>;
00026 // // You can reduce typing using a typedef:
00027 // typedef WS2811<maxLEDs> MyWS2811;
00028 // // Later, define instances of this template class, each with up to the maximum number of LEDs:
00029 // MyWS2811 lightStrip1(nLEDs, DATA_OUT_PIN1);
00030 // MyWS2811 lightStrip2(nLEDs, DATA_OUT_PIN2);
00031 // @endcode
00032 
00033 #ifndef MBED_WS2811_H
00034 #define MBED_WS2811_H
00035 
00036 #include "LedStrip.h"
00037 
00038 //
00039 // Configuration
00040 //
00041 
00042 #ifndef WS2811_IO_PORT
00043 #define WS2811_IO_PORT PORTD
00044 #endif
00045 
00046 #ifndef WS2811_IO_GPIO
00047 #define WS2811_IO_GPIO PTD
00048 #endif
00049 
00050 // define WS2811_DEBUG_PIN to identify a pin in WS2811_IOPORT used for debug output
00051 // #define WS2811_DEBUG_PIN 4 /* PTD4 debugOut */
00052 
00053 // Define WS2811_MONITOR_TPM0_PWM as non-zero to monitor PWM timing on PTD0 and PTD1
00054 // PTD0 TPM0/CH0 PWM_1 J2/06
00055 // PTD1 TPM0/CH1 PWM_2 J2/12 (also LED_BLUE)
00056 #define WS2811_MONITOR_TPM0_PWM 0
00057 
00058 extern "C" void DMA0_IRQHandler();
00059 extern "C" void TPM0_IRQHandler();
00060 
00061 template <unsigned MAX_LEDS_PER_STRIP>
00062 class WS2811 : public LedStrip
00063 {
00064 public:
00065     WS2811(unsigned n, unsigned pinNumber)
00066         : LedStrip(n)
00067         , pinMask(1U << pinNumber)
00068     {
00069         enabledPins |= pinMask;
00070         initialized  = false;
00071     }
00072 
00073     virtual void show()
00074     {
00075         uint16_t i, n = numPixels(); // 3 bytes per LED
00076         uint8_t *p = pixels;
00077 
00078         for (i=0; i<n; i++ )
00079         {
00080             writePixel(i, p);
00081             p += 3;
00082         }
00083     }
00084 
00085     virtual void begin()
00086     {
00087         blank();
00088         show();
00089     }
00090 
00091     virtual void blank()
00092     {
00093         std::memset(pixels, 0x00, numPixelBytes());
00094 
00095         std::memset(dmaData.dmaWords, 0x00, sizeof(dmaData.dmaWords));
00096     }
00097 
00098     static void startDMA();
00099     static unsigned maxLEDsPerStrip() { return MAX_LEDS_PER_STRIP; }
00100     static void wait_for_dma_done();
00101 
00102 private:
00103     uint32_t pinMask;
00104 
00105     void writePixel(unsigned n, uint8_t *p)
00106     {
00107         uint32_t *dest = dmaData.dmaWords + n * BITS_PER_RGB;
00108         writeByte(*p++, pinMask, dest + 0); // G
00109         writeByte(*p++, pinMask, dest + 8); // R
00110         writeByte(*p, pinMask, dest + 16); // B
00111     }
00112 
00113     // Class Static:
00114 
00115     static bool initialized;
00116     static uint32_t enabledPins;
00117 
00118     static void writeByte(uint8_t byte, uint32_t mask, uint32_t *dest)
00119     {
00120         for (uint8_t bm = 0x80; bm; bm >>= 1)
00121         {
00122             // MSBit first
00123             if (byte & bm)
00124                 *dest |= mask;
00125             else
00126                 *dest &= ~mask;
00127             dest++;
00128         }
00129     }
00130 
00131     static void hw_init();
00132     static void io_init();
00133     static void clock_init();
00134     static void dma_init();
00135     static void tpm_init();
00136     static void dma_data_init();
00137 
00138     friend void TPM0_IRQHandler();
00139 
00140     static const unsigned DMA_LEADING_ZEROS  = 2;
00141     static const unsigned BITS_PER_RGB       = 24;
00142     static const unsigned DMA_TRAILING_ZEROS = 1;
00143 
00144     struct DMALayout
00145     {
00146         uint32_t start_t1_low[ DMA_LEADING_ZEROS ];
00147         uint32_t dmaWords[ BITS_PER_RGB * MAX_LEDS_PER_STRIP ];
00148         uint32_t trailing_zeros_1[ DMA_TRAILING_ZEROS ];
00149 
00150         uint32_t start_t0_high[ DMA_LEADING_ZEROS - 1 ];
00151         uint32_t allOnes[ BITS_PER_RGB * MAX_LEDS_PER_STRIP ];
00152         uint32_t trailing_zeros_2[ DMA_TRAILING_ZEROS + 1 ];
00153     };
00154 
00155     static DMALayout dmaData;
00156 };
00157 
00158 #endif
00159 
00160 #if INSTANTIATE_TEMPLATES
00161 #include "WS2811.cpp"
00162 #endif
00163