Time to Complete: 45 minutes
Target Board: Raspberry Pi 5 (8GB) with RP1 Southbridge
The standard raspberry pi board gpio layout is a 40-pin (2x20) header operating at 3.3V logic. If you are starting a new embedded build in 2026, you should target the Raspberry Pi 5 (8GB) using the gpiozero Python library. Unlike the Pi 4, the Pi 5 routes GPIO through the dedicated RP1 southbridge chip, which changes how hardware PWM and I2C are addressed at the kernel level, but gpiozero abstracts this perfectly for application-level code.
This guide provides a concrete decision path for board selection, a complete hardware build for driving a 5V PWM fan, production-ready Python code with error handling, and a debugging matrix for the most common GPIO faults.
The Quick Decision: Which Raspberry Pi Board GPIO Layout Do You Need?
While the 40-pin physical footprint has remained unchanged since the Pi 1 B+, the underlying silicon and power delivery have shifted. Use this decision matrix to select the exact board variant for your project.
| Requirement | Raspberry Pi 5 (8GB) | Pi Zero 2 W | Raspberry Pi 4 (4GB) |
|---|---|---|---|
| Logic Level | 3.3V (RP1 chip) | 3.3V (BCM2710A1) | 3.3V (BCM2711) |
| Hardware PWM Channels | 4 dedicated channels | 2 shared channels | 2 shared channels |
| Max GPIO Current Draw | ~16mA per pin (50mA total bank) | ~16mA per pin (50mA total bank) | ~16mA per pin (50mA total bank) |
| Best Use Case | High I/O, PCIe NVMe, fast switching | Battery-powered, space-constrained IoT | Legacy HAT compatibility, budget builds |
Parts List and Pin Mapping for the Pi 5 (40-Pin Header)
For this build, we are wiring a 5V PWM cooling fan. Because the Raspberry Pi board GPIO pins output 3.3V logic and can only source ~16mA, you cannot drive a 5V fan directly from the pin. We will use an NPN transistor as a low-side switch to bridge the 3.3V logic to the 5V fan circuit.
Bill of Materials (BOM)
- Microcontroller: Raspberry Pi 5 (8GB variant) - ~$80.00
- Fan: Noctua NF-A4x10 5V PWM (40x10mm) - ~$15.00
- Transistor: 2N2222A NPN Bipolar Junction Transistor (TO-92 package) - ~$0.15
- Resistor: 1kΩ 1/4W Carbon Film (Base current limiter) - ~$0.02
- Wiring: 22 AWG solid core jumper wires and half-size breadboard
Pin Mapping Table
| Function | BCM GPIO # | Physical Pin # | Wiring Destination |
|---|---|---|---|
| 5V Power | N/A | Pin 2 or 4 | Fan VCC (Yellow Wire) |
| Ground | N/A | Pin 6 | Transistor Emitter & Fan GND (Black) |
| Hardware PWM0 | GPIO 18 | Pin 12 | 1kΩ Resistor -> Transistor Base |
Step-by-Step: Wiring a PWM Fan to the GPIO Header
- Prep the Transistor: Identify the pins on the 2N2222A (flat side facing you: Emitter=Left, Base=Middle, Collector=Right). Place it across the center trench of your breadboard.
- Wire the Base (Logic Side): Connect Physical Pin 12 (GPIO 18) to one end of the 1kΩ resistor. Connect the other end of the resistor to the Base (middle pin) of the 2N2222A.
- Wire the Emitter (Ground): Connect the Emitter (left pin) to the breadboard ground rail. Run a jumper from the ground rail to Physical Pin 6 (GND) on the Pi.
- Wire the Collector (Load Side): Connect the Collector (right pin) to the PWM control wire (usually blue) on the Noctua fan.
- Wire Fan Power: Connect the fan's VCC (yellow) to Physical Pin 2 (5V) on the Pi. Connect the fan's GND (black) to the breadboard ground rail.
- Verify: Before applying power, use a multimeter in continuity mode to verify there is no short between the 5V rail and the GPIO 18 line.
Complete Python Control Code (gpiozero with Error Handling)
The following script uses the gpiozero library, which is pre-installed on Raspberry Pi OS. It targets GPIO 18, ramps the fan up to 100%, drops to 40%, and handles hardware faults gracefully.
import time
import sys
from gpiozero import PWMOutputDevice
from gpiozero.exc import GPIOPinInUse, BadPinFactory
# Explicit pin definition - BCM numbering
FAN_PIN = 18
PWM_FREQ = 25000 # 25kHz is the standard for PC/PWM fans
def main():
try:
# Initialize PWM on GPIO 18
fan = PWMOutputDevice(FAN_PIN, frequency=PWM_FREQ, initial_value=0)
print(f"Successfully initialized PWM on GPIO {FAN_PIN}")
# Ramp up to 100%
fan.value = 1.0
print("Fan running at 100% duty cycle...")
time.sleep(5)
# Drop to 40% for quiet idle
fan.value = 0.4
print("Fan dropped to 40% duty cycle...")
time.sleep(5)
except GPIOPinInUse:
print(f"FATAL: GPIO {FAN_PIN} is already in use by another process.")
sys.exit(1)
except BadPinFactory as e:
print(f"FATAL: Pin factory error. Are you running on a Pi? Details: {e}")
sys.exit(1)
except RuntimeError as e:
# Catches /dev/mem access issues on older OS builds
print(f"FATAL: Runtime error accessing GPIO memory: {e}")
sys.exit(1)
except KeyboardInterrupt:
print("\nInterrupt received. Stopping fan...")
finally:
# Ensure the pin is cleaned up and fan is turned off
try:
fan.value = 0
fan.close()
print("GPIO cleaned up successfully.")
except NameError:
pass # Fan object was never created
if __name__ == "__main__":
main()
Debugging: "RuntimeError" and the First Three Things to Check
When working with the raspberry pi board gpio header, software and hardware faults often present identically. Here is the decision path for the most common errors.
Exact Error: RuntimeError: No access to /dev/mem. Try running as root!
- Cause 1 (Most Likely): You are running an older Raspberry Pi OS (Buster or earlier) where
gpiozerodefaults to theRPi.GPIObackend, which requires root privileges. - Fix: Upgrade to Raspberry Pi OS Bookworm or later, which uses the
lgpiobackend and allows standard user access via thegpiogroup. Alternatively, run the script withsudo python3 fan_control.py.
Exact Error: gpiozero.exc.GPIOPinInUse: pin 18 is already in use
- Cause 1: A previous instance of your script crashed without reaching the
finallyblock, leaving the pin locked in the kernel. - Cause 2: The
pwmconfigorfancontrolsystem daemons are actively managing the pin via device tree overlays. - Fix: Run
pinctrl get 18in the terminal to see what the RP1 chip thinks the pin is doing. Kill conflicting daemons withsudo systemctl stop fancontrol.
The First Three Things to Check When Hardware Fails
If the code runs without errors but the fan doesn't spin, do not rewrite the code. Check the physics:
- Measure the Base Voltage: Put your multimeter's red probe on the transistor Base and black on GND. When the script outputs 100%, you should read ~3.3V. If you read 0V, your jumper wire or breadboard contact is dead.
- Verify the 5V Rail Under Load: Measure Physical Pin 2 to Pin 6 while the fan is supposed to be spinning. If the voltage drops below 4.8V, your Pi's power supply is browning out. The Pi 5 requires a 27W USB-C PD supply; a standard 15W phone charger will cause peripheral brownouts.
- Check Transistor Orientation: The 2N2222A pinout is notoriously confused with the BC547. If you have it backwards, the Base-Emitter junction will act as a Zener diode and clamp the pin, potentially damaging the RP1 GPIO bank.
Extending or Simplifying Your GPIO Build
Once you have the base circuit working, you will inevitably need to adapt it for production or simplify it for a quick prototype.
How to Simplify (The Quick Prototype)
If you don't want to deal with bare transistors and resistors, buy a 5V Relay Module (Optocoupler isolated) or a dedicated Pi 5 Active Cooler HAT. The official Pi 5 Active Cooler ($5) plugs directly into the PWM fan header (a dedicated 4-pin JST connector next to the GPIO header, separate from the 40-pin array) and is managed natively by the Pi's firmware without requiring Python scripts.
How to Extend (Closed-Loop Control)
To make this a true closed-loop thermal system, you need RPM feedback. The Noctua fan has a 4th wire (Green) that outputs a tachometer square wave (2 pulses per revolution).
Next Steps for Extension:
- Wire the Green tachometer wire to GPIO 17 (Physical Pin 11).
- Use the
gpiozero.Buttonclass or thepigpiolibrary to count the falling edges on GPIO 17. - Calculate RPM:
RPM = (pulse_count / 2) * 60. - Implement a PID controller in Python to adjust the
fan.valuePWM duty cycle based on real-time RPM targets rather than blind time delays.
For deeper hardware-level documentation on the RP1 southbridge and peripheral addressing, refer to the official Raspberry Pi Hardware Documentation. Understanding the separation between the BCM2712 application processor and the RP1 I/O chip is critical for advanced debugging when standard Python abstractions fail.






