The port of adafruit dotstar library for arduino https://github.com/adafruit/Adafruit_DotStar

Files at this revision

API Documentation at this revision

Comitter:
hideakitai
Date:
Wed Apr 06 08:49:21 2016 +0000
Parent:
0:bae97ff743a6
Commit message:
support SPI, PortOut

Changed in this revision

DotStar.cpp Show annotated file Show diff for this revision Revisions of this file
DotStar.h Show annotated file Show diff for this revision Revisions of this file
diff -r bae97ff743a6 -r d09c288b8eb3 DotStar.cpp
--- a/DotStar.cpp	Fri Mar 25 07:41:51 2016 +0000
+++ b/DotStar.cpp	Wed Apr 06 08:49:21 2016 +0000
@@ -24,35 +24,106 @@
   License along with DotStar.  If not, see <http://www.gnu.org/licenses/>.
   ------------------------------------------------------------------------*/
 
+#include "mbed.h"
 #include "DotStar.h"
-// #include <SPI.h>
-
-SPI spi(p5, p6, p7); // mosi, miso, sclk
 
 // Constructor for hardware SPI -- must connect to MOSI, SCK pins
-Adafruit_DotStar::Adafruit_DotStar(uint16_t n, uint8_t o) :
- numLEDs(n), dataPin(p5), brightness(0), pixels(NULL),
- rOffset(o & 3), gOffset((o >> 2) & 3), bOffset((o >> 4) & 3)
+Adafruit_DotStar::Adafruit_DotStar(uint16_t n, PinName miso, PinName mosi, PinName sclk, int hz, uint8_t o)
+: numLEDs(n)
+, dataPin(USE_HW_SPI)
+, clockPin(USE_HW_SPI)
+, spi(NULL)
+, miso_(miso)
+, mosi_(mosi)
+, sclk_(sclk)
+, data_out(NULL)
+, sclk_out(NULL)
+, port(PortA)
+, port_out(NULL)
+, d_mask(0)
+, c_mask(0)
+, b_use_port(false)
+, brightness(0)
+, pixels(NULL)
+, rOffset(o & 3)
+, gOffset((o >> 2) & 3)
+, bOffset((o >> 4) & 3)
 {
-  updateLength(n);
+    updateLength(n);
 }
 
 // Constructor for 'soft' (bitbang) SPI -- any two pins can be used
-Adafruit_DotStar::Adafruit_DotStar(uint16_t n, uint8_t data, uint8_t clock,
-  uint8_t o) :
- dataPin(data), clockPin(clock), brightness(0), pixels(NULL),
- rOffset(o & 3), gOffset((o >> 2) & 3), bOffset((o >> 4) & 3)
+Adafruit_DotStar::Adafruit_DotStar(uint16_t n, PinName data, PinName clock, uint8_t o)
+: dataPin(data)
+, clockPin(clock)
+, spi(NULL)
+, miso_(NC)
+, mosi_(NC)
+, sclk_(NC)
+, data_out(NULL)
+, sclk_out(NULL)
+, port(PortA)
+, port_out(NULL)
+, d_mask(0)
+, c_mask(0)
+, b_use_port(false)
+, brightness(0)
+, pixels(NULL)
+, rOffset(o & 3)
+, gOffset((o >> 2) & 3)
+, bOffset((o >> 4) & 3)
 {
-  updateLength(n);
+    updateLength(n);
+}
+
+// Constructor for 'soft' (bitbang) SPI -- any two pins can be used
+Adafruit_DotStar::Adafruit_DotStar(uint16_t n, PortName p, int dmask, int cmask, uint8_t o)
+: dataPin(NC)
+, clockPin(NC)
+, spi(NULL)
+, miso_(NC)
+, mosi_(NC)
+, sclk_(NC)
+, data_out(NULL)
+, sclk_out(NULL)
+, port(p)
+, port_out(NULL)
+, d_mask(dmask)
+, c_mask(cmask)
+, b_use_port(true)
+, brightness(0)
+, pixels(NULL)
+, rOffset(o & 3)
+, gOffset((o >> 2) & 3)
+, bOffset((o >> 4) & 3)
+{
+    updateLength(n);
 }
 
 Adafruit_DotStar::~Adafruit_DotStar(void) { // Destructor
-  if(pixels)   free(pixels);
-  hw_spi_end();
+    if(pixels)                free(pixels);
+    if(dataPin == USE_HW_SPI) hw_spi_end();
+    else                      sw_spi_end();
 }
 
 void Adafruit_DotStar::begin(void) { // Initialize SPI
-  hw_spi_init();
+    if(dataPin == USE_HW_SPI) hw_spi_init();
+    else                      sw_spi_init();
+}
+
+// Change to hardware SPI -- must connect to MOSI, SCK pins
+void Adafruit_DotStar::updatePins(void) {
+    sw_spi_end();
+    dataPin = USE_HW_SPI;
+    hw_spi_init();
+}
+
+// Change to 'soft' (bitbang) SPI -- any two pins can be used
+void Adafruit_DotStar::updatePins(PinName data, PinName clock) {
+    hw_spi_end();
+    dataPin  = data;
+    clockPin = clock;
+    sw_spi_init();
 }
 
 // Length can be changed post-constructor for similar reasons (sketch
@@ -60,41 +131,61 @@
 // all that reallocation is likely to fragment and eventually fail.
 // Instead, set length once to longest strip.
 void Adafruit_DotStar::updateLength(uint16_t n) {
-  if(pixels) free(pixels);
-  uint16_t bytes = (rOffset == gOffset) ?
-    n + ((n + 3) / 4) : // MONO: 10 bits/pixel, round up to next byte
-    n * 3;              // COLOR: 3 bytes/pixel
-  if((pixels = (uint8_t *)malloc(bytes))) {
-    numLEDs = n;
-    clear();
-  } else {
-    numLEDs = 0;
-  }
+    if(pixels) free(pixels);
+    uint16_t bytes = (rOffset == gOffset) ?
+        n + ((n + 3) / 4) : // MONO: 10 bits/pixel, round up to next byte
+        n * 3;              // COLOR: 3 bytes/pixel
+    if((pixels = (uint8_t *)malloc(bytes))) {
+        numLEDs = n;
+        clear();
+    } else {
+        numLEDs = 0;
+    }
 }
 
 // SPI STUFF ---------------------------------------------------------------
 
 void Adafruit_DotStar::hw_spi_init(void) { // Initialize hardware SPI
-  // SPI.begin();
-  // SPI.setClockDivider((F_CPU + 4000000L) / 8000000L); // 8-ish MHz on Due
-  // SPI.setBitOrder(MSBFIRST);
-  // SPI.setDataMode(SPI_MODE0);   // Clock Polarity: 0, Clock Phase: 0
-
-  spi.format(8, 0);   // 8bit, mode:0
-  spi.frequency(8000000); // Hz
-
+    spi = new SPI(mosi_, miso_, sclk_); // mosi, miso, sclk
+    spi->format(8, 0);   // 8bit, mode:0
+    spi->frequency(8000000); // Hz
 }
 
 void Adafruit_DotStar::hw_spi_end(void) { // Stop hardware SPI
-  // SPI.end();
+    if (spi) delete spi;
+}
+
+void Adafruit_DotStar::sw_spi_init(void) { // Init 'soft' (bitbang) SPI
+    if (b_use_port) {
+        port_out = new PortOut(port, (d_mask | c_mask));
+    } else {
+        data_out = new DigitalOut(dataPin);
+        sclk_out = new DigitalOut(clockPin);
+    }
 }
 
-
-// All other boards have full-featured hardware support for SPI
+void Adafruit_DotStar::sw_spi_end() { // Stop 'soft' SPI
+    if (port_out) delete(port_out);
+    if (data_out) delete(data_out);
+    if (sclk_out) delete(sclk_out);
+}
 
-//#define spi_out(n) (void)spi.write(n)
-// Pipelining reads next byte while current byte is clocked out
-
+//inline void Adafruit_DotStar::sw_spi_out(uint8_t n) { // Bitbang SPI write
+//    if (b_use_port) {
+//        for(uint8_t i=8; i--; n <<= 1) {
+//            int mask = (n & 0x80) ? (d_mask | c_mask) : c_mask;
+//            *port_out = mask;
+//            *port_out = (mask & ~c_mask);
+//        }
+//    } else {
+//        for(uint8_t i=8; i--; n <<= 1) {
+//            if(n & 0x80) *data_out = 1;
+//            else         *data_out = 0;
+//            *sclk_out = 1;
+//            *sclk_out = 0;
+//        }
+//    }
+//}
 
 /* ISSUE DATA TO LED STRIP -------------------------------------------------
 
@@ -109,76 +200,95 @@
   own use, but any pull requests for this will NOT be merged, nuh uh!
 */
 
-void Adafruit_DotStar::show(void) {
-  if(!pixels) return;
-
-    uint8_t *ptr = pixels;            // -> LED data
-    uint16_t n   = numLEDs;              // Counter
-    uint16_t b16 = (uint16_t)brightness; // Type-convert for fixed-point math
+//inline void Adafruit_DotStar::show() {
+//  if(!pixels) return;
+//
+//    uint8_t *ptr = pixels;            // -> LED data
+//    uint16_t n   = numLEDs;              // Counter
+//    uint16_t b16 = (uint16_t)brightness; // Type-convert for fixed-point math
+//
+//    if(dataPin == USE_HW_SPI) {
+//      
+//      for(size_t i=0; i<4; i++) spi->write(0x00);    // 4 byte start-frame marker
+//      if(brightness) {                     // Scale pixel brightness on output
+//        for (size_t i=n; i>0; i--) {
+//            spi->write(0xFF);                   //  Pixel start
+//            for(size_t j=0; j<3; j++) spi->write((*ptr++ * b16) >> 8); // Scale, write RGB
+//        }
+//      } else {                             // Full brightness (no scaling)
+//        for (size_t i=n; i>0; i--) {
+//            spi->write(0xFF);                   //  Pixel start
+//            for(size_t j=0; j<3; j++) spi->write(*ptr++); // Write R,G,B
+//        }
+//      }
+//      // Four end-frame bytes are seemingly indistinguishable from a white
+//      // pixel, and empirical testing suggests it can be left out...but it's
+//      // always a good idea to follow the datasheet, in case future hardware
+//      // revisions are more strict (e.g. might mandate use of end-frame
+//      // before start-frame marker).  i.e. let's not remove this.
+//      for(size_t i=0; i<4; i++) spi->write(0xFF);
+//
+//  } else {                               // Soft (bitbang) SPI
+//
+//    for(size_t i=0; i<4; i++) sw_spi_out(0);    // Start-frame marker
+//    if(brightness) {                     // Scale pixel brightness on output
+//      do {                               // For each pixel...
+//        sw_spi_out(0xFF);                //  Pixel start
+//        for(size_t i=0; i<3; i++) sw_spi_out((*ptr++ * b16) >> 8); // Scale, write
+//      } while(--n);
+//    } else {                             // Full brightness (no scaling)
+//      do {                               // For each pixel...
+//        sw_spi_out(0xFF);                //  Pixel start
+//        for(size_t i=0; i<3; i++) sw_spi_out(*ptr++); // R,G,B
+//      } while(--n);
+//    }
+//    for(size_t i=0; i<4; i++) sw_spi_out(0xFF); // End-frame marker (see note above)
+//  }
+//}
 
-      for(size_t i=0; i<4; i++) spi.write(0x00);    // 4 byte start-frame marker
-      if(brightness) {                     // Scale pixel brightness on output
-        for (size_t i=n; i>0; i--) {
-            spi.write(0xFF);                   //  Pixel start
-            for(size_t j=0; j<3; j++) spi.write((*ptr++ * b16) >> 8); // Scale, write RGB
-        }
-      } else {                             // Full brightness (no scaling)
-        for (size_t i=n; i>0; i--) {
-            spi.write(0xFF);                   //  Pixel start
-            for(size_t j=0; j<3; j++) spi.write(*ptr++); // Write R,G,B
-        }
-      }
-      // Four end-frame bytes are seemingly indistinguishable from a white
-      // pixel, and empirical testing suggests it can be left out...but it's
-      // always a good idea to follow the datasheet, in case future hardware
-      // revisions are more strict (e.g. might mandate use of end-frame
-      // before start-frame marker).  i.e. let's not remove this.
-      for(size_t i=0; i<4; i++) spi.write(0xFF);
-}
-
-void Adafruit_DotStar::clear() { // Write 0s (off) to full pixel buffer
-  memset(pixels, 0, (rOffset == gOffset) ?
-    numLEDs + ((numLEDs + 3) / 4) : // MONO: 10 bits/pixel
-    numLEDs * 3);                   // COLOR: 3 bytes/pixel
+inline void Adafruit_DotStar::clear() { // Write 0s (off) to full pixel buffer
+    memset(pixels, 0, (rOffset == gOffset) ?
+        numLEDs + ((numLEDs + 3) / 4) : // MONO: 10 bits/pixel
+        numLEDs * 3);                   // COLOR: 3 bytes/pixel
 }
 
 // Set pixel color, separate R,G,B values (0-255 ea.)
-void Adafruit_DotStar::setPixelColor(
- uint16_t n, uint8_t r, uint8_t g, uint8_t b) {
-  if(n < numLEDs) {
-    uint8_t *p = &pixels[n * 3];
-    p[rOffset] = r;
-    p[gOffset] = g;
-    p[bOffset] = b;
-  }
-}
+//inline void Adafruit_DotStar::setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b)
+//{
+//  if(n < numLEDs) {
+//    uint8_t *p = &pixels[n * 3];
+//    p[rOffset] = r;
+//    p[gOffset] = g;
+//    p[bOffset] = b;
+//  }
+//}
 
 // Set pixel color, 'packed' RGB value (0x000000 - 0xFFFFFF)
-void Adafruit_DotStar::setPixelColor(uint16_t n, uint32_t c) {
-  if(n < numLEDs) {
-    uint8_t *p = &pixels[n * 3];
-    p[rOffset] = (uint8_t)(c >> 16);
-    p[gOffset] = (uint8_t)(c >>  8);
-    p[bOffset] = (uint8_t)c;
-  }
+inline void Adafruit_DotStar::setPixelColor(uint16_t n, uint32_t c) {
+    if(n < numLEDs) {
+        uint8_t *p = &pixels[n * 3];
+        p[rOffset] = (uint8_t)(c >> 16);
+        p[gOffset] = (uint8_t)(c >>  8);
+        p[bOffset] = (uint8_t)c;
+    }
 }
 
 // Convert separate R,G,B to packed value
-uint32_t Adafruit_DotStar::Color(uint8_t r, uint8_t g, uint8_t b) {
-  return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
+inline uint32_t Adafruit_DotStar::Color(uint8_t r, uint8_t g, uint8_t b) {
+    return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
 }
 
 // Read color from previously-set pixel, returns packed RGB value.
-uint32_t Adafruit_DotStar::getPixelColor(uint16_t n) const {
-  if(n >= numLEDs) return 0;
-  uint8_t *p = &pixels[n * 3];
-  return ((uint32_t)p[rOffset] << 16) |
-         ((uint32_t)p[gOffset] <<  8) |
-          (uint32_t)p[bOffset];
+inline uint32_t Adafruit_DotStar::getPixelColor(uint16_t n) const {
+    if(n >= numLEDs) return 0;
+    uint8_t *p = &pixels[n * 3];
+    return ((uint32_t)p[rOffset] << 16) |
+           ((uint32_t)p[gOffset] <<  8) |
+            (uint32_t)p[bOffset];
 }
 
-uint16_t Adafruit_DotStar::numPixels(void) { // Ret. strip length
-  return numLEDs;
+inline uint16_t Adafruit_DotStar::numPixels(void) { // Ret. strip length
+    return numLEDs;
 }
 
 // Set global strip brightness.  This does not have an immediate effect;
@@ -188,23 +298,23 @@
 // in this library is 'non destructive' -- it's applied as color data is
 // being issued to the strip, not during setPixel(), and also means that
 // getPixelColor() returns the exact value originally stored.
-void Adafruit_DotStar::setBrightness(uint8_t b) {
-  // Stored brightness value is different than what's passed.  This
-  // optimizes the actual scaling math later, allowing a fast 8x8-bit
-  // multiply and taking the MSB.  'brightness' is a uint8_t, adding 1
-  // here may (intentionally) roll over...so 0 = max brightness (color
-  // values are interpreted literally; no scaling), 1 = min brightness
-  // (off), 255 = just below max brightness.
-  brightness = b + 1;
+inline void Adafruit_DotStar::setBrightness(uint8_t b) {
+    // Stored brightness value is different than what's passed.  This
+    // optimizes the actual scaling math later, allowing a fast 8x8-bit
+    // multiply and taking the MSB.  'brightness' is a uint8_t, adding 1
+    // here may (intentionally) roll over...so 0 = max brightness (color
+    // values are interpreted literally; no scaling), 1 = min brightness
+    // (off), 255 = just below max brightness.
+    brightness = b + 1;
 }
 
-uint8_t Adafruit_DotStar::getBrightness(void) const {
-  return brightness - 1; // Reverse above operation
+inline uint8_t Adafruit_DotStar::getBrightness(void) const {
+    return brightness - 1; // Reverse above operation
 }
 
 // Return pointer to the library's pixel data buffer.  Use carefully,
 // much opportunity for mayhem.  It's mostly for code that needs fast
 // transfers, e.g. SD card to LEDs.  Color data is in BGR order.
-uint8_t *Adafruit_DotStar::getPixels(void) const {
-  return pixels;
+inline uint8_t *Adafruit_DotStar::getPixels(void) const {
+    return pixels;
 }
diff -r bae97ff743a6 -r d09c288b8eb3 DotStar.h
--- a/DotStar.h	Fri Mar 25 07:41:51 2016 +0000
+++ b/DotStar.h	Wed Apr 06 08:49:21 2016 +0000
@@ -30,51 +30,130 @@
 #define DOTSTAR_BGR (2 | (1 << 2) | (0 << 4))
 #define DOTSTAR_MONO 0 // Single-color strip WIP DO NOT USE YET
 
+#define USE_HW_SPI NC // Assign this to dataPin to indicate 'hard' SPI
+
+
 class Adafruit_DotStar {
 
- public:
+public:
 
-    Adafruit_DotStar(uint16_t n, uint8_t o=DOTSTAR_BRG);
-    Adafruit_DotStar(uint16_t n, uint8_t d, uint8_t c, uint8_t o=DOTSTAR_BRG);
-   ~Adafruit_DotStar(void);
-  void
-    begin(void),                            // Prime pins/SPI for output
-    clear(),                                // Set all pixel data to zero
-    setBrightness(uint8_t),                 // Set global brightness 0-255
-    setPixelColor(uint16_t n, uint32_t c),
-    setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b),
-    show(void),                             // Issue color data to strip
-    // updatePins(void),                       // Change pin assignments (HW)
-    // updatePins(uint8_t d, uint8_t c),       // Change pin assignments (SW)
-    updateLength(uint16_t n);               // Change length
-  uint32_t
-    Color(uint8_t r, uint8_t g, uint8_t b), // R,G,B to 32-bit color
-    getPixelColor(uint16_t n) const;        // Return 32-bit pixel color
-  uint16_t
-    numPixels(void);                        // Return number of pixels
-  uint8_t
-    getBrightness(void) const,              // Return global brightness
-   *getPixels(void) const;                  // Return pixel data pointer
+    Adafruit_DotStar(uint16_t n, PinName miso, PinName mosi, PinName sclk, int hz = 8000000, uint8_t o=DOTSTAR_BRG);
+    Adafruit_DotStar(uint16_t n, PinName d, PinName c, uint8_t o=DOTSTAR_BRG);
+    Adafruit_DotStar(uint16_t n, PortName p, int d_mask, int c_mask, uint8_t o=DOTSTAR_BRG);
+    ~Adafruit_DotStar(void);
+   
+    void begin(void);                            // Prime pins/SPI for output
+    void clear();                                // Set all pixel data to zero
+    void setBrightness(uint8_t);                 // Set global brightness 0-255
+    void setPixelColor(uint16_t n, uint32_t c);
+    void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b)
+    {
+        if(n < numLEDs) {
+            uint8_t *p = &pixels[n * 3];
+            p[rOffset] = r;
+            p[gOffset] = g;
+            p[bOffset] = b;
+        }
+    }
+    void show(void)                             // Issue color data to strip
+    {
+        if(!pixels) return;
+        
+        uint8_t *ptr = pixels;            // -> LED data
+        uint16_t n   = numLEDs;              // Counter
+        uint16_t b16 = (uint16_t)brightness; // Type-convert for fixed-point math
+        
+        if(dataPin == USE_HW_SPI) {
+          
+            for(size_t i=0; i<4; i++) spi->write(0x00);    // 4 byte start-frame marker
+            if(brightness) {                     // Scale pixel brightness on output
+                for (size_t i=n; i>0; i--) {
+                    spi->write(0xFF);                   //  Pixel start
+                    for(size_t j=0; j<3; j++) spi->write((*ptr++ * b16) >> 8); // Scale, write RGB
+                }
+            } else {                             // Full brightness (no scaling)
+                for (size_t i=n; i>0; i--) {
+                    spi->write(0xFF);                   //  Pixel start
+                    for(size_t j=0; j<3; j++) spi->write(*ptr++); // Write R,G,B
+                }
+            }
+            // Four end-frame bytes are seemingly indistinguishable from a white
+            // pixel, and empirical testing suggests it can be left out...but it's
+            // always a good idea to follow the datasheet, in case future hardware
+            // revisions are more strict (e.g. might mandate use of end-frame
+            // before start-frame marker).  i.e. let's not remove this.
+            for(size_t i=0; i<4; i++) spi->write(0xFF);
+        
+        } else {                               // Soft (bitbang) SPI
+        
+            for(size_t i=0; i<4; i++) sw_spi_out(0);    // Start-frame marker
+            if(brightness) {                     // Scale pixel brightness on output
+                do {                               // For each pixel...
+                    sw_spi_out(0xFF);                //  Pixel start
+                    for(size_t i=0; i<3; i++) sw_spi_out((*ptr++ * b16) >> 8); // Scale, write
+                } while(--n);
+            } else {                             // Full brightness (no scaling)
+                do {                               // For each pixel...
+                    sw_spi_out(0xFF);                //  Pixel start
+                    for(size_t i=0; i<3; i++) sw_spi_out(*ptr++); // R,G,B
+                } while(--n);
+            }
+            for(size_t i=0; i<4; i++) sw_spi_out(0xFF); // End-frame marker (see note above)
+        }
+    }
+    void updatePins(void);                       // Change pin assignments (HW)
+    void updatePins(PinName d, PinName c);       // Change pin assignments (SW)
+    void updateLength(uint16_t n);               // Change length
+    uint32_t Color(uint8_t r, uint8_t g, uint8_t b); // R,G,B to 32-bit color
+    uint32_t getPixelColor(uint16_t n) const;        // Return 32-bit pixel color
+    uint16_t numPixels(void);                        // Return number of pixels
+    uint8_t  getBrightness(void) const;              // Return global brightness
+    uint8_t* getPixels(void) const;                  // Return pixel data pointer
 
  private:
 
-  uint16_t
-    numLEDs;                                // Number of pixels
-  uint8_t
-    dataPin,                                // If soft SPI, data pin #
-    clockPin,                               // If soft SPI, clock pin #
-    brightness,                             // Global brightness setting
-   *pixels,                                 // LED RGB values (3 bytes ea.)
-    rOffset,                                // Index of red in 3-byte pixel
-    gOffset,                                // Index of green byte
-    bOffset;                                // Index of blue byte
-  void
-    hw_spi_init(void),                      // Start hardware SPI
-    hw_spi_end(void);                       // Stop hardware SPI
-    // sw_spi_init(void),                      // Start bitbang SPI
-    // sw_spi_out(uint8_t n),                  // Bitbang SPI write
-    // sw_spi_end(void);                       // Stop bitbang SPI
-
+    uint16_t numLEDs;                                // Number of pixels
+    PinName dataPin;                                // If soft SPI, data pin #
+    PinName clockPin;                               // If soft SPI, clock pin #
+    SPI* spi;
+    PinName miso_;
+    PinName mosi_;
+    PinName sclk_;
+    DigitalOut* data_out;
+    DigitalOut* sclk_out;
+    PortName port;
+    PortOut* port_out;
+    int d_mask;
+    int c_mask;
+    bool b_use_port;
+    uint8_t brightness;                             // Global brightness setting
+    uint8_t* pixels;                                 // LED RGB values (3 bytes ea.)
+    uint8_t rOffset;                                // Index of red in 3-byte pixel
+    uint8_t gOffset;                                // Index of green byte
+    uint8_t bOffset;                                // Index of blue byte
+    
+    void hw_spi_init(void);                      // Start hardware SPI
+    void hw_spi_end(void);                       // Stop hardware SPI
+    void sw_spi_init(void);                      // Start bitbang SPI
+    void sw_spi_end(void);                       // Stop bitbang SPI
+    inline void sw_spi_out(uint8_t n)                  // Bitbang SPI write
+    {
+        if (b_use_port) {
+            for(uint8_t i=8; i--; n <<= 1) {
+                int mask = (n & 0x80) ? (d_mask | c_mask) : c_mask;
+                *port_out = mask;
+                *port_out = (mask & ~c_mask);
+            }
+        } else {
+            for(uint8_t i=8; i--; n <<= 1) {
+                if(n & 0x80) *data_out = 1;
+                else         *data_out = 0;
+                *sclk_out = 1;
+                *sclk_out = 0;
+            }
+        }
+    }
+    
 };
 
 #endif // _ADAFRUIT_DOT_STAR_H_