The WS2812 Pixel driver commands

The 'P' commands support the popular WorldSemi® WS2812 Green-Red-Blue LED protocol.

The word "emit" below means "transmits the entire data array as defined by the pixel count out the default Port and Pins." The WS2812 default Port and Pins are configured using EEPROM addresses 12 and 13.

The "P" command group:
  P?       dispays (or prints) the pixel data array contents
  P?+      a "P?" option; prints in the foreground instead of the background
  P?-      a "P?" option; omits the "SRAM contents:" header row
  P-?+     both "P?" options above; can be input in any order

  P = ##   where '#' is the pixel count; BYTE count = pixel count time 3
           the maximum depends on the number of uVars.B[##] bytes used
           the BYTE count is the first WORD in the pixel data area

  PG = #   set BYTE 1; clear BYTEs 2 and 3 - These 3 commands each set only
  PR = #   set BYTE 2; clear BYTEs 1 and 3 -  one byte of an LED triplet and
  PB = #   set BYTE 3; clear BYTEs 1 and 2 -  emit the array upon completion

  PW = #   sets the same value in all BYTEs (i.e., "White") and emits the array
  PC = #[ #[ #]]"  sets the same color triplets to all LEDs and emits the array

  P0       zeroes all of the bytes in the WS2812 array but does not emit them
  P0U      zeroes all of the bytes in the WS2812 array and does emit them

  P # = #[[,] # ...]  writes one or more BYTEs into the G,R,B data array
                    the bytes start at the pixel number specified before "="
                    there are 3 BYTEs per pixel; multiple BYTEs may be entered
  PU # = #[[,] # ...] same as above but also emits them

  PU       updates (or emits) the pixel data array out to the WS2812 LEDs
           the "U" may be appended to commands which normally do not emit

  PZ       sleep; sends triplets of 0,0,0 to as many pixels as "P =" defined
           does not change the contents of the pixel data array
           this simply turns all of the defined pixels off
           it may be reversed with the simple "PU" command

  P@ ####  validates then loads a sequencer configuration from EEPROM address ####
           (after that, @ alone steps the sequencer routine one time)
Notes:
  "P?+-" is the same as "P-?+", which is the same as "P-+?", etc.
  "P0" is the same as "P 0"; "PU" is the same as "P U"
  "PU0" is the same as "PU 0", or "P U 0", or "P 0 U"
  for operators other than "=", use the "ES ### [op] #[ ...#]" syntax
>P?
SRAM contents:
>02A0:  00 00                                            ..
P = 8
>p?+
SRAM contents:
02A0:  18 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
02B0:  00 00 00 00 00 00 00 00-00 00                    ..........
>PG = 40
p+?
SRAM contents:
02A0:  18 00 28 00 00 28 00 00-28 00 00 28 00 00 28 00  ..(..(..(..(..(.
02B0:  00 28 00 00 28 00 00 28-00 00                    .(..(..(..
>PR = 0x80
>P ? -+
02A0:  18 00 00 80 00 00 80 00-00 80 00 00 80 00 00 80  ................
02B0:  00 00 80 00 00 80 00 00-80 00                    ..........
>pZ  ; This is a "sleep" command; no pixel data change
>p?
SRAM contents:
>02A0:  18 00 00 80 00 00 80 00-00 80 00 00 80 00 00 80  ................
02B0:  00 00 80 00 00 80 00 00-80 00                    ..........
P   0
>p+?
SRAM contents:
02A0:  18 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
02B0:  00 00 00 00 00 00 00 00-00 00                    ..........
>P 2 = 0x80 0 0x40 0 32 32 40 32 20 U
>P+?
SRAM contents:
02A0:  18 00 00 00 00 80 00 40-00 20 20 28 20 14 00 00  .......@.  ( ...
02B0:  00 00 00 00 00 00 00 00-00 00                    ..........
>                                                                               
Of course, the examples shown above lose something since the actual pixel output cannot be viewed unless a WS2812 LED string is actually connected to the controller. EEPROM address 12 and 13 select which PORT and PINs are those which the "P" command will cause to "wiggle" in order to emit the tightly-timed WS2812 command sequences.
EEPROM address 12 stores the default WS2712 Port & (single) Pin:
  MASK_DefPandP_PORT = B11110000 ; 0x0# = PORTA, 0x1# = PORTB, 0x2# = PORTC
  MASK_DefPandP_OFF  = B00001000 ; If TRUE, the next BYTE has the PIN map, else
  MASK_DefPandP_PINS = B00000111 ; 0=B00000001, 1=B00000010 ... , 7=B10000000
EEPROM address 13 is used only if the prior byte's bit 3 (B00001000) is ON
  bitmap of the PINs (using the prior byte's PORT) on which to emit WS2812 data

For example, to set the default output of the 'P' commands to:
  only PORT C, PIN 0, use "E 12 = 0x20"  or  "E 12 = 0x28 0x01"
  only PORT C, PIN 1, use "E 12 = 0x21"  or  "E 12 = 0x28 0x02"
  only PORT C, PIN 2, use "E 12 = 0x22"  or  "E 12 = 0x28 0x04"
  only PORT C, PIN 5, use "E 12 = 0x25"  or  "E 12 = 0x28 0x20"
       PORT C, PINS 0 through 2, use "E 12 = 0x28 0x07"
       PORT C, PINS 1 through 4, use "E 12 = 0x28 0x1E"
       PORT C, PINS 2 through 5, use "E 12 = 0x28 0x3C"
       PORT C, PINS 0 through 5, use "E 12 = 0x28 0x3F"
       PORT D, PINS 0 through 7, use "E 12 = 0x38 0xFF"
Up to 480 LEDs have been configured and worked successfully, when only the default number of uVars.B[##] variables (32) were configured. That means that the pixel data size is 2 + 480 * 3 = 1,442 bytes. The 328P microcontroller only has 2,048 bytes of SRAM, and 416 of them (0x100 through 0x29F) are always used by the MIRTOS Operating System. The pixel data array with 480 LEDs would then begin at SRAM address 0x2A0 and end at address 0x841. The stack is initialized at 0x8FF (the address of the last byte of SRAM), which leaves only 190 bytes (0x842 to 0x8FF) of stack space. That is really dangerously minimal! In fact, some commands will cause the stack to descend into that pixel configuration. Overwriting the stack WILL cause a system crash, so be very careful about how many LEDs are configured, particularly if over 400 or if using other features.

Most WS2812 devices encountered use Green-Red-Blue byte order, but some have been found to use a Red-Green-Blue byte order instead. This documentation is written with the GRB order in mind, but, in either case, the bytes are still emitted as the same bit stream to the pin(s) selected. How they are actually interpreted totally depends on the receiving LED device(s).

Finally, a WS2812 (EEPROM) configuration can be validated and loaded using the "P@ EEptr" command. The sequencer logic can then be stepped one time using the "@" command. An example of this is as shown in the following series of commented commands:
>DV+  ; Note that no configuration is loaded
SRAM contents:
0280:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0290:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
>P?+  ; Verify that pixels are not configured yet
SRAM contents:
02A0:  00 00                                            ..
>DE+ 0x240 48  ; There are 3 sequencer configurations
EEPROM contents:
0240:  00 12 3C 02 FF 20 00 FF-FF FC 28 00 1E 00 FF FF  ..<.. ....(.....
0250:  08 22 3C 02 E0 40 00 D0-D0 D0 A6 00 14 00 FF FF  ."<..@..........
0260:  10 E2 3C 00 00 40 00 60-AB AF C8 00 2D 00 FF A0  ..<..@.`....-...
>P@ 0x250  ; Validate & load the middle one
>dv+       ; Verify that config #2 was loaded
SRAM contents:
0280:  08 22 3C 02 E0 40 00 D0-D0 D0 A6 00 14 00 FF FF  ."<..@..........
0290:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
>p+?       ; No change to uVars[] yet
SRAM contents:
02A0:  00 00
>@
>; To step, the command must be "@" alone (not even "@ "!)
>p+?       ; Verify initializing step occurred
SRAM contents:
02A0:  C0 00 00 00 1E 00 00 2A-00 00 1B 00 00 0F 00 00  .......*........
02B0:  39 00 00 5B 00 00 B4 00-00 2C 00 00 23 00 00 06  9..[.....,..#...
02C0:  00 00 AB 00 00 3F 00 00-DF 00 00 9D 00 00 D8 00  .....?..........
02D0:  00 31 00 00 43 00 00 9B-00 00 77 00 00 3B 00 00  .1..C.....w..;..
02E0:  A6 00 00 62 00 00 71 00-00 3F 00 00 1D 00 00 70  ...b..q..?.....p
02F0:  00 00 06 00 00 68 00 00-BE 00 00 C1 00 00 B2 00  .....h..........
0300:  00 31 00 00 8C 00 00 A8-00 00 38 00 00 39 00 00  .1........8..9..
0310:  B2 00 00 BF 00 00 CA 00-00 CB 00 00 90 00 00 98  ................
0320:  00 00 9C 00 00 59 00 00-4D 00 00 88 00 00 54 00  .....Y..M.....T.
0330:  00 11 00 00 21 00 00 08-00 00 93 00 00 2E 00 00  ....!...........
0340:  D9 00 00 70 00 00 2B 00-00 D9 00 00 67 00 00 8D  ...p..+.....g...
0350:  00 00 D6 00 00 2C 00 00-6D 00 00 5B 00 00 C0 00  .....,..m..[....
0360:  00 2A                                            .*
>@
>; Also note: no need to be logged in to sequence one step
>P?+  ; Verify that the step caused a change in pixel data
SRAM contents:
02A0:  C0 00 00 00 1C 00 00 28-00 00 19 00 00 0D 00 00  .......(........
02B0:  37 00 00 59 00 00 B2 00-00 2A 00 00 21 00 00 04  7..Y.....*..!...
02C0:  00 00 A9 00 00 3D 00 00-DD 00 00 9B 00 00 D6 00  .....=..........
02D0:  00 2F 00 00 41 00 00 99-00 00 75 00 00 39 00 00  ./..A.....u..9..
02E0:  A4 00 00 60 00 00 6F 00-00 3D 00 00 1B 00 00 6E  ...`..o..=.....n
02F0:  00 00 04 00 00 66 00 00-BC 00 00 BF 00 00 B0 00  .....f..........
0300:  00 2F 00 00 8A 00 00 A6-00 00 36 00 00 37 00 00  ./........6..7..
0310:  B0 00 00 BD 00 00 C8 00-00 C9 00 00 8E 00 00 96  ................
0320:  00 00 9A 00 00 57 00 00-4B 00 00 86 00 00 52 00  .....W..K.....R.
0330:  00 0F 00 00 1F 00 00 06-00 00 91 00 00 2C 00 00  .............,..
0340:  D7 00 00 6E 00 00 29 00-00 D7 00 00 65 00 00 8B  ...n..).....e...
0350:  00 00 D4 00 00 2A 00 00-6B 00 00 59 00 00 BE 00  .....*..k..Y....
0360:  00 28                                            .(
>P@ 0x260  ; Load the 3rd config from EEPROM
>Dv+
SRAM contents:
0280:  10 E2 3C 00 00 40 00 60-AB AF C8 00 2D 00 FF A0  ..<..@.`....-...
0290:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
>                                                                               
See also:
  The At or @ command page.