Mercurial > code > home > repos > light9
comparison rgbled/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp @ 1231:ef4ae15f2661
copy in rgb led program for arduino
Ignore-this: ee63cf3e2100597625a4392bd95aba0d
author | Drew Perttula <drewp@bigasterisk.com> |
---|---|
date | Wed, 10 Jun 2015 04:55:39 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
1230:23377f8efd09 | 1231:ef4ae15f2661 |
---|---|
1 /*------------------------------------------------------------------------- | |
2 Arduino library to control a wide variety of WS2811- and WS2812-based RGB | |
3 LED devices such as Adafruit FLORA RGB Smart Pixels and NeoPixel strips. | |
4 Currently handles 400 and 800 KHz bitstreams on 8, 12 and 16 MHz ATmega | |
5 MCUs, with LEDs wired for RGB or GRB color order. 8 MHz MCUs provide | |
6 output on PORTB and PORTD, while 16 MHz chips can handle most output pins | |
7 (possible exception with upper PORT registers on the Arduino Mega). | |
8 | |
9 Written by Phil Burgess / Paint Your Dragon for Adafruit Industries, | |
10 contributions by PJRC and other members of the open source community. | |
11 | |
12 Adafruit invests time and resources providing this open source code, | |
13 please support Adafruit and open-source hardware by purchasing products | |
14 from Adafruit! | |
15 | |
16 ------------------------------------------------------------------------- | |
17 This file is part of the Adafruit NeoPixel library. | |
18 | |
19 NeoPixel is free software: you can redistribute it and/or modify | |
20 it under the terms of the GNU Lesser General Public License as | |
21 published by the Free Software Foundation, either version 3 of | |
22 the License, or (at your option) any later version. | |
23 | |
24 NeoPixel is distributed in the hope that it will be useful, | |
25 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
27 GNU Lesser General Public License for more details. | |
28 | |
29 You should have received a copy of the GNU Lesser General Public | |
30 License along with NeoPixel. If not, see | |
31 <http://www.gnu.org/licenses/>. | |
32 -------------------------------------------------------------------------*/ | |
33 | |
34 #include "Adafruit_NeoPixel.h" | |
35 | |
36 Adafruit_NeoPixel::Adafruit_NeoPixel(uint16_t n, uint8_t p, uint8_t t) : | |
37 numLEDs(n), numBytes(n * 3), pin(p), brightness(0), | |
38 pixels(NULL), type(t), endTime(0) | |
39 #ifdef __AVR__ | |
40 ,port(portOutputRegister(digitalPinToPort(p))), | |
41 pinMask(digitalPinToBitMask(p)) | |
42 #endif | |
43 { | |
44 if((pixels = (uint8_t *)malloc(numBytes))) { | |
45 memset(pixels, 0, numBytes); | |
46 } | |
47 if(t & NEO_GRB) { // GRB vs RGB; might add others if needed | |
48 rOffset = 1; | |
49 gOffset = 0; | |
50 bOffset = 2; | |
51 } else if (t & NEO_BRG) { | |
52 rOffset = 1; | |
53 gOffset = 2; | |
54 bOffset = 0; | |
55 } else { | |
56 rOffset = 0; | |
57 gOffset = 1; | |
58 bOffset = 2; | |
59 } | |
60 | |
61 } | |
62 | |
63 Adafruit_NeoPixel::~Adafruit_NeoPixel() { | |
64 if(pixels) free(pixels); | |
65 pinMode(pin, INPUT); | |
66 } | |
67 | |
68 void Adafruit_NeoPixel::begin(void) { | |
69 pinMode(pin, OUTPUT); | |
70 digitalWrite(pin, LOW); | |
71 } | |
72 | |
73 void Adafruit_NeoPixel::show(void) { | |
74 | |
75 if(!pixels) return; | |
76 | |
77 // Data latch = 50+ microsecond pause in the output stream. Rather than | |
78 // put a delay at the end of the function, the ending time is noted and | |
79 // the function will simply hold off (if needed) on issuing the | |
80 // subsequent round of data until the latch time has elapsed. This | |
81 // allows the mainline code to start generating the next frame of data | |
82 // rather than stalling for the latch. | |
83 while(!canShow()); | |
84 // endTime is a private member (rather than global var) so that mutliple | |
85 // instances on different pins can be quickly issued in succession (each | |
86 // instance doesn't delay the next). | |
87 | |
88 // In order to make this code runtime-configurable to work with any pin, | |
89 // SBI/CBI instructions are eschewed in favor of full PORT writes via the | |
90 // OUT or ST instructions. It relies on two facts: that peripheral | |
91 // functions (such as PWM) take precedence on output pins, so our PORT- | |
92 // wide writes won't interfere, and that interrupts are globally disabled | |
93 // while data is being issued to the LEDs, so no other code will be | |
94 // accessing the PORT. The code takes an initial 'snapshot' of the PORT | |
95 // state, computes 'pin high' and 'pin low' values, and writes these back | |
96 // to the PORT register as needed. | |
97 | |
98 noInterrupts(); // Need 100% focus on instruction timing | |
99 | |
100 #ifdef __AVR__ | |
101 | |
102 volatile uint16_t | |
103 i = numBytes; // Loop counter | |
104 volatile uint8_t | |
105 *ptr = pixels, // Pointer to next byte | |
106 b = *ptr++, // Current byte value | |
107 hi, // PORT w/output bit set high | |
108 lo; // PORT w/output bit set low | |
109 | |
110 // Hand-tuned assembly code issues data to the LED drivers at a specific | |
111 // rate. There's separate code for different CPU speeds (8, 12, 16 MHz) | |
112 // for both the WS2811 (400 KHz) and WS2812 (800 KHz) drivers. The | |
113 // datastream timing for the LED drivers allows a little wiggle room each | |
114 // way (listed in the datasheets), so the conditions for compiling each | |
115 // case are set up for a range of frequencies rather than just the exact | |
116 // 8, 12 or 16 MHz values, permitting use with some close-but-not-spot-on | |
117 // devices (e.g. 16.5 MHz DigiSpark). The ranges were arrived at based | |
118 // on the datasheet figures and have not been extensively tested outside | |
119 // the canonical 8/12/16 MHz speeds; there's no guarantee these will work | |
120 // close to the extremes (or possibly they could be pushed further). | |
121 // Keep in mind only one CPU speed case actually gets compiled; the | |
122 // resulting program isn't as massive as it might look from source here. | |
123 | |
124 // 8 MHz(ish) AVR --------------------------------------------------------- | |
125 #if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL) | |
126 | |
127 #ifdef NEO_KHZ400 | |
128 if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream | |
129 #endif | |
130 | |
131 volatile uint8_t n1, n2 = 0; // First, next bits out | |
132 | |
133 // Squeezing an 800 KHz stream out of an 8 MHz chip requires code | |
134 // specific to each PORT register. At present this is only written | |
135 // to work with pins on PORTD or PORTB, the most likely use case -- | |
136 // this covers all the pins on the Adafruit Flora and the bulk of | |
137 // digital pins on the Arduino Pro 8 MHz (keep in mind, this code | |
138 // doesn't even get compiled for 16 MHz boards like the Uno, Mega, | |
139 // Leonardo, etc., so don't bother extending this out of hand). | |
140 // Additional PORTs could be added if you really need them, just | |
141 // duplicate the else and loop and change the PORT. Each add'l | |
142 // PORT will require about 150(ish) bytes of program space. | |
143 | |
144 // 10 instruction clocks per bit: HHxxxxxLLL | |
145 // OUT instructions: ^ ^ ^ (T=0,2,7) | |
146 | |
147 #ifdef PORTD // PORTD isn't present on ATtiny85, etc. | |
148 | |
149 if(port == &PORTD) { | |
150 | |
151 hi = PORTD | pinMask; | |
152 lo = PORTD & ~pinMask; | |
153 n1 = lo; | |
154 if(b & 0x80) n1 = hi; | |
155 | |
156 // Dirty trick: RJMPs proceeding to the next instruction are used | |
157 // to delay two clock cycles in one instruction word (rather than | |
158 // using two NOPs). This was necessary in order to squeeze the | |
159 // loop down to exactly 64 words -- the maximum possible for a | |
160 // relative branch. | |
161 | |
162 asm volatile( | |
163 "headD:" "\n\t" // Clk Pseudocode | |
164 // Bit 7: | |
165 "out %[port] , %[hi]" "\n\t" // 1 PORT = hi | |
166 "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo | |
167 "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 | |
168 "rjmp .+0" "\n\t" // 2 nop nop | |
169 "sbrc %[byte] , 6" "\n\t" // 1-2 if(b & 0x40) | |
170 "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi | |
171 "out %[port] , %[lo]" "\n\t" // 1 PORT = lo | |
172 "rjmp .+0" "\n\t" // 2 nop nop | |
173 // Bit 6: | |
174 "out %[port] , %[hi]" "\n\t" // 1 PORT = hi | |
175 "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo | |
176 "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 | |
177 "rjmp .+0" "\n\t" // 2 nop nop | |
178 "sbrc %[byte] , 5" "\n\t" // 1-2 if(b & 0x20) | |
179 "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi | |
180 "out %[port] , %[lo]" "\n\t" // 1 PORT = lo | |
181 "rjmp .+0" "\n\t" // 2 nop nop | |
182 // Bit 5: | |
183 "out %[port] , %[hi]" "\n\t" // 1 PORT = hi | |
184 "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo | |
185 "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 | |
186 "rjmp .+0" "\n\t" // 2 nop nop | |
187 "sbrc %[byte] , 4" "\n\t" // 1-2 if(b & 0x10) | |
188 "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi | |
189 "out %[port] , %[lo]" "\n\t" // 1 PORT = lo | |
190 "rjmp .+0" "\n\t" // 2 nop nop | |
191 // Bit 4: | |
192 "out %[port] , %[hi]" "\n\t" // 1 PORT = hi | |
193 "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo | |
194 "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 | |
195 "rjmp .+0" "\n\t" // 2 nop nop | |
196 "sbrc %[byte] , 3" "\n\t" // 1-2 if(b & 0x08) | |
197 "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi | |
198 "out %[port] , %[lo]" "\n\t" // 1 PORT = lo | |
199 "rjmp .+0" "\n\t" // 2 nop nop | |
200 // Bit 3: | |
201 "out %[port] , %[hi]" "\n\t" // 1 PORT = hi | |
202 "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo | |
203 "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 | |
204 "rjmp .+0" "\n\t" // 2 nop nop | |
205 "sbrc %[byte] , 2" "\n\t" // 1-2 if(b & 0x04) | |
206 "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi | |
207 "out %[port] , %[lo]" "\n\t" // 1 PORT = lo | |
208 "rjmp .+0" "\n\t" // 2 nop nop | |
209 // Bit 2: | |
210 "out %[port] , %[hi]" "\n\t" // 1 PORT = hi | |
211 "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo | |
212 "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 | |
213 "rjmp .+0" "\n\t" // 2 nop nop | |
214 "sbrc %[byte] , 1" "\n\t" // 1-2 if(b & 0x02) | |
215 "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi | |
216 "out %[port] , %[lo]" "\n\t" // 1 PORT = lo | |
217 "rjmp .+0" "\n\t" // 2 nop nop | |
218 // Bit 1: | |
219 "out %[port] , %[hi]" "\n\t" // 1 PORT = hi | |
220 "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo | |
221 "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 | |
222 "rjmp .+0" "\n\t" // 2 nop nop | |
223 "sbrc %[byte] , 0" "\n\t" // 1-2 if(b & 0x01) | |
224 "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi | |
225 "out %[port] , %[lo]" "\n\t" // 1 PORT = lo | |
226 "sbiw %[count], 1" "\n\t" // 2 i-- (don't act on Z flag yet) | |
227 // Bit 0: | |
228 "out %[port] , %[hi]" "\n\t" // 1 PORT = hi | |
229 "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo | |
230 "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 | |
231 "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ | |
232 "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80) | |
233 "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi | |
234 "out %[port] , %[lo]" "\n\t" // 1 PORT = lo | |
235 "brne headD" "\n" // 2 while(i) (Z flag set above) | |
236 : [byte] "+r" (b), | |
237 [n1] "+r" (n1), | |
238 [n2] "+r" (n2), | |
239 [count] "+w" (i) | |
240 : [port] "I" (_SFR_IO_ADDR(PORTD)), | |
241 [ptr] "e" (ptr), | |
242 [hi] "r" (hi), | |
243 [lo] "r" (lo)); | |
244 | |
245 } else if(port == &PORTB) { | |
246 | |
247 #endif // PORTD | |
248 | |
249 // Same as above, just switched to PORTB and stripped of comments. | |
250 hi = PORTB | pinMask; | |
251 lo = PORTB & ~pinMask; | |
252 n1 = lo; | |
253 if(b & 0x80) n1 = hi; | |
254 | |
255 asm volatile( | |
256 "headB:" "\n\t" | |
257 "out %[port] , %[hi]" "\n\t" | |
258 "mov %[n2] , %[lo]" "\n\t" | |
259 "out %[port] , %[n1]" "\n\t" | |
260 "rjmp .+0" "\n\t" | |
261 "sbrc %[byte] , 6" "\n\t" | |
262 "mov %[n2] , %[hi]" "\n\t" | |
263 "out %[port] , %[lo]" "\n\t" | |
264 "rjmp .+0" "\n\t" | |
265 "out %[port] , %[hi]" "\n\t" | |
266 "mov %[n1] , %[lo]" "\n\t" | |
267 "out %[port] , %[n2]" "\n\t" | |
268 "rjmp .+0" "\n\t" | |
269 "sbrc %[byte] , 5" "\n\t" | |
270 "mov %[n1] , %[hi]" "\n\t" | |
271 "out %[port] , %[lo]" "\n\t" | |
272 "rjmp .+0" "\n\t" | |
273 "out %[port] , %[hi]" "\n\t" | |
274 "mov %[n2] , %[lo]" "\n\t" | |
275 "out %[port] , %[n1]" "\n\t" | |
276 "rjmp .+0" "\n\t" | |
277 "sbrc %[byte] , 4" "\n\t" | |
278 "mov %[n2] , %[hi]" "\n\t" | |
279 "out %[port] , %[lo]" "\n\t" | |
280 "rjmp .+0" "\n\t" | |
281 "out %[port] , %[hi]" "\n\t" | |
282 "mov %[n1] , %[lo]" "\n\t" | |
283 "out %[port] , %[n2]" "\n\t" | |
284 "rjmp .+0" "\n\t" | |
285 "sbrc %[byte] , 3" "\n\t" | |
286 "mov %[n1] , %[hi]" "\n\t" | |
287 "out %[port] , %[lo]" "\n\t" | |
288 "rjmp .+0" "\n\t" | |
289 "out %[port] , %[hi]" "\n\t" | |
290 "mov %[n2] , %[lo]" "\n\t" | |
291 "out %[port] , %[n1]" "\n\t" | |
292 "rjmp .+0" "\n\t" | |
293 "sbrc %[byte] , 2" "\n\t" | |
294 "mov %[n2] , %[hi]" "\n\t" | |
295 "out %[port] , %[lo]" "\n\t" | |
296 "rjmp .+0" "\n\t" | |
297 "out %[port] , %[hi]" "\n\t" | |
298 "mov %[n1] , %[lo]" "\n\t" | |
299 "out %[port] , %[n2]" "\n\t" | |
300 "rjmp .+0" "\n\t" | |
301 "sbrc %[byte] , 1" "\n\t" | |
302 "mov %[n1] , %[hi]" "\n\t" | |
303 "out %[port] , %[lo]" "\n\t" | |
304 "rjmp .+0" "\n\t" | |
305 "out %[port] , %[hi]" "\n\t" | |
306 "mov %[n2] , %[lo]" "\n\t" | |
307 "out %[port] , %[n1]" "\n\t" | |
308 "rjmp .+0" "\n\t" | |
309 "sbrc %[byte] , 0" "\n\t" | |
310 "mov %[n2] , %[hi]" "\n\t" | |
311 "out %[port] , %[lo]" "\n\t" | |
312 "sbiw %[count], 1" "\n\t" | |
313 "out %[port] , %[hi]" "\n\t" | |
314 "mov %[n1] , %[lo]" "\n\t" | |
315 "out %[port] , %[n2]" "\n\t" | |
316 "ld %[byte] , %a[ptr]+" "\n\t" | |
317 "sbrc %[byte] , 7" "\n\t" | |
318 "mov %[n1] , %[hi]" "\n\t" | |
319 "out %[port] , %[lo]" "\n\t" | |
320 "brne headB" "\n" | |
321 : [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i) | |
322 : [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi), | |
323 [lo] "r" (lo)); | |
324 | |
325 #ifdef PORTD | |
326 } // endif PORTB | |
327 #endif | |
328 | |
329 #ifdef NEO_KHZ400 | |
330 } else { // end 800 KHz, do 400 KHz | |
331 | |
332 // Timing is more relaxed; unrolling the inner loop for each bit is | |
333 // not necessary. Still using the peculiar RJMPs as 2X NOPs, not out | |
334 // of need but just to trim the code size down a little. | |
335 // This 400-KHz-datastream-on-8-MHz-CPU code is not quite identical | |
336 // to the 800-on-16 code later -- the hi/lo timing between WS2811 and | |
337 // WS2812 is not simply a 2:1 scale! | |
338 | |
339 // 20 inst. clocks per bit: HHHHxxxxxxLLLLLLLLLL | |
340 // ST instructions: ^ ^ ^ (T=0,4,10) | |
341 | |
342 volatile uint8_t next, bit; | |
343 | |
344 hi = *port | pinMask; | |
345 lo = *port & ~pinMask; | |
346 next = lo; | |
347 bit = 8; | |
348 | |
349 asm volatile( | |
350 "head20:" "\n\t" // Clk Pseudocode (T = 0) | |
351 "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) | |
352 "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) | |
353 "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) | |
354 "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 6) | |
355 "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7) | |
356 "dec %[bit]" "\n\t" // 1 bit-- (T = 8) | |
357 "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) | |
358 "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10) | |
359 "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12) | |
360 "rjmp .+0" "\n\t" // 2 nop nop (T = 14) | |
361 "rjmp .+0" "\n\t" // 2 nop nop (T = 16) | |
362 "rjmp .+0" "\n\t" // 2 nop nop (T = 18) | |
363 "rjmp head20" "\n\t" // 2 -> head20 (next bit out) | |
364 "nextbyte20:" "\n\t" // (T = 10) | |
365 "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12) | |
366 "nop" "\n\t" // 1 nop (T = 13) | |
367 "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 14) | |
368 "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 16) | |
369 "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) | |
370 "brne head20" "\n" // 2 if(i != 0) -> (next byte) | |
371 : [port] "+e" (port), | |
372 [byte] "+r" (b), | |
373 [bit] "+r" (bit), | |
374 [next] "+r" (next), | |
375 [count] "+w" (i) | |
376 : [hi] "r" (hi), | |
377 [lo] "r" (lo), | |
378 [ptr] "e" (ptr)); | |
379 } | |
380 #endif | |
381 | |
382 // 12 MHz(ish) AVR -------------------------------------------------------- | |
383 #elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL) | |
384 | |
385 #ifdef NEO_KHZ400 | |
386 if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream | |
387 #endif | |
388 | |
389 // In the 12 MHz case, an optimized 800 KHz datastream (no dead time | |
390 // between bytes) requires a PORT-specific loop similar to the 8 MHz | |
391 // code (but a little more relaxed in this case). | |
392 | |
393 // 15 instruction clocks per bit: HHHHxxxxxxLLLLL | |
394 // OUT instructions: ^ ^ ^ (T=0,4,10) | |
395 | |
396 volatile uint8_t next; | |
397 | |
398 #ifdef PORTD | |
399 | |
400 if(port == &PORTD) { | |
401 | |
402 hi = PORTD | pinMask; | |
403 lo = PORTD & ~pinMask; | |
404 next = lo; | |
405 if(b & 0x80) next = hi; | |
406 | |
407 // Don't "optimize" the OUT calls into the bitTime subroutine; | |
408 // we're exploiting the RCALL and RET as 3- and 4-cycle NOPs! | |
409 asm volatile( | |
410 "headD:" "\n\t" // (T = 0) | |
411 "out %[port], %[hi]" "\n\t" // (T = 1) | |
412 "rcall bitTimeD" "\n\t" // Bit 7 (T = 15) | |
413 "out %[port], %[hi]" "\n\t" | |
414 "rcall bitTimeD" "\n\t" // Bit 6 | |
415 "out %[port], %[hi]" "\n\t" | |
416 "rcall bitTimeD" "\n\t" // Bit 5 | |
417 "out %[port], %[hi]" "\n\t" | |
418 "rcall bitTimeD" "\n\t" // Bit 4 | |
419 "out %[port], %[hi]" "\n\t" | |
420 "rcall bitTimeD" "\n\t" // Bit 3 | |
421 "out %[port], %[hi]" "\n\t" | |
422 "rcall bitTimeD" "\n\t" // Bit 2 | |
423 "out %[port], %[hi]" "\n\t" | |
424 "rcall bitTimeD" "\n\t" // Bit 1 | |
425 // Bit 0: | |
426 "out %[port] , %[hi]" "\n\t" // 1 PORT = hi (T = 1) | |
427 "rjmp .+0" "\n\t" // 2 nop nop (T = 3) | |
428 "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 5) | |
429 "out %[port] , %[next]" "\n\t" // 1 PORT = next (T = 6) | |
430 "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7) | |
431 "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80) (T = 8) | |
432 "mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 9) | |
433 "nop" "\n\t" // 1 (T = 10) | |
434 "out %[port] , %[lo]" "\n\t" // 1 PORT = lo (T = 11) | |
435 "sbiw %[count], 1" "\n\t" // 2 i-- (T = 13) | |
436 "brne headD" "\n\t" // 2 if(i != 0) -> (next byte) | |
437 "rjmp doneD" "\n\t" | |
438 "bitTimeD:" "\n\t" // nop nop nop (T = 4) | |
439 "out %[port], %[next]" "\n\t" // 1 PORT = next (T = 5) | |
440 "mov %[next], %[lo]" "\n\t" // 1 next = lo (T = 6) | |
441 "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 7) | |
442 "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 0x80) (T = 8) | |
443 "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 9) | |
444 "nop" "\n\t" // 1 (T = 10) | |
445 "out %[port], %[lo]" "\n\t" // 1 PORT = lo (T = 11) | |
446 "ret" "\n\t" // 4 nop nop nop nop (T = 15) | |
447 "doneD:" "\n" | |
448 : [byte] "+r" (b), | |
449 [next] "+r" (next), | |
450 [count] "+w" (i) | |
451 : [port] "I" (_SFR_IO_ADDR(PORTD)), | |
452 [ptr] "e" (ptr), | |
453 [hi] "r" (hi), | |
454 [lo] "r" (lo)); | |
455 | |
456 } else if(port == &PORTB) { | |
457 | |
458 #endif // PORTD | |
459 | |
460 hi = PORTB | pinMask; | |
461 lo = PORTB & ~pinMask; | |
462 next = lo; | |
463 if(b & 0x80) next = hi; | |
464 | |
465 // Same as above, just set for PORTB & stripped of comments | |
466 asm volatile( | |
467 "headB:" "\n\t" | |
468 "out %[port], %[hi]" "\n\t" | |
469 "rcall bitTimeB" "\n\t" | |
470 "out %[port], %[hi]" "\n\t" | |
471 "rcall bitTimeB" "\n\t" | |
472 "out %[port], %[hi]" "\n\t" | |
473 "rcall bitTimeB" "\n\t" | |
474 "out %[port], %[hi]" "\n\t" | |
475 "rcall bitTimeB" "\n\t" | |
476 "out %[port], %[hi]" "\n\t" | |
477 "rcall bitTimeB" "\n\t" | |
478 "out %[port], %[hi]" "\n\t" | |
479 "rcall bitTimeB" "\n\t" | |
480 "out %[port], %[hi]" "\n\t" | |
481 "rcall bitTimeB" "\n\t" | |
482 "out %[port] , %[hi]" "\n\t" | |
483 "rjmp .+0" "\n\t" | |
484 "ld %[byte] , %a[ptr]+" "\n\t" | |
485 "out %[port] , %[next]" "\n\t" | |
486 "mov %[next] , %[lo]" "\n\t" | |
487 "sbrc %[byte] , 7" "\n\t" | |
488 "mov %[next] , %[hi]" "\n\t" | |
489 "nop" "\n\t" | |
490 "out %[port] , %[lo]" "\n\t" | |
491 "sbiw %[count], 1" "\n\t" | |
492 "brne headB" "\n\t" | |
493 "rjmp doneB" "\n\t" | |
494 "bitTimeB:" "\n\t" | |
495 "out %[port], %[next]" "\n\t" | |
496 "mov %[next], %[lo]" "\n\t" | |
497 "rol %[byte]" "\n\t" | |
498 "sbrc %[byte], 7" "\n\t" | |
499 "mov %[next], %[hi]" "\n\t" | |
500 "nop" "\n\t" | |
501 "out %[port], %[lo]" "\n\t" | |
502 "ret" "\n\t" | |
503 "doneB:" "\n" | |
504 : [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i) | |
505 : [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi), | |
506 [lo] "r" (lo)); | |
507 | |
508 #ifdef PORTD | |
509 } | |
510 #endif | |
511 | |
512 #ifdef NEO_KHZ400 | |
513 } else { // 400 KHz | |
514 | |
515 // 30 instruction clocks per bit: HHHHHHxxxxxxxxxLLLLLLLLLLLLLLL | |
516 // ST instructions: ^ ^ ^ (T=0,6,15) | |
517 | |
518 volatile uint8_t next, bit; | |
519 | |
520 hi = *port | pinMask; | |
521 lo = *port & ~pinMask; | |
522 next = lo; | |
523 bit = 8; | |
524 | |
525 asm volatile( | |
526 "head30:" "\n\t" // Clk Pseudocode (T = 0) | |
527 "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) | |
528 "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) | |
529 "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) | |
530 "rjmp .+0" "\n\t" // 2 nop nop (T = 6) | |
531 "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 8) | |
532 "rjmp .+0" "\n\t" // 2 nop nop (T = 10) | |
533 "rjmp .+0" "\n\t" // 2 nop nop (T = 12) | |
534 "rjmp .+0" "\n\t" // 2 nop nop (T = 14) | |
535 "nop" "\n\t" // 1 nop (T = 15) | |
536 "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 17) | |
537 "rjmp .+0" "\n\t" // 2 nop nop (T = 19) | |
538 "dec %[bit]" "\n\t" // 1 bit-- (T = 20) | |
539 "breq nextbyte30" "\n\t" // 1-2 if(bit == 0) | |
540 "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 22) | |
541 "rjmp .+0" "\n\t" // 2 nop nop (T = 24) | |
542 "rjmp .+0" "\n\t" // 2 nop nop (T = 26) | |
543 "rjmp .+0" "\n\t" // 2 nop nop (T = 28) | |
544 "rjmp head30" "\n\t" // 2 -> head30 (next bit out) | |
545 "nextbyte30:" "\n\t" // (T = 22) | |
546 "nop" "\n\t" // 1 nop (T = 23) | |
547 "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 24) | |
548 "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 26) | |
549 "sbiw %[count], 1" "\n\t" // 2 i-- (T = 28) | |
550 "brne head30" "\n" // 1-2 if(i != 0) -> (next byte) | |
551 : [port] "+e" (port), | |
552 [byte] "+r" (b), | |
553 [bit] "+r" (bit), | |
554 [next] "+r" (next), | |
555 [count] "+w" (i) | |
556 : [hi] "r" (hi), | |
557 [lo] "r" (lo), | |
558 [ptr] "e" (ptr)); | |
559 } | |
560 #endif | |
561 | |
562 // 16 MHz(ish) AVR -------------------------------------------------------- | |
563 #elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L) | |
564 | |
565 #ifdef NEO_KHZ400 | |
566 if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream | |
567 #endif | |
568 | |
569 // WS2811 and WS2812 have different hi/lo duty cycles; this is | |
570 // similar but NOT an exact copy of the prior 400-on-8 code. | |
571 | |
572 // 20 inst. clocks per bit: HHHHHxxxxxxxxLLLLLLL | |
573 // ST instructions: ^ ^ ^ (T=0,5,13) | |
574 | |
575 volatile uint8_t next, bit; | |
576 | |
577 hi = *port | pinMask; | |
578 lo = *port & ~pinMask; | |
579 next = lo; | |
580 bit = 8; | |
581 | |
582 asm volatile( | |
583 "head20:" "\n\t" // Clk Pseudocode (T = 0) | |
584 "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) | |
585 "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 128) | |
586 "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) | |
587 "dec %[bit]" "\n\t" // 1 bit-- (T = 5) | |
588 "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 7) | |
589 "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 8) | |
590 "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) (from dec above) | |
591 "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10) | |
592 "rjmp .+0" "\n\t" // 2 nop nop (T = 12) | |
593 "nop" "\n\t" // 1 nop (T = 13) | |
594 "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) | |
595 "nop" "\n\t" // 1 nop (T = 16) | |
596 "rjmp .+0" "\n\t" // 2 nop nop (T = 18) | |
597 "rjmp head20" "\n\t" // 2 -> head20 (next bit out) | |
598 "nextbyte20:" "\n\t" // (T = 10) | |
599 "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 11) | |
600 "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 13) | |
601 "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) | |
602 "nop" "\n\t" // 1 nop (T = 16) | |
603 "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) | |
604 "brne head20" "\n" // 2 if(i != 0) -> (next byte) | |
605 : [port] "+e" (port), | |
606 [byte] "+r" (b), | |
607 [bit] "+r" (bit), | |
608 [next] "+r" (next), | |
609 [count] "+w" (i) | |
610 : [ptr] "e" (ptr), | |
611 [hi] "r" (hi), | |
612 [lo] "r" (lo)); | |
613 | |
614 #ifdef NEO_KHZ400 | |
615 } else { // 400 KHz | |
616 | |
617 // The 400 KHz clock on 16 MHz MCU is the most 'relaxed' version. | |
618 | |
619 // 40 inst. clocks per bit: HHHHHHHHxxxxxxxxxxxxLLLLLLLLLLLLLLLLLLLL | |
620 // ST instructions: ^ ^ ^ (T=0,8,20) | |
621 | |
622 volatile uint8_t next, bit; | |
623 | |
624 hi = *port | pinMask; | |
625 lo = *port & ~pinMask; | |
626 next = lo; | |
627 bit = 8; | |
628 | |
629 asm volatile( | |
630 "head40:" "\n\t" // Clk Pseudocode (T = 0) | |
631 "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) | |
632 "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) | |
633 "mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 4) | |
634 "rjmp .+0" "\n\t" // 2 nop nop (T = 6) | |
635 "rjmp .+0" "\n\t" // 2 nop nop (T = 8) | |
636 "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 10) | |
637 "rjmp .+0" "\n\t" // 2 nop nop (T = 12) | |
638 "rjmp .+0" "\n\t" // 2 nop nop (T = 14) | |
639 "rjmp .+0" "\n\t" // 2 nop nop (T = 16) | |
640 "rjmp .+0" "\n\t" // 2 nop nop (T = 18) | |
641 "rjmp .+0" "\n\t" // 2 nop nop (T = 20) | |
642 "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 22) | |
643 "nop" "\n\t" // 1 nop (T = 23) | |
644 "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 24) | |
645 "dec %[bit]" "\n\t" // 1 bit-- (T = 25) | |
646 "breq nextbyte40" "\n\t" // 1-2 if(bit == 0) | |
647 "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 27) | |
648 "nop" "\n\t" // 1 nop (T = 28) | |
649 "rjmp .+0" "\n\t" // 2 nop nop (T = 30) | |
650 "rjmp .+0" "\n\t" // 2 nop nop (T = 32) | |
651 "rjmp .+0" "\n\t" // 2 nop nop (T = 34) | |
652 "rjmp .+0" "\n\t" // 2 nop nop (T = 36) | |
653 "rjmp .+0" "\n\t" // 2 nop nop (T = 38) | |
654 "rjmp head40" "\n\t" // 2 -> head40 (next bit out) | |
655 "nextbyte40:" "\n\t" // (T = 27) | |
656 "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 28) | |
657 "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 30) | |
658 "rjmp .+0" "\n\t" // 2 nop nop (T = 32) | |
659 "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 34) | |
660 "rjmp .+0" "\n\t" // 2 nop nop (T = 36) | |
661 "sbiw %[count], 1" "\n\t" // 2 i-- (T = 38) | |
662 "brne head40" "\n" // 1-2 if(i != 0) -> (next byte) | |
663 : [port] "+e" (port), | |
664 [byte] "+r" (b), | |
665 [bit] "+r" (bit), | |
666 [next] "+r" (next), | |
667 [count] "+w" (i) | |
668 : [ptr] "e" (ptr), | |
669 [hi] "r" (hi), | |
670 [lo] "r" (lo)); | |
671 } | |
672 #endif | |
673 | |
674 #else | |
675 #error "CPU SPEED NOT SUPPORTED" | |
676 #endif | |
677 | |
678 #elif defined(__arm__) | |
679 | |
680 #if defined(__MK20DX128__) || defined(__MK20DX256__) // Teensy 3.0 & 3.1 | |
681 #define CYCLES_800_T0H (F_CPU / 4000000) | |
682 #define CYCLES_800_T1H (F_CPU / 1250000) | |
683 #define CYCLES_800 (F_CPU / 800000) | |
684 #define CYCLES_400_T0H (F_CPU / 2000000) | |
685 #define CYCLES_400_T1H (F_CPU / 833333) | |
686 #define CYCLES_400 (F_CPU / 400000) | |
687 | |
688 uint8_t *p = pixels, | |
689 *end = p + numBytes, pix, mask; | |
690 volatile uint8_t *set = portSetRegister(pin), | |
691 *clr = portClearRegister(pin); | |
692 uint32_t cyc; | |
693 | |
694 ARM_DEMCR |= ARM_DEMCR_TRCENA; | |
695 ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; | |
696 | |
697 #ifdef NEO_KHZ400 | |
698 if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream | |
699 #endif | |
700 cyc = ARM_DWT_CYCCNT + CYCLES_800; | |
701 while(p < end) { | |
702 pix = *p++; | |
703 for(mask = 0x80; mask; mask >>= 1) { | |
704 while(ARM_DWT_CYCCNT - cyc < CYCLES_800); | |
705 cyc = ARM_DWT_CYCCNT; | |
706 *set = 1; | |
707 if(pix & mask) { | |
708 while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T1H); | |
709 } else { | |
710 while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T0H); | |
711 } | |
712 *clr = 1; | |
713 } | |
714 } | |
715 while(ARM_DWT_CYCCNT - cyc < CYCLES_800); | |
716 #ifdef NEO_KHZ400 | |
717 } else { // 400 kHz bitstream | |
718 cyc = ARM_DWT_CYCCNT + CYCLES_400; | |
719 while(p < end) { | |
720 pix = *p++; | |
721 for(mask = 0x80; mask; mask >>= 1) { | |
722 while(ARM_DWT_CYCCNT - cyc < CYCLES_400); | |
723 cyc = ARM_DWT_CYCCNT; | |
724 *set = 1; | |
725 if(pix & mask) { | |
726 while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T1H); | |
727 } else { | |
728 while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T0H); | |
729 } | |
730 *clr = 1; | |
731 } | |
732 } | |
733 while(ARM_DWT_CYCCNT - cyc < CYCLES_400); | |
734 } | |
735 #endif | |
736 | |
737 | |
738 | |
739 | |
740 | |
741 #elif defined(__MKL26Z64__) // Teensy-LC | |
742 | |
743 #if F_CPU == 48000000 | |
744 uint8_t *p = pixels, | |
745 pix, count, dly, | |
746 bitmask = digitalPinToBitMask(pin); | |
747 volatile uint8_t *reg = portSetRegister(pin); | |
748 uint32_t num = numBytes; | |
749 asm volatile( | |
750 "L%=_begin:" "\n\t" | |
751 "ldrb %[pix], [%[p], #0]" "\n\t" | |
752 "lsl %[pix], #24" "\n\t" | |
753 "movs %[count], #7" "\n\t" | |
754 "L%=_loop:" "\n\t" | |
755 "lsl %[pix], #1" "\n\t" | |
756 "bcs L%=_loop_one" "\n\t" | |
757 "L%=_loop_zero:" | |
758 "strb %[bitmask], [%[reg], #0]" "\n\t" | |
759 "movs %[dly], #4" "\n\t" | |
760 "L%=_loop_delay_T0H:" "\n\t" | |
761 "sub %[dly], #1" "\n\t" | |
762 "bne L%=_loop_delay_T0H" "\n\t" | |
763 "strb %[bitmask], [%[reg], #4]" "\n\t" | |
764 "movs %[dly], #13" "\n\t" | |
765 "L%=_loop_delay_T0L:" "\n\t" | |
766 "sub %[dly], #1" "\n\t" | |
767 "bne L%=_loop_delay_T0L" "\n\t" | |
768 "b L%=_next" "\n\t" | |
769 "L%=_loop_one:" | |
770 "strb %[bitmask], [%[reg], #0]" "\n\t" | |
771 "movs %[dly], #13" "\n\t" | |
772 "L%=_loop_delay_T1H:" "\n\t" | |
773 "sub %[dly], #1" "\n\t" | |
774 "bne L%=_loop_delay_T1H" "\n\t" | |
775 "strb %[bitmask], [%[reg], #4]" "\n\t" | |
776 "movs %[dly], #4" "\n\t" | |
777 "L%=_loop_delay_T1L:" "\n\t" | |
778 "sub %[dly], #1" "\n\t" | |
779 "bne L%=_loop_delay_T1L" "\n\t" | |
780 "nop" "\n\t" | |
781 "L%=_next:" "\n\t" | |
782 "sub %[count], #1" "\n\t" | |
783 "bne L%=_loop" "\n\t" | |
784 "lsl %[pix], #1" "\n\t" | |
785 "bcs L%=_last_one" "\n\t" | |
786 "L%=_last_zero:" | |
787 "strb %[bitmask], [%[reg], #0]" "\n\t" | |
788 "movs %[dly], #4" "\n\t" | |
789 "L%=_last_delay_T0H:" "\n\t" | |
790 "sub %[dly], #1" "\n\t" | |
791 "bne L%=_last_delay_T0H" "\n\t" | |
792 "strb %[bitmask], [%[reg], #4]" "\n\t" | |
793 "movs %[dly], #10" "\n\t" | |
794 "L%=_last_delay_T0L:" "\n\t" | |
795 "sub %[dly], #1" "\n\t" | |
796 "bne L%=_last_delay_T0L" "\n\t" | |
797 "b L%=_repeat" "\n\t" | |
798 "L%=_last_one:" | |
799 "strb %[bitmask], [%[reg], #0]" "\n\t" | |
800 "movs %[dly], #13" "\n\t" | |
801 "L%=_last_delay_T1H:" "\n\t" | |
802 "sub %[dly], #1" "\n\t" | |
803 "bne L%=_last_delay_T1H" "\n\t" | |
804 "strb %[bitmask], [%[reg], #4]" "\n\t" | |
805 "movs %[dly], #1" "\n\t" | |
806 "L%=_last_delay_T1L:" "\n\t" | |
807 "sub %[dly], #1" "\n\t" | |
808 "bne L%=_last_delay_T1L" "\n\t" | |
809 "nop" "\n\t" | |
810 "L%=_repeat:" "\n\t" | |
811 "add %[p], #1" "\n\t" | |
812 "sub %[num], #1" "\n\t" | |
813 "bne L%=_begin" "\n\t" | |
814 "L%=_done:" "\n\t" | |
815 : [p] "+r" (p), | |
816 [pix] "=&r" (pix), | |
817 [count] "=&r" (count), | |
818 [dly] "=&r" (dly), | |
819 [num] "+r" (num) | |
820 : [bitmask] "r" (bitmask), | |
821 [reg] "r" (reg) | |
822 ); | |
823 #else | |
824 #error "Sorry, only 48 MHz is supported, please set Tools > CPU Speed to 48 MHz" | |
825 #endif | |
826 | |
827 | |
828 #else // Arduino Due | |
829 | |
830 #define SCALE VARIANT_MCK / 2UL / 1000000UL | |
831 #define INST (2UL * F_CPU / VARIANT_MCK) | |
832 #define TIME_800_0 ((int)(0.40 * SCALE + 0.5) - (5 * INST)) | |
833 #define TIME_800_1 ((int)(0.80 * SCALE + 0.5) - (5 * INST)) | |
834 #define PERIOD_800 ((int)(1.25 * SCALE + 0.5) - (5 * INST)) | |
835 #define TIME_400_0 ((int)(0.50 * SCALE + 0.5) - (5 * INST)) | |
836 #define TIME_400_1 ((int)(1.20 * SCALE + 0.5) - (5 * INST)) | |
837 #define PERIOD_400 ((int)(2.50 * SCALE + 0.5) - (5 * INST)) | |
838 | |
839 int pinMask, time0, time1, period, t; | |
840 Pio *port; | |
841 volatile WoReg *portSet, *portClear, *timeValue, *timeReset; | |
842 uint8_t *p, *end, pix, mask; | |
843 | |
844 pmc_set_writeprotect(false); | |
845 pmc_enable_periph_clk((uint32_t)TC3_IRQn); | |
846 TC_Configure(TC1, 0, | |
847 TC_CMR_WAVE | TC_CMR_WAVSEL_UP | TC_CMR_TCCLKS_TIMER_CLOCK1); | |
848 TC_Start(TC1, 0); | |
849 | |
850 pinMask = g_APinDescription[pin].ulPin; // Don't 'optimize' these into | |
851 port = g_APinDescription[pin].pPort; // declarations above. Want to | |
852 portSet = &(port->PIO_SODR); // burn a few cycles after | |
853 portClear = &(port->PIO_CODR); // starting timer to minimize | |
854 timeValue = &(TC1->TC_CHANNEL[0].TC_CV); // the initial 'while'. | |
855 timeReset = &(TC1->TC_CHANNEL[0].TC_CCR); | |
856 p = pixels; | |
857 end = p + numBytes; | |
858 pix = *p++; | |
859 mask = 0x80; | |
860 | |
861 #ifdef NEO_KHZ400 | |
862 if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream | |
863 #endif | |
864 time0 = TIME_800_0; | |
865 time1 = TIME_800_1; | |
866 period = PERIOD_800; | |
867 #ifdef NEO_KHZ400 | |
868 } else { // 400 KHz bitstream | |
869 time0 = TIME_400_0; | |
870 time1 = TIME_400_1; | |
871 period = PERIOD_400; | |
872 } | |
873 #endif | |
874 | |
875 for(t = time0;; t = time0) { | |
876 if(pix & mask) t = time1; | |
877 while(*timeValue < period); | |
878 *portSet = pinMask; | |
879 *timeReset = TC_CCR_CLKEN | TC_CCR_SWTRG; | |
880 while(*timeValue < t); | |
881 *portClear = pinMask; | |
882 if(!(mask >>= 1)) { // This 'inside-out' loop logic utilizes | |
883 if(p >= end) break; // idle time to minimize inter-byte delays. | |
884 pix = *p++; | |
885 mask = 0x80; | |
886 } | |
887 } | |
888 while(*timeValue < period); // Wait for last bit | |
889 TC_Stop(TC1, 0); | |
890 | |
891 #endif // end Arduino Due | |
892 | |
893 #endif // end Architecture select | |
894 | |
895 interrupts(); | |
896 endTime = micros(); // Save EOD time for latch on next call | |
897 } | |
898 | |
899 // Set the output pin number | |
900 void Adafruit_NeoPixel::setPin(uint8_t p) { | |
901 pinMode(pin, INPUT); | |
902 pin = p; | |
903 pinMode(p, OUTPUT); | |
904 digitalWrite(p, LOW); | |
905 #ifdef __AVR__ | |
906 port = portOutputRegister(digitalPinToPort(p)); | |
907 pinMask = digitalPinToBitMask(p); | |
908 #endif | |
909 } | |
910 | |
911 // Set pixel color from separate R,G,B components: | |
912 void Adafruit_NeoPixel::setPixelColor( | |
913 uint16_t n, uint8_t r, uint8_t g, uint8_t b) { | |
914 if(n < numLEDs) { | |
915 if(brightness) { // See notes in setBrightness() | |
916 r = (r * brightness) >> 8; | |
917 g = (g * brightness) >> 8; | |
918 b = (b * brightness) >> 8; | |
919 } | |
920 uint8_t *p = &pixels[n * 3]; | |
921 p[rOffset] = r; | |
922 p[gOffset] = g; | |
923 p[bOffset] = b; | |
924 } | |
925 } | |
926 | |
927 // Set pixel color from 'packed' 32-bit RGB color: | |
928 void Adafruit_NeoPixel::setPixelColor(uint16_t n, uint32_t c) { | |
929 if(n < numLEDs) { | |
930 uint8_t | |
931 r = (uint8_t)(c >> 16), | |
932 g = (uint8_t)(c >> 8), | |
933 b = (uint8_t)c; | |
934 if(brightness) { // See notes in setBrightness() | |
935 r = (r * brightness) >> 8; | |
936 g = (g * brightness) >> 8; | |
937 b = (b * brightness) >> 8; | |
938 } | |
939 uint8_t *p = &pixels[n * 3]; | |
940 p[rOffset] = r; | |
941 p[gOffset] = g; | |
942 p[bOffset] = b; | |
943 } | |
944 } | |
945 | |
946 // Convert separate R,G,B into packed 32-bit RGB color. | |
947 // Packed format is always RGB, regardless of LED strand color order. | |
948 uint32_t Adafruit_NeoPixel::Color(uint8_t r, uint8_t g, uint8_t b) { | |
949 return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; | |
950 } | |
951 | |
952 // Query color from previously-set pixel (returns packed 32-bit RGB value) | |
953 uint32_t Adafruit_NeoPixel::getPixelColor(uint16_t n) const { | |
954 if(n >= numLEDs) { | |
955 // Out of bounds, return no color. | |
956 return 0; | |
957 } | |
958 uint8_t *p = &pixels[n * 3]; | |
959 uint32_t c = ((uint32_t)p[rOffset] << 16) | | |
960 ((uint32_t)p[gOffset] << 8) | | |
961 (uint32_t)p[bOffset]; | |
962 // Adjust this back up to the true color, as setting a pixel color will | |
963 // scale it back down again. | |
964 if(brightness) { // See notes in setBrightness() | |
965 //Cast the color to a byte array | |
966 uint8_t * c_ptr =reinterpret_cast<uint8_t*>(&c); | |
967 c_ptr[0] = (c_ptr[0] << 8)/brightness; | |
968 c_ptr[1] = (c_ptr[1] << 8)/brightness; | |
969 c_ptr[2] = (c_ptr[2] << 8)/brightness; | |
970 } | |
971 return c; // Pixel # is out of bounds | |
972 } | |
973 | |
974 // Returns pointer to pixels[] array. Pixel data is stored in device- | |
975 // native format and is not translated here. Application will need to be | |
976 // aware whether pixels are RGB vs. GRB and handle colors appropriately. | |
977 uint8_t *Adafruit_NeoPixel::getPixels(void) const { | |
978 return pixels; | |
979 } | |
980 | |
981 uint16_t Adafruit_NeoPixel::numPixels(void) const { | |
982 return numLEDs; | |
983 } | |
984 | |
985 // Adjust output brightness; 0=darkest (off), 255=brightest. This does | |
986 // NOT immediately affect what's currently displayed on the LEDs. The | |
987 // next call to show() will refresh the LEDs at this level. However, | |
988 // this process is potentially "lossy," especially when increasing | |
989 // brightness. The tight timing in the WS2811/WS2812 code means there | |
990 // aren't enough free cycles to perform this scaling on the fly as data | |
991 // is issued. So we make a pass through the existing color data in RAM | |
992 // and scale it (subsequent graphics commands also work at this | |
993 // brightness level). If there's a significant step up in brightness, | |
994 // the limited number of steps (quantization) in the old data will be | |
995 // quite visible in the re-scaled version. For a non-destructive | |
996 // change, you'll need to re-render the full strip data. C'est la vie. | |
997 void Adafruit_NeoPixel::setBrightness(uint8_t b) { | |
998 // Stored brightness value is different than what's passed. | |
999 // This simplifies the actual scaling math later, allowing a fast | |
1000 // 8x8-bit multiply and taking the MSB. 'brightness' is a uint8_t, | |
1001 // adding 1 here may (intentionally) roll over...so 0 = max brightness | |
1002 // (color values are interpreted literally; no scaling), 1 = min | |
1003 // brightness (off), 255 = just below max brightness. | |
1004 uint8_t newBrightness = b + 1; | |
1005 if(newBrightness != brightness) { // Compare against prior value | |
1006 // Brightness has changed -- re-scale existing data in RAM | |
1007 uint8_t c, | |
1008 *ptr = pixels, | |
1009 oldBrightness = brightness - 1; // De-wrap old brightness value | |
1010 uint16_t scale; | |
1011 if(oldBrightness == 0) scale = 0; // Avoid /0 | |
1012 else if(b == 255) scale = 65535 / oldBrightness; | |
1013 else scale = (((uint16_t)newBrightness << 8) - 1) / oldBrightness; | |
1014 for(uint16_t i=0; i<numBytes; i++) { | |
1015 c = *ptr; | |
1016 *ptr++ = (c * scale) >> 8; | |
1017 } | |
1018 brightness = newBrightness; | |
1019 } | |
1020 } | |
1021 | |
1022 //Return the brightness value | |
1023 uint8_t Adafruit_NeoPixel::getBrightness(void) const { | |
1024 return brightness - 1; | |
1025 } | |
1026 | |
1027 void Adafruit_NeoPixel::clear() { | |
1028 memset(pixels, 0, numBytes); | |
1029 } |