Not every device speaks the same voltage. In designing the SmartParallel serial-to-parallel printer adapter, I chose to use 5V as the VCC supply throughout the board. But I was constantly aware that some of the devices that might talk to the board – such as the Raspberry Pi – use 3.3V for their I/O. What to do?
There’s only a couple of points where the SmartParallel board talks to the outside world. There are the signals on the serial interface – TX, RX, RTS and CTS, with the latter two most likely not being used anyway.
Then there’s an I2C interface which I added to drive an optional LCD display. And that’s really it because the parallel port is best driven at 5V anyway.
I figured I could leave the I2C port at 5V because that’s what most displays expect. So no problem there. But what about that serial port?
One option would have been to forget about CTS and RTS, and use a resistor divider to drive the TX pin at 3.3V. If the host device uses 3.3V I/O, then the TX level would be right. And if it uses 5V… well, 3.3V would probably be enough. Same goes for any 3.3V signal coming from the host device via the RX pin.
Another option would be to make the resistor divider switchable, and include a switch or jumpers on the board to select between 3.3V and 5V levels.
I didn’t like any of the ideas above. For one thing, the assumption that 3.3V will ‘do’ when a device is actually expecting 5V just seems kludgy. Adding a switch increased complexity. (I know, I tried it on the schematic. It was ugly.) And it would be so easy to set the wrong level by mistake or forgetfulness.
Also, it didn’t address the CTS and RTS signals. I mean, if they’re there, you should be able to use them.
And so I arrived at what I thought was the best solution. The SmartParallel board would be 5V and that’s that. If you want to use it with a 3.3V device, then you’d have to take care of the level conversion somewhere else. And that’s what I did.
I’ve long been a fan of Adafruit’s handy level shifter breakout board built around the TXB0104 chip. I have a box full of these things. It shifts up to four signals between two voltages of your choice – typically between 3.3V and 5V but, in fact, the ‘high’ side can range between 1.65-5.5V and the ‘low’ side between 1.1V-3.3V. You set the levels by supplying two reference voltages to the chip.
My first instinct was to simply try to cobble together something on veroboard with one of these Adafruit devices. But then I thought it would be tidier to make a board of my own, using the TXB0104 chip, which takes care of things like the reference voltages.
The order of the pins on this port is not random, by the way. It matches the order used on all the FTDI-based USB-to-serial cables in my possession.
My plan is to use a right-angle male DuPont pin header. The FTDI cable will then plug straight on, once I’ve assured that I’m matching up ground pins.
For my serial shifter board, I’ll solder on right-angle female headers, so the board will, again, plug right in as a kind of daughterboard.
Designing the board
The shifter board is not complex. There are matching rows of headers each side of the board, although the row on the 3.3V side has one pin disconnected corresponding to +5V pin on the right. That 5V pin is the power input and I didn’t see any point in providing power output from the board.
The four signal lines just route via the pins on the TXB0104 chip.
Next up is an LM1117 voltage regulator which regulates the 5V input to produce a 3.3V output. So now we have both reference voltages on the board.
Because the TXB0104 is somewhat unusual in having two power inputs (effectively), I’ve added decoupling capacitors for both the 3.3V and 5V pins.
That provides all the necessary functionality. But, I hear you ask, where are the blinkenlights?!
Quite right. I threw on a power LED, linked to the incoming 5V supply. And I connected an LED to each of the RX and TX lines because… well, because. Of course, all three LEDs have power limiting resistors. I specified 470Ω on the schematic, but whatever…
All the components are surface mount to keep the board size small.
This is actually the third attempt at making this board. The first one worked fine but committed the sin of having only one LED (the power light). Version 1.1 added the TX and RX blinkenlights, at the expense of making the board slightly larger.
I’m calling this iteration version 2.0, which exaggerates the differences from the previous board. Aside from a little tidying up, all I’ve done is rotate the connectors by 180 degrees. The reason is simple. When I came to lay out the SmartParallel PCB, I had to perform a similar rotation in order to ease the process of routing tracks.
The older version of the level shifter board would have worked just fine, other than having to be connected upside-down. But this would have made the blinkenlights invisible. Sacrilege!
I’ve also taken the opportunity to throw in a couple of M3 mounting holes. You never know when you’ll need those.
One last detail. Note the order of the pins. Like I said, the order on the level shifter board matches the order on an FTDI cable. But on the SmartParallel board the TX and RX pins are swapped, eliminating any tedious cross-wiring.
[NB: UPDATE 22/07/2019] This ‘simple’ project has turned out to be anything but. In an attempt to use it between the SMartParallel stripboard prototype and a Raspberry Pi, I hit a bunch of problems. I’ll blog about these soon. But, in brief, this board kinda works, but has severe limitations, especially when used for serial communications.
• The KiCad project files are available on GitHub: https://github.com/mspeculatrix/Serial-Level-Shifter-2.0