CDL Modules
|
Files | |
file | led_ws2812_chain.cdl |
'Neopixel' LED chain driver module | |
module led_ws2812_chain::led_ws2812_chain | ( | clock | clk, |
input bit | reset_n, | ||
input bit | divider_400ns[8], | ||
output t_led_ws2812_request | led_request, | ||
input t_led_ws2812_data | led_data, | ||
output bit | led_chain | ||
) |
A chain of any length of Neopixel LEDs can be driven by this module
The interface is a request/data interface; this module presents a ready request to the client, which then presents a valid 24-bit RGB data value. When the module takes the data it removes its ready request. The client keeps supplying data in response to the ready requests.
To terminate the chain the client supplies data with a last indication asserted.
To ease implementation of the client, the request includes a first indicator and an led_number indicator - effectively a client can read a register file based on led_number and drive valid when the data is valid, and last if led_number matches the end of the register file.
This module copes with all of the requirements of the Neopixel chain, and it takes a constant clock input. To provide the correct frequency of data pin toggling to the Neopixels a clock divider value must be supplied, with the approximate number of clock ticks that make up 400ns (ideally 408ns).
The Neopixel WS2812 LED chains use a serial data stream with encoded clock to provide data to the LEDs.
If the LED chain data is held low for >50us then the stream performs a 'load to LEDs' - this transfers the serial data already loaded in to the LEDs to the actual LED drivers themselves.
Before loading the LEDs the chain should be fed data. The data is fed using a high/low data pulse per bit. The ratio high/low provides the data bit value.
A high/low of 1:2 provids a zero bit; a high/low of 1:2 provides a one bit. The total bit time should be 1.25us. Hence this logic requires a 1.25/3us, or roughly 400ns clock generator. This is performed using a clock divider and a user-supplied divide value, which will depend on the input clock frequency. For example, if the input clock frequency is 50MHz, which is a period of 20ns, then the divider should be set to 20.
The data is provided to the LEDs green, red then blue, most significant bit first, with 8 bits for each component.
The logic uses a simple state machine; when it is idle it will have no data in hand, and need data to feed in to the LED stream. At this point it requests a valid first LED data. When valid data is received into a buffer the state machine transitions to the data-in-hand state; it remains there until the data transmitter takes the data, when it either requests more data (as per idle), or if the last LED data was provided by the client, it moves to requests an LED load, and it waits in loading state until that completes. At this point it transitions back to idle, and the process restarts.
When there is valid LED data in the internal buffer the data transmitter can start; the data is transferred to the shift register, and it is driven out by the data transmitter to the LED chain one bit at a time.
[in] | clk | System clock - not the pin clock, which is derived from this |
[in] | reset_n | Active low reset |
[in] | divider_400ns | clock divider value to provide for generating a pulse every 400ns based on clk |
[out] | led_request | LED data request, to get data from the next LED to light |
[in] | led_data | LED data, for the requested led |
[out] | led_chain | Data pin for LED chain, modulated by this module to drive LED settings |