The port of adafruit dotstar library for arduino https://github.com/adafruit/Adafruit_DotStar
Diff: DotStar.cpp
- Revision:
- 1:d09c288b8eb3
- Parent:
- 0:bae97ff743a6
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; }