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.
WS2811.h
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
Generated on Wed Jul 13 2022 13:18:58 by 1.7.2