A conversion of the excellent Adafruit WS2801 library for Arduino to work on mbed
Adafruit_WS2801.cpp
- Committer:
- SomeRandomBloke
- Date:
- 2014-02-12
- Revision:
- 2:2fdaa13896a4
- Parent:
- 1:6ff477690983
- Child:
- 3:dfffbd9f8ac6
File content as of revision 2:2fdaa13896a4:
#include "mbed.h" #include "Adafruit_WS2801.h" // Example to control WS2801-based RGB LED Modules in a strand or strip // Written by Adafruit - MIT license /*****************************************************************************/ SPI spi(p16, p15, p13); // mosi, miso, sclk // Constructor for use with hardware SPI (specific clock/data pins): //Adafruit_WS2801::Adafruit_WS2801(uint16_t n, uint8_t order): clkpin(PTD4), datapin(PTA12) //{ // rgb_order = order; // alloc(n); // updatePins(); //} // Constructor for use with arbitrary clock/data pins: Adafruit_WS2801::Adafruit_WS2801(uint16_t n, PinName dpin, PinName cpin, uint8_t order) : clkpin(cpin), datapin(dpin) { rgb_order = order; alloc(n); // updatePins(dpin, cpin); } // Constructor for use with a matrix configuration, specify w, h for size of matrix // assumes configuration where string starts at coordinate 0,0 and continues to w-1,0, w-1,1 // and on to 0,1, 0,2 and on to w-1,2 and so on. Snaking back and forth till the end. // other function calls with provide access to pixels via an x,y coordinate system Adafruit_WS2801::Adafruit_WS2801(uint16_t w, uint16_t h, PinName dpin, PinName cpin, uint8_t order) : clkpin(cpin), datapin(dpin) { rgb_order = order; alloc(w * h); width = w; height = h; // updatePins(dpin, cpin); } // Allocate 3 bytes per pixel, init to RGB 'off' state: void Adafruit_WS2801::alloc(uint16_t n) { begun = false; numLEDs = ((pixels = (uint8_t *)calloc(n, 3)) != NULL) ? n : 0; // for(int bits = 0; bits <= numLEDs*24; bits++) { // spi.write(0x00); // clkpin = 0; // datapin = 0; // clkpin = 1; // } // clkpin = 0; } // via Michael Vogt/neophob: empty constructor is used when strand length // isn't known at compile-time; situations where program config might be // read from internal flash memory or an SD card, or arrive via serial // command. If using this constructor, MUST follow up with updateLength() // and updatePins() to establish the strand length and output pins! // Also, updateOrder() to change RGB vs GRB order (RGB is default). //Adafruit_WS2801::Adafruit_WS2801(void) : clkpin(PTD4), datapin(PTA12) //{ // begun = false; // numLEDs = 0; // pixels = NULL; // rgb_order = WS2801_RGB; // updatePins(); // Must assume hardware SPI until pins are set //} // Release memory (as needed): Adafruit_WS2801::~Adafruit_WS2801(void) { if (pixels != NULL) { free(pixels); } } // Activate hard/soft SPI as appropriate: void Adafruit_WS2801::begin(void) { if( hardwareSPI ) { // Setup the spi for 8 bit data, high steady state clock, // second edge capture, with a 1MHz clock rate spi.format(8,0); spi.frequency(1000000); } else { datapin = 0; clkpin = 0; } begun = true; } // Change pin assignments post-constructor, switching to hardware SPI: void Adafruit_WS2801::updatePins(void) { hardwareSPI = true; datapin = 0; clkpin = 0; } // Change pin assignments post-constructor, using arbitrary pins: //void Adafruit_WS2801::updatePins(PinName dpin, PinName cpin) //{ // Note: any prior clock/data pin directions are left as-is and are // NOT restored as inputs! // datapin = DigitalOut(dpin); // clkpin = DigitalOut(cpin); //} uint16_t Adafruit_WS2801::numPixels(void) { return numLEDs; } // Change strand length (see notes with empty constructor, above): void Adafruit_WS2801::updateLength(uint16_t n) { if(pixels != NULL) free(pixels); // Free existing data (if any) // Allocate new data -- note: ALL PIXELS ARE CLEARED numLEDs = ((pixels = (uint8_t *)calloc(n, 3)) != NULL) ? n : 0; // 'begun' state does not change -- pins retain prior modes } // Change RGB data order (see notes with empty constructor, above): void Adafruit_WS2801::updateOrder(uint8_t order) { rgb_order = order; // Existing LED data, if any, is NOT reformatted to new data order. // Calling function should clear or fill pixel data anew. } void Adafruit_WS2801::show(void) { uint16_t i, nl3 = numLEDs * 3; // 3 bytes per LED if( hardwareSPI ) { for(i=0; i<nl3; i++ ) { spi.write( pixels[i]); } wait_ms(1); // Data is latched by holding clock pin low for 1 millisecond } else { uint8_t bit; // Write 24 bits per pixel: for(i=0; i<nl3; i++ ) { for(bit=0x80; bit; bit >>= 1) { clkpin = 0; datapin = (pixels[i] & bit) ? 1 : 0; clkpin = 1; wait_us(100); } } datapin = 0; clkpin = 0; wait_ms(1); // Data is latched by holding clock pin low for 1 millisecond clkpin = 1; } } // Set pixel color from separate 8-bit R, G, B components: void Adafruit_WS2801::setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b) { if(n < numLEDs) { // Arrays are 0-indexed, thus NOT '<=' uint8_t *p = &pixels[n * 3]; // See notes later regarding color order if(rgb_order == WS2801_RGB) { *p++ = r; *p++ = g; } else { *p++ = g; *p++ = r; } *p++ = b; } } // Set pixel color from separate 8-bit R, G, B components using x,y coordinate system: void Adafruit_WS2801::setPixelColor(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b) { bool evenRow = ((y % 2) == 0); // calculate x offset first uint16_t offset = x % width; if (!evenRow) { offset = (width-1) - offset; } // add y offset offset += y * width; setPixelColor(offset, r, g, b); } // Set pixel color from 'packed' 32-bit RGB value: void Adafruit_WS2801::setPixelColor(uint16_t n, uint32_t c) { if(n < numLEDs) { // Arrays are 0-indexed, thus NOT '<=' uint8_t *p = &pixels[n * 3]; // To keep the show() loop as simple & fast as possible, the // internal color representation is native to different pixel // types. For compatibility with existing code, 'packed' RGB // values passed in or out are always 0xRRGGBB order. if(rgb_order == WS2801_RGB) { *p++ = c >> 16; // Red *p++ = c >> 8; // Green } else { *p++ = c >> 8; // Green *p++ = c >> 16; // Red } *p++ = c; // Blue } } // Set pixel color from 'packed' 32-bit RGB value using x,y coordinate system: void Adafruit_WS2801::setPixelColor(uint16_t x, uint16_t y, uint32_t c) { bool evenRow = ((y % 2) == 0); // calculate x offset first uint16_t offset = x % width; if (!evenRow) { offset = (width-1) - offset; } // add y offset offset += y * width; setPixelColor(offset, c); } // Query color from previously-set pixel (returns packed 32-bit RGB value) uint32_t Adafruit_WS2801::getPixelColor(uint16_t n) { if(n < numLEDs) { uint16_t ofs = n * 3; // To keep the show() loop as simple & fast as possible, the // internal color representation is native to different pixel // types. For compatibility with existing code, 'packed' RGB // values passed in or out are always 0xRRGGBB order. return (rgb_order == WS2801_RGB) ? ((uint32_t)pixels[ofs] << 16) | ((uint16_t) pixels[ofs + 1] << 8) | pixels[ofs + 2] : (pixels[ofs] << 8) | ((uint32_t)pixels[ofs + 1] << 16) | pixels[ofs + 2]; } return 0; // Pixel # is out of bounds }