A conversion of the excellent Adafruit WS2801 library for Arduino to work on mbed
Diff: Adafruit_WS2801.cpp
- Revision:
- 0:582e1b9c1cc1
- Child:
- 1:6ff477690983
diff -r 000000000000 -r 582e1b9c1cc1 Adafruit_WS2801.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adafruit_WS2801.cpp Fri Mar 08 08:49:04 2013 +0000 @@ -0,0 +1,285 @@ +#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 +}