Neopixel Library mod to control lots of LEDS with ATTINY85

I made some mods to the Adafruit_Neopixel library to allow me to control 300 LEDs instead of just 75.
I have tested it on my 300LEDs. Seems to work. I thought I would post the mods in case someone else has the same issue with not having sufficient memory for LEDs.

I have only modified the code section for 16Mhz (ish) processors. Also, I am not sure how critical timing is between LEDs. Maybe the asm routine could be made shorter if timing changes are no big deal.

Apologies in advance if I have broken etiquette – I don’t use forums much.

Background:
I built some lights inside jars and added clear marbles as a decorative display. I thought, “wouldn’t it be fun to have more jars in series”, but then I ran out of memory. Then I thought, couldn’t I just repeat the same 75 LEDs over and over again? So I modified the libraries as follows:

/*   call the function using:    */

strip.show(repeats);

/* where "strip" is a LED strip defined by an Adafruit_Neopixel call and
        repeats are number of times to repeat the pixels in the strip             */

/*   mods to Adafruit_Neopixel.h 
      line 210                       */

void              show(uint8_t);


/*   mods to Adafruit_Neopixel.cpp
      line 195                       */

void Adafruit_NeoPixel::show(uint8_t rpts) {


/*     lines 228-234  */

  volatile uint16_t i = (numBytes-1), ctrstore = (numBytes-1); // Loop counter
  volatile uint8_t
   *ptr = pixels,   // Pointer to next byte
   *ptrstr = pixels,// Pointer to next byte
    b   = *ptr++,   // Current byte value
    hi,             // PORT w/output bit set high
    lo;             // PORT w/output bit set low


/*             lines 1031-1092     */

    asm volatile(
     "head20:"                   "\n\t" // Clk  Pseudocode    (T =  0)
      "st   %a[port],  %[hi]"    "\n\t" // 2    PORT = hi     (T =  2)
      "sbrc %[byte],  7"         "\n\t" // 1-2  if(b & 128)
      "mov  %[next],  %[hi]"     "\n\t" // 0-1   next = hi    (T =  4)
      "dec  %[bit]"              "\n\t" // 1    bit--         (T =  5)
      "st   %a[port],  %[next]"  "\n\t" // 2    PORT = next   (T =  7)
      "mov  %[next] ,  %[lo]"    "\n\t" // 1    next = lo     (T =  8)
      "breq nextbyte20"          "\n\t" // 1-2  if(bit == 0) (from dec above)
      "rol  %[byte]"             "\n\t" // 1    b <<= 1       (T = 10)
      "rjmp .+0"                 "\n\t" // 2    nop nop       (T = 12)
      "nop"                      "\n\t" // 1    nop           (T = 13)
      "st   %a[port],  %[lo]"    "\n\t" // 2    PORT = lo     (T = 15)
      "nop"                      "\n\t" // 1    nop           (T = 16)
      "rjmp .+0"                 "\n\t" // 2    nop nop       (T = 18)
      "rjmp head20"              "\n\t" // 2    -> head20 (next bit out)
     "nextbyte20:"               "\n\t" //                    (T = 10)
      "ldi  %[bit]  ,  8"        "\n\t" // 1    bit = 8       (T = 11)
      "ld   %[byte] ,  %a[ptr]+" "\n\t" // 2    b = *ptr++    (T = 13)
      "st   %a[port], %[lo]"     "\n\t" // 2    PORT = lo     (T = 15)
      "nop"                      "\n\t" // 1    nop           (T = 16)
      "sbiw %[count], 1"         "\n\t" // 2    i--           (T = 18)
      "brne head20"              "\n\t"   // 2    if(i != 0) -> (next byte)
// last byte is done here, replacing 2xnop with code to set up for the next repeat
// the section below adds to the codespace, but preserves timing
// reset ptr, reset count, reset bit, reset b,  dec repeats 
	 "head21:"                   "\n\t" // Clk  Pseudocode    (T =  0)  no change
      "st   %a[port],  %[hi]"    "\n\t" // 2    PORT = hi     (T =  2)  no change
      "sbrc %[byte],   7"        "\n\t" // 1-2  if(b & 128)             no change
      "mov  %[next],   %[hi]"    "\n\t" // 0-1   next = hi    (T =  4)  no change
      "dec  %[bit]"              "\n\t" // 1    bit--         (T =  5)  no change
      "st   %a[port],  %[next]"  "\n\t" // 2    PORT = next   (T =  7)  no change
      "mov  %[next] ,  %[lo]"    "\n\t" // 1    next = lo     (T =  8)  no change
      "breq nextbyte21"          "\n\t" // 1-2  if(bit == 0) (from dec above)    new address location
      "rol  %[byte]"             "\n\t" // 1    b <<= 1       (T = 10)  no change
      "rjmp .+0"                 "\n\t" // 2    nop nop       (T = 12)  no change
      "nop"                      "\n\t" // 1    nop           (T = 13)  no change
      "st   %a[port],  %[lo]"    "\n\t" // 2    PORT = lo     (T = 15)  no change
      "nop"                      "\n\t" // 1    nop           (T = 16)  no change
      "rjmp .+0"                 "\n\t" // 2    nop nop       (T = 18)  no change
      "rjmp head21"              "\n\t" // 2    -> head21 (next bit out)
     "nextbyte21:"               "\n\t" //                    (T = 10)  new address
      "ldi  %[bit]  ,  8"        "\n\t" // 1    bit = 8       (T = 11)  no change, reset bit
      "movw %[count],  %[cntst]" "\n\t" // 1    (reset count) (T = 12)  formerly ld for byte, need to move two bytes
      "movw %[ptr],    %[ptrst]" "\n\t" // 1    (reset ptr)   (T = 13)  formerly ld for byte, need to move two bytes
      "ld   %[byte] ,  %a[ptr]+" "\n\t" // 2    b = *ptr++    (T = 17)  formerly 2xnop, reset b (byte)
      "st   %a[port],  %[lo]"    "\n\t" // 2    PORT = lo     (T = 15)  no change
      "dec  %[rpts]"             "\n\t" // 1    rpts--        (T = 18)  decrement repeats
      "brne head20"              "\n\t" // 2    if(rpts != 0) -> (go back and run the routine again) 
		  
      : [port]  "+e" (port),         //keep this the same, appears to be a two-byte pointer
        [byte]  "+r" (b),            //keep this the same, appears to be one byte in register
        [bit]   "+r" (bit),          //keep this the same, appears to be one byte in register
        [next]  "+r" (next),         //keep this the same, appears to be one byte in register
        [cntst] "+r" (ctrstore),     //need two registers to store the two bytes of count data
        [rpts]  "+r" (rpts),         //one register for "repeats"
        [count] "+w" (i)             //two registers for "count".  consider changing to one register
      : [ptr]    "e" (ptr),          //keep this the same, two bytes of pointer data
        [ptrst]  "r" (ptrstr),       //need two bytes to store data for ptr
        [hi]     "r" (hi),           //keep this the same, appears to be one byte in register
        [lo]     "r" (lo));          //keep this the same, appears to be one byte in register

Adafruit_NeoPixel.cpp (104 KB)

Adafruit_NeoPixel.h (17.5 KB)