...a Logic Analyzer, that is. The Pixif interacts with its host processor via SPI. Because the number of NeoPixels it can drive is configurable (up to a maximum determined by its 16-bit counters) it needs to know that number before it starts fetching RGB color byte data. The host provides the number of pixels to the Pixif during a Reset and Configuration Sequence:
First, the host fully resets the Pixif using its /Reset input. The logic analyzer trace above shows /Reset being asserted for 10 mSec - that's just an arbitrary duration I coded on the host. It could be much, much shorter and still work because the /Reset signal directly resets the PIC.
Following /Reset being negated (at 10 mSec), the Pixif waits for the /FrameSync input to be asserted by the host indicating the Pixif should perform a 2-byte SPI exchange. It's this exchange that determines how many pixels the Pixif will drive. As shown in the trace following the /Reset negation it takes the PIC a little time to get happy (about 18 mSec), recognize /FrameSync, and initiate the first SPI exchange. The green flag in the trace indicates when things begin to get serious: SPI /SS is negated, the /FrameSync assertion is noted, and the SPI pixel count exchanges are done (at about the 30 mS point in the trace).
The first SPI exchange (the "Configuration" portion of "Reset and Configuration") simultaneously informs the host of the maximum number of pixels the Pixif can drive and the Pixif of the number of pixels it should actually drive. If, for some reason, the host doesn't like the result (maybe it expected to be able to drive more pixels than the Pixif supports and sent down a number larger than the Pixif's maximum) it can simply assert /Reset and restart the process. Here's the detailed trace of the Configuration portion with the number of pixels to be driven set to 144:
One important note in this trace is the negation of /FrameSync at about 28 mSec. Following the exchange of pixel counts the Pixif waits for /FrameSync to be negated by the host. The Pixif then waits for a subsequent /FrameSync assertion to begin its retrieval of the pixels' RGB color bytes. This sequence allows the host to do any needed final preparation before allowing the Pixif to begin fetching pixel color data.
Once /FrameSync is asserted by the host the Pixif will assert SPI /SS and begin retrieving the RGB color bytes for the pixels. Here's a summary view:
This trace shows the first 3 full frames (and a portion of the 4th). Because the host leaves /FrameSync asserted the Pixif continues to retrieve all of the RGB color bytes its connected pixels. The green flag on this trace indicates the negation of /SS and the beginning of the "quiet time" reset interval needed by the NeoPixels. Note that the WS2812 Bitstream is being generated at the same time as the SPI exchanges are being done. Pulling this off on an 8-bit PIC was certainly one of the more challenging aspects of this project!
Here's the detail of the the first few SPI exchanges following the /SS assertion:
Remember simple? The other side of that coin is sometimes you have to do not-so-simple things to be able to do simple things. The above trace shows the SPI exchanges for the first 5 color bytes and the resulting WS2812 Bitstream created from the first 2 color bytes. But, why the delay in starting the bitstream if the received SPI color bytes are just handed off to the bitstream generation mechanism? Remember from the Data Sheet that the WS2812B color byte order is Green-Red-Blue? Ugh. Well, the entire created universe has always thought of color values as Red-Green-Blue and I wasn't about to burden my host-side software with any byte re-ordering silliness. So I buried that silliness in the Pixif. Here's the magic: the color byte order in the host's memory is RGB, so the transmitted order via SPI is RGB. That's cool. But the WS2812 bitstream order, being GRB, means the Pixif has to hold off generating Red's bitstream until after Green's. So, for each received RG portion of an RGB triplet the Pixif can't start the triplet's bitstream until after the Green byte is received via SPI. You can see this in the trace as the first SPI byte is a Red value (0x05) and the second is Green (0x01). If you decode the 16 bits of the WS2812 Bitstream trace you see what is sent to the pixels: Green followed by Red. (Blue's bitstream encoding follows immediately after Red's beyond 46100 uSec. It really is there - trust me! ;-)
It all hangs together and results in a coherent bitstream for the pixels because I carefully chose the SPI clock rate to blend with the bitstream clock rate and used the PIC's USART to create a "bit pipeline" to buy enough time for the PIC to handle the SPI exchange concurrently with feeding the bitstream generation mechanism. I wanted a SPI clock rate slow enough to not have electrical problems when run across a few inches of wire (does this antenna make my clock look bad?) and allow the host-side DMA to easily blend with all the other host-side memory bandwidth consumers. But that had to be balanced with the fact that a SPI clock rate that's too slow would result in gaps in the generated bitstream (a "pipeline stall" or "bubble") and all sorts of whackiness from the pixels! Yikes!
To finish up our deep-dive trip to LA here's what happens at the tail end of an /SS assertion:
The above trace shows the SPI exchange for the very last color byte (Blue) of the very last pixel along with the ongoing bitstream being generated from previous color bytes. Notice the Pixif stops clocking SPI after the last pixel's last byte but continues to "drain the pipeline" of the bitstream mechanism. The last pixel's Blue value appears in the bitstream, /SS is negated (@ the green flag), and the WS2812B reset interval begins. Following the reset interval the fun starts all over again!