The standard 40-pin raspberry pin out has remained physically unchanged since the Pi 1 Model B+, but the underlying software architecture shifted dramatically with the Raspberry Pi 5. If you are mapping pins today, the legacy RPi.GPIO library is dead on the Pi 5. You must use BCM (Broadcom) numbering via the gpiozero library with the lgpio backend, or your code will crash on boot.
This guide cuts through the generic pinout charts and gives you a decision-forward framework for selecting the right pins for I2C sensors and PWM hardware, followed by exact debugging steps for the most common bench failures.
The 40-Pin Raspberry Pin Out: Decision Matrix for Your Next Build
Not all pins are created equal. While any GPIO can be toggled high or low in software, hardware-accelerated functions are hardwired to specific physical pins on the BCM2712 chip. Use this decision tree to lock in your pin assignments before you cut a single wire.
| Requirement | Decision Path (If-Then) | Concrete Pick (BCM / Physical) |
|---|---|---|
| I2C Bus | IF connecting standard sensors (BME280, OLED) → THEN use the primary bus with built-in 1.8kΩ pull-ups. IF connecting a HAT with an onboard EEPROM → THEN use the reserved ID bus. |
Primary: BCM 2 (Pin 3) & BCM 3 (Pin 5) ID/Reserved: BCM 0 (Pin 27) & BCM 1 (Pin 28) |
| PWM (Motor/Fan) | IF driving a 4-pin PC fan or servo requiring jitter-free signals → THEN use Hardware PWM. IF just dimming an LED → THEN use Software PWM on any pin. |
Hardware PWM0: BCM 18 (Pin 12) or BCM 12 (Pin 32) Hardware PWM1: BCM 13 (Pin 33) or BCM 19 (Pin 35) |
| UART (Serial) | IF connecting a GPS module or ESP32 via TX/RX → THEN use the primary PL011 UART. IF you need a secondary debug console → THEN use the mini UART. |
Primary: BCM 14/TX (Pin 8) & BCM 15/RX (Pin 10) Mini: Requires dtoverlay config. |
| SPI | IF connecting a high-speed ADC or TFT display → THEN use SPI0. | SPI0: BCM 10/MOSI (Pin 19), BCM 9/MISO (Pin 21), BCM 11/SCLK (Pin 23), BCM 8/CE0 (Pin 24) |
Parts List & Spec Sheet for the Pi 5 Thermal Build
To demonstrate the pinout in action, we are building a closed-loop thermal controller. It reads ambient data via I2C and drives a hardware PWM fan based on the Pi 5's internal CPU temperature. This specific build targets the Raspberry Pi 5 8GB variant.
| Component | Exact Variant / Model | Estimated Cost (2026) |
|---|---|---|
| Microcontroller | Raspberry Pi 5 (8GB RAM) with active cooler | $80.00 |
| Environmental Sensor | Adafruit BME280 I2C Breakout (Product ID: 2652) | $12.50 |
| Cooling Fan | Noctua NF-A4x20 5V PWM (4-pin connector) | $15.00 |
| Wiring | 28 AWG silicone jumper wires (pre-crimped Dupont) | $8.00 |
Difficulty Rating: Intermediate (Requires I2C bus enabling and Python environment setup).
Time to Complete: 45 minutes.
Pin Mapping Table: BME280 and PWM Fan on the Pi 5
Here is the exact wiring map for this build. We are using BCM numbering for the code, but referencing the physical pin numbers for your physical connection. Always count from the top-left (Pin 1) with the USB ports facing you.
| Component Pin | Pi 5 BCM GPIO | Pi 5 Physical Pin | Wire Color | Notes |
|---|---|---|---|---|
| BME280 VIN | 3.3V Power | 1 | Red | Do NOT use 5V (Pin 2) for this Adafruit breakout. |
| BME280 GND | Ground | 6 | Black | Common ground reference. |
| BME280 SCK (SCL) | BCM 3 (SCL1) | 5 | Yellow | I2C Clock line. |
| BME280 SDI (SDA) | BCM 2 (SDA1) | 3 | Blue | I2C Data line. |
| Fan PWM (Pin 4) | BCM 18 (PWM0) | 12 | Green | Hardware PWM capable pin. |
| Fan VCC (Pin 2) | 5V Power | 4 | Red | Fan requires 5V, not 3.3V. |
| Fan GND (Pin 1) | Ground | 9 | Black | Shared ground with Pi and BME280. |
Complete Python Code with Hardware Error Handling
This script uses gpiozero for PWM and smbus2 for raw I2C communication. It explicitly forces the lgpio pin factory, which is mandatory for the Pi 5. If you are adapting this for a Pi 4, you can remove the factory override.
import os
import sys
import time
from smbus2 import SMBus
from gpiozero import CPUTemperature, PWMOutputDevice
# CRITICAL PI 5 FIX: Force lgpio backend to avoid RPi.GPIO crash
os.environ['GPIOZERO_PIN_FACTORY'] = 'lgpio'
# --- PIN DEFINITIONS ---
I2C_BUS = 1
BME280_ADDR = 0x77 # Adafruit default. Change to 0x76 if using generic eBay modules.
FAN_PWM_PIN = 18 # BCM 18 / Physical Pin 12 (Hardware PWM0)
# --- INITIALIZATION ---
try:
cpu = CPUTemperature()
fan = PWMOutputDevice(FAN_PWM_PIN, frequency=25000) # 25kHz is standard for 4-pin PC fans
bus = SMBus(I2C_BUS)
except FileNotFoundError as e:
print(f"FATAL: I2C bus not found. Did you enable I2C in raspi-config? Error: {e}")
sys.exit(1)
except Exception as e:
print(f"FATAL: GPIO initialization failed. Ensure lgpio is installed. Error: {e}")
sys.exit(1)
def read_bme280_temp():
"""Reads uncompensated temp from BME280 register 0xFA for quick polling."""
try:
# Read 3 bytes from temp register (0xFA)
data = bus.read_i2c_block_data(BME280_ADDR, 0xFA, 3)
adc_t = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
# Simplified conversion for demonstration (real impl requires calibration registers)
return (adc_t / 16384.0) * 25.0
except OSError as e:
print(f"I2C Read Error: {e}. Check wiring and pull-ups.")
return None
def main():
print("Starting Pi 5 Thermal Controller...")
try:
while True:
cpu_temp = cpu.temperature
ambient_temp = read_bme280_temp() or 25.0
# Decision logic: Ramp fan from 20% to 100% between 50C and 75C
if cpu_temp < 50:
fan.value = 0.20
elif cpu_temp > 75:
fan.value = 1.0
else:
fan.value = 0.20 + ((cpu_temp - 50) / 25) * 0.80
print(f"CPU: {cpu_temp:.1f}C | Ambient: {ambient_temp:.1f}C | Fan PWM: {fan.value*100:.0f}%")
time.sleep(2)
except KeyboardInterrupt:
print("\nShutting down safely...")
fan.off()
bus.close()
sys.exit(0)
if __name__ == '__main__':
main()
Debugging: Exact Error Strings and Ranked Causes
When working with the raspberry pin out on modern Pi OS (Bookworm or later), you will inevitably hit hardware abstraction errors. Here is how to diagnose the three most common failures.
Error 1: 'RuntimeError: Cannot access /dev/mem or /dev/gpiomem'
Ranked Causes:
- Missing lgpio backend: You are running legacy
RPi.GPIOcode on a Pi 5. Fix: Runsudo apt install python3-lgpioand add theos.environoverride shown in the code above. - Permissions issue: Your user isn't in the
gpiogroup. Fix: Runsudo usermod -aG gpio $USERand reboot.
Error 2: 'FileNotFoundError: [Errno 2] No such file or directory: '/dev/i2c-1''
Ranked Causes:
- I2C interface disabled: The kernel overlay isn't loaded. Fix: Run
sudo raspi-config, navigate to Interface Options -> I2C, and enable it. - Wrong bus number: You are querying
I2C_BUS = 0instead of1. Bus 0 is reserved for the HAT ID EEPROM on pins 27/28.
Error 3: 'OSError: [Errno 121] Remote I/O error'
Ranked Causes:
- Wrong I2C Address: Your BME280 breakout has the SDO pin tied to GND (address 0x76) instead of VCC (0x77). Fix: Change
BME280_ADDRin the code. - Missing Pull-up Resistors: You are using a cheap sensor module without onboard 4.7kΩ pull-ups. The Pi's internal pull-ups are too weak for high-speed I2C. Fix: Solder 4.7kΩ resistors between SDA/SCL and 3.3V.
- Wiring Fault: SDA and SCL are swapped. Physical Pin 3 is SDA, Pin 5 is SCL.
1. Run
ls /dev/i2c* /dev/gpiochip* in the terminal. If they don't list, your kernel overlays are broken.2. Run
i2cdetect -y 1. If you see a grid of dashes with no 77 or 76, your I2C wiring is physically disconnected or the sensor is dead.3. Verify Physical Pin 1 orientation. The Pi 5 board layout is slightly denser; ensure your ribbon cable or jumper block isn't offset by one pin, feeding 5V into the 3.3V rail.
Extending or Simplifying the Build
Depending on your project timeline and budget, you can scale this raspberry pin out implementation up or down.
To Simplify (The 'Just Make It Work' Route):
Drop the BME280 entirely. The Pi 5's internal thermal diode is highly accurate for CPU protection. Delete the smbus2 imports, remove the ambient temp logic, and wire the fan directly to BCM 18. This reduces your physical wiring to just three pins (5V, GND, PWM) and eliminates all I2C debugging.
To Extend (The 'Smart Home' Route):
Add an MQTT publisher to push the CPU and ambient temperatures to Home Assistant. You will need to install paho-mqtt (pip install paho-mqtt). Wire a secondary I2C device, like an SCD40 CO2 sensor, onto the exact same SDA/SCL pins (Physical 3 and 5). The I2C bus supports up to 127 devices, provided their addresses don't clash and your total bus capacitance stays under 400pF. If you add more than three sensors, you must add a dedicated I2C bus extender (like the PCA9600) to maintain signal integrity.
For authoritative reference on the BCM2712 pin multiplexing, always consult the official Raspberry Pi GPIO documentation. For advanced Python pin factory configurations, the gpiozero readthedocs remains the definitive source. If you are using Adafruit breakouts, their BME280 wiring guide provides excellent schematic references for pull-up resistor placement.






