Introduction
One of the things which is great about FPGA is their flexibility. You can also have fun creating simple games if you have an hour or two and a small development board.
With a few hours to spare, a Basys 3 dev board, a 8×8 NeoPixel array and a Pmod Con1 I was able to quickly and easily create a representation of a “connect four” type game.
This will be interesting to develop as we need real time control for the neo pixels which is something FPGA are good at along with sequential control for the game play element. This is something that perhaps could be implemented within a state machine but actually a little processor would be better.
Neo Pixel Timing
Before we rush off and create the Vivado design and the NeoPixel driver lets recap how NeoPixels work.
NeoPixels are digitally controlled red, green and blue pixels. As each color is represented by 8 bits giving a 24-bit total, this enables each pixel to display one of 16, 777, 216 colors.
NeoPixel Color Format
Each NeoPixel is actually a WS2812 LED. These LEDs contain five inputs and operate from a voltage range of 3.3V to 5.0V (VDD & VCC) with respect to ground (VSS).
Inputs and outputs from the WS2812 LEDs occurs on the DI and DO pins which are the data input and data output lines.
As each pixel requires a 24-bit word to set the RGB pixel value, both the input and the outputs use a serial self clocking format. This saves on the requirement for a clock input as well.
To transfer data, the WS2812 pixel use a non-return to zero (NRTZ) waveform.
This waveform’s bit period and duty cycle both change depending on whether the bit value represented is a 1 or 0. The timings are: T0H = 0.35μsec, T0L = 0.8μsec, T1H = 0.7μsec, and T1L = 0.6μsec. All timing values have a tolerance of ± 150nsec. These times give slightly different duration for a Low bit (1.15μsec) compared to a High bit (1.3μsec)
The observant will have noticed the 24-bit word that is applied to the NeoPixel does not contain and address field. Therefore, how does a NeoPixel know if the 24-bit value is used for itself or if it should pass on the word on its output?
How this is achieved is actually very simple, if after receiving a the 24-bit word, the NeoPixel does not receive another 24-bit word within 50 uS the value is latched in and displayed. If the NeoPixel does receive another word inside 50 uS the NeoPixel will output the previously received word.
NeoPixel output demonstrating three NeoPixels
This means we can drive potentially a infinite length of NeoPixels we are just limited by the power supply needed and the time an update takes.
Neo Pixel IP Core
To drive the NeoPixels we can use the previously developed IP core we have used before and is available here from my GitHub.
This IP block is designed to interface with a BlockRAM which has a 32 bit data width. The first address in the BlockRAM tells the block how many NeoPixels there are in the string. The IP block will then read out each memory address which contains a NeoPixel setting and output it. This enables the IP block to work with a very variable