During lockdown, I found various form factors of programmable LEDS (WS2812/Smart/Neopixel) and wanted to make some Christmas tree lights with them (See Smart LEDs for details of the LEDs).
Some of them were waterproof and I came up with a few ideas. I started with the embedded WS2811 strings, each LED has a controller chip in a sealed block, 12mm in diameter and 40mm long. With these I used 4 strands of 50 LEDs per tree (so 400 in total). The latest version uses the inline WS2812, epoxied onto the cable, with 8 strands of 40 per tree (so 640 in total).
More strands gives more pattern options. Shorter strands (see later about the folding) can be mounted lower in the tree (which is much easier!). The later LEDs are much smaller and neater, so they get less tangled.
Here are the main components:
The House controller: sends DMX like commands to the trees. This is indoors, and signals both trees, so the patterns are synchronised. One day I'll put it on a proper board, but this has worked for several years!
The PIC16F15325 does all the work, the top connector is from a 5V power supply, the lower ones are the differential signalling to the trees. The resistor switches between normal patterns, and a New Year's even firework only show.
The Tree controller (1 per tree): Receives the DMX commands, stores them in RAM, and then sends them to the strands.
The top block is a 300W DC:DC buck convertor, the lower block is a PIC16F15325 with buffer resistors. The grey cable comes from the house, the 8 black cables go to the strand connectors.
The strands (8 per tree): Receives the WS2812 signalling, via the 3-pin waterproof connector, and decode this to control the brightness of the individual LEDs.
These have 40 WS2812 LEDs epoxied directly onto the cable. They are 10cm spacing, so I've folded the strand in half, so it's 2meters long. The Din pin on the LEDs are quite sensitive, so there is a buffer resistor between the connector and the data in pin, this protects the strings if they are connected up wrong.
Power: There is a 24V power supply indoors, this is dropped to 5V in the tree box, and sent to the strands. Individually the LEDs are very low power, but with all of the LEDs at full brightness, this is the equivalent to 2.4kW of lighting! I set the tree controller to use half the brightness that is sent to it, which is more comfortable. With it all switched on for about 6 hours per evening, the whole system averages about 22p per week in electricity!
The LEDs strands need a stable 5V power supply, but each tree can draw a lot of power, which causes a voltage drop on the cable from the house. I use a single 24V supply in the house, and each tree uses a 300W DC:DC buck converter to drop the 24V (minus voltage drop) to 5V. This 5V powers the tree controller and the strands.
A problem with the voltage drop, is that it's split between both the +ve and -ve lines, so the signalling 0V (reference) moves around (depending on string brightness). From all on to all off this is about 1volt!
In theatre lighting DMX was developed to avoid this sort of problem. This uses differential signalling. The TX device sends data over two wires, for a '1' the A-wire is higher than the B-Wire, for a '0', the A-wire is lower than the B-wire. At the receiving end a comparator is used to decode A>B=1 or A<B=0. This is sent at 250kBaud, with 1-start/1-stop bits, so 40uSec per byte.
For the basic tree control I use DMX signalling, with 320 (8x40) channels per tree (So blocks of 321 bytes). This give 8-bits per LED in a packed 3-R, 3-G, 2-B format.
For RGB, sending the whole tree would result in very long packets, so instead I uses some special commands (0xB? for per string RGB, and and 0xC? for per string packed RGB), this sends 121 byte blocks per string for RGB, or 41 byte blocks per string for packed 3/3/2 R/G/B bytes.
This uses a PIC16F15325 to generate and send the patterns. It has dual serial USARTs, and multiple CLC (configurable logic cells). The CLCs are programmed to invert the USART outputs to other pins, the two sets of USART signals (left and right tree, normal and inverted) are sent to the trees. The dual USARTs allow both trees to be sent at the same time, so the trees are better synchronised.
Patterns are sent to the trees at 40uSec/byte, with the break at the start, this is about 13ms for the whole tree in packed mode. For a single RGB strand 6.5ms, for a single packed strand 1.75ms.
R1/R2 select the New Year fireworks, or normal mode. J2/J3 go to the trees. Pins 6/9 are the USART outputs, 7/8 are the inverted versions generated by the CLC blocks. I've not actually made the PCB, so am still using a prototyping board, where I've only fitted the power pins, not the full programming connector.
These also uses the PIC16F15325. The comparitor block is used to decode the differential signalling, the PPS (Peripheral Pin Select) maps the comparitor output pin to the input of the USART. The bytes from from the USART are decoded and stored in RAM. When a string is updated, the RGB values are sent to the strands using the SPI controller and some CLC programming (See Smart LEDs for details). The PPS is used to move the CLC output pin between the 8 strands.
Again the PIC does all of the work. The 220R buffer resistors are really to reduce the switching noise (at 800kHz!), they also protect the PIC if any of the connections get shorted out. The 330R resistors limit the current from the main controller (the voltage drop on the GND line to the tree can be as much as 1V, so a 0V signal from the house can be -1V when measured at the tree). Pins 12/13 are the comparator inputs, pin 11 is the output. Internally, pin 11 is mapped to be the USART input, so no extra pins/wiring is required. Again, I've not actually put this on a PCB, it's so simple I've just used some matrix board. I have fitted the programming header, and the 330R resistors allow for in-circuit programming.
There are 40 LEDs per string, but the pre-wired LEDs have 10cm between the LEDs which makes for 4meter long strands. Instead of lots of soldering, I simply folded the strips, with an offset to get 5cm spacing. Clear heatshrink every few LEDs holds everything in place. The software knows about the alternate sequence, so stores the bytes in the modified order. Via DMX they are sent 1,2,3,...39,40, but in memory they are stored (then sent to the strands) as LED 40 (at the top), then LED 1 (first down from top), then 39,2,38...22,19,21,20.
This is sent at 1.5usec per bit, with 8-bits per R,G,B channels, so 24 bits / 36usec per LED.
The DMX to memory is slower than sending the memory to the strand with WS2812 signalling. So we buffer the strands in RAM, once a strand has been received, then the strand data starts sending. The send of memory to the strand is faster than the fastest DMX to memory block, so it can always keep up.
This uses my open source header files, and MPASM (Included for free in MPLAB-X V5.35 and earlier, needs Windows 10 or earlier). dmx_dual.asm is the source code for the house controller, and dmx_rgb.asm is the source code for the tree controller.
Tree light source code