Some more details, including sample code for talking to them:
I think this code is working more by luck than by anything else.
Assuming the pixels are set to high speed mode (800Kbps) then each bit
period is 1.25usec long. It appears that the WS2881 reads each incoming
bit by looking for a rising edge at the beginning of each bit cell, and
then sampling 1/2 way through each cell - if it’s high a 1 is being
transmitted, if it’s low then it’s a 0.
The example code is using a 4MHz SPI clock and writing 8 bits for each
bit of the value it is sending, either 0b10000000 for zero or 0b11110000
for a one. 8 bits @ 4MHz = 2usec per bit cell or an effective baud rate
of 500Kbps, whereas the spec says it should be 800Kbps, so it’s 37.5%
out - a huge margin. I think the only reason it works is because the
WS2881 must be re-syncing on the rising edge at the start of each bit
cell - if this was a normal async serial connection it just wouldn’t
work with that degree of clock skew.
What the code should be doing is writing 5 bits for each bit it sends,
say 0b10000 for 0 and 0b11110 for 1. 5 bits @ 4MHz = 1.25usec, which is
the specified bit cell length. Of course, writing 5 bits a time is a
lot more complicated to implement as there’s a more bit-fiddling to do
to marshal the 5-bit chunks into the 8-bit SPI output register.
On the AVR it may be possible to do this more easily with the USART
than with the SPI hardware. The USART has a synchronous mode where it
doesn’t use start/stop bits, using instead a clock signal on one of the
pins. If I’ve read the docs correctly, it should be possible to get
it to run at 4MHz (just!). The advantage of the USART is that it can be
set to transmit 5-bit frames, which will then give exactly the right bit
cell length of 1.25usec. The other advantage that the USART has over
the SPI hardware is that unlike the SPI hardware it is double-buffered,
so you can drive it at full line speed.
There’s other not-so-good stuff in the code as well, such as the use of
the modulo operator and multiplication instead of bit masking and
shifting. It might work OK on a 64Mhz PIC but on an AVR the
consequential multiplication and division operations will be problematic.