Tag: level shifting

  • Hardware hacking, part 3: using my 5 V FTDI cable on 3.3 V UARTs without killing the board

    Hardware hacking, part 3: using my 5 V FTDI cable on 3.3 V UARTs without killing the board

    Part 3 of 7 in the Hardware hacking series. Part 1: updating the firmware on a Pinecil V2. Part 2: the bench I work on.

    My USB serial cable has an FTDI FT232RL in it and is sold as a 5 V cable. Most router and IoT consoles run their UART at 3.3 V, a few at 1.8 V. Feed a 5 V transmit line into a 3.3 V receiver and you are past what the chip is rated for. I would rather spend a few cents on resistors than find out whether a board survives.

    This is for boards I own, powered from a low-voltage supply. I have not opened the cable. The seller says 5 V and I expect the data lines are 5 V too, but cables that look alike can differ, so the meter has the last word.

    Two directions, two problems

    The diagram above is one I drew: the wiring order, the divider and the one wire that stays disconnected.

    A UART link crosses over: cable TX to target RX, target TX to cable RX.

    The cable receiving is the easy direction. The FT232R datasheet (version 2.07, Table 5.3, VCCIO = 5.0 V) gives an input switching threshold of 1.0 V minimum, 1.2 V typical and 1.5 V maximum. It says “switching threshold”, not VIH, so I don’t call it that either. Anything a 3.3 V device drives above 1.5 V reads as high, and the absolute maximum input is VCC + 0.5 V, where VCC is the chip’s own supply (USB, about 5 V). No shifting needed.

    The cable transmitting is the problem. Same table: output high is 3.2 V minimum, 4.1 V typical, 4.9 V maximum at 2 mA. The ESP32 datasheet (version 5.3, Table 5-3) shows what a 3.3 V part expects: input high tops out at VDD + 0.3 V, so 3.6 V. It is only an example where I can point at the number. Only the cable’s TX wire has to come down.

    A two-resistor divider

    The cheapest fix is 1 kΩ in series from the cable’s TX, then 2 kΩ from the target’s RX pin to ground, so the pin sees two thirds of what the cable drives. This is the check I ran:

    R1, R2 = 1000.0, 2000.0
    cases = {"Voh min": 3.2, "Voh typ": 4.1, "Voh max": 4.9,
             "5.0 V ideal": 5.0, "VCCIO max 5.25 V": 5.25}
    for name, v in cases.items():
        i = v / (R1 + R2)
        print(f"{name:17s} Vout={v*R2/(R1+R2):5.3f} V  I={i*1000:4.2f} mA")

    The screenshot is the real output of that script. The 3 kΩ load draws 1.07 to 1.75 mA, below the 2 mA the datasheet uses as its test condition for Voh, so those figures are a fair basis. The pair dissipates about 9 mW at 5.25 V, nothing for a 1/8 W resistor.

    At the target’s pin that is 2.13 V worst case, 2.73 V typical and 3.27 V at the maximum. A receiver that needs 2.0 V for a high passes, though not by much. The SN74LVC1G125 datasheet, for one, specifies 2 V at a 3 to 3.6 V supply. With 1% resistors the worst case is 2.12 V, with 5% resistors 2.06 V, and that assumes nothing else loads the pin. A pull-down on the target’s RX eats the margin, and so does a USB port that sags below 5 V. A receiver that wants 0.75 × VDD, like the ESP32, needs 2.475 V. It passes at 2.73 V typical and fails at 2.13 V. So the divider suits the usual LVTTL-style console receivers and is marginal for strict CMOS inputs. I would rather say that than call it safe.

    The image is page 18 of FTDI’s datasheet, with a red box I added around the Voh row of Table 5.3.

    I don’t use 2.2 kΩ and 3.3 kΩ even though they give a neat 3.00 V unloaded: at the minimum Voh they give 1.92 V, which fails even a 2.0 V input. The high end matters too. At the maximum VCCIO of 5.25 V (Table 5.2), my 1 kΩ and 2 kΩ pair with 5% resistors can put 3.61 V on the pin, just over that 3.6 V ceiling, and lower rails make it worse. With 1% resistors the worst case is 3.52 V, so I buy 1% parts. Speed is no issue: with 20 to 50 pF of pin and wire capacitance the time constant is 13 to 33 ns, against 8.68 µs per bit at 115200 baud.

    When I would skip the divider

    For a margin I can defend, a buffer is better. The SN74LVC1G125 is a single non-inverting buffer. Powered from 3.3 V, its inputs accept up to 5.5 V (recommended range, section 5.3) and 2 V counts as high. Cable TX goes into pin 2, pin 4 goes to the target’s RX, and pin 1 (OE, active low) is tied to ground. It works in one direction, which is all this wire needs. The supply comes from the target’s 3.3 V rail once I have identified it with a meter, or from a separate 3.3 V source with common grounds, and the datasheet recommends a 0.1 µF bypass capacitor across it.

    The TXS0108E is the bidirectional option. Its A port runs from 1.4 to 3.6 V and its B port from 1.65 to 5.5 V with VCCA never above VCCB, so the target goes on A, the cable on B, and OE goes high to the target’s 3.3 V rail. The only job I would give the cable’s red wire is powering VCCB, never the target. It is more chip than a console needs. A 3.3 V cable or adapter removes the problem entirely.

    A 1.8 V target is a different case, and I look for it before I wire anything. Its output cannot exceed 1.8 V, only 0.3 V above the cable’s 1.5 V maximum threshold, so the cable may not read it reliably, and the divider would hand a 1.8 V receiver about 3.3 V. That target needs a proper shifter or a 1.8 V adapter.

    What I do at the bench

    I never connect the cable’s red 5 V wire to a target. It gets insulated and parked. I haven’t verified the wire colours on my cable, so I read its pinout card.

    Before connecting anything I measure. With the target powered from its own supply and nothing else attached, I put a multimeter between its TX pad and ground, at idle, since a toggling line gives a misleading average. If I don’t see about 3.3 V I stop. That covers 1.8 V, 2.5 V, a floating reading, and anything well above 3.6 V. I use insulated probe tips and hold the board still, because a slipped probe shorting two fine pads is a real risk. Then I plug the cable into USB with nothing on its header and measure TXD against its ground wire. A listing that says 5 V may only describe the power wire.

    Wiring goes in this order, with the cable unplugged from USB and the target off: cable ground to target ground, target TX straight to cable RXD, then cable TXD through the 1 kΩ to the target’s RX with the 2 kΩ from that point to ground. Then I power the target from its own supply, never from the cable as well, and plug the cable in last. At idle the target’s RX pin should read about 3.3 V with an ideal 5 V cable. Under 2 V means something is loading the line, and anything above the target’s VDD + 0.3 V means I unplug at once. To disconnect I unplug USB first, power the target down, then remove the wires. The order matters because a cable plugged into a dead board puts about 3.3 V on its RX pin, and some of that can leak through the chip’s protection structures into a board that should be off.

    The last rule has no numbers. I never connect to a device that is plugged into mains. Smart plugs, bulbs and some routers use non-isolated supplies, where the board’s ground can sit at mains potential, and a serial cable then ties that to your PC. A USB isolator reduces the risk without making it safe. If I don’t know what powers a board, I don’t connect. If the target runs from a battery, I disconnect the battery before soldering, and I never short one or charge a swollen cell. I touch an earthed metal object before handling boards, hold them by the edges, and unplug before soldering or moving wires.

    Part 4 uses this adapter to find the console on my own router, with the logic analyzer to work out the baud rate.

    Other parts of the Hardware hacking series: 1, updating the firmware on a Pinecil V2; 2, the bench I work on; 3, using my 5 V FTDI cable on 3.3 V UARTs; 4, finding the UART console on a router I own (publishes Nov 10); 5, reading SPI flash without wrecking it (publishes Nov 11); 6, decoding I2C and SPI with sigrok (publishes Nov 12); 7, JTAG and SWD basics (publishes Nov 13).