WS2812_Command

Purpose: Toggle one or more PORT output BITs with the method and timing specified by the WorldSemi® WS2812 LED protocol.
Assumes:   Each output used should be restored to its incoming state upon exit.
Register R1 might not have its customary value of zero (0).
The MCU is being clocked at 8 MHz.
Passed: R25:R24   BYTE *   bPtrData   pointer to start of the SRAM buffer to transmit, with three (3) BYTEs per pixel
R23:R22 INT iCount positive: number of BYTEs (not pixels) to be transmitted OR
negative: number of BYTEs (not pixels) to send the WS2812 OFF command
R20   BYTE bPORT PORT to toggle: 5 (PORTB), 8 (PORTC) or 11 (PORTD) for a 328P
R18   BYTE   bBitMask   which BIT or BITs are to be modulated with the WS2812 timing protocol
Returns: Nothing.
Alters: R18 through R27, R30, R31, and the FLAGs (SREG)
 

WS2812_Cmd_PortSet

Notes: Everything (Purpose, Assumes, Passed, Returns, Alters) is the same as WS2812_Cmd above, except:
Passed: R21:R20   WORD   wPORTasSRAM   SRAM address of the PORT in which to toggle the BITs:
PORTB = 0x0025, PORTC = 0x0028, PORTD = 0x002B, PORTE = 0x002E, etc.

Example:  
;   Setup for the WS2812_Command() call
; R25:R24 is the pointer to the first buffered BYTE in SRAM
;     R22 is the number of BYTEs to display in LEDs (1 to 10)
;     R20 is the PORT to use (customary: PORTC = 8)
;     R18 is the BITMASK of BIT(s) to use

WS2812_GRBDebugRange:
   CPI     R22, 0                 ; The value passed in R22 must be 1 to 10
   BREQ    AInvalidExit           ;  BYTEs, because with 10 BYTES of data
   CPI     R22, 11                ;  to display, 240 pixel data BYTEs are
   BRLO    ABegin                 ;  generated
InvalidExit:
   RET
   
Begin:
   CALL    APushAll               ; PushAll() changes no Registers or FLAGs
   CALL    AStackAlloc250         ; StackAlloc250() changes R0, R26 and R27
   MOVW    R16, R30               ; Save the buffer pointer returned
   MOVW    R26, R24               ; Transfer the caller's data pointer to 'X'

   LDI     R23, 3 * 8             ; With 3 colors per LED and 8 BITS per data
   MUL     R23, R22               ;  BYTE, calculate WS2812 Tx count (R1 = 0)

   LDI     R21, 30                ; Set the GREEN component's intensity
   LDI     R23, 25                ; Set the RED component's intensity
   LDI     R24, 0                 ; Set the BLUE component's intensity

OuterLoop:
   LD      R25, X+                ; Read the next data BYTE into R25
   LDI     R19, 8                 ; Initialize the BITs/BYTE loop count

InnerLoop:
   ROR     R25                    ; Output the BYTE in Little-Endian order
;  ADD     R25, R25               ; Output the BYTE in Big-Endian order
   BRCC    AClearGREENandRED      ; The next data BIT is now in CARRY
   ST      Z+, R21                ; Set GREEN = value set above (30)
   ST      Z+, R23                ; Set RED   = value set above (25)
   RJMP    AClearBLUE

ClearGREENandRED:
   ST      Z+, R24                ; Set GREEN = 0
   ST      Z+, R24                ; Set RED   = 0

ClearBLUE:
   ST      Z+, R24                ; Set BLUE  = 0
   DEC     R19                    ; Decrement the bits/byte counter and loop
   BRNE    AInnerLoop             ;  back unless it has reached zero bits
   DEC     R22                    ; Decrement the byte counter and loop back
   BRNE    AOuterLoop             ;  until it has processed all BYTEs

   MOVW    R24, R16               ; Point to STACK-based buffer just populated
   MOVW    R22, R0                ; Load the WS2812 transmit BYTE count WORD
   CALL    AWS2812_Command        ; Call; R20 (PORT) & R18 (BITS) are as passed

LocalExit:
   CALL    AStackFree250          ; Release the STACK-based buffer

LocalPopAll:
   JMP     APopAll                ; Restore all Registers used
Setup:
.ORG   0x1000
   LDI     R25, sWallClock >> 8   ; Point to the clock: second, minute, hour,
   LDI     R24, sWallClock & 0xFF ;  day of week, date, month, year
   LDI     R22, 7                 ; Display all seven (7) of them
   LDI     R20, PORTC
   LDI     R18, B00001100         ; Specify two (2) bits: PORTC2 and PORTC3
   CALL    AWS2812_GRBDebugRange  ; Call the buffer setup routine shown above
   RET
Test it: Attach an 8x8 WS2812 GRB LED array to one of the outputs and power it in order to view the example shown below.      
An example of that device is the Adafruit® NeoPixel NeoMatrix, Product ID 1487 or 2612.
m>@ 4096                 ; Call the routine at 0x1000 (= 4096)
m>@ 4096                 ; The time and date: a Binary Clock
m>                       ; Interesting, but how about this instead?
>                        ; Logout (not required, but shortens lines)
>E 0x2D = 24             ; Point EEbTaskList_UVIndex at uVars.B[ 24 ] = 0x298
>ESW 0x298 = 250 0 4096  ; Every 250 mSec call address 0x1000 (
>E 1 ^= 0x80             ; Enable task list processing
>T = 0 0 15              ; Set the time to 3:00.00 PM
>T = 0 2 15 1 11 7 16    ; Sec=0, Min=0, Hr=15, Day=Monday, 11th, July, 2016
>                                                                               
Notes:The WS2812_Command System Function validates the PORT BYTE passed.
WS2812_Cmd_PortSet does not check the PORT SRAM address WORD passed to it.
Neither function uses any Register below R18, which means that they can be used for small, temporary buffers.
Dropin:  
(setup
code)
;   Setup for the WS2812_Command() call:
; Passed: R25:R24 BYTE * pointer to the first SRAM buffered BYTE to transmit
;         R23:R22 INT    the number of BYTES to be transmitted
;                        Note 1: negative value sends OFF to ABS (value)
;                        Note 2: ATmega memory limits the pixel count
;             R20 BYTE   the ATmega PORT on which BIT(s) will be toggled
;                        may only be 5 (PORTB), 8 (PORTC) or 11 (PORTD)
;             R18 BYTE   bitmask for that PORT's BIT(s) to change
; Returns: Nothing.
; Alters:  R18 through R27, R30, R31, and the FLAGs (SREG)

;   Setup for the WS2812_Cmd_PortSet() call
; Passed: R25:R24 BYTE * pointer to the first SRAM buffered BYTE to transmit
;         R23:R22 INT    the number of BYTES to be transmitted
;                        Note 1: negative value sends OFF to ABS (value)
;                        Note 2: ATmega memory limits the pixel count
;         R21:R20 WORD   the SRAM address of the PORT to use (PORTC = 0x28)
;             R18 BYTE   bitmask for that PORT's BIT(s) to change
; Returns: Nothing.
; Alters:  R18 through R27, R30, R31, and the FLAGs (SREG)
Also see:   The COM receive and COM transmit buffer status System Functions, the system time and task list configuration and concept web pages, as well as the EEbSystemMode configuration variable and EEfptrWS2812Exts WS2812 extension pointer in EEPROM.