Light_WS2812 library V2.0 – Part I: Understanding the WS2812

WS2812 LEDs are amazing devices – they combine a programmable constant current controller chip with a RGB LED in a single package.  Each LED has one data input and one data output pin. By connecting the data output pin to the data input pin of the next device, it is possible to daisy chain the LEDs to theoretically arbitrary length.

Unfortunately, the single-line serial protocol is not supported by standard microcontroller periphery. It has to be emulated by re-purposing suitable hardware or by software timed I/O toggling, also known as bit-banging. Bit-banging is the preferred approach on 8 bit microcontrollers. However,  this is especially challenging with low clock rates due to the relatively high data rate of the protocol. In addition, there are many different revisions of data sheets with conflicting information about the protocol timing. My contribution to this was the light_ws2812 library V1.0 for AVR and Cortex-M0, which was published a while ago. A V2.0 rewrite of the lib was in order due to various reasons. And, to do it right, I decided to reverse engineer and understand the WS2812 LED protocol to make sure the lib works on all devices.

ws2812_compared

As of now, there are two different revisions of the WS2812 on the market: The original 6 pin WS2812(S) and the newer 4 pin WS2812B. The data sheets can be downloaded from the website of world-semi, the original manufacturer, here and here.

ws2812_protocol

The data transmission protocol itself is relatively simple: a digital “1” is encoded as a long high-pulse, “0” as a short pulse on “Din”. When the data line is held low for more than 50µs, the device is reset. After reset, each device reads the first 24 bit (GRB 8:8:8) of data into an internal buffer. All consecutive bits after the first 24 are forwarded to the next device go through internal data reshaping and are then forwarded via “Dout” to the next device. The internal buffer is written to the PWM controller during the next reset.ws2812_timing

So far so good. This is where things get confusing. I copied the timing specification from both datasheets above. As you can see, both devices have slightly different timing for the encoding of the “1”. Furthermore, the tolerances for the “data transfer time” are completely different and are in conflict with the “voltage time”. So what are the real tolerances and can we find a set of timing parameters that fits both devices?

Luckily there is a relatively easy way to probe the inner workings of the device: When data is forwarded, it is passed through the internal reshaping mechanism. Therefore we can exercise Din and verify the correct interpretation of the input data by comparing it to Dout. To do this, I hooked a single WS2812 to a ATtiny 85 which took the role of a signal generator. I then monitored both Din and Dout with a Saleae logic analyzer. There are some issues with aliasing, since the maximum sampling speed is only 24 Mhz, but the data seemed still sufficient to understand the WS2812.

WS2812_reset_sweep

In my first experiment I tried to determine the minimum time needed to reset the LED. My program emitted blocks of 48 bits with increasing delay time in between the blocks. As you can see above on the left side, all input data is forwarded to the output if the reset delay is too short. Once a certain delay threshold is reached, a reset is issues and data forwarding will only start after the first 24 bits, as seen on the right side. For the WS2812 under test here, the minimum reset length was 8.95 µs, way below the specifications. The suggested reset time of 50 µs is therefore more than sufficient to reset the LEDs. On the other hand, it means that no more than 9 µs of idle time may occur during data transfer, or a reset may mistakenly be issued.

ws2812_timing_definitions

In the next step I looked at the data timing itself. The image above shows an exemplary measurement of input and reshaped output waveforms. Both waveforms can be described by two parameters each: The duration of the hi pulse and the total period. I programmed the microcontroller to cycle through all possible pulse input combinations between  62.5 ns (1 CPU cycle at 16 MHz) and 4 µs with a granularity of 62.5 ns. You can find the code is here.

My original intention was to perform an automatic evaluation of the captured data to create a shmoo plot. However, I quickly noticed that the behavior was quite regular and instead opted to analyze the data manually.

One of the first observations was that the delay between the leading edge of the input pulse and the leading edge of the output pulse, T_delay_in_out, was constant regardless of the timing of the input pulse.

ws2812_hi_variation

The image above shows a variation of T_hi_in for a constant T_period_in. The period length, called total data transfer time in the datasheet was set to the specification value of 1250 ns. As is obvious, there are only two states of the output signal: A short pulse for a “0” and a long pulse for a “1”. Even the shortest input pulse (62.5 ns) is identified as  “0”, while even the longest input pulse (1250-62.5=1187.5 ns) is identified as a “1”. The threshold between “0” and “1” is somewhere between 563 and 625 ns. The LED brightness changes accordingly, suggesting that the observations from the output signal are indeed consistent with the internal state of the LED.

ws2812_period

Next, I varied T_period_in. When the period time of the input signal was much shorter than 1250 ns, the WS2812 started to reject input pulses. As can be seen for 333 ns, only about every fifth input pulse is replicated in the output pulses. The shortest pulse period time where all input pulses appeared on the data output was 1063 ns. Below that the input pulses were partially or fully rejected. Above this threshold all input pulses were interpreted correctly and the period of the output signal reflected the period of the input signal up to 9 µs when the reset condition was met.

This is an interesting observation, because it means that while there is a strict lower limit for the period time of the input signal, there is no real upper limit. For practical purposes, this allows relaxed timing in the software driver.

ws2812_timing_table

The table above summarizes my findings from the WS2812 and WS2812B each. It is possible that there are significant differences between production batches of both types, therefore these number can only serve as a rough indication. All timings seem to be a bit shorter on the WS2812. This is consistent with the data-sheet which indicates a longer pulse time for the “1” on the WS2812B.

An interesting observation is that the timing values for both LEDs are multiples of a smaller number, ~208 ns for the WS2812B and ~166 ns of the WS2812. It appears that the internal controller circuit is actually a clocked design – possibly realized by a small state machine.

ws2812_cycles

This becomes much more obvious with the diagram above, which normalizes the timing to “WS2812 cycles”. The internal WS2812 state machine only needs to sample the input twice per bit: First, it waits for a rising edge of the input. This will initiate the sequence above. The input is latched again after cycle 2. The voltage of the input pin at this point determines whether a ‘1’ or a ‘0’ is read. Depending on whether the LED already has received 24 bits or not, this value will either be loaded into an internal shift register or decide whether a 2 or 4 cycle ‘hi’ level signal is emitted. The sequence ends after cycle 5 and repeats again with the next rising edge.

So, what did we learn from this?

  • A reset is issued as early as at 9 µs, contrary to the 50 µs mentioned in the data sheet. Longer delays between transmissions should be avoided.
  • The cycle time of a bit should be at least 1.25 µs, the value given in the data sheet, and at most ~9 µs, the shortest time for a reset.
  • A “0” can be encoded with a pulse as short as 62.5 ns, but should not be longer than ~500 ns (maximum on WS2812).
  • A “1” can be encoded with pulses almost as long as the total cycle time, but it should not be shorter than ~625 ns (minimum on WS2812B).

Next part: Optimized “Bit-Banging”

About these ads

24 thoughts on “Light_WS2812 library V2.0 – Part I: Understanding the WS2812

  1. The only thing I’m curious or surprised about is that you can’t pack the short bits closer together than the long bits, that the period has to be >1250 for both. I.e. that the low time has to be the opposite length.

    • Yes, that surprised me too. But on the other hand it provides some level of robustness towards glitches. I don’t think this behavior really adds complexity to the state machine.

  2. Thanks for this investigation cpldcpu. The WS28xx datasheets are quite poor, so it was nice to find some more in-depth testing.

    I have a fairly dumb question, but one I haven’t seen answered anywhere. I’d like to design a bicycle-wheel POV thing with some of these LEDs, and I haven’t been able to tell what happens when the string is reset. Do all of the LEDs go dark, and then turn back on, one at a time, as the new data is clocked in? Or does each LED retain its previous state until the new data reaches it? As you may imagine, the distinction is make-or-break for a POV project.

    • The LEDs are updated almost instantly after a reset without a blanking period.

      However, you should note that the WS2812 is PWM based with a frequency of roughly 400 Hz. There is visible flicker when moving the LEDs quickly. In a POV application you are probably limited to maximum and minimum brightness to avoid the “dotted line” problem with PWM.

      • Oh wow, I can’t believe I didn’t come across that little detail (PWM) in the datasheet or anywhere else online! That completely rules it out for my application. Guess I’ll have to keep looking.

    • Nice! For some reason Cypress really seems to like the WS2812. They also had some on display on their booth at EW2014.

      No bits are bashed anywhere, though!

  3. Big thanks for this useful post.
    I’m working on ws2811 using this post and I want to drive it. I would like to know is there any problem if I use read my RGB colors data from a MMC. I want to store my lighting effects to a MMC and read them by AVR and send data to a ribbon of 5050 leds are driven by ws2811.
    I know how to read MMC by AVR and how to send data to ws2811 but I want to know if it is fast enough and is it possible at all?
    Please help me to do this.

    • You have to store the data in the SRAM intermediately, you cannot read from the MMC and write to the WS2811 at the same time, as the MMC my cause delays that are too long for the WS2811.

      • thanks for your reply.
        This process, reading data from MMC and write to SRAM and then send to ws2811 as data takes time. Dose not this time (delay) cause problem? I have a ribbon including 700 leds and for each color one byte is needed so I must read 700*3=2100 bytes. Reading this 2100 bytes takes time.

  4. “So, what did we learn from this?”

    …That you’re a legend, Tim, for having researched and published this information and those vital four points.
    I had been frustrating over these devices for too many hours but thanks to you, I got my little critter to work.

    Note for http://www.world-semi.com/en/ : publish a spec’ sheet which is truly useful, not just a ‘guide’.

    Cheers and grateful thanks…

    • You are welcome! :)

      Yeah, World-Semi is puzzling me. They are messing up the launch of their successor device (WS2821) by not publishing anything about it. But on the other hand, the “maker” business is probably only a small fraction of their revenue, so I can’t blame them…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s