The Raspberry Pi 4 GPIO Pinout: What You Actually Have to Work With

The Raspberry Pi 4 Model B features a 40-pin header, but treating it as 40 available I/O pins is a fast track to a fried board. This guide targets the Raspberry Pi 4 Model B (4GB or 8GB variant) running Raspberry Pi OS (64-bit, Bookworm or later). Before wiring anything, you must understand the hard electrical limits of the BCM2711 SoC.

⚠️ Critical Hardware Limits:
Logic Level: 3.3V. Feeding 5V into any GPIO pin will permanently destroy the SoC.
Max Current Per Pin: 16mA (safe continuous).
Total GPIO Current Limit: ~50mA across all pins combined. Do not use GPIO pins to power multiple LEDs or sensors directly.
Table 1: Essential Raspberry Pi 4 Power and Ground Pins
Physical PinBCM GPIOFunctionNotes
1N/A3.3V PowerMax 50mA total draw
2, 4N/A5V PowerDirect from USB-C input (minus polyfuse drop)
6, 9, 14, 20, 25, 30, 34, 39N/AGround (GND)Always use a common ground with external supplies
3, 5GPIO 2, 3I2C SDA/SCLHardware 1.8kΩ pull-ups to 3.3V on the board
8, 10GPIO 14, 15UART TX/RXDefault serial console; disable in raspi-config for general I/O

Decision Tree: How to Interface Real-World Hardware to 3.3V Logic

The most common mistake makers make is connecting 5V Arduino modules or 12V industrial sensors directly to the Pi 4. Use this decision matrix to select the exact interface component you need.

Table 2: GPIO Interfacing Decision Path
Your Hardware ScenarioElectrical ConstraintRequired InterfaceConcrete Part Pick
Reading a standard 3.3V tactile switchVoltage matches, needs pull-upDirect GPIO (Internal Pull-up)None (Use software config)
Reading a 5V TTL sensor output5V > 3.3V limitUnidirectional Level Shifter74AHCT125 or SparkFun Logic Level Converter
Reading a 12V/24V industrial proximity sensorHigh voltage, inductive noiseOpto-Isolator ModulePC817 4-Channel Optocoupler Board
Switching a 5V 500mA relay or solenoidCurrent > 16mA limitLogic-Level MOSFET or Driver ICIRLZ44N MOSFET or ULN2003 Darlington Array
Switching a 120V AC mains applianceLethal voltage, isolation neededOpto-Isolated Relay BoardSongle SRD-05VDC-SL-C Relay Module (Active LOW)

Default Recommendation: If you are interfacing anything outside a bare 3.3V breadboard environment, always default to an opto-isolated relay or optocoupler module. The $6 cost saves your $55 Pi from ground-loop spikes.

Project Build: Opto-Isolated Input and Relay Output Controller

We will build a robust controller that reads a 12V industrial-style switch (simulated here with a standard switch through an opto-isolator) and triggers a 5V relay to switch a higher-power load.

Parts List

  • Board: Raspberry Pi 4 Model B (4GB)
  • Input Isolation: PC817 4-Channel Optocoupler Isolation Module (approx. $8)
  • Output Switching: 4-Channel 5V Relay Module with Songle SRD-05VDC-SL-C relays (approx. $7)
  • Wiring: 22 AWG solid-core jumper wires, 2x20 female GPIO header
  • Power: Official Raspberry Pi 27W USB-C Power Supply

Pin Mapping Table (BCM Numbering)

ComponentPi 4 BCM GPIOPhysical PinWire Color (Standard)
Opto-Isolator CH1 (Input)GPIO 1711Blue
Opto-Isolator CH2 (Input)GPIO 2713Green
Relay IN1 (Output)GPIO 2215Orange
Relay IN2 (Output)GPIO 2316Yellow
VCC (Opto & Relay)5V (Pin 2)2Red
GND (Opto & Relay)GND (Pin 6)6Black

Wiring Steps

  1. De-energize: Unplug the Pi 4 USB-C power supply. Never wire the 40-pin header while powered.
  2. Power the Modules: Connect the 5V (Red) and GND (Black) wires from Physical Pins 2 and 6 to the VCC and GND rails on both the opto-isolator and relay modules. Note: Many relay modules have a jumper linking VCC and JD-VCC. Remove this jumper and supply JD-VCC separately if driving heavy inductive loads to maintain true isolation.
  3. Wire Inputs: Connect GPIO 17 (Blue) to the output side (usually labeled OUT1 or DO1) of the opto-isolator. Connect your external 12V switch to the input side (DC+ and CH1) of the opto-isolator.
  4. Wire Outputs: Connect GPIO 22 (Orange) to IN1 on the relay module. Most Pi-compatible relay modules are Active LOW, meaning the relay triggers when the GPIO pin is pulled to 0V.
  5. Verify: Use a multimeter in continuity mode to verify no shorts between 5V and GND before applying power.

Python Control Code with Robust Error Handling

For Raspberry Pi OS Bookworm (64-bit), the legacy RPi.GPIO library frequently fails to compile or throws runtime warnings. The modern, officially supported standard is gpiozero. It handles pin cleanup automatically and abstracts the Active LOW logic of relay boards.

import sys
import logging
import signal
from gpiozero import Button, OutputDevice

# Configure logging for debugging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# --- PIN DEFINITIONS (BCM Numbering) ---
# Inputs (Active LOW on the opto-isolator output)
OPTO_INPUT_1 = 17
OPTO_INPUT_2 = 27

# Outputs (Active LOW for standard Songle relay modules)
RELAY_OUTPUT_1 = 22
RELAY_OUTPUT_2 = 23

def setup_hardware():
    # Button class automatically configures internal pull-ups and handles debouncing
    # pull_up=False because the opto-isolator pulls the line to GND when triggered
    input1 = Button(OPTO_INPUT_1, pull_up=True, bounce_time=0.05, active_state=False)
    input2 = Button(OPTO_INPUT_2, pull_up=True, bounce_time=0.05, active_state=False)
    
    # OutputDevice with active_high=False handles the Active LOW relay logic automatically
    relay1 = OutputDevice(RELAY_OUTPUT_1, active_high=False, initial_value=False)
    relay2 = OutputDevice(RELAY_OUTPUT_2, active_high=False, initial_value=False)
    
    return input1, input2, relay1, relay2

def main():
    try:
        in1, in2, out1, out2 = setup_hardware()
        logging.info('GPIO initialized successfully. Waiting for inputs...')
        
        # Bind events
        in1.when_pressed = out1.on
        in1.when_released = out1.off
        
        in2.when_pressed = out2.on
        in2.when_released = out2.off
        
        # Keep the script running gracefully
        signal.pause()
        
    except Exception as e:
        logging.critical(f'Fatal GPIO Error: {e}')
        sys.exit(1)

if __name__ == '__main__':
    # Handle Ctrl+C gracefully
    signal.signal(signal.SIGINT, lambda s, f: sys.exit(0))
    main()

Debugging the Big Three: When Your GPIO Script Fails

When your script crashes, do not guess. Check these exact error strings and follow the ranked causes.

❌ Error String 1: gpiozero.exc.PinFactoryFallback: Falling back from rpigpio: No module named 'RPi.GPIO'
Ranked Causes:
1. You are on 64-bit Raspberry Pi OS Bookworm, where RPi.GPIO is deprecated and removed from default repos.
2. You installed a virtual environment without installing the fallback lgpio or RPi.GPIO packages.
Fix: Stop using RPi.GPIO. Rewrite your code using gpiozero (as shown above), which uses the lgpio backend natively on modern Pi OS. Install it via sudo apt install python3-gpiozero python3-lgpio.
❌ Error String 2: RuntimeError: This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.
Ranked Causes:
1. A previous run of your script crashed before executing GPIO.cleanup(), leaving the pin locked in the kernel.
2. Another background service (like a home automation daemon) is currently holding the pin.
Fix: If using legacy RPi.GPIO, add GPIO.setwarnings(False) at the top of your script. Better yet, switch to gpiozero, which automatically releases pins when the Python garbage collector destroys the object.
❌ Error String 3: PermissionError: [Errno 13] Permission denied: '/dev/gpiomem'
Ranked Causes:
1. You are running the script as a user who is not in the gpio group.
2. You are trying to access hardware PWM or I2C/SPI pins which require /dev/mem (root access) instead of /dev/gpiomem.
Fix: Add your user to the gpio group: sudo usermod -aG gpio $USER, then log out and log back in. Never run GPIO scripts with sudo as a crutch; it creates security vulnerabilities and file ownership nightmares.

The First Three Things to Check When Hardware Fails

If the code runs without errors but the physical relay doesn't click or the input doesn't register:

  1. Verify Permissions and Groupings: Run ls -l /dev/gpiomem. It must show crw-rw---- 1 root gpio. If it shows root root, your OS image is corrupted or misconfigured.
  2. Check Peripheral Conflicts: Open sudo raspi-config -> Interface Options. Ensure I2C, SPI, and Serial Console are disabled if you are trying to use pins 2, 3, 7-11, 14, or 15. The kernel will silently block your Python script from toggling these pins if a hardware overlay claims them.
  3. Measure Physical Voltages: Set your multimeter to DC Volts. Probe Physical Pin 1 (should read 3.25V - 3.35V) and Physical Pin 2 (should read 4.9V - 5.1V). If Pin 2 reads below 4.6V, your USB-C power supply is failing or the board's polyfuse has tripped due to a short circuit on your breadboard.

Extending and Simplifying the Build

Once the base opto-isolated circuit is proven, you have two paths for scaling:

Path A: Simplify for Low-Risk Prototyping

If you are moving this to a controlled indoor environment (like a desk-bound weather station) and dropping the 12V industrial sensors, strip out the opto-isolators. Connect 3.3V tactile switches directly to GPIO 17 and 27, using the Pi's internal pull-up resistors via gpiozero's Button(pin, pull_up=True) class. This reduces part count and wiring complexity by 50%.

Path B: Extend for Industrial I/O Density

If you need to read 16+ inputs or drive 8+ relays, you will exhaust the Pi 4's safe GPIO pins and hit the 50mA total current limit. Do not daisy-chain more direct GPIO modules. Instead, migrate to an I2C I/O expander. Add an Adafruit MCP23017 16-Channel I/O Expander (approx. $12). It connects to just two pins (GPIO 2 and 3 for I2C SDA/SCL) and handles all the pin-state logic internally, drawing minimal current from the Pi's 3.3V rail while providing robust 5V-tolerant I/O on the expander side.