Skip to content
Newer
Older
100644 292 lines (256 sloc) 8.84 KB
003090f @ladyada typo fixes
ladyada authored Mar 6, 2012
1 #include "Adafruit_WS2801.h"
627c5c5 @ladyada Working code with examples
ladyada authored Jul 18, 2011
2
3 // Example to control WS2801-based RGB LED Modules in a strand or strip
4 // Written by Adafruit - MIT license
5 /*****************************************************************************/
6
ce12ff6 @PaintYourDragon Trinket, Gemma & Due support (experimental)
PaintYourDragon authored Jun 28, 2014
7 #ifdef __AVR_ATtiny85__
8
9 // Teensy/Gemma-specific stuff for hardware-assisted SPI @ 1 MHz
10
11 #if(F_CPU > 8000000L)
12 #define SPI_DELAY asm volatile("rjmp .+0\nrjmp .+0"); // Burn 4 cycles
13 #elif(F_CPU > 4000000L)
14 #define SPI_DELAY asm volatile("rjmp .+0"); // Burn 2 cycles
15 #else
16 #define SPI_DELAY // Run max speed
17 #endif
18
19 #define SPIBIT \
20 USICR = ((1<<USIWM0)|(1<<USITC)); \
21 SPI_DELAY \
22 USICR = ((1<<USIWM0)|(1<<USITC)|(1<<USICLK)); \
23 SPI_DELAY
24
25 static void spi_out(uint8_t n) {
26 USIDR = n;
27 SPIBIT
28 SPIBIT
29 SPIBIT
30 SPIBIT
31 SPIBIT
32 SPIBIT
33 SPIBIT
34 SPIBIT
35 }
36
37 #else
38
39 // All other boards support Full and Proper Hardware SPI
40
41 #include <SPI.h>
42 #define spi_out(n) (void)SPI.transfer(n)
43
44 #endif
45
46 /*****************************************************************************/
47
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 12, 2011
48 // Constructor for use with hardware SPI (specific clock/data pins):
b6045bd @ladyada rename!
ladyada authored Mar 6, 2012
49 Adafruit_WS2801::Adafruit_WS2801(uint16_t n, uint8_t order) {
c91e268 @PaintYourDragon Additions for 36mm LED pixels 'GRB' order
PaintYourDragon authored Mar 6, 2012
50 rgb_order = order;
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
51 alloc(n);
52 updatePins();
8e2a50f @PaintYourDragon Reduced memory footprint (3 bytes rather than 4 per LED), added hardw…
PaintYourDragon authored Nov 16, 2011
53 }
627c5c5 @ladyada Working code with examples
ladyada authored Jul 18, 2011
54
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
55 // Constructor for use with arbitrary clock/data pins:
b6045bd @ladyada rename!
ladyada authored Mar 6, 2012
56 Adafruit_WS2801::Adafruit_WS2801(uint16_t n, uint8_t dpin, uint8_t cpin, uint8_t order) {
c91e268 @PaintYourDragon Additions for 36mm LED pixels 'GRB' order
PaintYourDragon authored Mar 6, 2012
57 rgb_order = order;
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
58 alloc(n);
59 updatePins(dpin, cpin);
60 }
61
ce12ff6 @PaintYourDragon Trinket, Gemma & Due support (experimental)
PaintYourDragon authored Jun 29, 2014
62 // Constructor for use with a matrix configuration, specify w, h for size
63 // of matrix. Assumes configuration where string starts at coordinate 0,0
64 // and continues to w-1,0, w-1,1 and on to 0,1, 0,2 and on to w-1,2 and
65 // so on. Snaking back and forth till the end. Other function calls
66 // provide access to pixels via an x,y coordinate system
1b33ad4 @dkavanagh Added basic methods to treat string as 2 dimensional RGB display
dkavanagh authored Dec 6, 2012
67 Adafruit_WS2801::Adafruit_WS2801(uint16_t w, uint16_t h, uint8_t dpin, uint8_t cpin, uint8_t order) {
68 rgb_order = order;
69 alloc(w * h);
ce12ff6 @PaintYourDragon Trinket, Gemma & Due support (experimental)
PaintYourDragon authored Jun 29, 2014
70 width = w;
1b33ad4 @dkavanagh Added basic methods to treat string as 2 dimensional RGB display
dkavanagh authored Dec 6, 2012
71 height = h;
72 updatePins(dpin, cpin);
73 }
74
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
75 // Allocate 3 bytes per pixel, init to RGB 'off' state:
b6045bd @ladyada rename!
ladyada authored Mar 6, 2012
76 void Adafruit_WS2801::alloc(uint16_t n) {
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
77 begun = false;
774ad14 @PaintYourDragon Added getPixelColor() and empty constructor via neophob's request
PaintYourDragon authored Jan 9, 2012
78 numLEDs = ((pixels = (uint8_t *)calloc(n, 3)) != NULL) ? n : 0;
79 }
80
81 // via Michael Vogt/neophob: empty constructor is used when strand length
82 // isn't known at compile-time; situations where program config might be
83 // read from internal flash memory or an SD card, or arrive via serial
84 // command. If using this constructor, MUST follow up with updateLength()
85 // and updatePins() to establish the strand length and output pins!
c91e268 @PaintYourDragon Additions for 36mm LED pixels 'GRB' order
PaintYourDragon authored Mar 6, 2012
86 // Also, updateOrder() to change RGB vs GRB order (RGB is default).
b6045bd @ladyada rename!
ladyada authored Mar 6, 2012
87 Adafruit_WS2801::Adafruit_WS2801(void) {
c91e268 @PaintYourDragon Additions for 36mm LED pixels 'GRB' order
PaintYourDragon authored Mar 6, 2012
88 begun = false;
89 numLEDs = 0;
90 pixels = NULL;
91 rgb_order = WS2801_RGB;
774ad14 @PaintYourDragon Added getPixelColor() and empty constructor via neophob's request
PaintYourDragon authored Jan 9, 2012
92 updatePins(); // Must assume hardware SPI until pins are set
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
93 }
627c5c5 @ladyada Working code with examples
ladyada authored Jul 18, 2011
94
ed424b3 @jrcutler Fixed memory leak on destruction.
jrcutler authored Apr 6, 2012
95 // Release memory (as needed):
96 Adafruit_WS2801::~Adafruit_WS2801(void) {
ce12ff6 @PaintYourDragon Trinket, Gemma & Due support (experimental)
PaintYourDragon authored Jun 29, 2014
97 if(pixels) free(pixels);
ed424b3 @jrcutler Fixed memory leak on destruction.
jrcutler authored Apr 6, 2012
98 }
99
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
100 // Activate hard/soft SPI as appropriate:
b6045bd @ladyada rename!
ladyada authored Mar 6, 2012
101 void Adafruit_WS2801::begin(void) {
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
102 if(hardwareSPI == true) {
103 startSPI();
104 } else {
105 pinMode(datapin, OUTPUT);
106 pinMode(clkpin , OUTPUT);
107 }
108 begun = true;
109 }
627c5c5 @ladyada Working code with examples
ladyada authored Jul 18, 2011
110
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
111 // Change pin assignments post-constructor, switching to hardware SPI:
b6045bd @ladyada rename!
ladyada authored Mar 6, 2012
112 void Adafruit_WS2801::updatePins(void) {
ce12ff6 @PaintYourDragon Trinket, Gemma & Due support (experimental)
PaintYourDragon authored Jun 29, 2014
113 pinMode(datapin, INPUT); // Restore data and clock pins to inputs
114 pinMode(clkpin , INPUT);
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
115 datapin = clkpin = 0;
ce12ff6 @PaintYourDragon Trinket, Gemma & Due support (experimental)
PaintYourDragon authored Jun 29, 2014
116 hardwareSPI = true;
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
117 // If begin() was previously invoked, init the SPI hardware now:
118 if(begun == true) startSPI();
119 // Otherwise, SPI is NOT initted until begin() is explicitly called.
627c5c5 @ladyada Working code with examples
ladyada authored Jul 18, 2011
120 }
121
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
122 // Change pin assignments post-constructor, using arbitrary pins:
b6045bd @ladyada rename!
ladyada authored Mar 6, 2012
123 void Adafruit_WS2801::updatePins(uint8_t dpin, uint8_t cpin) {
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
124 if(begun == true) { // If begin() was previously invoked...
125 // If previously using hardware SPI, turn that off:
ce12ff6 @PaintYourDragon Trinket, Gemma & Due support (experimental)
PaintYourDragon authored Jun 29, 2014
126 if(hardwareSPI) {
127 #ifdef __AVR_ATtiny85__
128 DDRB &= ~(_BV(PORTB1) | _BV(PORTB2));
129 #else
130 SPI.end();
131 #endif
132 } else {
133 pinMode(datapin, INPUT); // Restore prior data and clock pins to inputs
134 pinMode(clkpin , INPUT);
135 }
136 pinMode(dpin, OUTPUT); // Enable output on 'soft' SPI pins:
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
137 pinMode(cpin, OUTPUT);
ce12ff6 @PaintYourDragon Trinket, Gemma & Due support (experimental)
PaintYourDragon authored Jun 29, 2014
138 }
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
139
140 datapin = dpin;
141 clkpin = cpin;
ce12ff6 @PaintYourDragon Trinket, Gemma & Due support (experimental)
PaintYourDragon authored Jun 29, 2014
142 #ifdef __AVR__
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
143 clkport = portOutputRegister(digitalPinToPort(cpin));
144 clkpinmask = digitalPinToBitMask(cpin);
145 dataport = portOutputRegister(digitalPinToPort(dpin));
146 datapinmask = digitalPinToBitMask(dpin);
ce12ff6 @PaintYourDragon Trinket, Gemma & Due support (experimental)
PaintYourDragon authored Jun 29, 2014
147 #endif
148 hardwareSPI = false;
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
149 }
8e2a50f @PaintYourDragon Reduced memory footprint (3 bytes rather than 4 per LED), added hardw…
PaintYourDragon authored Nov 17, 2011
150
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
151 // Enable SPI hardware and set up protocol details:
b6045bd @ladyada rename!
ladyada authored Mar 6, 2012
152 void Adafruit_WS2801::startSPI(void) {
ce12ff6 @PaintYourDragon Trinket, Gemma & Due support (experimental)
PaintYourDragon authored Jun 29, 2014
153 #ifdef __AVR_ATtiny85__
154 PORTB &= ~(_BV(PORTB1) | _BV(PORTB2)); // Outputs
155 DDRB |= _BV(PORTB1) | _BV(PORTB2); // DO (NOT MOSI) + SCK
156 #else
157 SPI.begin();
158 SPI.setBitOrder(MSBFIRST);
159 SPI.setDataMode(SPI_MODE0);
160 #if defined(__AVR__) || defined(CORE_TEENSY)
161 SPI.setClockDivider(SPI_CLOCK_DIV16); // 1MHz max, else flicker
162 #else
163 SPI.setClockDivider((F_CPU + 500000L) / 1000000L);
164 #endif
165 #endif
627c5c5 @ladyada Working code with examples
ladyada authored Jul 18, 2011
166 }
167
b6045bd @ladyada rename!
ladyada authored Mar 6, 2012
168 uint16_t Adafruit_WS2801::numPixels(void) {
627c5c5 @ladyada Working code with examples
ladyada authored Jul 18, 2011
169 return numLEDs;
170 }
171
774ad14 @PaintYourDragon Added getPixelColor() and empty constructor via neophob's request
PaintYourDragon authored Jan 9, 2012
172 // Change strand length (see notes with empty constructor, above):
b6045bd @ladyada rename!
ladyada authored Mar 6, 2012
173 void Adafruit_WS2801::updateLength(uint16_t n) {
774ad14 @PaintYourDragon Added getPixelColor() and empty constructor via neophob's request
PaintYourDragon authored Jan 9, 2012
174 if(pixels != NULL) free(pixels); // Free existing data (if any)
175 // Allocate new data -- note: ALL PIXELS ARE CLEARED
176 numLEDs = ((pixels = (uint8_t *)calloc(n, 3)) != NULL) ? n : 0;
177 // 'begun' state does not change -- pins retain prior modes
178 }
179
c91e268 @PaintYourDragon Additions for 36mm LED pixels 'GRB' order
PaintYourDragon authored Mar 6, 2012
180 // Change RGB data order (see notes with empty constructor, above):
b6045bd @ladyada rename!
ladyada authored Mar 6, 2012
181 void Adafruit_WS2801::updateOrder(uint8_t order) {
c91e268 @PaintYourDragon Additions for 36mm LED pixels 'GRB' order
PaintYourDragon authored Mar 6, 2012
182 rgb_order = order;
183 // Existing LED data, if any, is NOT reformatted to new data order.
184 // Calling function should clear or fill pixel data anew.
185 }
186
b6045bd @ladyada rename!
ladyada authored Mar 6, 2012
187 void Adafruit_WS2801::show(void) {
8e2a50f @PaintYourDragon Reduced memory footprint (3 bytes rather than 4 per LED), added hardw…
PaintYourDragon authored Nov 17, 2011
188 uint16_t i, nl3 = numLEDs * 3; // 3 bytes per LED
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
189 uint8_t bit;
8e2a50f @PaintYourDragon Reduced memory footprint (3 bytes rather than 4 per LED), added hardw…
PaintYourDragon authored Nov 17, 2011
190
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
191 // Write 24 bits per pixel:
192 if(hardwareSPI) {
ce12ff6 @PaintYourDragon Trinket, Gemma & Due support (experimental)
PaintYourDragon authored Jun 29, 2014
193 for(i=0; i<nl3; i++) spi_out(pixels[i]);
8e2a50f @PaintYourDragon Reduced memory footprint (3 bytes rather than 4 per LED), added hardw…
PaintYourDragon authored Nov 17, 2011
194 } else {
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
195 for(i=0; i<nl3; i++ ) {
196 for(bit=0x80; bit; bit >>= 1) {
ce12ff6 @PaintYourDragon Trinket, Gemma & Due support (experimental)
PaintYourDragon authored Jun 29, 2014
197 #ifdef __AVR__
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
198 if(pixels[i] & bit) *dataport |= datapinmask;
199 else *dataport &= ~datapinmask;
200 *clkport |= clkpinmask;
201 *clkport &= ~clkpinmask;
ce12ff6 @PaintYourDragon Trinket, Gemma & Due support (experimental)
PaintYourDragon authored Jun 29, 2014
202 #else
203 if(pixels[i] & bit) digitalWrite(datapin, HIGH);
204 else digitalWrite(datapin, LOW);
205 digitalWrite(clkpin, HIGH);
206 digitalWrite(clkpin, LOW);
207 #endif
8e2a50f @PaintYourDragon Reduced memory footprint (3 bytes rather than 4 per LED), added hardw…
PaintYourDragon authored Nov 17, 2011
208 }
627c5c5 @ladyada Working code with examples
ladyada authored Jul 18, 2011
209 }
8e2a50f @PaintYourDragon Reduced memory footprint (3 bytes rather than 4 per LED), added hardw…
PaintYourDragon authored Nov 17, 2011
210 }
211
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
212 delay(1); // Data is latched by holding clock pin low for 1 millisecond
627c5c5 @ladyada Working code with examples
ladyada authored Jul 18, 2011
213 }
214
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
215 // Set pixel color from separate 8-bit R, G, B components:
b6045bd @ladyada rename!
ladyada authored Mar 6, 2012
216 void Adafruit_WS2801::setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b) {
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
217 if(n < numLEDs) { // Arrays are 0-indexed, thus NOT '<='
218 uint8_t *p = &pixels[n * 3];
c91e268 @PaintYourDragon Additions for 36mm LED pixels 'GRB' order
PaintYourDragon authored Mar 6, 2012
219 // See notes later regarding color order
220 if(rgb_order == WS2801_RGB) {
221 *p++ = r;
222 *p++ = g;
223 } else {
224 *p++ = g;
225 *p++ = r;
226 }
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
227 *p++ = b;
228 }
627c5c5 @ladyada Working code with examples
ladyada authored Jul 18, 2011
229 }
230
1b33ad4 @dkavanagh Added basic methods to treat string as 2 dimensional RGB display
dkavanagh authored Dec 6, 2012
231 // Set pixel color from separate 8-bit R, G, B components using x,y coordinate system:
232 void Adafruit_WS2801::setPixelColor(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b) {
233 boolean evenRow = ((y % 2) == 0);
234 // calculate x offset first
235 uint16_t offset = x % width;
236 if (!evenRow) {
237 offset = (width-1) - offset;
238 }
239 // add y offset
240 offset += y * width;
241 setPixelColor(offset, r, g, b);
242 }
243
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
244 // Set pixel color from 'packed' 32-bit RGB value:
b6045bd @ladyada rename!
ladyada authored Mar 6, 2012
245 void Adafruit_WS2801::setPixelColor(uint16_t n, uint32_t c) {
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
246 if(n < numLEDs) { // Arrays are 0-indexed, thus NOT '<='
247 uint8_t *p = &pixels[n * 3];
c91e268 @PaintYourDragon Additions for 36mm LED pixels 'GRB' order
PaintYourDragon authored Mar 6, 2012
248 // To keep the show() loop as simple & fast as possible, the
249 // internal color representation is native to different pixel
250 // types. For compatibility with existing code, 'packed' RGB
251 // values passed in or out are always 0xRRGGBB order.
252 if(rgb_order == WS2801_RGB) {
253 *p++ = c >> 16; // Red
254 *p++ = c >> 8; // Green
255 } else {
256 *p++ = c >> 8; // Green
257 *p++ = c >> 16; // Red
258 }
259 *p++ = c; // Blue
48e6f97 @PaintYourDragon Added updatePins() method at neophob's request
PaintYourDragon authored Dec 13, 2011
260 }
627c5c5 @ladyada Working code with examples
ladyada authored Jul 18, 2011
261 }
262
1b33ad4 @dkavanagh Added basic methods to treat string as 2 dimensional RGB display
dkavanagh authored Dec 6, 2012
263 // Set pixel color from 'packed' 32-bit RGB value using x,y coordinate system:
264 void Adafruit_WS2801::setPixelColor(uint16_t x, uint16_t y, uint32_t c) {
265 boolean evenRow = ((y % 2) == 0);
266 // calculate x offset first
267 uint16_t offset = x % width;
268 if (!evenRow) {
269 offset = (width-1) - offset;
270 }
271 // add y offset
272 offset += y * width;
273 setPixelColor(offset, c);
274 }
275
774ad14 @PaintYourDragon Added getPixelColor() and empty constructor via neophob's request
PaintYourDragon authored Jan 9, 2012
276 // Query color from previously-set pixel (returns packed 32-bit RGB value)
b6045bd @ladyada rename!
ladyada authored Mar 6, 2012
277 uint32_t Adafruit_WS2801::getPixelColor(uint16_t n) {
774ad14 @PaintYourDragon Added getPixelColor() and empty constructor via neophob's request
PaintYourDragon authored Jan 9, 2012
278 if(n < numLEDs) {
279 uint16_t ofs = n * 3;
c91e268 @PaintYourDragon Additions for 36mm LED pixels 'GRB' order
PaintYourDragon authored Mar 6, 2012
280 // To keep the show() loop as simple & fast as possible, the
281 // internal color representation is native to different pixel
282 // types. For compatibility with existing code, 'packed' RGB
283 // values passed in or out are always 0xRRGGBB order.
284 return (rgb_order == WS2801_RGB) ?
d221943 @AntonKast add cast to unsigned in getPixelColor() to prevent overflow
AntonKast authored Aug 10, 2012
285 ((uint32_t)pixels[ofs] << 16) | ((uint16_t) pixels[ofs + 1] << 8) | pixels[ofs + 2] :
9fdc7b4 @jrcutler Fixed `Adafruit_WS2801::getPixelColor()` to return all 24 bits of col…
jrcutler authored Apr 4, 2012
286 (pixels[ofs] << 8) | ((uint32_t)pixels[ofs + 1] << 16) | pixels[ofs + 2];
774ad14 @PaintYourDragon Added getPixelColor() and empty constructor via neophob's request
PaintYourDragon authored Jan 9, 2012
287 }
288
289 return 0; // Pixel # is out of bounds
290 }
291
Something went wrong with that request. Please try again.