Longan NANO + WS2812B
Now that we have a working Tx only SPI+DMA, it's time to play with a new toy : WS2812B RGB leds.
These are picky and encode 0 & 1 as high state/low state pulse of a given duration for a "0" and for another duration for a "1".
So a zero is ~ 400 ns high, 800 ns low and a one is 800 ns high, 400 ns low, +-150ns.
So we must find a spi speed giving us the right waveform AND which is simple enough to encode.
The short version :
The simpler is Clock divider=16, with 3 bits high/5 bits low and 5 bits high/3 bits low to give us the correct waveform
So to encode a 0 bit, we send 3 bits at 1 and 5 bits at 0 => 0xE0
to encode a "1", we sent 5 bits at 1 and 3 bits at 0=> 0xf8
The conversion is a simple lookup table that converts 4 bits at a time and generate 32 bits output at a time.
The drawback is that a single led needs 8*3=24 bytes in memory.
Computation is easy, dma is cheap, and.............
It works but the first led is acting funny.
Let's have a look at the waveform with an oscilloscope :
The SPI first bit has an extra 100ns duration that confuses the WS2812B.
When it is used as a "real" spi, it does not matter as the signal is only sampled on a clock edge.
No problem, we'll shorten the "high" state of the first SPI byte.
I.e. instead of sending 11100000 we'll send 11000000 (same for the other one), the hw will add the extra '"1" at the beginning and we are still ok as far as the low state duration is concerned.
It mostly works!
But, while checking the signals with the scope, the MOSI pin goes slowly back to zero at the end of the sequence. Using SPI mode 1 fixes that.
Works fine now ! And it's fast enough.
The end result is :
We expand our Leds colors using the lookup table, taking brightness into account.
Fixes the first byte of the end result to shorten the "high" duration
Send the whole thing over SPI+DMA, doing something else meanwhile
The code is on github
Comments
Post a Comment