I was looking for a relatively inexpensive way to drive a large number of WS2811/WS2812 LED Pixels from Vixen/Falcon Pi Player, for my Christmas light display. Most pre-built controllers I found are expensive and most diy versions are a single channel/universe per controller. So, I set out to code/build my own.
Hardware:On the hardware side, the ESP8266 fit the price point well, and even though I wasn't initially crazy about a wireless solution, I set out to see how many pixels I could get it to successfully drive. I settled on the Wemos D1 Mini Pro for the job. They can be purchased from Banggood, AliExpress, or Ebay for under $5 US.
With only a single usable TX port (the other for programming and debugging), needed for writing with the proper timing for the WS2811/WS2812 addressable pixels, I needed an inexpensive component that would be able to switch at very high speed to support multiplexing the data output across the output channels. The SN74HCT125N 4 channel buffer/driver chips offered the functionality perfect functionality and can be found on Ebay for around $0.50 US.
Last but not least, don't forget the 10K ohm resistors. While it will probably work without these, the pixels may not completely latch when the driver disables the output. When this happens, the "Y" output port voltage can float, the resistance to ground will maintain the pixel led latch.
On the software side, I needed 3 main components, 1 to receive data from a coordinator across the network, 1 to write the data to the pixel strands, and 1 to glue the 2 together.
Receive Data Component:
The E1.31 DMX protocol is open, supported by both Vixen and Falcon Pi Player, so a short search resulted in finding the forkineye/E131 library for Arduino. As I would be programming my ESP8266's from the Arduino GUI, this library would be perfect, and only require a few small changes for simplification and ease of use. The DMX protocol does limit the number of channels per universe to 512, and with each pixel taking 3 channels, we are limited to 170 pixels per universe.
Pixel Driver Component:
There are a number of libraries out there that drive pixels by bit banging, this was not an option, I wanted to use the UART so I wouldn't have to worry about timing. The problem is, the ESP only has 2 UART TX ports, one of which gets used up by the USB/debug port. Time for some math...
If my lighting display uses a conservative 50 ms refresh rate...
Using the fast 800kbps pixels it takes 30us per pixel to update, with a maximum of 170 pixels per universe.
Time to write one universe of pixels: 30us/1000 * 170 = 5.1ms
Multiplexing this value across 8 output channels of pixels results in a total of refresh time of 40.8ms. This falls under the 50ms refresh coming from the show player, if we are using all pixels for all channels.
*In actual testing, over 1000 pixels can be a bit sketchy, freezes and reboots can occur as the processor gets overwhelmed.
I found the Makuna/NeoPixelBus library, it's a great library but I only needed two files, NeoEsp8266UartMethod.h and NeoEsp8266UartMethod.cpp. I updated them to handle multiplexing a single UART across multiple pixel channels. While it only writes to TXD1 on port D4, it now enables and disables the GPIO pins (D0, D1, D2, D3, D5, D6, D7, D8) corresponding to the pixel channel(s) to which is is sending the data. I optimized for the files for multiplexing and any unnecessary code was removed.
The Glue:
I wrote my own buffering, as I would need more then just the double buffer from the NeoPixelBus. Added a state machine on top to control the process and finally added Arduino OTA support for over the air updates.
Comments