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