This is a fork of Adafruit_WS2801 found http://developer.mbed.org/users/SomeRandomBloke/code/Adafruit_WS2801/ It was the work of SomeRandomBloke, and I changed some baked in settings to work with the STM32F401RE.

Fork of Adafruit_WS2801 by Andrew Lindsay

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Adafruit_WS2801.cpp Source File

Adafruit_WS2801.cpp

00001 #include "mbed.h"
00002 #include "Adafruit_WS2801.h"
00003 
00004 
00005 // Example to control WS2801-based RGB LED Modules in a strand or strip
00006 // Written by Adafruit - MIT license
00007 /*****************************************************************************/
00008 
00009 SPI spi(SPI_MOSI, SPI_MISO, SPI_SCK); // mosi, miso, sclk
00010 
00011 // Constructor for use with hardware SPI (specific clock/data pins):
00012 /*Adafruit_WS2801::Adafruit_WS2801(uint16_t n, uint8_t order): clkpin(PTD4), datapin(PTA12)
00013 {
00014     rgb_order = order;
00015     alloc(n);
00016     updatePins();
00017 }*/
00018 
00019 // Constructor for use with arbitrary clock/data pins:
00020 Adafruit_WS2801::Adafruit_WS2801(int16_t n, PinName dpin, PinName cpin, uint8_t order) 
00021     : clkpin(cpin), datapin(dpin)
00022 {
00023     rgb_order = order;
00024     alloc(n);
00025     width = 1;
00026     height = n;
00027     hardwareSPI = false;
00028 //  updatePins(dpin, cpin);
00029 }
00030 
00031 // Constructor for use with a matrix configuration, specify w, h for size of matrix
00032 // assumes configuration where string starts at coordinate 0,0 and continues to w-1,0, w-1,1
00033 // and on to 0,1, 0,2 and on to w-1,2 and so on. Snaking back and forth till the end.
00034 // other function calls with provide access to pixels via an x,y coordinate system
00035 Adafruit_WS2801::Adafruit_WS2801(int16_t w, int16_t h, PinName dpin, PinName cpin, uint8_t order) 
00036     : clkpin(cpin), datapin(dpin)
00037 {
00038     rgb_order = order;
00039     alloc(w * h);
00040     width = w;
00041     height = h;
00042     hardwareSPI = false;
00043 //  updatePins(dpin, cpin);
00044 }
00045 
00046 // Allocate 3 bytes per pixel, init to RGB 'off' state:
00047 void Adafruit_WS2801::alloc(uint16_t n)
00048 {
00049     begun   = false;
00050     numLEDs = ((pixels = (uint8_t *)calloc(n, 3)) != NULL) ? n : 0;
00051     hardwareSPI = true;
00052 
00053 //    for(int bits = 0; bits <= numLEDs*24; bits++) {
00054 //        spi.write(0x00);
00055 //        clkpin = 0;
00056 //        datapin = 0;
00057 //        clkpin = 1;
00058 //    }
00059 //    clkpin = 0;
00060 }
00061 
00062 // Constructor for use with a matrix configuration, specify w, h for size of matrix
00063 // assumes configuration where string starts at coordinate 0,0 and continues to w-1,0, w-1,1
00064 // and on to 0,1, 0,2 and on to w-1,2 and so on. Snaking back and forth till the end.
00065 // other function calls with provide access to pixels via an x,y coordinate system
00066 /*Adafruit_WS2801::Adafruit_WS2801(uint16_t w, uint16_t h, uint8_t order)
00067 {
00068     rgb_order = order;
00069     alloc(w * h);
00070     width = w;
00071     height = h;
00072     hardwareSPI = true;
00073 //  updatePins(dpin, cpin);
00074 }
00075 */
00076 
00077 
00078 
00079 // via Michael Vogt/neophob: empty constructor is used when strand length
00080 // isn't known at compile-time; situations where program config might be
00081 // read from internal flash memory or an SD card, or arrive via serial
00082 // command.  If using this constructor, MUST follow up with updateLength()
00083 // and updatePins() to establish the strand length and output pins!
00084 // Also, updateOrder() to change RGB vs GRB order (RGB is default).
00085 //Adafruit_WS2801::Adafruit_WS2801(void) : clkpin(PTD4), datapin(PTA12)
00086 //{
00087 //    begun     = false;
00088 //    numLEDs   = 0;
00089 //    pixels    = NULL;
00090 //    rgb_order = WS2801_RGB;
00091 //    updatePins(); // Must assume hardware SPI until pins are set
00092 //}
00093 
00094 // Release memory (as needed):
00095 Adafruit_WS2801::~Adafruit_WS2801(void)
00096 {
00097     if (pixels != NULL) {
00098         free(pixels);
00099     }
00100 }
00101 
00102 // Activate hard/soft SPI as appropriate:
00103 void Adafruit_WS2801::begin(void)
00104 {
00105     if( hardwareSPI ) {
00106         // Setup the spi for 8 bit data, high steady state clock,
00107         // second edge capture, with a 1MHz clock rate
00108         spi.format(8,0);
00109         spi.frequency(1000000);
00110     } else {
00111         datapin = 0;
00112         clkpin = 0;
00113     }
00114     begun = true;
00115 }
00116 
00117 // Change pin assignments post-constructor, switching to hardware SPI:
00118 void Adafruit_WS2801::updatePins(void)
00119 {
00120     hardwareSPI = true;
00121     datapin = 0;
00122     clkpin = 0;
00123 }
00124 
00125 
00126 // Change pin assignments post-constructor, using arbitrary pins:
00127 void Adafruit_WS2801::updatePins(PinName dpin, PinName cpin)
00128 {
00129     // Note: any prior clock/data pin directions are left as-is and are
00130     // NOT restored as inputs!
00131 
00132     datapin     = DigitalOut(dpin);
00133     clkpin      = DigitalOut(cpin);
00134 }
00135 
00136 // Return the number of LEDs
00137 uint16_t Adafruit_WS2801::numPixels(void)
00138 {
00139     return numLEDs;
00140 }
00141 
00142 // Change strand length (see notes with empty constructor, above):
00143 void Adafruit_WS2801::updateLength(uint16_t n)
00144 {
00145     if(pixels != NULL) free(pixels); // Free existing data (if any)
00146     // Allocate new data -- note: ALL PIXELS ARE CLEARED
00147     numLEDs = ((pixels = (uint8_t *)calloc(n, 3)) != NULL) ? n : 0;
00148     // 'begun' state does not change -- pins retain prior modes
00149 }
00150 
00151 // Change RGB data order (see notes with empty constructor, above):
00152 void Adafruit_WS2801::updateOrder(uint8_t order)
00153 {
00154     rgb_order = order;
00155     // Existing LED data, if any, is NOT reformatted to new data order.
00156     // Calling function should clear or fill pixel data anew.
00157 }
00158 
00159 void Adafruit_WS2801::show(void)
00160 {
00161     uint16_t i, nl3 = numLEDs * 3; // 3 bytes per LED
00162 
00163     if( hardwareSPI ) {
00164         for(i=0; i<nl3; i++ ) {
00165             spi.write( pixels[i]);
00166         }        
00167         wait_ms(1); // Needed otherwise sometimes doesnt display
00168     } else {
00169         uint8_t  bit;
00170 
00171         // Write 24 bits per pixel:
00172         for(i=0; i<nl3; i++ ) {
00173             for(bit=0x80; bit; bit >>= 1) {
00174                 clkpin = 0;
00175                 datapin = (pixels[i] & bit) ? 1 : 0;
00176                 clkpin = 1;
00177                 wait_us(100);
00178             }
00179         }
00180         datapin = 0;
00181 
00182         clkpin = 0;
00183         wait_ms(1); // Data is latched by holding clock pin low for 1 millisecond
00184         clkpin = 1;
00185     }
00186 }
00187 
00188 // Set pixel color from separate 8-bit R, G, B components:
00189 void Adafruit_WS2801::setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b)
00190 {
00191     if(n < numLEDs) { // Arrays are 0-indexed, thus NOT '<='
00192         uint8_t *p = &pixels[n * 3];
00193         // See notes later regarding color order
00194         if(rgb_order == WS2801_RGB) {
00195             *p++ = r;
00196             *p++ = g;
00197         } else {
00198             *p++ = g;
00199             *p++ = r;
00200         }
00201         *p++ = b;
00202     }
00203 }
00204 
00205 // Set pixel color from separate 8-bit R, G, B components using x,y coordinate system:
00206 void Adafruit_WS2801::setPixelColor(int16_t x, int16_t y, uint8_t r, uint8_t g, uint8_t b)
00207 {
00208     if( x < 0 || x >= width || y < 0 || y >= height )
00209         return;         // Dont try to update a pixel that doesnt exist
00210 
00211     bool evenRow = ((y % 2) == 0);
00212     // calculate x offset first
00213     uint16_t offset = x % width;
00214 
00215     if (!evenRow) {
00216         offset = (width-1) - offset;
00217     }
00218     // add y offset
00219     offset += y * width;
00220     setPixelColor(offset, r, g, b);
00221 }
00222 
00223 // Set pixel color from 'packed' 32-bit RGB value:
00224 void Adafruit_WS2801::setPixelColor(uint16_t n, uint32_t c)
00225 {
00226     if( n < numLEDs) { // Arrays are 0-indexed, thus NOT '<='
00227         uint8_t *p = &pixels[n * 3];
00228         // To keep the show() loop as simple & fast as possible, the
00229         // internal color representation is native to different pixel
00230         // types.  For compatibility with existing code, 'packed' RGB
00231         // values passed in or out are always 0xRRGGBB order.
00232         if(rgb_order == WS2801_RGB) {
00233             *p++ = c >> 16; // Red
00234             *p++ = c >>  8; // Green
00235         } else {
00236             *p++ = c >>  8; // Green
00237             *p++ = c >> 16; // Red
00238         }
00239         *p++ = c;         // Blue
00240     }
00241 }
00242 
00243 // Set pixel color from 'packed' 32-bit RGB value using x,y coordinate system:
00244 void Adafruit_WS2801::setPixelColor(int16_t x, int16_t y, uint32_t c)
00245 {
00246     if( x < 0 || x >= width || y < 0 || y >= height )
00247         return;         // Dont try to update a pixel that doesnt exist
00248         
00249     bool evenRow = ((y % 2) == 0);
00250     // calculate x offset first
00251     uint16_t offset = x % width;
00252     if (!evenRow) {
00253         offset = (width-1) - offset;
00254     }
00255     // add y offset
00256     offset += y * width;
00257     setPixelColor(offset, c);
00258 }
00259 
00260 // Query color from previously-set pixel (returns packed 32-bit RGB value)
00261 uint32_t Adafruit_WS2801::getPixelColor(uint16_t n)
00262 {
00263     if(n < numLEDs) {
00264         uint16_t ofs = n * 3;
00265         // To keep the show() loop as simple & fast as possible, the
00266         // internal color representation is native to different pixel
00267         // types.  For compatibility with existing code, 'packed' RGB
00268         // values passed in or out are always 0xRRGGBB order.
00269         return (rgb_order == WS2801_RGB) ?
00270                ((uint32_t)pixels[ofs] << 16) | ((uint16_t) pixels[ofs + 1] <<  8) | pixels[ofs + 2] :
00271                (pixels[ofs] <<  8) | ((uint32_t)pixels[ofs + 1] << 16) | pixels[ofs + 2];
00272     }
00273 
00274     return 0; // Pixel # is out of bounds
00275 }
00276 
00277 // bresenham's algorithm - thx wikpedia
00278 void Adafruit_WS2801::drawLine(int16_t x0, int16_t y0, 
00279                 int16_t x1, int16_t y1, 
00280                 uint32_t color) {
00281   int16_t steep = abs(y1 - y0) > abs(x1 - x0);
00282   if (steep) {
00283     ws_swap(x0, y0);
00284     ws_swap(x1, y1);
00285   }
00286 
00287   if (x0 > x1) {
00288     ws_swap(x0, x1);
00289     ws_swap(y0, y1);
00290   }
00291 
00292   int16_t dx, dy;
00293   dx = x1 - x0;
00294   dy = abs(y1 - y0);
00295 
00296   int16_t err = dx / 2;
00297   int16_t ystep;
00298 
00299   if (y0 < y1) {
00300     ystep = 1;
00301   } else {
00302     ystep = -1;
00303   }
00304 
00305   for (; x0<=x1; x0++) {
00306     if (steep) {
00307       setPixelColor(y0, x0, color);
00308     } else {
00309       setPixelColor(x0, y0, color);
00310     }
00311     err -= dy;
00312     if (err < 0) {
00313       y0 += ystep;
00314       err += dx;
00315     }
00316   }
00317 }
00318 
00319 void Adafruit_WS2801::drawFastVLine(int16_t x, int16_t y, 
00320                  int16_t h, uint32_t color) {
00321   // stupidest version - update in subclasses if desired!
00322   drawLine(x, y, x, y+h-1, color);
00323 }
00324 
00325 
00326 void Adafruit_WS2801::drawFastHLine(int16_t x, int16_t y, 
00327                  int16_t w, uint32_t color) {
00328   // stupidest version - update in subclasses if desired!
00329   drawLine(x, y, x+w-1, y, color);
00330 }
00331 
00332 
00333 // draw a rectangle
00334 void Adafruit_WS2801::drawRect(int16_t x, int16_t y, 
00335                 int16_t w, int16_t h, uint32_t color) {
00336   drawFastHLine(x, y, w, color);
00337   drawFastHLine(x, y+h-1, w, color);
00338   drawFastVLine(x, y, h, color);
00339   drawFastVLine(x+w-1, y, h, color);
00340 }
00341 
00342 // draw a circle outline
00343 void Adafruit_WS2801::drawCircle(int16_t x0, int16_t y0, int16_t r, uint32_t color) {
00344   int16_t f = 1 - r;
00345   int16_t ddF_x = 1;
00346   int16_t ddF_y = -2 * r;
00347   int16_t x = 0;
00348   int16_t y = r;
00349 
00350   setPixelColor(x0, y0+r, color);
00351   setPixelColor(x0, y0-r, color);
00352   setPixelColor(x0+r, y0, color);
00353   setPixelColor(x0-r, y0, color);
00354 
00355   while (x<y) {
00356     if (f >= 0) {
00357       y--;
00358       ddF_y += 2;
00359       f += ddF_y;
00360     }
00361     x++;
00362     ddF_x += 2;
00363     f += ddF_x;
00364   
00365     setPixelColor(x0 + x, y0 + y, color);
00366     setPixelColor(x0 - x, y0 + y, color);
00367     setPixelColor(x0 + x, y0 - y, color);
00368     setPixelColor(x0 - x, y0 - y, color);
00369     setPixelColor(x0 + y, y0 + x, color);
00370     setPixelColor(x0 - y, y0 + x, color);
00371     setPixelColor(x0 + y, y0 - x, color);
00372     setPixelColor(x0 - y, y0 - x, color);
00373     
00374   }
00375 }
00376 /*
00377 void Adafruit_WS2801::fillCircle(int16_t x0, int16_t y0, int16_t r, uint32_t color) {
00378   drawFastVLine(x0, y0-r, 2*r+1, color);
00379   fillCircleHelper(x0, y0, r, 3, 0, color);
00380 }
00381 
00382 // used to do circles and roundrects!
00383 void Adafruit_WS2801::fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
00384                     uint8_t cornername, int16_t delta, uint32_t color) {
00385 
00386   int16_t f     = 1 - r;
00387   int16_t ddF_x = 1;
00388   int16_t ddF_y = -2 * r;
00389   int16_t x     = 0;
00390   int16_t y     = r;
00391 
00392   while (x<y) {
00393     if (f >= 0) {
00394       y--;
00395       ddF_y += 2;
00396       f     += ddF_y;
00397     }
00398     x++;
00399     ddF_x += 2;
00400     f     += ddF_x;
00401 
00402     if (cornername & 0x1) {
00403       drawFastVLine(x0+x, y0-y, 2*y+1+delta, color);
00404       drawFastVLine(x0+y, y0-x, 2*x+1+delta, color);
00405     }
00406     if (cornername & 0x2) {
00407       drawFastVLine(x0-x, y0-y, 2*y+1+delta, color);
00408       drawFastVLine(x0-y, y0-x, 2*x+1+delta, color);
00409     }
00410   }
00411 }
00412 */