Driving intelligent LEDs from a microcontroller: Level shifting, isolation, and more...

Ideally, you want to use 5v logic level to communicate with NeoPixels and other intelligent LEDs.

This is actually… well, mostly reasonable. Part of why 5v still gets used is because it’s relatively fault tolerant and easy to work with. Lower voltages are going to be more susceptible to noise unless you add some sort of fault-tolerance mechanisms and they will just fade to nothingness with the resistance of the line… but at the same time, it’s not so high as to be dangerous or require large voltage swings. There’s things like LVDS that are great for going faster but that’s going to make everything more complicated.

Conversely, it’s generally fairly advantageous for the processor to be running at 3.3v or less. Your processor can switch faster if it’s running at a lower voltage 3.3v or maybe closer to 1v these days, plus it’ll generate less heat when it does, plus when you’ve shrunken all of the transistors that small, they physically can’t handle 5v without burning up.

Thus, we’re stuck in a world where most of the modern day popular microcontrollers have 3.3v GPIO ports, a lot of useful peripherals are 5v, and things need to be interfaced. And it’s probably only a matter of time before 2.5v microcontrollers become a thing.

A lot of guides will tell you that the strips are 5v strips and you need to level-shift to drive them at all off of your 3.3v Pi or microcontroller. Except, you know what? I’ve totally gotten away without doing anything like that and it’s been fine.

But, I’m going to have to level with you here… this is a “fine, until it isn’t” thing.


In the very earliest digital circuits with tubes, you’d probably have power going into the cathode terminal on some of the tubes. When transistors became a thing, you’d tend towards the equivalent common terminal. As a shorthand, they started to write the name for that pin as VCC.

For NMOS that became the drain pin, so VDD became, technically speaking, more correct.

Although it’s all kinda silly, really, because they are talking about one particular part of the circuit and where that connects. And everybody ended up picking one term and used it inaccurately… so these days you can see both VDD and VCC being used somewhat interchangeably to describe the power pin where maybe calling it V+ or VIN would just be easier.

Either way, VCC, VDD, VIN, or V+ are all synonyms for the power pin or pins of a chip.

The ins and outs of VOH(min) and VIH(min)


Digital signals have a specific set of requirements to designate a “high” or 1 versus a “low” or 0.

To transmit a “low” value, the transmitting chip will try to keep the voltage somewhere between 0 volts and VOL. To transmit a “high” value, the transmitting chip will try to keep it above VOH. It will generally try not to allow the voltage in the gray area between the two for very long.


Conversely, the receiving chip will treat a voltage between 0 volts and VIL as a “low” value and a voltage above VIH as a “high” value. In the drawing above, the darker green represents the sort of VIH you would encounter with a part that expects 5v inputs and the lighter green represents the sort of VIH you would encounter with a part designed for 3.3v inputs as well as 5v inputs.

In between is undefined, so you can’t know for sure what value is there, although you can get Schmitt Trigger devices that will act a little bit more reliably.

Furthermore, VOH is generally not given absolutely, but as a set of boundaries, where they guarantee that a high value is at least above VOH(min), but it might actually be higher when you actually have the device wired up for real world usages.

Thus, if you have two devices, you need to make sure that VOH(min) of the transmitting device is above VIH(min) on the receiving end. For the most part, all 3.3v parts are perfectly content to talk to other 3.3v parts, all 5v parts are perfectly content to talk to other 5v parts. But these numbers are different, depending on who is making the part, which might require you to dive into the datasheets to know for sure.

A lot of parts will intentionally design the VIH(min) to be low, specifically to make it easier to drive the 5v part off of a 3.3v microcontroller.

Furthermore, IO pins also frequently have a maximum voltage. Generally, that’s a little bit above the supply voltage so even if you have a 5v part, it won’t be able to handle 5v when you are powering it at 3.3v. However, for a lot of 3.3v microcontrollers, they’ll declare that some or all of the input pins are “5v tolerant” and can handle higher voltages.

One example part is the ATMega328. When it’s powered by 5v, it’s going to output VOH(min) of 4.1v, which is plenty for any 5v part. However, if you are powering it at 3.3v, now VOH(min) is 2.3v, plus the inputs are not 5v tolerant.

The ESP32 specifies the VOH(min) as 0.8 × VCC, so you would expect 2.64v minimum voltage. Curiously, the data sheet doesn’t actually tell you if it’s 5v tolerant or not, but the CEO posted on Facebook that it is. One of the hazards of saying “5v tolerant” is that sometimes designers will try to power the device with 5v as well, doubly so with the ESP32’s audience.

The ATSAMD21 and ATSAMD51 not only tell you the VOH(min) as 0.8 × VCC but it also gives a VOH(typ) of 0.9 × VCC, which means that you can plan on at least 2.64v but it’ll probably go up to at least 2.97v. Plus it is not 5v tolerant.

The i.MX RT1060 specifies their VOH(min) as VCC - 0.15v, which means you can get 3.1v out of the output lines. It’s not 5v tolerant either.

Unfortunately, with LED strips, by the way that they come via a circuitous route to you, it’s hard to know for sure exactly what they are expecting.

The earliest WS2811 and WS2812 list their VIH(min) as 0.7 × VCC, so 3.5v assuming a 5v power supply, but the more recent WS2812B-V5 datasheet now lists a VIH(min) of 2.7v. The SK6812 and SK6812RGBW datasheet lists it as 3.4v. The SK9822 (generally the chip APA102s actually are) datasheet doesn’t specify VIH(min). However, I’ve run plenty of strips that describe themselves as SK6812RGBW or SK9822 off of 3.3v signals just fine.

Thus, depending on what particular batch of LEDs and board you’ve got, you might be able to totally get away with no level conversion. Or, even worse, it’s marginal and only works sometimes.

General purpose voltage translator IC’s like the TXB0108 or TXS0102

Folks have reported poor results with the general-purpose bidirectional voltage translator ICs like a TXB0108 or TXS0102 or similar. They just don’t have enough drive capacity for some wires that may be going a distance.

I’ve never tried them. Mostly, they are more expensive than they ought to be for these purposes.

Unidirectional general-purpose IC’s: The logical choice

A 74AHCT125 example

One popularly recommended option is the 74AHCT125. It’s available as a through-hole DIP part. You can power it with 5v and the thresholds are low enough that it’ll level-translate pretty well. And it’ll translate for 4 channels independently. This particular part has a VIH(min) set relatively low, lower than most of the other parts of the same series, and it’s able to drive 8 mA.

A 74AHC245 example

Another popular option is the 74AHCT245, which can drive 8 channels where all of the channels are controlled with one set of lines, which is frequently what you’d want anyway.

A 74AHC245 example

The 74LV1T34 is a tiny surface-mount part that’s designed as a really good level shifter. It doesn’t have any control lines, and it’s just one gate.

I’d thought I found a few promising differently-shaped devices, but they either didn’t have a VIH(min) that would work with 3.3v devices or the VCC range was such the design VCC only went up to 3.6V so it’s important to be a real buffer buff and scan the datasheet because as best I can tell, those particular 74AHCT parts have special lower levels for level shifting and the rest of the lineup doesn’t.

Abusing MOSFET drivers to drive lines: A totally gate option for longer lines

One option is to use a relatively fast MOSFET driver. One popular one is the TC4427 or TC4427A (the A means it’s slightly faster).

A 74LV1T34, 74AHCT125, or 74AHCT245 is designed to swing maybe 8 mA of current. A MOSFET driver is designed to swing an amp or more of current.

Why is this important?

Well, a transmission line is a bit of a resistor and a bit of a capacitor. The resistor part means that a little bit of the voltage evaporates as heat. The capacitor part means that it’s got a bit of voltage that it’s storing in the insulator between the ground line and the signal line… because that’s what a capacitor is made from anyway. This means that what you are actually doing is charging and discharging a tiny capacitor every time you change the value on the line.

Ergo, a 74LV1T34 is going to move 8 mA of current into or out of the line, whereas the TC4427 is going to move 1.5 A in and out of the line, so it’s going to swing the voltage a LOT faster. For a relatively short transmission line, they both are going to get the line at the correct voltage probably about the same, but if you are running a longer line, the gate driver is going to let you run longer lines.

A 74AHC245 example

The TC4427 and TC4427A have a VIH(min) of 2.4v so it will only work with some 3.3v chips. It’s probably worth looking around and experimenting with because there are some that switch at a lower voltage.

Also, I’m not sure how well these would hold up for a APA102 intelligent LED that’s run at full speed, whereas it’s more than enough for NeoPixels.

Impedance-matching termination resistor and anti-zap resistor

It’s good practice to put a resistor, the value of which you need to determine by using an oscilloscope, in between the data pin and the first pixel.

As you string out a long piece of cable between the microcontroller and the LED strip, you have enough of a cable now that transmission line effects start to play a role. We’ll call this the “terminator” resistor usage and this is a very common thing when you are running cables.

Furthermore, there’s the potential for zapping a microcontroller’s pin because this is an off-board connector that might occasionally go weird. As such, it’s generally “better” to toss in a 300-400 ohm resistor there, which won’t hurt the signal integrity for short cable runs but will prevent voltage spikes on the line from hurting your microcontroller. This is basically working as a current limiting resistor, just like the one you use on an LED. We’ll call this the “anti-zap” resistor usage… and, as best I can tell, it’s at least somewhat urban legend?

QuinLED has some oscilloscope graphs showing some tests showing the same length of cable where one test has the data line a distance away from the power lines and the other test has the data line bundled up with the power lines. And the problem is that you can’t really easily tell without a scope or just trying a few values until it works.

This is much less importance if you are using a a gate driver. A gate driver comes with it’s own set of ESD protection hardware and it’s going to also want to move a lot more current so the only thing you’d want is a termination resistor.


An optoisolator is designed to completely electrically isolate two parts of a circuit. There are two benefits to this:

First, if something goes wrong, it’ll zap the optoisolator instead of your microcontroller.

Second, it can completely electrically isolate power rails. You can have two power supplies without the ground lines connected at all, which makes it even harder to zap the microcontroller.

Plus, you get level shifting for free.

The way this works is that there’s a little tiny infrared LED in a package coupled to a little tiny photo-transistor or photo-diode and supporting driver electronics. If you look at the pinout, you see that there’s a hard line between the receiving end and the transmitting end in the pinout; I’m sure that disassembling one would be fun to see how they made sure that voltage shocks couldn’t travel from one side to the other!

This also means that if you use an optoisolator that’s got two or more channels, they all have to go in the same direction.

You need a relatively good optoisolator for this to work, maybe something like the 6N137 or VO2630 that are designed for 10 MBps.

These two devices work as inverters, so you want to arrange the LED so that it’s active-low instead of the usual active-high configuration, which I’ll demonstrate in the schematic:

An optoisolator example

Rcurrent is really just driving an LED that takes between 1.1 and 1.7v, 1.4v typical, and needs to get 5 mA, preferably 10 mA. In general 470 ohm will work for a 5v part, 330 ohm for a 3.3v part, but you might want to check your microcontroller data sheet to make sure that a pin can source at least 5 mA (sometimes they can’t) and what the high and low voltages would be.

I’ve drawn in gray the part of the circuit that can operate with a completely separate ground and power.

Again, a APA102 intelligent run at full speed might be too fast for these, 10 MBps is still slower than the full speed some of those can handle.

I2C and more complex protocols are completely different!

I’m focusing here on just driving NeoPixels or other such LEDs off of a 3.3V microcontrlller. I2C is a completely different beast and works entirely differently.


I’ve actually been able to get away with blindly driving LED strips with 3.3V logic on many occasions. You can too!

If you are just making a small project and are running a relatively short cable and have reasonably recently purcahsed NeoPixels, it’ll probably just work and you can spare yourself some soldering and opportunities for things to go wrong. If you are trying to have longer cable runs, maybe you want to add some complexity and make a perfboard with a level shifter.

If you are making a PCB, it’s probably a good idea to just throw the level shifters in.

Also, it’s fairly important to read the datasheet. Also, if you are using a standard 74xxx series part, it is probably also a good idea to read the datasheet for the exact version you are purchasing if you are using it for level shifters.