The GPIO pin layout on the Raspberry Pi 5 retains the standard 40-pin physical footprint we’ve relied on since the Pi 1 Model B+, but the underlying architecture has fundamentally changed. With the Pi 5, I/O control moved from the main BCM2711 SoC to the dedicated RP1 southbridge chip. While the physical pins and Broadcom (BCM) numbering remain identical to the Pi 4, the software backend on Debian Bookworm requires a completely different library approach. If you are still trying to use the legacy RPi.GPIO library, your code will fail.

This guide provides a bench-tested breakdown of the 40-pin header, a complete hardware PWM project to test your wiring, and a debugging matrix for the exact errors you will encounter on modern Pi OS.

The 40-Pin Header: Physical vs. BCM Mapping

When working with the Raspberry Pi, you must choose a numbering scheme. Physical numbering counts pins 1 through 40 sequentially down the header. BCM numbering refers to the internal Broadcom/RP1 channel numbers. In Python, always use BCM numbering; it abstracts away physical layout changes across board revisions.

Bench Tip: The Pi 5 removed the default 1.8kΩ pull-up resistors on the I2C pins (BCM 2 and 3) that were present on the Pi 4. If your I2C sensors are failing to read on a Pi 5, you must add external 4.7kΩ pull-up resistors to the 3.3V rail.

Critical Pin Reference Table

Function BCM Pin Physical Pin Notes & Constraints
3.3V Power N/A 1, 17 Max draw ~50mA. Do not use for motors.
5V Power N/A 2, 4 Tied to USB-C PD input. High current capacity on Pi 5.
Ground N/A 6, 9, 14, 20, 25, 30, 34, 39 Use multiple grounds for high-frequency signals to reduce noise.
I2C1 SDA 2 3 Requires external 4.7kΩ pull-ups on Pi 5.
I2C1 SCL 3 5 Requires external 4.7kΩ pull-ups on Pi 5.
UART TX 14 8 3.3V logic. Do not connect directly to RS232.
UART RX 15 10 Disable serial console in raspi-config to use for data.
Hardware PWM0 18 12 Best pin for audio or precise motor/fan control.
SPI0 MOSI 10 19 Standard SPI data out.
SPI0 MISO 9 21 Standard SPI data in.

For the complete 40-pin diagram, bookmark the authoritative Pinout.xyz interactive guide.

Project Build: Hardware PWM Cooling Fan Controller

The Pi 5 runs significantly hotter than its predecessors. While it has a dedicated 4-pin JST fan header, learning to drive a PWM fan via the 40-pin GPIO layout is a foundational skill for custom enclosures and secondary cooling zones.

Difficulty: Intermediate | Time: 45 Minutes
Target Board: Raspberry Pi 5 (4GB/8GB) running Debian Bookworm (64-bit)
Backend Requirement: rpi-lgpio (Replaces legacy RPi.GPIO)

Parts List

  • Microcontroller: Raspberry Pi 5 (8GB variant recommended for heavy compilation loads)
  • Fan: Noctua NF-A4x20 5V PWM (4-pin)
  • Switching Component: 2N7000 N-channel MOSFET (Logic-level, Vgs(th) ~2.0V)
  • Resistor: 10kΩ (Gate pull-down to prevent spin-up during Pi boot)
  • Wiring: 22 AWG solid core jumper wires, half-size breadboard

Wiring Steps

  1. De-energize: Ensure the Pi is powered off and unplugged before wiring the GPIO header.
  2. Gate Connection: Connect Pi BCM 18 (Physical Pin 12) to the Gate (left pin) of the 2N7000 MOSFET.
  3. Pull-down Resistor: Place the 10kΩ resistor between the MOSFET Gate and Source to keep the fan off during OS boot sequences.
  4. Source to Ground: Connect the MOSFET Source (right pin) to Pi Ground (Physical Pin 6).
  5. Fan PWM Wire: Connect the Fan’s PWM wire (usually blue, Pin 4 on the fan connector) to the MOSFET Drain (middle pin).
  6. Power Delivery: Connect the Fan VCC (yellow/red) to Pi 5V (Physical Pin 2) and Fan GND (black) to Pi Ground (Physical Pin 9). Note: The Pi 5’s 5V rail via USB-C PD can comfortably supply the ~100mA draw of a 5V Noctua fan.

Compilable Python Code

This script uses gpiozero, the modern standard for Pi I/O. It ramps the fan from 20% to 100% duty cycle.

from gpiozero import PWMOutputDevice
from time import sleep
import sys

# Target: Raspberry Pi 5 (Bookworm OS) using rpi-lgpio backend
# BCM 18 is Hardware PWM0 (Physical Pin 12)
FAN_PIN = 18 

# Standard PC/PWM fans require a 25kHz carrier frequency
FAN_FREQ = 25000 

def main():
    try:
        # Initialize PWM device
        fan = PWMOutputDevice(FAN_PIN, frequency=FAN_FREQ)
        print(f"PWM Fan initialized on BCM {FAN_PIN} at {FAN_FREQ}Hz.")
        
        # Ramp up test
        for duty_cycle in [0.2, 0.4, 0.6, 0.8, 1.0]:
            fan.value = duty_cycle
            print(f"Setting fan duty cycle to {int(duty_cycle * 100)}%")
            sleep(3) # Hold each speed for 3 seconds
            
    except KeyboardInterrupt:
        print("\nUser interrupted. Stopping fan.")
    except Exception as e:
        print(f"Hardware error: {e}")
        sys.exit(1)
    finally:
        # Ensure fan turns off on exit to prevent battery drain on UPS setups
        try:
            fan.off()
            fan.close()
        except NameError:
            pass

if __name__ == '__main__':
    main()

Debugging GPIO Failures: Errors and Fixes

When your GPIO circuit fails, do not start rewriting code. The first three things to check are:

  1. Verify the mapping: Run pinout in the terminal to confirm your physical wire matches the BCM number in your code.
  2. Check the OS/Library matrix: Are you on Bullseye (uses RPi.GPIO) or Bookworm (requires rpi-lgpio)?
  3. Test continuity: Use a multimeter in continuity mode to verify the breadboard ground rail is actually connected to the Pi’s ground pin. Breadboard power rails are frequently split in the middle.

Error Matrix: Exact Strings and Ranked Causes

Error String: gpiozero.exc.GpioZeroError: No enabled pin factories found

  • Cause 1 (Most Likely): You are on Raspberry Pi OS Bookworm but haven't installed the lgpio backend. Fix: Run sudo apt install python3-rpi-lgpio.
  • Cause 2: You are running the script inside a virtual environment (venv) that lacks system site-packages. Fix: Recreate venv with python3 -m venv --system-site-packages myenv.

Error String: RuntimeError: No access to /dev/mem. Try running as root!

  • Cause 1 (Most Likely): You are trying to use the legacy RPi.GPIO library on Bookworm without sudo. Fix: Abandon RPi.GPIO. It is deprecated and fundamentally incompatible with the Pi 5's RP1 chip architecture. Migrate to gpiozero.
  • Cause 2: If you absolutely must use legacy code, you lack udev rules for GPIO access. Fix: Run with sudo python3 script.py (not recommended for production).

For official OS-level configuration details, refer to the Raspberry Pi GPIO Configuration Documentation.

Frequently Asked Questions

Are the Raspberry Pi 4 and Pi 5 GPIO pin layouts exactly the same?

Physically and logically, yes. The 40-pin footprint, power rail locations, and BCM numbering are identical. Electrically, there are nuances. The Pi 5’s RP1 southbridge operates at slightly different voltage thresholds, and as mentioned, the internal I2C pull-up resistors were removed. Furthermore, the Pi 5 GPIO pins are strictly 3.3V tolerant; applying 5V to any data pin will permanently destroy the RP1 chip, whereas the Pi 4’s BCM2711 was slightly more forgiving (though still officially 3.3V only).

How do I find the GPIO pin layout on Raspberry Pi without a diagram?

Open your terminal and type pinout. This built-in CLI tool (part of the gpiozero package) prints a beautiful, color-coded ASCII diagram of your specific board’s GPIO layout, including the board revision, RAM, and active I2C/SPI interfaces. It is the fastest way to verify a pin number while sitting at the workbench.

Can I use 5V logic sensors directly on the Raspberry Pi GPIO pins?

No. The Raspberry Pi (all models) uses 3.3V logic levels for data pins. Connecting a 5V output from an Arduino or a legacy 5V sensor directly to a Pi GPIO pin will fry the input buffer. You must use a bidirectional logic level converter (like the BSS138 MOSFET-based TXB0108 modules) or a simple voltage divider (2kΩ and 3.3kΩ resistors) to step the 5V signal down to a safe 3.3V.

How do I extend or simplify this PWM fan build?

To simplify: If you only need one fan for the CPU, skip the GPIO and MOSFET entirely. The Pi 5 features a dedicated 4-pin JST connector labeled FAN near the USB-C port. You can plug a standard 5V PWM fan directly into it and let the Pi’s onboard firmware manage the thermal curve automatically via config.txt parameters.

To extend: Add an I2C temperature sensor (like the BME280) to BCM 2/3. Read the ambient or CPU temperature in Python, map the temperature range (e.g., 40°C to 70°C) to a PWM duty cycle (20% to 100%), and create a custom, silent thermal management loop that doesn't rely on the OS-level thermal throttling daemon.