eBoard ๐Ÿ‰  โ‘ โ‘งโ‘จ
Written for SIA 2017/2018
eagle_NeoPixel.h
Go to the documentation of this file.
1 #ifndef EAGLE_EBOARD_HELPLIB_NEOPIXEL
2 #define EAGLE_EBOARD_HELPLIB_NEOPIXEL
3 
4  // Codesection based on official NeoPixel library
5  // RGB NeoPixel permutations; white and red offsets are always same
6  // Offset: W R G B
8  #define EBOARD_NEO_RGB ((0 << 6) | (0 << 4) | (1 << 2) | (2))
9  #define EBOARD_NEO_RBG ((0 << 6) | (0 << 4) | (2 << 2) | (1))
11  #define EBOARD_NEO_GRB ((1 << 6) | (1 << 4) | (0 << 2) | (2))
13  #define EBOARD_NEO_GBR ((2 << 6) | (2 << 4) | (0 << 2) | (1))
15  #define EBOARD_NEO_BRG ((1 << 6) | (1 << 4) | (2 << 2) | (0))
17  #define EBOARD_NEO_BGR ((2 << 6) | (2 << 4) | (1 << 2) | (0))
19 
20  // RGBW NeoPixel permutations; all 4 offsets are distinct
21  // Offset: W R G B
23  #define EBOARD_NEO_WRGB ((0 << 6) | (1 << 4) | (2 << 2) | (3))
24  #define EBOARD_NEO_WRBG ((0 << 6) | (1 << 4) | (3 << 2) | (2))
26  #define EBOARD_NEO_WGRB ((0 << 6) | (2 << 4) | (1 << 2) | (3))
28  #define EBOARD_NEO_WGBR ((0 << 6) | (3 << 4) | (1 << 2) | (2))
30  #define EBOARD_NEO_WBRG ((0 << 6) | (2 << 4) | (3 << 2) | (1))
32  #define EBOARD_NEO_WBGR ((0 << 6) | (3 << 4) | (2 << 2) | (1))
34  #define EBOARD_NEO_RWGB ((1 << 6) | (0 << 4) | (2 << 2) | (3))
36  #define EBOARD_NEO_RWBG ((1 << 6) | (0 << 4) | (3 << 2) | (2))
38  #define EBOARD_NEO_RGWB ((2 << 6) | (0 << 4) | (1 << 2) | (3))
40  #define EBOARD_NEO_RGBW ((3 << 6) | (0 << 4) | (1 << 2) | (2))
42  #define EBOARD_NEO_RBWG ((2 << 6) | (0 << 4) | (3 << 2) | (1))
44  #define EBOARD_NEO_RBGW ((3 << 6) | (0 << 4) | (2 << 2) | (1))
46  #define EBOARD_NEO_GWRB ((1 << 6) | (2 << 4) | (0 << 2) | (3))
48  #define EBOARD_NEO_GWBR ((1 << 6) | (3 << 4) | (0 << 2) | (2))
50  #define EBOARD_NEO_GRWB ((2 << 6) | (1 << 4) | (0 << 2) | (3))
52  #define EBOARD_NEO_GRBW ((3 << 6) | (1 << 4) | (0 << 2) | (2))
54  #define EBOARD_NEO_GBWR ((2 << 6) | (3 << 4) | (0 << 2) | (1))
56  #define EBOARD_NEO_GBRW ((3 << 6) | (2 << 4) | (0 << 2) | (1))
58  #define EBOARD_NEO_BWRG ((1 << 6) | (2 << 4) | (3 << 2) | (0))
60  #define EBOARD_NEO_BWGR ((1 << 6) | (3 << 4) | (2 << 2) | (0))
62  #define EBOARD_NEO_BRWG ((2 << 6) | (1 << 4) | (3 << 2) | (0))
64  #define EBOARD_NEO_BRGW ((3 << 6) | (1 << 4) | (2 << 2) | (0))
66  #define EBOARD_NEO_BGWR ((2 << 6) | (3 << 4) | (1 << 2) | (0))
68  #define EBOARD_NEO_BGRW ((3 << 6) | (2 << 4) | (1 << 2) | (0))
70 
71 
73  #define EBOARD_NEO_800KHZ 0x0000
74  #define EBOARD_NEO_400KHZ 0x0100
76 
77  // uint16_t can be uint8_t in 800Khz mode ^^
116  struct NeoPixel{
124  NeoPixel(uint16_t n, uint8_t p = 6, uint16_t t = EBOARD_NEO_GRB + EBOARD_NEO_800KHZ);
132  NeoPixel(void);
134  ~NeoPixel(void);
138  void begin(void);
142  void show(void);
147  void setPin(uint8_t p);
155  void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b);
164  void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w);
170  void setPixelColor(uint16_t n, uint32_t c);
178  void setBrightness(uint8_t val);
182  void clear(void);
187  void updateLength(uint16_t n);
192  void updateType(uint16_t t);
197  inline uint8_t *getPixels(void) const;
202  inline uint8_t getBrightness(void) const;
207  inline int8_t getPin(void);
212  inline uint16_t numPixels(void) const;
219  static inline uint32_t Color(uint8_t r, uint8_t g, uint8_t b);
227  static inline uint32_t Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w);
232  uint32_t getPixelColor(uint16_t n) const;
237  inline bool canShow(void);
238  protected:
240  bool is800KHz;
242  bool begun;
244  uint16_t numLEDs; //maybe shorten with PrepConst 'extendetLED'?
246  uint16_t numBytes;
251  int8_t pin;
253  uint8_t brightness;
255  uint8_t *pixels;
257  uint8_t aOffset[4];
259  uint32_t endTime; //used for diff calc
260  #ifdef __AVR__ //not needed (rem?)
261  volatile uint8_t *port;// Output PORT register
264  uint8_t pinMask; // Output PORT bitmask
265  #endif
266 
267  };
268 
270 
271 
272  inline bool NeoPixel::canShow(void) { return (micros() - endTime) >= 300L; }
273 
274  uint8_t *NeoPixel::getPixels(void) const {
275  return pixels;
276  }
277 
278  uint16_t NeoPixel::numPixels(void) const {
279  return numLEDs;
280  }
281 
282  uint8_t NeoPixel::getBrightness(void) const {
283  return brightness - 1;
284  }
285  NeoPixel::NeoPixel(uint16_t n, uint8_t p, uint16_t t) :
286  begun(false), brightness(0), pixels(NULL), endTime(0) {
287  updateType(t);
288  updateLength(n);
289  setPin(p);
290  }
292  is800KHz(true),
293  begun(false), numLEDs(0), numBytes(0), pin(-1), brightness(0), pixels(NULL),
294  endTime(0)
295  {aOffset[0]=1;aOffset[1]=0;aOffset[2]=2;aOffset[3]=1;}
296 
298  if(pixels) free(pixels);
299  if(pin >= 0) pinMode(pin, INPUT);
300  }
301 
302  void NeoPixel::begin(void) {
303  if(pin >= 0) {
304  pinMode(pin, OUTPUT);
305  digitalWrite(pin, LOW);
306  }
307  begun = true;
308 
309  }
310 
311  void NeoPixel::updateLength(uint16_t n) {
312  if(pixels) free(pixels);
313  numBytes = n * ((aOffset[3] == aOffset[0]) ? 3 : 4);
314  if((pixels = (uint8_t *)malloc(numBytes))) {
315  memset(pixels, 0, numBytes);
316  numLEDs = n;
317  } else {
318  numLEDs = numBytes = 0;
319  }
320  }
321 
322  void NeoPixel::updateType(uint16_t t) {
323  boolean oldThreeBytesPerPixel = (aOffset[3] == aOffset[0]); // false if RGBW
324 
325  aOffset[3] = (t >> 6) & 0b11;
326  aOffset[0] = (t >> 4) & 0b11;
327  aOffset[1] = (t >> 2) & 0b11;
328  aOffset[2] = t & 0b11;
329  is800KHz = (t < 256); // 400 KHz flag is 1<<8
330 
331  if(pixels) {
332  boolean newThreeBytesPerPixel = (aOffset[3] == aOffset[0]);
333  if(newThreeBytesPerPixel != oldThreeBytesPerPixel) updateLength(numLEDs);
334  }
335  }
336 
337  #if defined(ESP8266)
338  // ESP8266 show() is external to enforce ICACHE_RAM_ATTR execution
339  extern "C" void ICACHE_RAM_ATTR espShow(
340  uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t type);
341  #elif defined(ESP32)
342  extern "C" void espShow(
343  uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t type);
344  #endif
345 
346  void NeoPixel::show(void) {
347  if(!pixels) return;
348  while(!canShow()); //maybe timeout ?
349  noInterrupts(); // Need 100% focus on instruction timing
350 
351  #ifdef __AVR__
352  volatile uint16_t
353  i = numBytes;
354  volatile uint8_t
355  *ptr = pixels,
356  b = *ptr++,
357  hi,
358  lo;
359 
360  #if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL)
361 
362  if(is800KHz) {
363  volatile uint8_t n1, n2 = 0;
364 
365  #if defined(PORTD)
366  #if defined(PORTB) || defined(PORTC) || defined(PORTF)
367  if(port == &PORTD) {
368  #endif
369 
370  hi = PORTD | pinMask;
371  lo = PORTD & ~pinMask;
372  n1 = lo;
373  if(b & 0x80) n1 = hi;
374 
375  asm volatile(
376  "headD:" "\n\t" // Clk Pseudocode
377  // Bit 7:
378  "out %[port] , %[hi]" "\n\t" // 1 PORT = hi
379  "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
380  "out %[port] , %[n1]" "\n\t" // 1 PORT = n1
381  "rjmp .+0" "\n\t" // 2 nop nop
382  "sbrc %[byte] , 6" "\n\t" // 1-2 if(b & 0x40)
383  "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
384  "out %[port] , %[lo]" "\n\t" // 1 PORT = lo
385  "rjmp .+0" "\n\t" // 2 nop nop
386  // Bit 6:
387  "out %[port] , %[hi]" "\n\t" // 1 PORT = hi
388  "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
389  "out %[port] , %[n2]" "\n\t" // 1 PORT = n2
390  "rjmp .+0" "\n\t" // 2 nop nop
391  "sbrc %[byte] , 5" "\n\t" // 1-2 if(b & 0x20)
392  "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
393  "out %[port] , %[lo]" "\n\t" // 1 PORT = lo
394  "rjmp .+0" "\n\t" // 2 nop nop
395  // Bit 5:
396  "out %[port] , %[hi]" "\n\t" // 1 PORT = hi
397  "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
398  "out %[port] , %[n1]" "\n\t" // 1 PORT = n1
399  "rjmp .+0" "\n\t" // 2 nop nop
400  "sbrc %[byte] , 4" "\n\t" // 1-2 if(b & 0x10)
401  "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
402  "out %[port] , %[lo]" "\n\t" // 1 PORT = lo
403  "rjmp .+0" "\n\t" // 2 nop nop
404  // Bit 4:
405  "out %[port] , %[hi]" "\n\t" // 1 PORT = hi
406  "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
407  "out %[port] , %[n2]" "\n\t" // 1 PORT = n2
408  "rjmp .+0" "\n\t" // 2 nop nop
409  "sbrc %[byte] , 3" "\n\t" // 1-2 if(b & 0x08)
410  "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
411  "out %[port] , %[lo]" "\n\t" // 1 PORT = lo
412  "rjmp .+0" "\n\t" // 2 nop nop
413  // Bit 3:
414  "out %[port] , %[hi]" "\n\t" // 1 PORT = hi
415  "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
416  "out %[port] , %[n1]" "\n\t" // 1 PORT = n1
417  "rjmp .+0" "\n\t" // 2 nop nop
418  "sbrc %[byte] , 2" "\n\t" // 1-2 if(b & 0x04)
419  "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
420  "out %[port] , %[lo]" "\n\t" // 1 PORT = lo
421  "rjmp .+0" "\n\t" // 2 nop nop
422  // Bit 2:
423  "out %[port] , %[hi]" "\n\t" // 1 PORT = hi
424  "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
425  "out %[port] , %[n2]" "\n\t" // 1 PORT = n2
426  "rjmp .+0" "\n\t" // 2 nop nop
427  "sbrc %[byte] , 1" "\n\t" // 1-2 if(b & 0x02)
428  "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
429  "out %[port] , %[lo]" "\n\t" // 1 PORT = lo
430  "rjmp .+0" "\n\t" // 2 nop nop
431  // Bit 1:
432  "out %[port] , %[hi]" "\n\t" // 1 PORT = hi
433  "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
434  "out %[port] , %[n1]" "\n\t" // 1 PORT = n1
435  "rjmp .+0" "\n\t" // 2 nop nop
436  "sbrc %[byte] , 0" "\n\t" // 1-2 if(b & 0x01)
437  "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
438  "out %[port] , %[lo]" "\n\t" // 1 PORT = lo
439  "sbiw %[count], 1" "\n\t" // 2 i-- (don't act on Z flag yet)
440  // Bit 0:
441  "out %[port] , %[hi]" "\n\t" // 1 PORT = hi
442  "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
443  "out %[port] , %[n2]" "\n\t" // 1 PORT = n2
444  "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++
445  "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80)
446  "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
447  "out %[port] , %[lo]" "\n\t" // 1 PORT = lo
448  "brne headD" "\n" // 2 while(i) (Z flag set above)
449  : [byte] "+r" (b),
450  [n1] "+r" (n1),
451  [n2] "+r" (n2),
452  [count] "+w" (i)
453  : [port] "I" (_SFR_IO_ADDR(PORTD)),
454  [ptr] "e" (ptr),
455  [hi] "r" (hi),
456  [lo] "r" (lo));
457 
458  #if defined(PORTB) || defined(PORTC) || defined(PORTF)
459  } else
460  #endif
461  #endif
462  #if defined(PORTB)
463  #if defined(PORTD) || defined(PORTC) || defined(PORTF)
464  if(port == &PORTB) {
465  #endif // defined(PORTD/C/F)
466  hi = PORTB | pinMask;
467  lo = PORTB & ~pinMask;
468  n1 = lo;
469  if(b & 0x80) n1 = hi;
470 
471  asm volatile(
472  "headB:" "\n\t"
473  "out %[port] , %[hi]" "\n\t"
474  "mov %[n2] , %[lo]" "\n\t"
475  "out %[port] , %[n1]" "\n\t"
476  "rjmp .+0" "\n\t"
477  "sbrc %[byte] , 6" "\n\t"
478  "mov %[n2] , %[hi]" "\n\t"
479  "out %[port] , %[lo]" "\n\t"
480  "rjmp .+0" "\n\t"
481  "out %[port] , %[hi]" "\n\t"
482  "mov %[n1] , %[lo]" "\n\t"
483  "out %[port] , %[n2]" "\n\t"
484  "rjmp .+0" "\n\t"
485  "sbrc %[byte] , 5" "\n\t"
486  "mov %[n1] , %[hi]" "\n\t"
487  "out %[port] , %[lo]" "\n\t"
488  "rjmp .+0" "\n\t"
489  "out %[port] , %[hi]" "\n\t"
490  "mov %[n2] , %[lo]" "\n\t"
491  "out %[port] , %[n1]" "\n\t"
492  "rjmp .+0" "\n\t"
493  "sbrc %[byte] , 4" "\n\t"
494  "mov %[n2] , %[hi]" "\n\t"
495  "out %[port] , %[lo]" "\n\t"
496  "rjmp .+0" "\n\t"
497  "out %[port] , %[hi]" "\n\t"
498  "mov %[n1] , %[lo]" "\n\t"
499  "out %[port] , %[n2]" "\n\t"
500  "rjmp .+0" "\n\t"
501  "sbrc %[byte] , 3" "\n\t"
502  "mov %[n1] , %[hi]" "\n\t"
503  "out %[port] , %[lo]" "\n\t"
504  "rjmp .+0" "\n\t"
505  "out %[port] , %[hi]" "\n\t"
506  "mov %[n2] , %[lo]" "\n\t"
507  "out %[port] , %[n1]" "\n\t"
508  "rjmp .+0" "\n\t"
509  "sbrc %[byte] , 2" "\n\t"
510  "mov %[n2] , %[hi]" "\n\t"
511  "out %[port] , %[lo]" "\n\t"
512  "rjmp .+0" "\n\t"
513  "out %[port] , %[hi]" "\n\t"
514  "mov %[n1] , %[lo]" "\n\t"
515  "out %[port] , %[n2]" "\n\t"
516  "rjmp .+0" "\n\t"
517  "sbrc %[byte] , 1" "\n\t"
518  "mov %[n1] , %[hi]" "\n\t"
519  "out %[port] , %[lo]" "\n\t"
520  "rjmp .+0" "\n\t"
521  "out %[port] , %[hi]" "\n\t"
522  "mov %[n2] , %[lo]" "\n\t"
523  "out %[port] , %[n1]" "\n\t"
524  "rjmp .+0" "\n\t"
525  "sbrc %[byte] , 0" "\n\t"
526  "mov %[n2] , %[hi]" "\n\t"
527  "out %[port] , %[lo]" "\n\t"
528  "sbiw %[count], 1" "\n\t"
529  "out %[port] , %[hi]" "\n\t"
530  "mov %[n1] , %[lo]" "\n\t"
531  "out %[port] , %[n2]" "\n\t"
532  "ld %[byte] , %a[ptr]+" "\n\t"
533  "sbrc %[byte] , 7" "\n\t"
534  "mov %[n1] , %[hi]" "\n\t"
535  "out %[port] , %[lo]" "\n\t"
536  "brne headB" "\n"
537  : [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i)
538  : [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi),
539  [lo] "r" (lo));
540 
541  #if defined(PORTD) || defined(PORTC) || defined(PORTF)
542  }
543  #endif
544  #if defined(PORTC) || defined(PORTF)
545  else
546  #endif
547  #endif
548 
549  #if defined(PORTC)
550  #if defined(PORTD) || defined(PORTB) || defined(PORTF)
551  if(port == &PORTC) {
552  #endif
553 
554  hi = PORTC | pinMask;
555  lo = PORTC & ~pinMask;
556  n1 = lo;
557  if(b & 0x80) n1 = hi;
558 
559  asm volatile(
560  "headC:" "\n\t"
561  "out %[port] , %[hi]" "\n\t"
562  "mov %[n2] , %[lo]" "\n\t"
563  "out %[port] , %[n1]" "\n\t"
564  "rjmp .+0" "\n\t"
565  "sbrc %[byte] , 6" "\n\t"
566  "mov %[n2] , %[hi]" "\n\t"
567  "out %[port] , %[lo]" "\n\t"
568  "rjmp .+0" "\n\t"
569  "out %[port] , %[hi]" "\n\t"
570  "mov %[n1] , %[lo]" "\n\t"
571  "out %[port] , %[n2]" "\n\t"
572  "rjmp .+0" "\n\t"
573  "sbrc %[byte] , 5" "\n\t"
574  "mov %[n1] , %[hi]" "\n\t"
575  "out %[port] , %[lo]" "\n\t"
576  "rjmp .+0" "\n\t"
577  "out %[port] , %[hi]" "\n\t"
578  "mov %[n2] , %[lo]" "\n\t"
579  "out %[port] , %[n1]" "\n\t"
580  "rjmp .+0" "\n\t"
581  "sbrc %[byte] , 4" "\n\t"
582  "mov %[n2] , %[hi]" "\n\t"
583  "out %[port] , %[lo]" "\n\t"
584  "rjmp .+0" "\n\t"
585  "out %[port] , %[hi]" "\n\t"
586  "mov %[n1] , %[lo]" "\n\t"
587  "out %[port] , %[n2]" "\n\t"
588  "rjmp .+0" "\n\t"
589  "sbrc %[byte] , 3" "\n\t"
590  "mov %[n1] , %[hi]" "\n\t"
591  "out %[port] , %[lo]" "\n\t"
592  "rjmp .+0" "\n\t"
593  "out %[port] , %[hi]" "\n\t"
594  "mov %[n2] , %[lo]" "\n\t"
595  "out %[port] , %[n1]" "\n\t"
596  "rjmp .+0" "\n\t"
597  "sbrc %[byte] , 2" "\n\t"
598  "mov %[n2] , %[hi]" "\n\t"
599  "out %[port] , %[lo]" "\n\t"
600  "rjmp .+0" "\n\t"
601  "out %[port] , %[hi]" "\n\t"
602  "mov %[n1] , %[lo]" "\n\t"
603  "out %[port] , %[n2]" "\n\t"
604  "rjmp .+0" "\n\t"
605  "sbrc %[byte] , 1" "\n\t"
606  "mov %[n1] , %[hi]" "\n\t"
607  "out %[port] , %[lo]" "\n\t"
608  "rjmp .+0" "\n\t"
609  "out %[port] , %[hi]" "\n\t"
610  "mov %[n2] , %[lo]" "\n\t"
611  "out %[port] , %[n1]" "\n\t"
612  "rjmp .+0" "\n\t"
613  "sbrc %[byte] , 0" "\n\t"
614  "mov %[n2] , %[hi]" "\n\t"
615  "out %[port] , %[lo]" "\n\t"
616  "sbiw %[count], 1" "\n\t"
617  "out %[port] , %[hi]" "\n\t"
618  "mov %[n1] , %[lo]" "\n\t"
619  "out %[port] , %[n2]" "\n\t"
620  "ld %[byte] , %a[ptr]+" "\n\t"
621  "sbrc %[byte] , 7" "\n\t"
622  "mov %[n1] , %[hi]" "\n\t"
623  "out %[port] , %[lo]" "\n\t"
624  "brne headC" "\n"
625  : [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i)
626  : [port] "I" (_SFR_IO_ADDR(PORTC)), [ptr] "e" (ptr), [hi] "r" (hi),
627  [lo] "r" (lo));
628 
629  #if defined(PORTD) || defined(PORTB) || defined(PORTF)
630  }
631  #endif
632  #if defined(PORTF)
633  else
634  #endif
635  #endif
636 
637  #if defined(PORTF)
638  #if defined(PORTD) || defined(PORTB) || defined(PORTC)
639  if(port == &PORTF) {
640  #endif // defined(PORTD/B/C)
641 
642  hi = PORTF | pinMask;
643  lo = PORTF & ~pinMask;
644  n1 = lo;
645  if(b & 0x80) n1 = hi;
646 
647  asm volatile(
648  "headF:" "\n\t"
649  "out %[port] , %[hi]" "\n\t"
650  "mov %[n2] , %[lo]" "\n\t"
651  "out %[port] , %[n1]" "\n\t"
652  "rjmp .+0" "\n\t"
653  "sbrc %[byte] , 6" "\n\t"
654  "mov %[n2] , %[hi]" "\n\t"
655  "out %[port] , %[lo]" "\n\t"
656  "rjmp .+0" "\n\t"
657  "out %[port] , %[hi]" "\n\t"
658  "mov %[n1] , %[lo]" "\n\t"
659  "out %[port] , %[n2]" "\n\t"
660  "rjmp .+0" "\n\t"
661  "sbrc %[byte] , 5" "\n\t"
662  "mov %[n1] , %[hi]" "\n\t"
663  "out %[port] , %[lo]" "\n\t"
664  "rjmp .+0" "\n\t"
665  "out %[port] , %[hi]" "\n\t"
666  "mov %[n2] , %[lo]" "\n\t"
667  "out %[port] , %[n1]" "\n\t"
668  "rjmp .+0" "\n\t"
669  "sbrc %[byte] , 4" "\n\t"
670  "mov %[n2] , %[hi]" "\n\t"
671  "out %[port] , %[lo]" "\n\t"
672  "rjmp .+0" "\n\t"
673  "out %[port] , %[hi]" "\n\t"
674  "mov %[n1] , %[lo]" "\n\t"
675  "out %[port] , %[n2]" "\n\t"
676  "rjmp .+0" "\n\t"
677  "sbrc %[byte] , 3" "\n\t"
678  "mov %[n1] , %[hi]" "\n\t"
679  "out %[port] , %[lo]" "\n\t"
680  "rjmp .+0" "\n\t"
681  "out %[port] , %[hi]" "\n\t"
682  "mov %[n2] , %[lo]" "\n\t"
683  "out %[port] , %[n1]" "\n\t"
684  "rjmp .+0" "\n\t"
685  "sbrc %[byte] , 2" "\n\t"
686  "mov %[n2] , %[hi]" "\n\t"
687  "out %[port] , %[lo]" "\n\t"
688  "rjmp .+0" "\n\t"
689  "out %[port] , %[hi]" "\n\t"
690  "mov %[n1] , %[lo]" "\n\t"
691  "out %[port] , %[n2]" "\n\t"
692  "rjmp .+0" "\n\t"
693  "sbrc %[byte] , 1" "\n\t"
694  "mov %[n1] , %[hi]" "\n\t"
695  "out %[port] , %[lo]" "\n\t"
696  "rjmp .+0" "\n\t"
697  "out %[port] , %[hi]" "\n\t"
698  "mov %[n2] , %[lo]" "\n\t"
699  "out %[port] , %[n1]" "\n\t"
700  "rjmp .+0" "\n\t"
701  "sbrc %[byte] , 0" "\n\t"
702  "mov %[n2] , %[hi]" "\n\t"
703  "out %[port] , %[lo]" "\n\t"
704  "sbiw %[count], 1" "\n\t"
705  "out %[port] , %[hi]" "\n\t"
706  "mov %[n1] , %[lo]" "\n\t"
707  "out %[port] , %[n2]" "\n\t"
708  "ld %[byte] , %a[ptr]+" "\n\t"
709  "sbrc %[byte] , 7" "\n\t"
710  "mov %[n1] , %[hi]" "\n\t"
711  "out %[port] , %[lo]" "\n\t"
712  "brne headF" "\n"
713  : [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i)
714  : [port] "I" (_SFR_IO_ADDR(PORTF)), [ptr] "e" (ptr), [hi] "r" (hi),
715  [lo] "r" (lo));
716 
717  #if defined(PORTD) || defined(PORTB) || defined(PORTC)
718  }
719  #endif // defined(PORTD/B/C)
720  #endif // defined(PORTF)
721  } else {
722 
723  volatile uint8_t next, bit;
724 
725  hi = *port | pinMask;
726  lo = *port & ~pinMask;
727  next = lo;
728  bit = 8;
729 
730  asm volatile(
731  "head20:" "\n\t" // Clk Pseudocode (T = 0)
732  "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
733  "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128)
734  "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4)
735  "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 6)
736  "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7)
737  "dec %[bit]" "\n\t" // 1 bit-- (T = 8)
738  "breq nextbyte20" "\n\t" // 1-2 if(bit == 0)
739  "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10)
740  "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12)
741  "rjmp .+0" "\n\t" // 2 nop nop (T = 14)
742  "rjmp .+0" "\n\t" // 2 nop nop (T = 16)
743  "rjmp .+0" "\n\t" // 2 nop nop (T = 18)
744  "rjmp head20" "\n\t" // 2 -> head20 (next bit out)
745  "nextbyte20:" "\n\t" // (T = 10)
746  "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12)
747  "nop" "\n\t" // 1 nop (T = 13)
748  "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 14)
749  "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 16)
750  "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18)
751  "brne head20" "\n" // 2 if(i != 0) -> (next byte)
752  : [port] "+e" (port),
753  [byte] "+r" (b),
754  [bit] "+r" (bit),
755  [next] "+r" (next),
756  [count] "+w" (i)
757  : [hi] "r" (hi),
758  [lo] "r" (lo),
759  [ptr] "e" (ptr));
760  }
761  #elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL)
762  if(is800KHz) {
763  volatile uint8_t next;
764 
765  // PORTD OUTPUT ----------------------------------------------------
766 
767  #if defined(PORTD)
768  #if defined(PORTB) || defined(PORTC) || defined(PORTF)
769  if(port == &PORTD) {
770  #endif
771 
772  hi = PORTD | pinMask;
773  lo = PORTD & ~pinMask;
774  next = lo;
775  if(b & 0x80) next = hi;
776  asm volatile(
777  "headD:" "\n\t" // (T = 0)
778  "out %[port], %[hi]" "\n\t" // (T = 1)
779  "rcall bitTimeD" "\n\t" // Bit 7 (T = 15)
780  "out %[port], %[hi]" "\n\t"
781  "rcall bitTimeD" "\n\t" // Bit 6
782  "out %[port], %[hi]" "\n\t"
783  "rcall bitTimeD" "\n\t" // Bit 5
784  "out %[port], %[hi]" "\n\t"
785  "rcall bitTimeD" "\n\t" // Bit 4
786  "out %[port], %[hi]" "\n\t"
787  "rcall bitTimeD" "\n\t" // Bit 3
788  "out %[port], %[hi]" "\n\t"
789  "rcall bitTimeD" "\n\t" // Bit 2
790  "out %[port], %[hi]" "\n\t"
791  "rcall bitTimeD" "\n\t" // Bit 1
792  // Bit 0:
793  "out %[port] , %[hi]" "\n\t" // 1 PORT = hi (T = 1)
794  "rjmp .+0" "\n\t" // 2 nop nop (T = 3)
795  "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 5)
796  "out %[port] , %[next]" "\n\t" // 1 PORT = next (T = 6)
797  "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7)
798  "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80) (T = 8)
799  "mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 9)
800  "nop" "\n\t" // 1 (T = 10)
801  "out %[port] , %[lo]" "\n\t" // 1 PORT = lo (T = 11)
802  "sbiw %[count], 1" "\n\t" // 2 i-- (T = 13)
803  "brne headD" "\n\t" // 2 if(i != 0) -> (next byte)
804  "rjmp doneD" "\n\t"
805  "bitTimeD:" "\n\t" // nop nop nop (T = 4)
806  "out %[port], %[next]" "\n\t" // 1 PORT = next (T = 5)
807  "mov %[next], %[lo]" "\n\t" // 1 next = lo (T = 6)
808  "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 7)
809  "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 0x80) (T = 8)
810  "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 9)
811  "nop" "\n\t" // 1 (T = 10)
812  "out %[port], %[lo]" "\n\t" // 1 PORT = lo (T = 11)
813  "ret" "\n\t" // 4 nop nop nop nop (T = 15)
814  "doneD:" "\n"
815  : [byte] "+r" (b),
816  [next] "+r" (next),
817  [count] "+w" (i)
818  : [port] "I" (_SFR_IO_ADDR(PORTD)),
819  [ptr] "e" (ptr),
820  [hi] "r" (hi),
821  [lo] "r" (lo));
822 
823  #if defined(PORTB) || defined(PORTC) || defined(PORTF)
824  } else
825  #endif
826  #endif
827 
828  #if defined(PORTB)
829  #if defined(PORTD) || defined(PORTC) || defined(PORTF)
830  if(port == &PORTB) {
831  #endif
832 
833  hi = PORTB | pinMask;
834  lo = PORTB & ~pinMask;
835  next = lo;
836  if(b & 0x80) next = hi;
837 
838  asm volatile(
839  "headB:" "\n\t"
840  "out %[port], %[hi]" "\n\t"
841  "rcall bitTimeB" "\n\t"
842  "out %[port], %[hi]" "\n\t"
843  "rcall bitTimeB" "\n\t"
844  "out %[port], %[hi]" "\n\t"
845  "rcall bitTimeB" "\n\t"
846  "out %[port], %[hi]" "\n\t"
847  "rcall bitTimeB" "\n\t"
848  "out %[port], %[hi]" "\n\t"
849  "rcall bitTimeB" "\n\t"
850  "out %[port], %[hi]" "\n\t"
851  "rcall bitTimeB" "\n\t"
852  "out %[port], %[hi]" "\n\t"
853  "rcall bitTimeB" "\n\t"
854  "out %[port] , %[hi]" "\n\t"
855  "rjmp .+0" "\n\t"
856  "ld %[byte] , %a[ptr]+" "\n\t"
857  "out %[port] , %[next]" "\n\t"
858  "mov %[next] , %[lo]" "\n\t"
859  "sbrc %[byte] , 7" "\n\t"
860  "mov %[next] , %[hi]" "\n\t"
861  "nop" "\n\t"
862  "out %[port] , %[lo]" "\n\t"
863  "sbiw %[count], 1" "\n\t"
864  "brne headB" "\n\t"
865  "rjmp doneB" "\n\t"
866  "bitTimeB:" "\n\t"
867  "out %[port], %[next]" "\n\t"
868  "mov %[next], %[lo]" "\n\t"
869  "rol %[byte]" "\n\t"
870  "sbrc %[byte], 7" "\n\t"
871  "mov %[next], %[hi]" "\n\t"
872  "nop" "\n\t"
873  "out %[port], %[lo]" "\n\t"
874  "ret" "\n\t"
875  "doneB:" "\n"
876  : [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i)
877  : [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi),
878  [lo] "r" (lo));
879 
880  #if defined(PORTD) || defined(PORTC) || defined(PORTF)
881  }
882  #endif
883  #if defined(PORTC) || defined(PORTF)
884  else
885  #endif
886  #endif
887 
888  #if defined(PORTC)
889  #if defined(PORTD) || defined(PORTB) || defined(PORTF)
890  if(port == &PORTC) {
891  #endif
892 
893  hi = PORTC | pinMask;
894  lo = PORTC & ~pinMask;
895  next = lo;
896  if(b & 0x80) next = hi;
897 
898  asm volatile(
899  "headC:" "\n\t"
900  "out %[port], %[hi]" "\n\t"
901  "rcall bitTimeC" "\n\t"
902  "out %[port], %[hi]" "\n\t"
903  "rcall bitTimeC" "\n\t"
904  "out %[port], %[hi]" "\n\t"
905  "rcall bitTimeC" "\n\t"
906  "out %[port], %[hi]" "\n\t"
907  "rcall bitTimeC" "\n\t"
908  "out %[port], %[hi]" "\n\t"
909  "rcall bitTimeC" "\n\t"
910  "out %[port], %[hi]" "\n\t"
911  "rcall bitTimeC" "\n\t"
912  "out %[port], %[hi]" "\n\t"
913  "rcall bitTimeC" "\n\t"
914  "out %[port] , %[hi]" "\n\t"
915  "rjmp .+0" "\n\t"
916  "ld %[byte] , %a[ptr]+" "\n\t"
917  "out %[port] , %[next]" "\n\t"
918  "mov %[next] , %[lo]" "\n\t"
919  "sbrc %[byte] , 7" "\n\t"
920  "mov %[next] , %[hi]" "\n\t"
921  "nop" "\n\t"
922  "out %[port] , %[lo]" "\n\t"
923  "sbiw %[count], 1" "\n\t"
924  "brne headC" "\n\t"
925  "rjmp doneC" "\n\t"
926  "bitTimeC:" "\n\t"
927  "out %[port], %[next]" "\n\t"
928  "mov %[next], %[lo]" "\n\t"
929  "rol %[byte]" "\n\t"
930  "sbrc %[byte], 7" "\n\t"
931  "mov %[next], %[hi]" "\n\t"
932  "nop" "\n\t"
933  "out %[port], %[lo]" "\n\t"
934  "ret" "\n\t"
935  "doneC:" "\n"
936  : [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i)
937  : [port] "I" (_SFR_IO_ADDR(PORTC)), [ptr] "e" (ptr), [hi] "r" (hi),
938  [lo] "r" (lo));
939 
940  #if defined(PORTD) || defined(PORTB) || defined(PORTF)
941  }
942  #endif
943  #if defined(PORTF)
944  else
945  #endif
946  #endif
947 
948  #if defined(PORTF)
949  #if defined(PORTD) || defined(PORTB) || defined(PORTC)
950  if(port == &PORTF) {
951  #endif
952 
953  hi = PORTF | pinMask;
954  lo = PORTF & ~pinMask;
955  next = lo;
956  if(b & 0x80) next = hi;
957 
958  asm volatile(
959  "headF:" "\n\t"
960  "out %[port], %[hi]" "\n\t"
961  "rcall bitTimeC" "\n\t"
962  "out %[port], %[hi]" "\n\t"
963  "rcall bitTimeC" "\n\t"
964  "out %[port], %[hi]" "\n\t"
965  "rcall bitTimeC" "\n\t"
966  "out %[port], %[hi]" "\n\t"
967  "rcall bitTimeC" "\n\t"
968  "out %[port], %[hi]" "\n\t"
969  "rcall bitTimeC" "\n\t"
970  "out %[port], %[hi]" "\n\t"
971  "rcall bitTimeC" "\n\t"
972  "out %[port], %[hi]" "\n\t"
973  "rcall bitTimeC" "\n\t"
974  "out %[port] , %[hi]" "\n\t"
975  "rjmp .+0" "\n\t"
976  "ld %[byte] , %a[ptr]+" "\n\t"
977  "out %[port] , %[next]" "\n\t"
978  "mov %[next] , %[lo]" "\n\t"
979  "sbrc %[byte] , 7" "\n\t"
980  "mov %[next] , %[hi]" "\n\t"
981  "nop" "\n\t"
982  "out %[port] , %[lo]" "\n\t"
983  "sbiw %[count], 1" "\n\t"
984  "brne headF" "\n\t"
985  "rjmp doneC" "\n\t"
986  "bitTimeC:" "\n\t"
987  "out %[port], %[next]" "\n\t"
988  "mov %[next], %[lo]" "\n\t"
989  "rol %[byte]" "\n\t"
990  "sbrc %[byte], 7" "\n\t"
991  "mov %[next], %[hi]" "\n\t"
992  "nop" "\n\t"
993  "out %[port], %[lo]" "\n\t"
994  "ret" "\n\t"
995  "doneC:" "\n"
996  : [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i)
997  : [port] "I" (_SFR_IO_ADDR(PORTF)), [ptr] "e" (ptr), [hi] "r" (hi),
998  [lo] "r" (lo));
999 
1000  #if defined(PORTD) || defined(PORTB) || defined(PORTC)
1001  }
1002  #endif
1003  #endif
1004  } else {
1005  volatile uint8_t next, bit;
1006 
1007  hi = *port | pinMask;
1008  lo = *port & ~pinMask;
1009  next = lo;
1010  bit = 8;
1011 
1012  asm volatile(
1013  "head30:" "\n\t" // Clk Pseudocode (T = 0)
1014  "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
1015  "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128)
1016  "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4)
1017  "rjmp .+0" "\n\t" // 2 nop nop (T = 6)
1018  "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 8)
1019  "rjmp .+0" "\n\t" // 2 nop nop (T = 10)
1020  "rjmp .+0" "\n\t" // 2 nop nop (T = 12)
1021  "rjmp .+0" "\n\t" // 2 nop nop (T = 14)
1022  "nop" "\n\t" // 1 nop (T = 15)
1023  "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 17)
1024  "rjmp .+0" "\n\t" // 2 nop nop (T = 19)
1025  "dec %[bit]" "\n\t" // 1 bit-- (T = 20)
1026  "breq nextbyte30" "\n\t" // 1-2 if(bit == 0)
1027  "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 22)
1028  "rjmp .+0" "\n\t" // 2 nop nop (T = 24)
1029  "rjmp .+0" "\n\t" // 2 nop nop (T = 26)
1030  "rjmp .+0" "\n\t" // 2 nop nop (T = 28)
1031  "rjmp head30" "\n\t" // 2 -> head30 (next bit out)
1032  "nextbyte30:" "\n\t" // (T = 22)
1033  "nop" "\n\t" // 1 nop (T = 23)
1034  "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 24)
1035  "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 26)
1036  "sbiw %[count], 1" "\n\t" // 2 i-- (T = 28)
1037  "brne head30" "\n" // 1-2 if(i != 0) -> (next byte)
1038  : [port] "+e" (port),
1039  [byte] "+r" (b),
1040  [bit] "+r" (bit),
1041  [next] "+r" (next),
1042  [count] "+w" (i)
1043  : [hi] "r" (hi),
1044  [lo] "r" (lo),
1045  [ptr] "e" (ptr));
1046  }
1047  #elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L)
1048  if(is800KHz) {
1049  volatile uint8_t next, bit;
1050 
1051  hi = *port | pinMask;
1052  lo = *port & ~pinMask;
1053  next = lo;
1054  bit = 8;
1055 
1056  asm volatile(
1057  "head20:" "\n\t" // Clk Pseudocode (T = 0)
1058  "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
1059  "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 128)
1060  "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4)
1061  "dec %[bit]" "\n\t" // 1 bit-- (T = 5)
1062  "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 7)
1063  "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 8)
1064  "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) (from dec above)
1065  "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10)
1066  "rjmp .+0" "\n\t" // 2 nop nop (T = 12)
1067  "nop" "\n\t" // 1 nop (T = 13)
1068  "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15)
1069  "nop" "\n\t" // 1 nop (T = 16)
1070  "rjmp .+0" "\n\t" // 2 nop nop (T = 18)
1071  "rjmp head20" "\n\t" // 2 -> head20 (next bit out)
1072  "nextbyte20:" "\n\t" // (T = 10)
1073  "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 11)
1074  "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 13)
1075  "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15)
1076  "nop" "\n\t" // 1 nop (T = 16)
1077  "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18)
1078  "brne head20" "\n" // 2 if(i != 0) -> (next byte)
1079  : [port] "+e" (port),
1080  [byte] "+r" (b),
1081  [bit] "+r" (bit),
1082  [next] "+r" (next),
1083  [count] "+w" (i)
1084  : [ptr] "e" (ptr),
1085  [hi] "r" (hi),
1086  [lo] "r" (lo));
1087  } else {
1088 
1089  volatile uint8_t next, bit;
1090 
1091  hi = *port | pinMask;
1092  lo = *port & ~pinMask;
1093  next = lo;
1094  bit = 8;
1095 
1096  asm volatile(
1097  "head40:" "\n\t" // Clk Pseudocode (T = 0)
1098  "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
1099  "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128)
1100  "mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 4)
1101  "rjmp .+0" "\n\t" // 2 nop nop (T = 6)
1102  "rjmp .+0" "\n\t" // 2 nop nop (T = 8)
1103  "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 10)
1104  "rjmp .+0" "\n\t" // 2 nop nop (T = 12)
1105  "rjmp .+0" "\n\t" // 2 nop nop (T = 14)
1106  "rjmp .+0" "\n\t" // 2 nop nop (T = 16)
1107  "rjmp .+0" "\n\t" // 2 nop nop (T = 18)
1108  "rjmp .+0" "\n\t" // 2 nop nop (T = 20)
1109  "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 22)
1110  "nop" "\n\t" // 1 nop (T = 23)
1111  "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 24)
1112  "dec %[bit]" "\n\t" // 1 bit-- (T = 25)
1113  "breq nextbyte40" "\n\t" // 1-2 if(bit == 0)
1114  "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 27)
1115  "nop" "\n\t" // 1 nop (T = 28)
1116  "rjmp .+0" "\n\t" // 2 nop nop (T = 30)
1117  "rjmp .+0" "\n\t" // 2 nop nop (T = 32)
1118  "rjmp .+0" "\n\t" // 2 nop nop (T = 34)
1119  "rjmp .+0" "\n\t" // 2 nop nop (T = 36)
1120  "rjmp .+0" "\n\t" // 2 nop nop (T = 38)
1121  "rjmp head40" "\n\t" // 2 -> head40 (next bit out)
1122  "nextbyte40:" "\n\t" // (T = 27)
1123  "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 28)
1124  "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 30)
1125  "rjmp .+0" "\n\t" // 2 nop nop (T = 32)
1126  "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 34)
1127  "rjmp .+0" "\n\t" // 2 nop nop (T = 36)
1128  "sbiw %[count], 1" "\n\t" // 2 i-- (T = 38)
1129  "brne head40" "\n" // 1-2 if(i != 0) -> (next byte)
1130  : [port] "+e" (port),
1131  [byte] "+r" (b),
1132  [bit] "+r" (bit),
1133  [next] "+r" (next),
1134  [count] "+w" (i)
1135  : [ptr] "e" (ptr),
1136  [hi] "r" (hi),
1137  [lo] "r" (lo));
1138  }
1139  #else
1140  #error "CPU SPEED NOT SUPPORTED"
1141  #endif
1142  #elif defined(__arm__)
1143 
1144 
1145  #if defined(TEENSYDUINO) && defined(KINETISK) // Teensy 3.0, 3.1, 3.2, 3.5, 3.6
1146  #define CYCLES_800_T0H (F_CPU / 4000000)
1147  #define CYCLES_800_T1H (F_CPU / 1250000)
1148  #define CYCLES_800 (F_CPU / 800000)
1149  #define CYCLES_400_T0H (F_CPU / 2000000)
1150  #define CYCLES_400_T1H (F_CPU / 833333)
1151  #define CYCLES_400 (F_CPU / 400000)
1152 
1153  uint8_t *p = pixels,
1154  *end = p + numBytes, pix, mask;
1155  volatile uint8_t *set = portSetRegister(pin),
1156  *clr = portClearRegister(pin);
1157  uint32_t cyc;
1158 
1159  ARM_DEMCR |= ARM_DEMCR_TRCENA;
1160  ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
1161 
1162  if(is800KHz) {
1163  cyc = ARM_DWT_CYCCNT + CYCLES_800;
1164  while(p < end) {
1165  pix = *p++;
1166  for(mask = 0x80; mask; mask >>= 1) {
1167  while(ARM_DWT_CYCCNT - cyc < CYCLES_800);
1168  cyc = ARM_DWT_CYCCNT;
1169  *set = 1;
1170  if(pix & mask) {
1171  while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T1H);
1172  } else {
1173  while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T0H);
1174  }
1175  *clr = 1;
1176  }
1177  }
1178  while(ARM_DWT_CYCCNT - cyc < CYCLES_800);
1179  } else {
1180  cyc = ARM_DWT_CYCCNT + CYCLES_400;
1181  while(p < end) {
1182  pix = *p++;
1183  for(mask = 0x80; mask; mask >>= 1) {
1184  while(ARM_DWT_CYCCNT - cyc < CYCLES_400);
1185  cyc = ARM_DWT_CYCCNT;
1186  *set = 1;
1187  if(pix & mask) {
1188  while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T1H);
1189  } else {
1190  while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T0H);
1191  }
1192  *clr = 1;
1193  }
1194  }
1195  while(ARM_DWT_CYCCNT - cyc < CYCLES_400);
1196  }
1197  #else
1198  #error "Sorry, only 48 MHz is supported, please set Tools > CPU Speed to 48 MHz"
1199  #endif
1200  #elif defined(ESP8266) || defined(ESP32)
1201 
1202  espShow(pin, pixels, numBytes, is800KHz);
1203 
1204  #elif defined(__ARDUINO_ARC__)
1205 
1206  // Arduino 101 -----------------------------------------------------------
1207 
1208  #define NOPx7 { __builtin_arc_nop(); \
1209  __builtin_arc_nop(); __builtin_arc_nop(); \
1210  __builtin_arc_nop(); __builtin_arc_nop(); \
1211  __builtin_arc_nop(); __builtin_arc_nop(); }
1212 
1213  PinDescription *pindesc = &g_APinDescription[pin];
1214  register uint32_t loop = 8 * numBytes; // one loop to handle all bytes and all bits
1215  register uint8_t *p = pixels;
1216  register uint32_t currByte = (uint32_t) (*p);
1217  register uint32_t currBit = 0x80 & currByte;
1218  register uint32_t bitCounter = 0;
1219  register uint32_t first = 1;
1220 
1221  if (pindesc->ulGPIOType == SS_GPIO) {
1222  register uint32_t reg = pindesc->ulGPIOBase + SS_GPIO_SWPORTA_DR;
1223  uint32_t reg_val = __builtin_arc_lr((volatile uint32_t)reg);
1224  register uint32_t reg_bit_high = reg_val | (1 << pindesc->ulGPIOId);
1225  register uint32_t reg_bit_low = reg_val & ~(1 << pindesc->ulGPIOId);
1226 
1227  loop += 1;
1228  while(loop--) {
1229  if(!first) {
1230  currByte <<= 1;
1231  bitCounter++;
1232  }
1233 
1234  // 1 is >550ns high and >450ns low; 0 is 200..500ns high and >450ns low
1235  __builtin_arc_sr(first ? reg_bit_low : reg_bit_high, (volatile uint32_t)reg);
1236  if(currBit) { // ~400ns HIGH (740ns overall)
1237  NOPx7
1238  NOPx7
1239  }
1240  // ~340ns HIGH
1241  NOPx7
1242  __builtin_arc_nop();
1243 
1244  // 820ns LOW; per spec, max allowed low here is 5000ns */
1245  __builtin_arc_sr(reg_bit_low, (volatile uint32_t)reg);
1246  NOPx7
1247  NOPx7
1248 
1249  if(bitCounter >= 8) {
1250  bitCounter = 0;
1251  currByte = (uint32_t) (*++p);
1252  }
1253 
1254  currBit = 0x80 & currByte;
1255  first = 0;
1256  }
1257  } else if(pindesc->ulGPIOType == SOC_GPIO) {
1258  register uint32_t reg = pindesc->ulGPIOBase + SOC_GPIO_SWPORTA_DR;
1259  uint32_t reg_val = MMIO_REG_VAL(reg);
1260  register uint32_t reg_bit_high = reg_val | (1 << pindesc->ulGPIOId);
1261  register uint32_t reg_bit_low = reg_val & ~(1 << pindesc->ulGPIOId);
1262 
1263  loop += 1; // include first, special iteration
1264  while(loop--) {
1265  if(!first) {
1266  currByte <<= 1;
1267  bitCounter++;
1268  }
1269  MMIO_REG_VAL(reg) = first ? reg_bit_low : reg_bit_high;
1270  if(currBit) { // ~430ns HIGH (740ns overall)
1271  NOPx7
1272  NOPx7
1273  __builtin_arc_nop();
1274  }
1275  // ~310ns HIGH
1276  NOPx7
1277 
1278  // 850ns LOW; per spec, max allowed low here is 5000ns */
1279  MMIO_REG_VAL(reg) = reg_bit_low;
1280  NOPx7
1281  NOPx7
1282 
1283  if(bitCounter >= 8) {
1284  bitCounter = 0;
1285  currByte = (uint32_t) (*++p);
1286  }
1287 
1288  currBit = 0x80 & currByte;
1289  first = 0;
1290  }
1291  }
1292 
1293  #else
1294  #error Architecture not supported
1295  #endif
1296 
1297  interrupts();
1298 
1299  endTime = micros();
1300  }
1301 
1302  void NeoPixel::setPin(uint8_t p) {
1303  if(begun && (pin >= 0)) pinMode(pin, INPUT);
1304  pin = p;
1305  if(begun) {
1306  pinMode(p, OUTPUT);
1307  digitalWrite(p, LOW);
1308  }
1309  #ifdef __AVR__
1310  port = portOutputRegister(digitalPinToPort(p));
1311  pinMask = digitalPinToBitMask(p);
1312  #endif
1313  }
1314 
1316  uint16_t n, uint8_t r, uint8_t g, uint8_t b) {
1317 
1318  if(n < numLEDs) {
1319  if(brightness) { // See notes in setBrightness()
1320  r = (r * brightness) >> 8;
1321  g = (g * brightness) >> 8;
1322  b = (b * brightness) >> 8;
1323  }
1324  uint8_t *p;
1325  if(aOffset[3] == aOffset[0]) {
1326  p = &pixels[n * 3];
1327  } else {
1328  p = &pixels[n * 4];
1329  p[aOffset[3]] = 0;
1330  }
1331  p[aOffset[0]] = r;
1332  p[aOffset[1]] = g;
1333  p[aOffset[2]] = b;
1334  }
1335  }
1336 
1338  uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
1339 
1340  if(n < numLEDs) {
1341  if(brightness) {
1342  r = (r * brightness) >> 8;
1343  g = (g * brightness) >> 8;
1344  b = (b * brightness) >> 8;
1345  w = (w * brightness) >> 8;
1346  }
1347  uint8_t *p;
1348  if(aOffset[3] == aOffset[0]) {
1349  p = &pixels[n * 3];
1350  } else {
1351  p = &pixels[n * 4];
1352  p[aOffset[3]] = w;
1353  }
1354  p[aOffset[0]] = r;
1355  p[aOffset[1]] = g;
1356  p[aOffset[2]] = b;
1357  }
1358  }
1359 
1360  void NeoPixel::setPixelColor(uint16_t n, uint32_t c) {
1361  if(n < numLEDs) {
1362  uint8_t *p,
1363  r = (uint8_t)(c >> 16),
1364  g = (uint8_t)(c >> 8),
1365  b = (uint8_t)c;
1366  if(brightness) {
1367  r = (r * brightness) >> 8;
1368  g = (g * brightness) >> 8;
1369  b = (b * brightness) >> 8;
1370  }
1371  if(aOffset[3] == aOffset[0]) {
1372  p = &pixels[n * 3];
1373  } else {
1374  p = &pixels[n * 4];
1375  uint8_t w = (uint8_t)(c >> 24);
1376  p[aOffset[3]] = brightness ? ((w * brightness) >> 8) : w;
1377  }
1378  p[aOffset[0]] = r;
1379  p[aOffset[1]] = g;
1380  p[aOffset[2]] = b;
1381  }
1382  }
1383 
1384  uint32_t NeoPixel::Color(uint8_t r, uint8_t g, uint8_t b) {
1385  return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
1386  }
1387 
1388  uint32_t NeoPixel::Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
1389  return ((uint32_t)w << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
1390  }
1391 
1392  uint32_t NeoPixel::getPixelColor(uint16_t n) const {
1393  if(n >= numLEDs) return 0;
1394 
1395  uint8_t *p;
1396 
1397  if(aOffset[3] == aOffset[0]) {
1398  p = &pixels[n * 3];
1399  if(brightness) {
1400 
1401  return (((uint32_t)(p[aOffset[0]] << 8) / brightness) << 16) |
1402  (((uint32_t)(p[aOffset[1]] << 8) / brightness) << 8) |
1403  ( (uint32_t)(p[aOffset[2]] << 8) / brightness );
1404  } else {
1405  return ((uint32_t)p[aOffset[0]] << 16) |
1406  ((uint32_t)p[aOffset[1]] << 8) |
1407  (uint32_t)p[aOffset[2]];
1408  }
1409  } else {
1410  p = &pixels[n * 4];
1411  if(brightness) {
1412  return (((uint32_t)(p[aOffset[3]] << 8) / brightness) << 24) |
1413  (((uint32_t)(p[aOffset[0]] << 8) / brightness) << 16) |
1414  (((uint32_t)(p[aOffset[1]] << 8) / brightness) << 8) |
1415  ( (uint32_t)(p[aOffset[2]] << 8) / brightness );
1416  } else {
1417  return ((uint32_t)p[aOffset[3]] << 24) |
1418  ((uint32_t)p[aOffset[0]] << 16) |
1419  ((uint32_t)p[aOffset[1]] << 8) |
1420  (uint32_t)p[aOffset[2]];
1421  }
1422  }
1423  }
1424 
1425 
1426 
1427  void NeoPixel::setBrightness(uint8_t b) {
1428 
1429  uint8_t newBrightness = b + 1;
1430  if(newBrightness != brightness) {
1431  uint8_t c,
1432  *ptr = pixels,
1433  oldBrightness = brightness - 1;
1434  uint16_t scale;
1435  if(oldBrightness == 0) scale = 0; // Avoid /0
1436  else if(b == 255) scale = 65535 / oldBrightness;
1437  else scale = (((uint16_t)newBrightness << 8) - 1) / oldBrightness;
1438  for(uint16_t i=0; i<numBytes; i++) {
1439  c = *ptr;
1440  *ptr++ = (c * scale) >> 8;
1441  }
1442  brightness = newBrightness;
1443  }
1444  }
1445 
1446 
1447 
1448  void NeoPixel::clear() {
1449  memset(pixels, 0, numBytes);
1450  }
1451 
1453 #endif
uint8_t * pixels
stores the pixels
int8_t pin
stores the pin -1 if the pin wasn&#39;t set
uint8_t aOffset[4]
stores the offsets in rgbw format
bool canShow(void)
this will determine if the next show is available [last show finished]
uint8_t getBrightness(void) const
returns the current set brightness
uint16_t numLEDs
stores the amount of LEDs
~NeoPixel(void)
the destructor [calling free on pixel and freeing input pin]
bool begun
true if NeoPixel::begin has been called
int8_t getPin(void)
this will return the set data pin
NeoPixel pixels
the NeoPixel-object we use
void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b)
sets the rgb color of a specific pixel
void updateLength(uint16_t n)
this changes the length of the connected LED stripe
uint16_t numBytes
stores the byte size [pixels] used internally
static uint32_t Color(uint8_t r, uint8_t g, uint8_t b)
returns a color value that can be used with NeoPixel::setPixelColor()
void setPin(uint8_t p)
sets pin for communication
void clear(void)
this will reset all set pixels [won&#39;t call NeoPixel::show()]
uint8_t * getPixels(void) const
this will give you access to the pixels
#define EBOARD_NEO_GRB
void updateType(uint16_t t)
this changes the type of communication between arduino and LED stripe
NeoPixel(void)
the empty constructor
uint32_t endTime
stores the last call time of show for NeoPixel::canShow()
void setBrightness(uint8_t val)
changes the brightness for all further acceses via NeoPixel::setPixelColor()
uint8_t brightness
stores the brightness
#define EBOARD_NEO_800KHZ
bool is800KHz
determines the speed the communcation is working on
void begin(void)
this has to be called to start the communcation (you should call NeoPixel::setPin() before) ...
[NEO] this allows you to access Adafruit LED-stripes
uint32_t getPixelColor(uint16_t n) const
returns the color of a specific pixel
void show(void)
this will reveal the setPixels [via NeoPixel::setPixelColor() etc...]
uint16_t numPixels(void) const
returns the size of the LED stripe