Things to know about the source code:
1. They are written in assembly not C/C++. But can be called easily from a C/C++ program.
2. The project file was created in MPLAB X IDE v1.85.
3. The program uses PORTA’s pin 0 to output data line information.
4. The program does several things in its initialization such as disabling Analog-to-Digital module and others. While integrating with your source, you may want to avoid pain by remembering this.
5. The program contains configuration under ‘MAIN’ code block to set the number of LEDs to work with. This may be helpful if you your power source cannot provide enough current for all of the LEDs in the strip
6. For the first source, you may notice that the LED flickers. It’s because the refresh rate is too fast. To accomplish a refresh rate of 60 Hz, the PIC has to execute more than 83,000 nops (There are better methods as executing ‘sleep’ instruction and waking up the system using the system’s WatchDog timer). I was too lazy to implement this.
This post will deal with driving WS2811 chip with Microchip’s PIC16F877A microprocessor to control a strip of LEDs connected in parallel. Although, the processor can operate with different configurations, the following was mine (and which I believe is the only one that can provide the max execution speed for this processor line):
External clock frequency (Operating frequency): 20 MHz
Actual instruction execution frequency (Internal frequency): 5 MHz (Hence, one cycle instruction will take 200 ns to execute)
Port pin voltage: 5 V
The LED strip itself is 1 meter long with 60 LEDs connected in parallel with WS2811 chip internally connected by the manufacturer. There are four wires on the either side of the strip where the red wire is the input for the LEDs requiring 5 V, blue for data input line also of 5 V for logic high ‘1’ and 0 V for logic low ‘0’ (WS2811 can tolerate low voltage of even ‘3.5 V’ as high, read the ‘Electrical Characteristics’ section’s ‘Input voltage level’ of the datasheet for WS2811 – link given below for information about tolerance values) and two black wires for ground (they can be connected to the same ground).
Things to know about WS2811:
Despite there being a documented datasheet being available at http://www.adafruit.com/datasheets/WS2811.pdf, some information in the datasheet is either incorrect or cannot be interpreted easily. So here’s a summary of what you need to know to control this chip.
Suppose that you have 60 LEDs, so you must send data in the following order:
Required data transmission rate: 800 Kbits/sec (Also called a high speed transmission mode, if you are unsure of whether your LED strip’s WS2811 has been wired as high speed or low speed (Refer to datasheet on how they can be set to either mode if you are wiring the chip yourself) and you ordered the strip online from a Chinese supplier, you can be pretty sure it’s in high speed mode)
Line coding used is: Non Return to Zero
Bit representation: Start bit represented by a high bit for at least 200 ns followed by either a high or low represented as high or low at 625 ns followed by a stop bit represented by a logic low
Sending byte order: 8-bit Green color data then 8-bit Red color data then 8-bit Blue color data (Datasheet says they must be sent as Red then Green then Blue but this is not correct, possibly because the wiring is done different in the LED strip)
Sending bit order: High bits go first
Time required by one bit/bit cell width: 1.25 us
Sending a logic low ‘0’: Set pin to high for 0.25 us then to low for 1.0 us
Sending a logic high ‘1’: Set pin to high for 0.6 us then to low for 0.65us
NOTE: As you can see that adding high and low time for either bit adds up to 1.25 us which is the bit cell width mentioned earlier.
Reset time: 50 us for both high or low speed (As according to the data sheet)
If I want the LEDs to glow in the same color, need I keep sending the same data on the end of each refresh cycle?: No, WS2811 chip will hold you last color data and the LEDs will glow with the same color until you begin sending new update data
NOTE: For our microprocessor running at 5MHz, execution of one instruction takes 0.2 us which barely makes it for the requirement mentioned above, hence while sending bits timing is crucial. Lags of 50 ns as such in above can be forgiven.
Delays: It was found that delays during transmission of bits of one block of 24-bits data can mess things up, especially when time is so crucial for us. So, 24-bits of RGB data must be sent serially ASAP. In order to accomplish this, in the second source code above, I have done away with loops and instead unrolled the loop into sections of code handling each bit separately. Though after sending 24-bit, sending the next block need not begin immediately. In my tests, I inserted 10 nops leading to delays of 2 us and yet the LEDs did not show any difference. But it may be a better if you do your calculations during the reset time wait, rather than here, as there is more than enough wait time required for most tasks.
Power requirements: 1 LED consumes at least 0.05 A, as they are connected in parallel total current required for ‘n’ LEDs would be n * 0.05 A + Current requirements for WS2811. For 60 LEDs, current requirement ~ More than 3 A. So, a current source of about 10 A and voltage of 5 V (other DC voltages may be brought to 5V using appropriate resistors) will be appropriate. Remember that even though all the LEDs may be off yet, the chip will consume power so a transistor to keep it in high impedance for complete shut off may be appropriate.
I have also tried driving the strip using SPI which is not working right now. From tests, it doesn’t seem that SPI’s hardware based bitbanging allows for any comfort on our tight execution timings as SPI consumes some instruction cycle for its own housekeeping. Unfortunately, without a oscilloscope and unclear datasheet on SPI aspects, developing a SPI solution is delayed for right now, if not dropped.