PyRaspBeta

Level shifter

Many of the sensors here speak 5 V logic while the Pi speaks 3.3 V, and a GPIO fed 5 V is damaged by it. A level shifter costs $3.50 and is the tidy fix: each channel is a BSS138 MOSFET whose gate sits on the low-side rail, with a 10 kΩ pull-up on each side. It is bidirectional and automatic — pull either side low and the other follows — so the same four channels carry 3.3 V signals up to 5 V and 5 V signals down to 3.3 V. What it cannot do is drive a load: the pull-ups are 10 kΩ, good for signals only.

Level shifter, 4-channel

Pins

PinWhat it isType
LVLow-side supply (2.5–5.5 V)power
HVHigh-side supply (4.5–5.5 V)power
LV1Channel 1, low sideio
LV2Channel 2, low sideio
LV3Channel 3, low sideio
LV4Channel 4, low sideio
HV1Channel 1, high sideio
HV2Channel 2, high sideio
HV3Channel 3, high sideio
HV4Channel 4, high sideio

LV is the low-side supply (the Pi's 3V3) and HV the high side (5 V); they must satisfy HV ≥ LV. The four channels are LV1–LV4 and HV1–HV4: one side of each is wired to a 3.3 V signal, the other to the 5 V signal. There is no ground pin — both circuits already share the board's ground.

Wiring it in circuit.py

An HC-SR04 sonar with both of its signals shifted: the trigger goes up to 5 V, the echo comes back down.

circuit.py
from wiring import *

pi = Pi()
shifter = LevelShifter()
sonar = HCSR04()

pi.V3_3 >> shifter.lv            # the low side: 3.3 V logic
pi.V5 >> shifter.hv              # the high side: 5 V logic
pi.V5 >> sonar.vcc
sonar.gnd >> pi.GND

pi.GPIO17 >> shifter.lv1         # 3.3 V out, 5 V in: the trigger
shifter.hv1 >> sonar.trig

sonar.echo >> shifter.hv2        # 5 V out, 3.3 V in: the echo
pi.GPIO27 >> shifter.lv2

The usual alternative — a resistor divider on the echo and a straight 3.3 V trigger — works for the HC-SR04 because its trigger happens to accept 3.3 V as high. The shifter is the general answer, and it also protects the pin: whatever the 5 V side does, the GPIO only ever sees LV.

Driving it in main.py

main.py
from gpiozero import DistanceSensor
from time import sleep

sensor = DistanceSensor(echo=27, trigger=17)  # both signals behind the shifter

while True:
    print(f"{sensor.distance * 100:.1f} cm")
    sleep(0.5)

Electrical notes

  • A low on the low side turns the channel on through the gate (3.3 V above the source). A low on the high side first pulls the source down through the MOSFET's body diode, and the channel takes over as soon as the source drops a threshold below the gate. Both directions are in the simulator's tests.
  • The 10 kΩ pull-ups set the speed: about 2 MHz into a few tens of picofarads, and slow edges on long wires.
  • Channel resistance is a couple of ohms, so a shifted signal can carry a milliamp or two — enough for a logic input, not for an LED.
  • Only a few BSS138 models are in the simulator's library (BSS138, 2N7000, IRLZ44N, AO3401); the module here uses the BSS138.
  • Like every part, it is flattened into its real components when the board runs: four MOSFETs, eight resistors and four body diodes — one channel's worth of each per side. Select it and press Open internals in the Inspector to watch a channel work: the module drawn against the Pi, its parts, and the live voltage on every net inside.

Simulator vs real hardware

  • The body diode is drawn as an explicit 1N4148 in the model, because the simulator's MOSFET has no body diode yet; a real BSS138 has one inside, and it is what makes the high-to-low direction work.
  • Real shifters are picky about the low rail: with LV at 1.8 V a BSS138's threshold is marginal, which is why the datasheet's circuit is quoted for 2.5 V and up.