Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of Adafruit_WS2801 by
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 }