Saturday, January 19, 2013

Fun with RGB LED Strips - Part 3: WS2811 Timing

The WS2811 is a nice little constant-current three-output PWM LED driver with a single data input and one data output for chaining. After a reset condition (more on that in a moment), each device will look for and interpret 24 bits of data, 8 bits per color component (sent MSB first), with each bit being sent as a hi/lo NRZ waveform with specific timing; once a device has read 24 bits, it then mirrors all subsequent data on its data out line. A reset waveform (low input for at least 50 µs) causes each device to update its RGB PWM outputs according to the RGB triplet it just read; the PWM state of these outputs stays as programmed until the device receives another RGB triplet and reset condition.

According to the WS2811 datasheet, the low-speed 400 KHz NRZ waveform timings are as follows (we'll ignore rise and fall times and permissible slop for now and just focus on idealized timings):


The datasheet does not give explicit timings for the high-speed 800 KHz data rate, but rather just indicates that all parameters are half of the given 400 KHz values except for the reset condition minimum duration of 50 µs (though it's not clear whether the "half" also applies to the parameter tolerance of ± 150 ns). Therefore the high-speed 800 KHz timings will be:


I didn't want to bit-bang since that's not very portable. The best approach seemed to be to try to make use of a serial peripheral. Speeds on the USARTs aren't as high as would be required, so I decided to look at SPI instead. The most logical approach would be to treat each NRZ pattern as an 8-bit byte and then attempt to come up with a SPI peripheral clock that would provide edges as close to the nominal timings as possible. The NRZ pattern period at 800 KHz is 1.25 µs; 1/8 of that period is 156.25 ns which is a bit rate of 6.4 MHz. That would be my target.

The processor on my Discovery board is an ST Microelectronics STM32F407 and has an 8 MHz external crystal. The STM32F4xx family contains a reasonably sophisticated clock generation scheme (the RCC subsystem); after a little calculation, I determined that I could configure the clocks to provide a 25.625 MHz SPI peripheral clock, and divide by 4 to yield a SPI bit clock of 6.4063 MHz, or a bit timing of 156.10 ns.

Here's a comparison of the edges at this bit rate with the desired 800 KHz NRZ pattern edges:


Two of the SPI bit edges align with the ideal NRZ edges with errors of 62 and 24 ns. This should let me generate NRZ hi and lo times that are within the tolerances given in the WS2811 datasheet, even if those tolerances are divided by 2 for 800 KHz operation (± 75 ns).

According to the choices of edges above, to generate a '0' pattern, I'll have to send two high bits followed by six low bits (byte value = 0xC0); to generate a '1' pattern, I'll send four high bits followed by four low bits (byte value = 0xF0).

This means that for every 24-bit RGB triplet, I'll send 24 separate bytes - one for each bit in the triplet. Note that since the patterns both contain multiples of 2 bits' worth of ones and zeros, I could optimize memory usage by halving the SPI bit rate and sending two NRZ bit patterns at a time (one in each nybble of the transmitted SPI byte); to get things going, however, I decided to defer making this optimization until later.

Before continuing with implementation, I'll make a separate post describing the STM32Fxx clock configuration for anyone who might be interested.

1 comment:

  1. Manejaste el ws2811 con SPI? Podrias mostrarme esquema de conexion del microcontrolador a este integrado?

    ReplyDelete