A conversion of the excellent Adafruit WS2801 library for Arduino to work on mbed

Dependents:   WiFiDipCortex_Cheerlights

Committer:
SomeRandomBloke
Date:
Wed Feb 12 22:05:44 2014 +0000
Revision:
2:2fdaa13896a4
Parent:
1:6ff477690983
Child:
3:dfffbd9f8ac6
Updated to use hardware SPI on SPI0, only tested on WiFiDIPCortex, LPC1347 based board.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
SomeRandomBloke 0:582e1b9c1cc1 1 #include "mbed.h"
SomeRandomBloke 0:582e1b9c1cc1 2 #include "Adafruit_WS2801.h"
SomeRandomBloke 0:582e1b9c1cc1 3
SomeRandomBloke 0:582e1b9c1cc1 4 // Example to control WS2801-based RGB LED Modules in a strand or strip
SomeRandomBloke 0:582e1b9c1cc1 5 // Written by Adafruit - MIT license
SomeRandomBloke 0:582e1b9c1cc1 6 /*****************************************************************************/
SomeRandomBloke 0:582e1b9c1cc1 7
SomeRandomBloke 2:2fdaa13896a4 8 SPI spi(p16, p15, p13); // mosi, miso, sclk
SomeRandomBloke 2:2fdaa13896a4 9
SomeRandomBloke 0:582e1b9c1cc1 10 // Constructor for use with hardware SPI (specific clock/data pins):
SomeRandomBloke 1:6ff477690983 11 //Adafruit_WS2801::Adafruit_WS2801(uint16_t n, uint8_t order): clkpin(PTD4), datapin(PTA12)
SomeRandomBloke 1:6ff477690983 12 //{
SomeRandomBloke 1:6ff477690983 13 // rgb_order = order;
SomeRandomBloke 1:6ff477690983 14 // alloc(n);
SomeRandomBloke 1:6ff477690983 15 // updatePins();
SomeRandomBloke 1:6ff477690983 16 //}
SomeRandomBloke 0:582e1b9c1cc1 17
SomeRandomBloke 0:582e1b9c1cc1 18 // Constructor for use with arbitrary clock/data pins:
SomeRandomBloke 0:582e1b9c1cc1 19 Adafruit_WS2801::Adafruit_WS2801(uint16_t n, PinName dpin, PinName cpin, uint8_t order) : clkpin(cpin), datapin(dpin)
SomeRandomBloke 0:582e1b9c1cc1 20 {
SomeRandomBloke 0:582e1b9c1cc1 21 rgb_order = order;
SomeRandomBloke 0:582e1b9c1cc1 22 alloc(n);
SomeRandomBloke 2:2fdaa13896a4 23
SomeRandomBloke 0:582e1b9c1cc1 24 // updatePins(dpin, cpin);
SomeRandomBloke 0:582e1b9c1cc1 25 }
SomeRandomBloke 0:582e1b9c1cc1 26
SomeRandomBloke 0:582e1b9c1cc1 27 // Constructor for use with a matrix configuration, specify w, h for size of matrix
SomeRandomBloke 0:582e1b9c1cc1 28 // assumes configuration where string starts at coordinate 0,0 and continues to w-1,0, w-1,1
SomeRandomBloke 0:582e1b9c1cc1 29 // and on to 0,1, 0,2 and on to w-1,2 and so on. Snaking back and forth till the end.
SomeRandomBloke 0:582e1b9c1cc1 30 // other function calls with provide access to pixels via an x,y coordinate system
SomeRandomBloke 0:582e1b9c1cc1 31 Adafruit_WS2801::Adafruit_WS2801(uint16_t w, uint16_t h, PinName dpin, PinName cpin, uint8_t order) : clkpin(cpin), datapin(dpin)
SomeRandomBloke 0:582e1b9c1cc1 32 {
SomeRandomBloke 0:582e1b9c1cc1 33 rgb_order = order;
SomeRandomBloke 0:582e1b9c1cc1 34 alloc(w * h);
SomeRandomBloke 0:582e1b9c1cc1 35 width = w;
SomeRandomBloke 0:582e1b9c1cc1 36 height = h;
SomeRandomBloke 0:582e1b9c1cc1 37 // updatePins(dpin, cpin);
SomeRandomBloke 0:582e1b9c1cc1 38 }
SomeRandomBloke 0:582e1b9c1cc1 39
SomeRandomBloke 0:582e1b9c1cc1 40 // Allocate 3 bytes per pixel, init to RGB 'off' state:
SomeRandomBloke 0:582e1b9c1cc1 41 void Adafruit_WS2801::alloc(uint16_t n)
SomeRandomBloke 0:582e1b9c1cc1 42 {
SomeRandomBloke 0:582e1b9c1cc1 43 begun = false;
SomeRandomBloke 0:582e1b9c1cc1 44 numLEDs = ((pixels = (uint8_t *)calloc(n, 3)) != NULL) ? n : 0;
SomeRandomBloke 0:582e1b9c1cc1 45
SomeRandomBloke 2:2fdaa13896a4 46
SomeRandomBloke 2:2fdaa13896a4 47 // for(int bits = 0; bits <= numLEDs*24; bits++) {
SomeRandomBloke 2:2fdaa13896a4 48 // spi.write(0x00);
SomeRandomBloke 2:2fdaa13896a4 49 // clkpin = 0;
SomeRandomBloke 2:2fdaa13896a4 50 // datapin = 0;
SomeRandomBloke 2:2fdaa13896a4 51 // clkpin = 1;
SomeRandomBloke 2:2fdaa13896a4 52 // }
SomeRandomBloke 2:2fdaa13896a4 53 // clkpin = 0;
SomeRandomBloke 0:582e1b9c1cc1 54 }
SomeRandomBloke 0:582e1b9c1cc1 55
SomeRandomBloke 0:582e1b9c1cc1 56 // via Michael Vogt/neophob: empty constructor is used when strand length
SomeRandomBloke 0:582e1b9c1cc1 57 // isn't known at compile-time; situations where program config might be
SomeRandomBloke 0:582e1b9c1cc1 58 // read from internal flash memory or an SD card, or arrive via serial
SomeRandomBloke 0:582e1b9c1cc1 59 // command. If using this constructor, MUST follow up with updateLength()
SomeRandomBloke 0:582e1b9c1cc1 60 // and updatePins() to establish the strand length and output pins!
SomeRandomBloke 0:582e1b9c1cc1 61 // Also, updateOrder() to change RGB vs GRB order (RGB is default).
SomeRandomBloke 1:6ff477690983 62 //Adafruit_WS2801::Adafruit_WS2801(void) : clkpin(PTD4), datapin(PTA12)
SomeRandomBloke 1:6ff477690983 63 //{
SomeRandomBloke 1:6ff477690983 64 // begun = false;
SomeRandomBloke 1:6ff477690983 65 // numLEDs = 0;
SomeRandomBloke 1:6ff477690983 66 // pixels = NULL;
SomeRandomBloke 1:6ff477690983 67 // rgb_order = WS2801_RGB;
SomeRandomBloke 1:6ff477690983 68 // updatePins(); // Must assume hardware SPI until pins are set
SomeRandomBloke 1:6ff477690983 69 //}
SomeRandomBloke 0:582e1b9c1cc1 70
SomeRandomBloke 0:582e1b9c1cc1 71 // Release memory (as needed):
SomeRandomBloke 0:582e1b9c1cc1 72 Adafruit_WS2801::~Adafruit_WS2801(void)
SomeRandomBloke 0:582e1b9c1cc1 73 {
SomeRandomBloke 0:582e1b9c1cc1 74 if (pixels != NULL) {
SomeRandomBloke 0:582e1b9c1cc1 75 free(pixels);
SomeRandomBloke 0:582e1b9c1cc1 76 }
SomeRandomBloke 0:582e1b9c1cc1 77 }
SomeRandomBloke 0:582e1b9c1cc1 78
SomeRandomBloke 0:582e1b9c1cc1 79 // Activate hard/soft SPI as appropriate:
SomeRandomBloke 0:582e1b9c1cc1 80 void Adafruit_WS2801::begin(void)
SomeRandomBloke 0:582e1b9c1cc1 81 {
SomeRandomBloke 2:2fdaa13896a4 82 if( hardwareSPI ) {
SomeRandomBloke 2:2fdaa13896a4 83 // Setup the spi for 8 bit data, high steady state clock,
SomeRandomBloke 2:2fdaa13896a4 84 // second edge capture, with a 1MHz clock rate
SomeRandomBloke 2:2fdaa13896a4 85 spi.format(8,0);
SomeRandomBloke 2:2fdaa13896a4 86 spi.frequency(1000000);
SomeRandomBloke 2:2fdaa13896a4 87 } else {
SomeRandomBloke 2:2fdaa13896a4 88 datapin = 0;
SomeRandomBloke 2:2fdaa13896a4 89 clkpin = 0;
SomeRandomBloke 2:2fdaa13896a4 90 }
SomeRandomBloke 0:582e1b9c1cc1 91 begun = true;
SomeRandomBloke 0:582e1b9c1cc1 92 }
SomeRandomBloke 0:582e1b9c1cc1 93
SomeRandomBloke 0:582e1b9c1cc1 94 // Change pin assignments post-constructor, switching to hardware SPI:
SomeRandomBloke 0:582e1b9c1cc1 95 void Adafruit_WS2801::updatePins(void)
SomeRandomBloke 0:582e1b9c1cc1 96 {
SomeRandomBloke 0:582e1b9c1cc1 97 hardwareSPI = true;
SomeRandomBloke 0:582e1b9c1cc1 98 datapin = 0;
SomeRandomBloke 0:582e1b9c1cc1 99 clkpin = 0;
SomeRandomBloke 0:582e1b9c1cc1 100 }
SomeRandomBloke 2:2fdaa13896a4 101
SomeRandomBloke 0:582e1b9c1cc1 102
SomeRandomBloke 0:582e1b9c1cc1 103 // Change pin assignments post-constructor, using arbitrary pins:
SomeRandomBloke 1:6ff477690983 104 //void Adafruit_WS2801::updatePins(PinName dpin, PinName cpin)
SomeRandomBloke 1:6ff477690983 105 //{
SomeRandomBloke 0:582e1b9c1cc1 106 // Note: any prior clock/data pin directions are left as-is and are
SomeRandomBloke 0:582e1b9c1cc1 107 // NOT restored as inputs!
SomeRandomBloke 0:582e1b9c1cc1 108
SomeRandomBloke 1:6ff477690983 109 // datapin = DigitalOut(dpin);
SomeRandomBloke 1:6ff477690983 110 // clkpin = DigitalOut(cpin);
SomeRandomBloke 1:6ff477690983 111 //}
SomeRandomBloke 0:582e1b9c1cc1 112
SomeRandomBloke 0:582e1b9c1cc1 113 uint16_t Adafruit_WS2801::numPixels(void)
SomeRandomBloke 0:582e1b9c1cc1 114 {
SomeRandomBloke 0:582e1b9c1cc1 115 return numLEDs;
SomeRandomBloke 0:582e1b9c1cc1 116 }
SomeRandomBloke 0:582e1b9c1cc1 117
SomeRandomBloke 0:582e1b9c1cc1 118 // Change strand length (see notes with empty constructor, above):
SomeRandomBloke 0:582e1b9c1cc1 119 void Adafruit_WS2801::updateLength(uint16_t n)
SomeRandomBloke 0:582e1b9c1cc1 120 {
SomeRandomBloke 0:582e1b9c1cc1 121 if(pixels != NULL) free(pixels); // Free existing data (if any)
SomeRandomBloke 0:582e1b9c1cc1 122 // Allocate new data -- note: ALL PIXELS ARE CLEARED
SomeRandomBloke 0:582e1b9c1cc1 123 numLEDs = ((pixels = (uint8_t *)calloc(n, 3)) != NULL) ? n : 0;
SomeRandomBloke 0:582e1b9c1cc1 124 // 'begun' state does not change -- pins retain prior modes
SomeRandomBloke 0:582e1b9c1cc1 125 }
SomeRandomBloke 0:582e1b9c1cc1 126
SomeRandomBloke 0:582e1b9c1cc1 127 // Change RGB data order (see notes with empty constructor, above):
SomeRandomBloke 0:582e1b9c1cc1 128 void Adafruit_WS2801::updateOrder(uint8_t order)
SomeRandomBloke 0:582e1b9c1cc1 129 {
SomeRandomBloke 0:582e1b9c1cc1 130 rgb_order = order;
SomeRandomBloke 0:582e1b9c1cc1 131 // Existing LED data, if any, is NOT reformatted to new data order.
SomeRandomBloke 0:582e1b9c1cc1 132 // Calling function should clear or fill pixel data anew.
SomeRandomBloke 0:582e1b9c1cc1 133 }
SomeRandomBloke 0:582e1b9c1cc1 134
SomeRandomBloke 0:582e1b9c1cc1 135 void Adafruit_WS2801::show(void)
SomeRandomBloke 0:582e1b9c1cc1 136 {
SomeRandomBloke 0:582e1b9c1cc1 137 uint16_t i, nl3 = numLEDs * 3; // 3 bytes per LED
SomeRandomBloke 2:2fdaa13896a4 138
SomeRandomBloke 2:2fdaa13896a4 139 if( hardwareSPI ) {
SomeRandomBloke 2:2fdaa13896a4 140 for(i=0; i<nl3; i++ ) {
SomeRandomBloke 2:2fdaa13896a4 141 spi.write( pixels[i]);
SomeRandomBloke 2:2fdaa13896a4 142 }
SomeRandomBloke 2:2fdaa13896a4 143 wait_ms(1); // Data is latched by holding clock pin low for 1 millisecond
SomeRandomBloke 2:2fdaa13896a4 144 } else {
SomeRandomBloke 2:2fdaa13896a4 145 uint8_t bit;
SomeRandomBloke 0:582e1b9c1cc1 146
SomeRandomBloke 2:2fdaa13896a4 147 // Write 24 bits per pixel:
SomeRandomBloke 2:2fdaa13896a4 148 for(i=0; i<nl3; i++ ) {
SomeRandomBloke 2:2fdaa13896a4 149 for(bit=0x80; bit; bit >>= 1) {
SomeRandomBloke 2:2fdaa13896a4 150 clkpin = 0;
SomeRandomBloke 2:2fdaa13896a4 151 datapin = (pixels[i] & bit) ? 1 : 0;
SomeRandomBloke 2:2fdaa13896a4 152 clkpin = 1;
SomeRandomBloke 2:2fdaa13896a4 153 wait_us(100);
SomeRandomBloke 2:2fdaa13896a4 154 }
SomeRandomBloke 0:582e1b9c1cc1 155 }
SomeRandomBloke 2:2fdaa13896a4 156 datapin = 0;
SomeRandomBloke 0:582e1b9c1cc1 157
SomeRandomBloke 2:2fdaa13896a4 158 clkpin = 0;
SomeRandomBloke 2:2fdaa13896a4 159 wait_ms(1); // Data is latched by holding clock pin low for 1 millisecond
SomeRandomBloke 2:2fdaa13896a4 160 clkpin = 1;
SomeRandomBloke 2:2fdaa13896a4 161 }
SomeRandomBloke 0:582e1b9c1cc1 162 }
SomeRandomBloke 0:582e1b9c1cc1 163
SomeRandomBloke 0:582e1b9c1cc1 164 // Set pixel color from separate 8-bit R, G, B components:
SomeRandomBloke 0:582e1b9c1cc1 165 void Adafruit_WS2801::setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b)
SomeRandomBloke 0:582e1b9c1cc1 166 {
SomeRandomBloke 0:582e1b9c1cc1 167 if(n < numLEDs) { // Arrays are 0-indexed, thus NOT '<='
SomeRandomBloke 0:582e1b9c1cc1 168 uint8_t *p = &pixels[n * 3];
SomeRandomBloke 0:582e1b9c1cc1 169 // See notes later regarding color order
SomeRandomBloke 0:582e1b9c1cc1 170 if(rgb_order == WS2801_RGB) {
SomeRandomBloke 0:582e1b9c1cc1 171 *p++ = r;
SomeRandomBloke 0:582e1b9c1cc1 172 *p++ = g;
SomeRandomBloke 0:582e1b9c1cc1 173 } else {
SomeRandomBloke 0:582e1b9c1cc1 174 *p++ = g;
SomeRandomBloke 0:582e1b9c1cc1 175 *p++ = r;
SomeRandomBloke 0:582e1b9c1cc1 176 }
SomeRandomBloke 0:582e1b9c1cc1 177 *p++ = b;
SomeRandomBloke 0:582e1b9c1cc1 178 }
SomeRandomBloke 0:582e1b9c1cc1 179 }
SomeRandomBloke 0:582e1b9c1cc1 180
SomeRandomBloke 0:582e1b9c1cc1 181 // Set pixel color from separate 8-bit R, G, B components using x,y coordinate system:
SomeRandomBloke 0:582e1b9c1cc1 182 void Adafruit_WS2801::setPixelColor(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b)
SomeRandomBloke 0:582e1b9c1cc1 183 {
SomeRandomBloke 0:582e1b9c1cc1 184 bool evenRow = ((y % 2) == 0);
SomeRandomBloke 0:582e1b9c1cc1 185 // calculate x offset first
SomeRandomBloke 0:582e1b9c1cc1 186 uint16_t offset = x % width;
SomeRandomBloke 0:582e1b9c1cc1 187 if (!evenRow) {
SomeRandomBloke 0:582e1b9c1cc1 188 offset = (width-1) - offset;
SomeRandomBloke 0:582e1b9c1cc1 189 }
SomeRandomBloke 0:582e1b9c1cc1 190 // add y offset
SomeRandomBloke 0:582e1b9c1cc1 191 offset += y * width;
SomeRandomBloke 0:582e1b9c1cc1 192 setPixelColor(offset, r, g, b);
SomeRandomBloke 0:582e1b9c1cc1 193 }
SomeRandomBloke 0:582e1b9c1cc1 194
SomeRandomBloke 0:582e1b9c1cc1 195 // Set pixel color from 'packed' 32-bit RGB value:
SomeRandomBloke 0:582e1b9c1cc1 196 void Adafruit_WS2801::setPixelColor(uint16_t n, uint32_t c)
SomeRandomBloke 0:582e1b9c1cc1 197 {
SomeRandomBloke 0:582e1b9c1cc1 198 if(n < numLEDs) { // Arrays are 0-indexed, thus NOT '<='
SomeRandomBloke 0:582e1b9c1cc1 199 uint8_t *p = &pixels[n * 3];
SomeRandomBloke 0:582e1b9c1cc1 200 // To keep the show() loop as simple & fast as possible, the
SomeRandomBloke 0:582e1b9c1cc1 201 // internal color representation is native to different pixel
SomeRandomBloke 0:582e1b9c1cc1 202 // types. For compatibility with existing code, 'packed' RGB
SomeRandomBloke 0:582e1b9c1cc1 203 // values passed in or out are always 0xRRGGBB order.
SomeRandomBloke 0:582e1b9c1cc1 204 if(rgb_order == WS2801_RGB) {
SomeRandomBloke 0:582e1b9c1cc1 205 *p++ = c >> 16; // Red
SomeRandomBloke 0:582e1b9c1cc1 206 *p++ = c >> 8; // Green
SomeRandomBloke 0:582e1b9c1cc1 207 } else {
SomeRandomBloke 0:582e1b9c1cc1 208 *p++ = c >> 8; // Green
SomeRandomBloke 0:582e1b9c1cc1 209 *p++ = c >> 16; // Red
SomeRandomBloke 0:582e1b9c1cc1 210 }
SomeRandomBloke 0:582e1b9c1cc1 211 *p++ = c; // Blue
SomeRandomBloke 0:582e1b9c1cc1 212 }
SomeRandomBloke 0:582e1b9c1cc1 213 }
SomeRandomBloke 0:582e1b9c1cc1 214
SomeRandomBloke 0:582e1b9c1cc1 215 // Set pixel color from 'packed' 32-bit RGB value using x,y coordinate system:
SomeRandomBloke 0:582e1b9c1cc1 216 void Adafruit_WS2801::setPixelColor(uint16_t x, uint16_t y, uint32_t c)
SomeRandomBloke 0:582e1b9c1cc1 217 {
SomeRandomBloke 0:582e1b9c1cc1 218 bool evenRow = ((y % 2) == 0);
SomeRandomBloke 0:582e1b9c1cc1 219 // calculate x offset first
SomeRandomBloke 0:582e1b9c1cc1 220 uint16_t offset = x % width;
SomeRandomBloke 0:582e1b9c1cc1 221 if (!evenRow) {
SomeRandomBloke 0:582e1b9c1cc1 222 offset = (width-1) - offset;
SomeRandomBloke 0:582e1b9c1cc1 223 }
SomeRandomBloke 0:582e1b9c1cc1 224 // add y offset
SomeRandomBloke 0:582e1b9c1cc1 225 offset += y * width;
SomeRandomBloke 0:582e1b9c1cc1 226 setPixelColor(offset, c);
SomeRandomBloke 0:582e1b9c1cc1 227 }
SomeRandomBloke 0:582e1b9c1cc1 228
SomeRandomBloke 0:582e1b9c1cc1 229 // Query color from previously-set pixel (returns packed 32-bit RGB value)
SomeRandomBloke 0:582e1b9c1cc1 230 uint32_t Adafruit_WS2801::getPixelColor(uint16_t n)
SomeRandomBloke 0:582e1b9c1cc1 231 {
SomeRandomBloke 0:582e1b9c1cc1 232 if(n < numLEDs) {
SomeRandomBloke 0:582e1b9c1cc1 233 uint16_t ofs = n * 3;
SomeRandomBloke 0:582e1b9c1cc1 234 // To keep the show() loop as simple & fast as possible, the
SomeRandomBloke 0:582e1b9c1cc1 235 // internal color representation is native to different pixel
SomeRandomBloke 0:582e1b9c1cc1 236 // types. For compatibility with existing code, 'packed' RGB
SomeRandomBloke 0:582e1b9c1cc1 237 // values passed in or out are always 0xRRGGBB order.
SomeRandomBloke 0:582e1b9c1cc1 238 return (rgb_order == WS2801_RGB) ?
SomeRandomBloke 0:582e1b9c1cc1 239 ((uint32_t)pixels[ofs] << 16) | ((uint16_t) pixels[ofs + 1] << 8) | pixels[ofs + 2] :
SomeRandomBloke 0:582e1b9c1cc1 240 (pixels[ofs] << 8) | ((uint32_t)pixels[ofs + 1] << 16) | pixels[ofs + 2];
SomeRandomBloke 0:582e1b9c1cc1 241 }
SomeRandomBloke 0:582e1b9c1cc1 242
SomeRandomBloke 0:582e1b9c1cc1 243 return 0; // Pixel # is out of bounds
SomeRandomBloke 0:582e1b9c1cc1 244 }