Single Cat-6 Power and Data for WS2815 LED strips

One of the biggest hassles with addressable LED strip installations is that you usually end up running data and power separately. Sure, in theory, a Neopixel type installation just needs three conductors – one for data, one for ground, and one for +5V or +12V. In practice this doesn’t work on large installations for two reasons:

  1. If the first pixel is too far away from the controller, the quality of the data signal degrades quickly. After a few feet, you are likely to see glitches.
  2. You need fairly chunky cables to avoid voltage drop in the power cable. Most LED strips, in fact, have so much voltage drop in the strip themselves that you can only run about 300 pixels before you have to re-inject power.

Last year, I created a big (40′) LED antenna so I could find my way home at Burning Man. I solved the first problem by using differential signaling (RS-422), and the second problem by injecting power every 300 pixels. It looked and worked great:

The trouble was all the cables. I had CAT-5 cables (I used the flat kind) going to each strip with the data, then I used heavy 14awg speaker wire to inject power. As you can see here, the amount of cable (and its complexity) were not insignificant:

I wasn’t really happy with this solution and finally thought, dammit, I’m gonna just run power AND signal over one frigging ethernet cable, I don’t care if you say it’s impossible.

Well, I’m here to report that it’s not impossible. CAT-6 comes with four twisted pairs. I’m using one of the pairs for RS-422 differential signaling. Then I use three of the remaining wires for GND and three for +12V.

I chose CAT-6 because it is available in 23awg, which seems to be the thickest copper you can get in ethernet cabling. At that gauge, there is still some voltage drop. Over about 75 feet, which is the longest you wanna go, you will see a voltage drop from about 12 volts to under 10 volts. That is still within the range that can power a WS2815 strip with 300 pixels happily. I actually plan to plug this into Mean Well power supplies which allow you to juice up the volts to about 13.8 at the origin.

Now, as you can see from the picture of the antenna, my obsession is not having a lot of messy cables or circuitboards up near the base of the LED strips. So I designed this cute little circuit board:

It’s slim enough that you can just heat shrink it and it will basically disappear in between your LED strip and your CAT-6 cable. It has three functions:

  1. Collect the power from 6 wires and send it to the LED strip
  2. Decode the differential signal using a MAX485 chip (this is powered using a basic 12V to 5V voltage regulator)
  3. Three capacitors on the right handle power surges from the LED strip so you can make epileptic flashing white strobes to your heart’s content (not tested).

Here’s a schematic:

These things cost me about $5 each plus shipping to get made in China (including the PCB board, assembly, and all the parts).

In the end I’m psyched that every LED strip in my project will have one simple CAT-6 of exactly the right length going back to my project box!

Using Teensy 4.1 With FastLED

Got a Teensy 4.1? Want to use it with FastLED? You’ve come to the right place. The Teensy 4.1 is an incredibly powerful microprocessor at a very reasonable price, and FastLED is still one of the best libraries for driving WS2812 type addressable LEDs from Arduino type projects.

Paul Stoffregen, creator of Teensy, has a library called OctoWS2811 that provides fairly basic operations to send RGB data out to addressable LEDs. Unlike FastLED, it doesn’t have all the fancy color manipulation, palettes, fast math operations, etc… just basic “set the pixel color” type operations. But OctoWS2811 is blazingly fast and works perfectly on the Teensy 4.1. One of the reasons it is so fast is because it can drive strips using any and all GPIO pins in parallel and without using a lot of CPU time. (More about my experience here).

So what you really want to do is combine OctoWS2811 with FastLED and you will be cooking with fire. Here’s how to do that.

Step one – get the latest version of OctoWS2811 from GitHub. (Make sure you have version 3.5).

You can use OctoWS2811 directly to write to the LEDs. Here’s an example using 8 pins, numbered 33-40:

  const int numPins = 8;
  byte pinList[numPins] = {33, 34, 35, 36, 37, 38, 39, 40};
  const int ledsPerStrip = 300;
  CRGB rgbarray[numPins * ledsPerStrip];

  // These buffers need to be large enough for all the pixels.
  // The total number of pixels is "ledsPerStrip * numPins".
  // Each pixel needs 3 bytes, so multiply by 3.  An "int" is
  // 4 bytes, so divide by 4.  The array is created using "int"
  // so the compiler will align it to 32 bit memory.
  DMAMEM int displayMemory[ledsPerStrip * numPins * 3 / 4];
  int drawingMemory[ledsPerStrip * numPins * 3 / 4];
  OctoWS2811 octo(ledsPerStrip, displayMemory, drawingMemory, WS2811_RGB | WS2811_800kHz, numPins, pinList);

Now to hook this up with FastLED, you create a custom FastLED “controller” which just forwards the bits to OctoWS2811. This is the simplest possible FastLED controller; it looks like this:

#include <OctoWS2811.h>
#include <FastLED.h>
#include <Arduino.h>

template <EOrder RGB_ORDER = RGB,
          uint8_t CHIP = WS2811_800kHz>
class CTeensy4Controller : public CPixelLEDController<RGB_ORDER, 8, 0xFF>
{
    OctoWS2811 *pocto;

public:
    CTeensy4Controller(OctoWS2811 *_pocto)
        : pocto(_pocto){};

    virtual void init() {}
    virtual void showPixels(PixelController<RGB_ORDER, 8, 0xFF> &pixels)
    {

        uint32_t i = 0;
        while (pixels.has(1))
        {
            uint8_t r = pixels.loadAndScale0();
            uint8_t g = pixels.loadAndScale1();
            uint8_t b = pixels.loadAndScale2();
            pocto->setPixel(i++, r, g, b);
            pixels.stepDithering();
            pixels.advanceData();
        }

        pocto->show();
    }
};

To use this new controller:

  CTeensy4Controller<RGB, WS2811_800kHz> *pcontroller;

  void setup()
  {
    octo.begin();
    pcontroller = new CTeensy4Controller<RGB, WS2811_800kHz>(&octo);

    FastLED.setBrightness(255);
    FastLED.addLeds(pcontroller, rgbarray, numPins * ledsPerStrip);
  }

Tip: This works for Teensy 4.0, too.

Another tip: You can use any and all pins in any order. Just change numPins and pinList.

Enjoy!

Teensy 4.1 is Amazing

For the future Turtle Antenna, I’m using 16 of these “flex led” strips. Each strip is 5 meters of WS2815 in a nice IP68 frosty silicone sleeve which creates beautiful, diffuse pastel colors. They are 60 pixels per meter so I’m using a total of 4800 LEDs.

If you asked me a year ago I would have said that this year I’d be using ESP32s as controllers.

Teensy 4.1 is a game changer.

Here I’m running:

  • 4800 LEDs (WS2815b)
  • 107 frames per second
  • 16 strips, in parallel, each on their own pin
  • RAM used 111284 bytes (21%)
  • CPU load: negligible
  • Peak AC power consumption (full white) 500 watts / 6amps
  • For each WS2815b strip of 300 12v LEDs, I am only injecting power once at the bottom.

The prototype breadboard here shows one Teensy 4.1, two level shifters (8 strips each), and four RS422 encoders (4 strips each). Then I drive the signal over CAT5 to a tiny RS422 decoder board. The whole RS422 thing is not necessary if your controller is within about 5m of your strips. I haven’t tried going further but I would not be surprised if you could run 20,000 pixels at 60fps off of one Teensy 4.1…. without using any kind of shift register or extra hardware.

Power Injection

I have been experimenting with various ways to build power injection cables for long runs of LEDs that will be outdoors in suboptimal conditions. Here’s what I came up with, all using parts easily procured from Amazon.

This is the power supply I chose. I like it because it is already reasonably weatherproof. I have also heard very good things about Meanwell power supplies, like the LRS-350-12, but that needs to be put in a box and you would need to wire up your own AC cable.

I found this cool tool for removing the outer jackets. If you’re following along with me, strip 5/8″ of the outer jacket.

Then strip the wires to 1/4″:

Then I crimped on these cute things. I think they are called ferules? “Insulated Bootlace Ferules,” I am told. Anyway, they make it safe to connect the stranded cable to a screw terminal.

Next, get these outdoor “junction boxes.” They come in 2 way and 3 way versions. They have cable glands on both ends which make a watertight seal as long as you use cable with a circular cross-section.

Here’s a 2 way connector, exploded:

Stick the wire through…

Technically these things have three internal connectors. I only use two for power injection. But if you are also sending WS2812 data, the third post is available.

Now you need to choose what kind of cable you are going to use for your power injection cable.

Use an online voltage drop calculator to figure out what gauge you need. This depends on whether your LEDs are 5v or 12v. If you are already building power injection cables, it sounds like you are planning long runs of power. In that case you will be much happier with 12v LEDs like ws2815.

In my case, and with a lot of testing, I decided 14awg was enough. I bought this speaker cable, but be warned: because this cable has a “slip sleeve” instead of a perfectly circular moulding, it will not make a watertight seal with the cable glands! That is OK for my application but if you want something watertight, find a circular cable.

Next:

The junction boxes are available as T’s, which is what I used at each power injection point. This is a female two-conductor “Ray Wu Connector” which powers a single LED strip that came from the factory with a male two-conductor connector.

Ferrules! Cute as a button!

Here ‘s the whole thing before screwing together?

Here are two complete assemblies.

In my situation each power supply powers 4 five-meter strips; each strip has 300 pixels at 12v.

Transmitting WS2812b Signals Over Longer Distances

The WS2812b protocol is a fairly simply protocol based on toggling the data pin between 0v and 5v. That makes something akin to a square wave. I have heard people refer to this hardware protocol as TTL (“transistor to transistor logic”) and it is common on circuit boards.

The trouble with this square wave is it can’t be transmitted very far. Your mileage may vary, but from what I’ve heard, a couple of meters is really pushing the limit. Above that and you’ll start to see flashing LEDs, dropouts, noise, and general unhappiness. This is caused because electromagnetic interference from the environment interferes with the square wave and distorts the TTL signal. The longer the run, the more interference you get.

If you plan to put your controller more than a meter or two away from the beginning of your LED strips, or if you need to run a long dark wire between two of the LEDs on your strip, you should seriously consider using something called differential signaling for those sections. The most common protocol you’ll see here is RS-422.

The theory behind RS-422 is pretty simple: it uses two wires. One of them has a signal on it and the other one has the reverse of that signal. Any interference affects both wires equally. Therefore, the difference between the two signals stays the same even when there is interference.

As a result, you can expect to be able to run ws2812b signals hundreds of meters using the RS-422 protocol.

The easiest way to get started with RS-422 is to buy pairs of dinky little “MAX485” boards. Just search for this on Amazon or Ebay and you’ll find loads of them; they look like this:

Here’s how you hook them up:

  1. On both sides, connect VCC to 5V and GND to ground.
  2. On the transmit side, connect DI to your input and DE and RE to VCC.
  3. On the receive side, connect RO to your output and DE and RE to GND.
  4. Then connect the A and B between the two boards with twisted pair, as long as you want.

Those little boards are built around a common, readily available chip, the MAX485. Depending on your situation you can just build your own little circuit board… it’s just a single IC, some resistors, and capacitors. Here’s a schematic:

The LED on that schematic is totally optional. If you want to use 12V instead of 5V, well, technically, the MAX485 is rated up to a max of 12V, but to be safe, I put in a tiny little LD11177V50C which steps 12V down to 5V. This is useful when you are using long runs of 12V LEDs and you only have 12V available at the beginning of the LED strip.

Big, Interactive LED Art!

I thought it might be fun to learn how some of the really big, interactive, inspiring LED art was built. I’m talking about things like:

All of these great works of art were build with dedicated, smart teams, custom hardware, and amazing code. I realized I had to learn about pixel-addressable LEDs, electrical engineering, embedded microcontrollers, and a lot more.

The common denominator of these LED projects is little pixels that can show any color. Each pixel consists of three LEDs very close to each other: one red, one green, and one blue. There’s a little tiny integrated circuit for each one that reads a signal from a wire telling it what color to be, and then blinks the red, green, and blue at high speeds. Your eye doesn’t notice the blinking so it feels like you’re just seeing different colors. Here’s what a strip of them looks like, close up:

There are various versions of these pixels. If you’re getting started you may want to look at the NeoPixels and DotStar versions sold by Adafruit, but once you need thousands of pixels or variants that Adafruit doesn’t stock, you can buy them pretty cheaply from manufacturers in China (in particular Ray Wu’s store, on Aliexpress, is considered very reliable and has good customer service).

The version of chip I like is called the WS2815. If you’re interested in why, I wrote a more detailed review of the popular options.

In order to set the color of these things you need to send a digital signal with all the RGB values of the colors that you want on the entire strip. The first pixel reads the first color, shows that color itself, and sends the rest of the signal down the line to the next pixel, which does the same thing until you get to the end of the strip.

How do you make such a digital signal? You need an electrical circuit!

At the heart of the circuit is a microcontroller. This is basically just a tiny computer that is so small it doesn’t even have an operating system, but it can be programmed in languages like C++ and has a decent amount of memory. If you’ve heard of Arduino, that is a common microcontroller family that is a popular learning platform.

I built some custom hardware that can generate the signals for up to 8 different LED strips with up to 550 pixels each. It’s called Branch Controller and it looks like this:

The microcontroller I decided to use was the Teensy 3.2. If you rummage around this site you can see the various explorations I went through before I settled on the Teensy. You can see the green Teensy board in the bottom. It is plugged into MicroUSB which is where it gets power from. This USB port can also be used to download new code that you compiled on your computer, which is then stored in flash memory. One nice feature of microcontrollers is that as soon as they get power, they just start working instantly. You don’t have to wait for the operating system to boot up first like you would have with a Raspberry Pi.

What else is in that picture? In the bottom right you can see two jacks which accept standard CAT 6 cables. Each cable has eight wires in it, and it can feed data into four LED strips.

In the bottom left is a little ethernet network adapter. This basically just puts the Teensy on a local area network. You can connect to it with a web browser to configure various options. You can also run a program on a more powerful PC on the network to feed color data, over ethernet, to the controller.

This is subtle but it’s the reason why I built Branch Controller in the first place! A microcontroller is not very powerful; it can make pretty colors but it doesn’t have any kind of graphics processor (GPU) to do really fancy stuff. My theory is, you can run fancy interactive graphics programs on your powerful PC, using its GPU for high performance, and then calculate the color of every pixel and ship that, over a TCP connection, to the Branch Controller which will send it to the pixels.

Remember how I said each Branch Controller could handle up to 8 strips of 550 pixels? That turns out to be the maximum number of pixels you can drive with one Teensy 3.2 if you still want to update each pixel 60 times a second (for fast “persistence of vision” effects that look really smooth). But if you need more than 4400 pixels, no problem: just use multiple Branch Controllers! Then you are only limited by how many pixels a fast computer with a good graphics card can pump out, which is probably in the millions.

My Branch Controller has a tiny little OLED display screen on it which is handy for status information. It has a blinking green LED just so you know that it’s working. And, it has an infrared sensor which lets you control it via a remote control for frequent operations like setting the brightness.

Here’s what it all looks like in the test setup on my desk:

If you’re interested in more details, check out the github repository!

The Branch Controller Circuit Board

The plot so far: suppose you want to build a large, pixel-addressable LED installation with the following parameters:

  • Runs at 60 frames per second
  • More than 4400 LEDs
  • Fully-programmable from a PC or otherwise
  • Survives the desert

You can run a Teensy 3.2 with the FastLED library and parallel output on 8 different pins: that gets you 4416 pixels. To get more pixels than that, your best bet is to connect a bunch of Teensy’s over ethernet.

I decided to build a basic circuit board which combined:

Here’s what all that looked like on a breadboard:

I also started writing the code to run this whole thing, although that is still very much a work in progress so far. The problem I immediately hit is that the messy prototype wiring is really kinda flaky and half the time something falls out and wastes an hour of my time debugging what happened.

Since I’m going to want a PCB version of this eventually, I downloaded KiCad, which I had literally never used before, and got started. In the course of one weekend I was able to build the schematic:

… and design a prototype board:

It’s probably not the world’s fanciest circuit board, there are probably lots of ways to make it better, but it’s just a prototype and it is the first prototype board I’ve ever designed. I’ve sent it off to Osh Park to get made, which is going to take a few weeks, and then we’ll discover all the things I did wrong.

Control your projects with IR Remote Controls!

When you build electronics projects for the desert you always need some kind of basic controls. For LED projects you might want brightness controls, for example, or buttons which switch between various preset visual programs.

The trouble is that it’s very hard to come up with a reliable way to have pushbuttons and knobs which can survive with all the dust.

Last year I found two options which worked pretty well. The first option I used for DMX-controlled lighting. I used three main components:

  • a Wifi / DMX bridge; there are various options for this but I was using all ADJ lights so I got their AirStream DMX Bridge.
  • This went in a large SockitBox. Never heard of the SockitBox? It’s my favorite thing for electronics in the desert. It has enough room in it for a power strip and a nice solid clip-on plastic lid with a rubber gasket that sealed it nicely. There are little gaps, with their own rubber seals, that you can use to feed in a few outdoor-rated cables. By the way, I used SockitBoxes of every size wherever there were power strips or extension cords in our camp.
This is a large SockitBox.
  • Then I controlled the DMX system using software on an iPad, which itself was enclosed in a very tough outdoor / waterproof case.

This solution was a good start. But for my custom electronics projects, I was worried about exposing anything to anything. So I put my circuit boards into IP66 rated, sealed cases like this Polycase SK series:

SK-14-02
A Polycase case

Polycase has a whole system of knockouts and connectors you can use to get power cables in and out, and the cases come in all different sizes. I’m going to design my future circuit boards to fit perfectly in one of these cases.

Now, notice that there is an option with the SK cases to get a clear cover. The magic of that is that you can now use an infrared remote control for all your control needs. Just solder a little IR receiver, like the Vishay TSOP34438 (reviewed) (about $1), onto your circuit board:

Now you can use any kind of IR remote control, most of which are hermetically sealed and all of which cost about $2. If you search for “44 key LED controller” on Aliexpress you’ll find tons of remote controls that look like this:

These have a cheapo plastic membrane which means dust doesn’t get in, and you have a bunch of usefully-labeled buttons to control just about any aspect of your LED project.

Some useful tips on single wire protocols

I built this cute little board with 16 LED strips arranged in a star to use as a test bed for my upcoming projects. In doing so, I made a couple of mistakes and learned the hard way how to drive these very finicky strips.

I figured that all 16 strips could just share a ground. Why not? Ground is ground, right? It’s shared everywhere. So I build a little copper ring as the ground and routed that back to the Teensy controller, and used ribbon cable for all the signals.

Guess what? It didn’t work at all. There was a ton of interference between the data wires and the lights flashed like crazy.

Here’s what I learned:

  1. You have to use twisted pair GND+Signal, from each and every LED strip, all the way back to the controller. 24AWG CAT6 cable is nice for this. You can’t share the grounds like a bolshevik. It won’t work.
  2. I had been using 3.3v signals since that’s what the Teensy 3.2 puts out. I know, everyone said you have to use level shifters, but I had looked closely at the data sheets and it seemed to me like modern WS2815s are willing to take 3.3 volts. Well, they are, but you can’t transmit very far. Please put back the level shifters and run at 5 volts.
  3. And finally, I kept seeing this weird claim that you need to put a little 100 ohm resistor before the first LED. Was it to “protect” the LEDs? Or “match impedence”? Or prevent “reflections“? Who knows. I didn’t really get it either and it seemed to work without out. You know what? Put the damn resistor in there. I mean, it’s one resistor, Michael. What could it cost? Ten dollars?

So yeah. Level shift to 5v, signal+GND, resistors. Here’s what it looks like now:

Teensy 3.2 + Ethernet

Teensy 3.2 with a (standard Arduino) W5500 ethernet shield

As a part of my project to scale beyond the ~4000 pixels that Teensy 3.2 supports at 60Hz, I’m looking into ways of using multiple Teensy 3.2’s and farming out pixels to each of them. The idea would be to build a simple “Branch Controller” consisting of a Teensy 3.2, a WIZnet W5500 Ethernet adapter, and an OctoWS2811 adapter.

The first part of the project was just making sure that I could use the W5500 with Teensy 3.2. I had bought the Arduino Shield version of the W5500 ($23). The whole Arduino Shield is large and clunky and includes an SD card slot I don’t need, so I really should have used a WIZ850io ($20) which is just the ethernet adapter in a much more compact form, so I switched to that:

Teensy 3.2 wired up to a WIZnet WIX850io 10/100 BASE-T Ethernet adapter

To get the Ethernet to work with the Teensy 3.2, all I had to do was make six connections (see the picture above):

Teensy 3.2 PinsW5500 Ethernet Shield PinsWIZ850io Pins
(pinout)
10 – SCSD10SCNn
11 – MOSID11MOSI
12 – MISOD12MISO
13 – SCLKD13SCLK
GNDGNDGND
Vin (3.6 to 6.0 Volts)5V
3.3V3.3V

Then I connected the W5500 to my local area network and plugged the Teensy into the computer. From the Arduino IDE, I loaded the Ethernet > Web Server example, and uncommented the line Ethernet.init(10) in setup(). After running this I had a web server running and everything seemed to be working perfectly.

Next step: I want to see how much data I can push down to the Teensy how fast. The W5500 is a 10/100 ethernet board, but the serial protocol it’s using to talk to the board will slow that down a lot.

The first experiment I did was just a minimal web server running on the Teensy. For the client, I ran node.js calling request-promise in a loop. This was able to make about 100 HTTP requests per second, which could provide a decent frame rate, but there is no data payload yet.

Next I added some payload to try to figure out the bandwidth of a Teensy. The first experiment I did got about 100 kilobytes/sec. This could handle pixel-level data for:

555 pixelsat 60 fps
1110 pixelsat 30 fps
4416 pixelsat 7.5 fps

That’s pretty disappointing; it almost defeats the purpose of using the OctoWS2811 to drive 8 separate strands. According to Paul Stoffregen’s benchmark, I ought to be able to get about 958 kilobytes per second. Which would be enough for my needs! So there was obviously some kind of optimization I’m missing.

Looking closely at the sample web server code I was using, I noticed that it was set up to read one byte at a time, no matter how many bytes were available. A modification to the Teensy code to read blocks of bytes into a 256 byte buffer got much better results; I was able to get up to 500 kilobytes per second! Which translates to:

2777 pixelsat 60 fps
4416 pixelsat 37 fps

This is a significant improvement and probably adequate, but I wasn’t happy.

I wondered if the fact that the test computer was on WiFi instead of a wired LAN could be the bottleneck. Sure enough, moving my computer to LAN dramatically improved the throughput, and I got 1,125,093 bytes across in a second, which was faster than even Paul’s benchmark. This would translate to a frame rate of 85 frames per second with 4416 pixels, well above the 60 fps limit of the WS2812b-type LED strips!

Finally, I tried combining the Ethernet and LED code into one script (branchController) to see how the timing was. The ideal architecture, I thought, would be to open a client connection to the branchController every time you have another frame to send. The trouble with this method is that there is too much overhead to opening each connection. I only got about 20 frames per second doing it this way. Another option is to send four frames at a time (connecting 15 times per second)… this worked fine (but as the code is structured right now, probably freezes LED refresh unnecessarily while the TCP connection is happening).

What I think I’m really going to need to do is open a connection and keep it open, then stuff down one frame of data whenever I have one. That will require changing the protocol a bit so that the connection is expected to stay open, which will require rejiggering the code a bit, but I’m pretty confident that is going to work and have the performance that I expect.