A conversion of the excellent Adafruit WS2801 library for Arduino to work on mbed
Adafruit_WS2801.cpp
- Committer:
- SomeRandomBloke
- Date:
- 2013-03-08
- Revision:
- 0:582e1b9c1cc1
- Child:
- 1:6ff477690983
File content as of revision 0:582e1b9c1cc1:
#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 /*****************************************************************************/ // 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++) { 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 == true) { startSPI(); } else { // pinMode(datapin, OUTPUT); // pinMode(clkpin , OUTPUT); } begun = true; } // Change pin assignments post-constructor, switching to hardware SPI: void Adafruit_WS2801::updatePins(void) { hardwareSPI = true; datapin = 0; clkpin = 0; // If begin() was previously invoked, init the SPI hardware now: if(begun == true) startSPI(); // Otherwise, SPI is NOT initted until begin() is explicitly called. // Note: any prior clock/data pin directions are left as-is and are // NOT restored as inputs! } // Change pin assignments post-constructor, using arbitrary pins: void Adafruit_WS2801::updatePins(PinName dpin, PinName cpin) { if(begun == true) { // If begin() was previously invoked... // If previously using hardware SPI, turn that off: // if(hardwareSPI == true) SPI.end(); // Regardless, now enable output on 'soft' SPI pins: // pinMode(dpin, OUTPUT); // pinMode(cpin, OUTPUT); } // Otherwise, pins are not set to outputs until begin() is called. // Note: any prior clock/data pin directions are left as-is and are // NOT restored as inputs! hardwareSPI = false; datapin = dpin; clkpin = cpin; // clkport = portOutputRegister(digitalPinToPort(cpin)); // clkpinmask = digitalPinToBitMask(cpin); // dataport = portOutputRegister(digitalPinToPort(dpin)); // datapinmask = digitalPinToBitMask(dpin); } // Enable SPI hardware and set up protocol details: void Adafruit_WS2801::startSPI(void) { // SPI.begin(); // SPI.setBitOrder(MSBFIRST); // SPI.setDataMode(SPI_MODE0); // SPI.setClockDivider(SPI_CLOCK_DIV16); // 1 MHz max, else flicker } 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 uint8_t bit; // Write 24 bits per pixel: // if(hardwareSPI) { // for(i=0; i<nl3; i++) { // SPDR = pixels[i]; // while(!(SPSR & (1<<SPIF))); // } // } else { /* for(int LED_number = 0 ; LED_number < _STRIP_LENGTH ; LED_number++) { if(_level != 100) { int R = ((strip_colors[LED_number] & 0x00ff0000) >> 16)*_level/100; int G = ((strip_colors[LED_number] & 0x0000ff00) >> 8)*_level/100; int B = (strip_colors[LED_number] & 0x000000ff)*_level/100; strip_colors_leveled[LED_number] = (R << 16)|(G << 8)|B; } else strip_colors_leveled[LED_number] = strip_colors[LED_number]; int this_led_color = strip_colors_leveled[LED_number]; //24 bits of color data for(char color_bit = 23 ; color_bit != 255 ; color_bit--) { _CKI = 0; mask = 1 << color_bit; if(this_led_color & mask)_SDI = 1; else _SDI = 0; _CKI = 1; //Data is latched when clock goes high } } _CKI = 0; wait_us(_reset_delay); //Wait for 1ms to go into reset */ for(i=0; i<nl3; i++ ) { for(bit=0x80; bit; bit >>= 1) { clkpin = 0; if(pixels[i] & bit) datapin = 1; else datapin = 0; clkpin = 1; } } // } wait_ms(1); // Data is latched by holding clock pin low for 1 millisecond } // 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 }