Philip Walne / DotStar

Dependents:   335_project

Fork of DotStar by Hideaki Tai

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DotStar.cpp Source File

DotStar.cpp

00001 /*------------------------------------------------------------------------
00002   Arduino library to control Adafruit Dot Star addressable RGB LEDs.
00003 
00004   Written by Limor Fried and Phil Burgess for Adafruit Industries.
00005 
00006   Adafruit invests time and resources providing this open source code,
00007   please support Adafruit and open-source hardware by purchasing products
00008   from Adafruit!
00009 
00010   ------------------------------------------------------------------------
00011   This file is part of the Adafruit Dot Star library.
00012 
00013   Adafruit Dot Star is free software: you can redistribute it and/or
00014   modify it under the terms of the GNU Lesser General Public License
00015   as published by the Free Software Foundation, either version 3 of
00016   the License, or (at your option) any later version.
00017 
00018   Adafruit Dot Star is distributed in the hope that it will be useful,
00019   but WITHOUT ANY WARRANTY; without even the implied warranty of
00020   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021   GNU Lesser General Public License for more details.
00022 
00023   You should have received a copy of the GNU Lesser General Public
00024   License along with DotStar.  If not, see <http://www.gnu.org/licenses/>.
00025   ------------------------------------------------------------------------*/
00026 
00027 #include "mbed.h"
00028 #include "DotStar.h"
00029 
00030 // Constructor for hardware SPI -- must connect to MOSI, SCK pins
00031 Adafruit_DotStar::Adafruit_DotStar(uint16_t n, PinName miso, PinName mosi, PinName sclk, int hz, uint8_t o)
00032 : numLEDs(n)
00033 , dataPin(USE_HW_SPI)
00034 , clockPin(USE_HW_SPI)
00035 , spi(NULL)
00036 , miso_(miso)
00037 , mosi_(mosi)
00038 , sclk_(sclk)
00039 , data_out(NULL)
00040 , sclk_out(NULL)
00041 , port(Port0)
00042 , port_out(NULL)
00043 , d_mask(0)
00044 , c_mask(0)
00045 , b_use_port(false)
00046 , brightness(0)
00047 , pixels(NULL)
00048 , rOffset(o & 3)
00049 , gOffset((o >> 2) & 3)
00050 , bOffset((o >> 4) & 3)
00051 {
00052     updateLength(n);
00053 }
00054 
00055 // Constructor for 'soft' (bitbang) SPI -- any two pins can be used
00056 Adafruit_DotStar::Adafruit_DotStar(uint16_t n, PinName data, PinName clock, uint8_t o)
00057 : dataPin(data)
00058 , clockPin(clock)
00059 , spi(NULL)
00060 , miso_(NC)
00061 , mosi_(NC)
00062 , sclk_(NC)
00063 , data_out(NULL)
00064 , sclk_out(NULL)
00065 , port(Port0)
00066 , port_out(NULL)
00067 , d_mask(0)
00068 , c_mask(0)
00069 , b_use_port(false)
00070 , brightness(0)
00071 , pixels(NULL)
00072 , rOffset(o & 3)
00073 , gOffset((o >> 2) & 3)
00074 , bOffset((o >> 4) & 3)
00075 {
00076     updateLength(n);
00077 }
00078 
00079 // Constructor for 'soft' (bitbang) SPI -- any two pins can be used
00080 Adafruit_DotStar::Adafruit_DotStar(uint16_t n, PortName p, int dmask, int cmask, uint8_t o)
00081 : dataPin(NC)
00082 , clockPin(NC)
00083 , spi(NULL)
00084 , miso_(NC)
00085 , mosi_(NC)
00086 , sclk_(NC)
00087 , data_out(NULL)
00088 , sclk_out(NULL)
00089 , port(p)
00090 , port_out(NULL)
00091 , d_mask(dmask)
00092 , c_mask(cmask)
00093 , b_use_port(true)
00094 , brightness(0)
00095 , pixels(NULL)
00096 , rOffset(o & 3)
00097 , gOffset((o >> 2) & 3)
00098 , bOffset((o >> 4) & 3)
00099 {
00100     updateLength(n);
00101 }
00102 
00103 Adafruit_DotStar::~Adafruit_DotStar(void) { // Destructor
00104     if(pixels)                free(pixels);
00105     if(dataPin == USE_HW_SPI) hw_spi_end();
00106     else                      sw_spi_end();
00107 }
00108 
00109 void Adafruit_DotStar::begin(void) { // Initialize SPI
00110     if(dataPin == USE_HW_SPI) hw_spi_init();
00111     else                      sw_spi_init();
00112 }
00113 
00114 // Change to hardware SPI -- must connect to MOSI, SCK pins
00115 void Adafruit_DotStar::updatePins(void) {
00116     sw_spi_end();
00117     dataPin = USE_HW_SPI;
00118     hw_spi_init();
00119 }
00120 
00121 // Change to 'soft' (bitbang) SPI -- any two pins can be used
00122 void Adafruit_DotStar::updatePins(PinName data, PinName clock) {
00123     hw_spi_end();
00124     dataPin  = data;
00125     clockPin = clock;
00126     sw_spi_init();
00127 }
00128 
00129 // Length can be changed post-constructor for similar reasons (sketch
00130 // config not hardcoded).  But DON'T use this for "recycling" strip RAM...
00131 // all that reallocation is likely to fragment and eventually fail.
00132 // Instead, set length once to longest strip.
00133 void Adafruit_DotStar::updateLength(uint16_t n) {
00134     if(pixels) free(pixels);
00135     uint16_t bytes = (rOffset == gOffset) ?
00136         n + ((n + 3) / 4) : // MONO: 10 bits/pixel, round up to next byte
00137         n * 3;              // COLOR: 3 bytes/pixel
00138     if((pixels = (uint8_t *)malloc(bytes))) {
00139         numLEDs = n;
00140         clear();
00141     } else {
00142         numLEDs = 0;
00143     }
00144 }
00145 
00146 // SPI STUFF ---------------------------------------------------------------
00147 
00148 void Adafruit_DotStar::hw_spi_init(void) { // Initialize hardware SPI
00149     spi = new SPI(mosi_, miso_, sclk_); // mosi, miso, sclk
00150     spi->format(8, 0);   // 8bit, mode:0
00151     spi->frequency(8000000); // Hz
00152 }
00153 
00154 void Adafruit_DotStar::hw_spi_end(void) { // Stop hardware SPI
00155     if (spi) delete spi;
00156 }
00157 
00158 void Adafruit_DotStar::sw_spi_init(void) { // Init 'soft' (bitbang) SPI
00159     if (b_use_port) {
00160         port_out = new PortOut(port, (d_mask | c_mask));
00161     } else {
00162         data_out = new DigitalOut(dataPin);
00163         sclk_out = new DigitalOut(clockPin);
00164     }
00165 }
00166 
00167 void Adafruit_DotStar::sw_spi_end() { // Stop 'soft' SPI
00168     if (port_out) delete(port_out);
00169     if (data_out) delete(data_out);
00170     if (sclk_out) delete(sclk_out);
00171 }
00172 
00173 //inline void Adafruit_DotStar::sw_spi_out(uint8_t n) { // Bitbang SPI write
00174 //    if (b_use_port) {
00175 //        for(uint8_t i=8; i--; n <<= 1) {
00176 //            int mask = (n & 0x80) ? (d_mask | c_mask) : c_mask;
00177 //            *port_out = mask;
00178 //            *port_out = (mask & ~c_mask);
00179 //        }
00180 //    } else {
00181 //        for(uint8_t i=8; i--; n <<= 1) {
00182 //            if(n & 0x80) *data_out = 1;
00183 //            else         *data_out = 0;
00184 //            *sclk_out = 1;
00185 //            *sclk_out = 0;
00186 //        }
00187 //    }
00188 //}
00189 
00190 /* ISSUE DATA TO LED STRIP -------------------------------------------------
00191 
00192   Although the LED driver has an additional per-pixel 5-bit brightness
00193   setting, it is NOT used or supported here because it's a brain-dead
00194   misfeature that's counter to the whole point of Dot Stars, which is to
00195   have a much faster PWM rate than NeoPixels.  It gates the high-speed
00196   PWM output through a second, much slower PWM (about 400 Hz), rendering
00197   it useless for POV.  This brings NOTHING to the table that can't be
00198   already handled better in one's sketch code.  If you really can't live
00199   without this abomination, you can fork the library and add it for your
00200   own use, but any pull requests for this will NOT be merged, nuh uh!
00201 */
00202 
00203 //inline void Adafruit_DotStar::show() {
00204 //  if(!pixels) return;
00205 //
00206 //    uint8_t *ptr = pixels;            // -> LED data
00207 //    uint16_t n   = numLEDs;              // Counter
00208 //    uint16_t b16 = (uint16_t)brightness; // Type-convert for fixed-point math
00209 //
00210 //    if(dataPin == USE_HW_SPI) {
00211 //      
00212 //      for(size_t i=0; i<4; i++) spi->write(0x00);    // 4 byte start-frame marker
00213 //      if(brightness) {                     // Scale pixel brightness on output
00214 //        for (size_t i=n; i>0; i--) {
00215 //            spi->write(0xFF);                   //  Pixel start
00216 //            for(size_t j=0; j<3; j++) spi->write((*ptr++ * b16) >> 8); // Scale, write RGB
00217 //        }
00218 //      } else {                             // Full brightness (no scaling)
00219 //        for (size_t i=n; i>0; i--) {
00220 //            spi->write(0xFF);                   //  Pixel start
00221 //            for(size_t j=0; j<3; j++) spi->write(*ptr++); // Write R,G,B
00222 //        }
00223 //      }
00224 //      // Four end-frame bytes are seemingly indistinguishable from a white
00225 //      // pixel, and empirical testing suggests it can be left out...but it's
00226 //      // always a good idea to follow the datasheet, in case future hardware
00227 //      // revisions are more strict (e.g. might mandate use of end-frame
00228 //      // before start-frame marker).  i.e. let's not remove this.
00229 //      for(size_t i=0; i<4; i++) spi->write(0xFF);
00230 //
00231 //  } else {                               // Soft (bitbang) SPI
00232 //
00233 //    for(size_t i=0; i<4; i++) sw_spi_out(0);    // Start-frame marker
00234 //    if(brightness) {                     // Scale pixel brightness on output
00235 //      do {                               // For each pixel...
00236 //        sw_spi_out(0xFF);                //  Pixel start
00237 //        for(size_t i=0; i<3; i++) sw_spi_out((*ptr++ * b16) >> 8); // Scale, write
00238 //      } while(--n);
00239 //    } else {                             // Full brightness (no scaling)
00240 //      do {                               // For each pixel...
00241 //        sw_spi_out(0xFF);                //  Pixel start
00242 //        for(size_t i=0; i<3; i++) sw_spi_out(*ptr++); // R,G,B
00243 //      } while(--n);
00244 //    }
00245 //    for(size_t i=0; i<4; i++) sw_spi_out(0xFF); // End-frame marker (see note above)
00246 //  }
00247 //}
00248 
00249 inline void Adafruit_DotStar::clear() { // Write 0s (off) to full pixel buffer
00250     memset(pixels, 0, (rOffset == gOffset) ?
00251         numLEDs + ((numLEDs + 3) / 4) : // MONO: 10 bits/pixel
00252         numLEDs * 3);                   // COLOR: 3 bytes/pixel
00253 }
00254 
00255 // Set pixel color, separate R,G,B values (0-255 ea.)
00256 //inline void Adafruit_DotStar::setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b)
00257 //{
00258 //  if(n < numLEDs) {
00259 //    uint8_t *p = &pixels[n * 3];
00260 //    p[rOffset] = r;
00261 //    p[gOffset] = g;
00262 //    p[bOffset] = b;
00263 //  }
00264 //}
00265 
00266 // Set pixel color, 'packed' RGB value (0x000000 - 0xFFFFFF)
00267 inline void Adafruit_DotStar::setPixelColor(uint16_t n, uint32_t c) {
00268     if(n < numLEDs) {
00269         uint8_t *p = &pixels[n * 3];
00270         p[rOffset] = (uint8_t)(c >> 16);
00271         p[gOffset] = (uint8_t)(c >>  8);
00272         p[bOffset] = (uint8_t)c;
00273     }
00274 }
00275 
00276 // Convert separate R,G,B to packed value
00277 inline uint32_t Adafruit_DotStar::Color(uint8_t r, uint8_t g, uint8_t b) {
00278     return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
00279 }
00280 
00281 // Read color from previously-set pixel, returns packed RGB value.
00282 inline uint32_t Adafruit_DotStar::getPixelColor(uint16_t n) const {
00283     if(n >= numLEDs) return 0;
00284     uint8_t *p = &pixels[n * 3];
00285     return ((uint32_t)p[rOffset] << 16) |
00286            ((uint32_t)p[gOffset] <<  8) |
00287             (uint32_t)p[bOffset];
00288 }
00289 
00290 inline uint16_t Adafruit_DotStar::numPixels(void) { // Ret. strip length
00291     return numLEDs;
00292 }
00293 
00294 // Set global strip brightness.  This does not have an immediate effect;
00295 // must be followed by a call to show().  Not a fan of this...for various
00296 // reasons I think it's better handled in one's sketch, but it's here for
00297 // parity with the NeoPixel library.  Good news is that brightness setting
00298 // in this library is 'non destructive' -- it's applied as color data is
00299 // being issued to the strip, not during setPixel(), and also means that
00300 // getPixelColor() returns the exact value originally stored.
00301 inline void Adafruit_DotStar::setBrightness(uint8_t b) {
00302     // Stored brightness value is different than what's passed.  This
00303     // optimizes the actual scaling math later, allowing a fast 8x8-bit
00304     // multiply and taking the MSB.  'brightness' is a uint8_t, adding 1
00305     // here may (intentionally) roll over...so 0 = max brightness (color
00306     // values are interpreted literally; no scaling), 1 = min brightness
00307     // (off), 255 = just below max brightness.
00308     brightness = b + 1;
00309 }
00310 
00311 inline uint8_t Adafruit_DotStar::getBrightness(void) const {
00312     return brightness - 1; // Reverse above operation
00313 }
00314 
00315 // Return pointer to the library's pixel data buffer.  Use carefully,
00316 // much opportunity for mayhem.  It's mostly for code that needs fast
00317 // transfers, e.g. SD card to LEDs.  Color data is in BGR order.
00318 inline uint8_t *Adafruit_DotStar::getPixels(void) const {
00319     return pixels;
00320 }