The Raspberry Pi 3 Model B and B+ feature a 40-pin GPIO header operating at 3.3V logic. Understanding the gpio pin layout raspberry pi 3 requires distinguishing between Physical pin numbers (1-40) and Broadcom (BCM) SOC channel numbers. Physical Pin 1 is the 3.3V power rail, located nearest to the SD card slot and HDMI ports, while Pin 2 is 5V. Feeding 5V directly into any BCM GPIO pin will instantly destroy the SoC. Always use a multimeter to verify physical pin 1 (3.3V) before wiring active components.

The GPIO Pin Layout Raspberry Pi 3: 40-Pin Header Reference

Below is the data-dense reference table for the most critical pins on the Pi 3 header. While the header contains 40 pins, many are duplicated grounds or reserved for specific hardware interfaces (I2C, SPI, UART). This table maps the Physical Pin, BCM GPIO, and primary function.

Physical Pin BCM GPIO Name / Function Notes & Hardware Constraints
1-3.3V PowerMax draw ~50mA combined across all 3.3V pins
2-5V PowerTied directly to USB 5V input; max draw depends on PSU
32GPIO2 (SDA1)I2C Data; includes 1.8kΩ onboard pull-up to 3.3V
53GPIO3 (SCL1)I2C Clock; includes 1.8kΩ onboard pull-up to 3.3V
6-GroundPrimary ground reference for 3.3V logic
814GPIO14 (TXD)Primary UART Transmit; defaults to serial console on boot
1015GPIO15 (RXD)Primary UART Receive; defaults to serial console on boot
1117GPIO17General Purpose; safe for PWM and digital I/O
1218GPIO18 (PWM0)Hardware PWM0; ideal for motor/fan speed control
14-GroundLocated adjacent to GPIO15 and GPIO18
1623GPIO23General Purpose; defaults to input with pull-down
1910GPIO10 (MOSI)SPI0 Master Out Slave In
219GPIO9 (MISO)SPI0 Master In Slave Out
2311GPIO11 (SCLK)SPI0 Serial Clock
25-GroundLocated adjacent to GPIO24 and GPIO8
270GPIO0 (ID_SD)I2C ID EEPROM Data; reserved for HAT identification

For a complete visual map of all 40 pins, the community-standard Pinout.xyz remains the definitive interactive reference. Always cross-reference physical pinouts with the official Raspberry Pi documentation when working with HATs.

Project Build: 5V PWM Fan Controller with Tachometer Feedback

Difficulty: Intermediate | Time: 45 Minutes | Target Board: Raspberry Pi 3 Model B+ (1.4GHz, 1GB LPDDR2)

The Pi 3 runs hot under sustained load. This project uses a 3.3V GPIO pin to drive a 5V PWM fan via a logic-level MOSFET, while reading the fan's tachometer signal back to the Pi to verify RPM.

Parts List

  • Microcontroller: Raspberry Pi 3 Model B+ (Running Raspberry Pi OS Bullseye 32-bit or 64-bit Legacy)
  • Fan: Noctua NF-A4x20 5V PWM (4-pin variant: VCC, GND, PWM, Tach)
  • Switching Component: 2N7000 N-Channel Logic-Level MOSFET (Vgs threshold ~2.0V, fully on at 3.3V)
  • Resistors: 1x 1kΩ (Gate resistor), 1x 10kΩ (Gate pull-down), 1x 10kΩ (Tach pull-up)
  • Wiring: 22 AWG solid core hookup wire, half-size breadboard

Project Pin Mapping

Pi 3 Physical Pin BCM GPIO Component Target Purpose
2-Fan VCC (Pin 2)5V Power to Fan
6-Fan GND (Pin 1) & MOSFET SourceCommon Ground
1117MOSFET Gate (via 1kΩ)PWM Signal Output
1327Fan Tach (Pin 4)RPM Pulse Input

Wiring Steps and Physical Connections

SAFETY CALL: De-energize the Pi (unplug the USB-C/Micro-USB power) before wiring. The Pi 3 GPIO pins are strictly 3.3V tolerant. Accidentally routing the 5V fan VCC line into BCM 17 or 27 will permanently short the SoC.

  1. Establish Common Ground: Connect Physical Pin 6 (GND) to the breadboard's negative rail. Connect the Noctua fan's black wire (GND) and the 2N7000 MOSFET's Source pin to this same rail.
  2. Wire the 5V Power: Connect Physical Pin 2 (5V) directly to the Noctua fan's yellow wire (VCC). Do not route 5V through the breadboard's main power rails if you are also using 3.3V logic elsewhere; keep 5V isolated to prevent accidental cross-wiring.
  3. Build the MOSFET Gate Drive: Connect BCM 17 (Physical 11) through a 1kΩ resistor to the 2N7000 Gate. This resistor limits inrush current from the GPIO pin's parasitic capacitance.
  4. Add the Gate Pull-Down: Connect a 10kΩ resistor between the MOSFET Gate and GND. Critical E-E-A-T tip: During Pi boot, GPIO pins float. Without this 10kΩ pull-down, the fan will spin at 100% for 10-15 seconds during OS load, causing unnecessary wear and noise.
  5. Wire the Tachometer: Connect the fan's green wire (Tach) to BCM 27 (Physical 13). Because the Noctua tach output is open-collector, you must add a 10kΩ pull-up resistor between BCM 27 and the 3.3V rail (Physical Pin 1).
  6. Verify: Use a multimeter in continuity mode to ensure the 5V line does not short to the 3.3V line or any GPIO pins before applying power.

Complete Python Control Code (RPi.GPIO)

The following code targets the RPi.GPIO library, which is natively supported on Raspberry Pi OS Bullseye. (Note: If you upgrade the Pi 3 to Bookworm, RPi.GPIO is deprecated in favor of lgpio or gpiozero, but Bullseye remains the stable baseline for Pi 3 legacy deployments).

import RPi.GPIO as GPIO
import time
import sys

# --- PIN DEFINITIONS (BCM Numbering) ---
PWM_PIN = 17
TACH_PIN = 27

# --- GLOBAL VARIABLES ---
pulse_count = 0
pulses_per_rev = 2  # Standard for most PC/Noctua fans

def tach_callback(channel):
    global pulse_count
    pulse_count += 1

def calculate_rpm(elapsed_seconds):
    global pulse_count
    if elapsed_seconds == 0:
        return 0
    # (Pulses / Pulses per Rev) / (Time in minutes)
    revs = pulse_count / pulses_per_rev
    minutes = elapsed_seconds / 60.0
    rpm = revs / minutes
    pulse_count = 0  # Reset for next interval
    return int(rpm)

def main():
    global pulse_count
    
    # Explicitly set BCM mode and disable warnings for clean restarts
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    
    try:
        # Setup PWM Output
        GPIO.setup(PWM_PIN, GPIO.OUT)
        pwm = GPIO.PWM(PWM_PIN, 25000)  # 25kHz frequency (Intel 4-wire spec)
        pwm.start(0)
        
        # Setup Tachometer Input with Pull-Up
        GPIO.setup(TACH_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
        GPIO.add_event_detect(TACH_PIN, GPIO.FALLING, callback=tach_callback)
        
        print("Fan controller initialized. Press Ctrl+C to exit.")
        
        # Ramp up to 70% duty cycle
        target_duty = 70
        pwm.ChangeDutyCycle(target_duty)
        print(f"Set PWM to {target_duty}%")
        
        while True:
            time.sleep(2)  # Measure RPM over a 2-second window
            rpm = calculate_rpm(2)
            print(f"Current RPM: {rpm}")
            
    except RuntimeError as e:
        # Catch specific RPi.GPIO hardware conflicts
        print(f"[FATAL GPIO ERROR] {e}")
        sys.exit(1)
    except KeyboardInterrupt:
        print("\nInterrupt received. Cleaning up...")
    finally:
        # CRITICAL: Always clean up to release hardware locks
        GPIO.cleanup()
        print("GPIO pins reset to safe input state.")

if __name__ == '__main__':
    main()

Debugging: Fatal GPIO Errors and the "First Three" Checklist

When working with the Pi 3 GPIO header, hardware-level exceptions are common. If your script crashes, look for these exact error strings in your terminal output.

Ranked Error Causes

  1. Exact Error: RuntimeError: Channel 17 is already in use
    • Cause: A previous execution of your script crashed before reaching GPIO.cleanup(), leaving the kernel's sysfs lock engaged on that pin. Alternatively, a background daemon (like a pre-installed fan shim service) is holding the pin.
    • Fix: Run sudo killall python3 or reboot the Pi. In code, use GPIO.setwarnings(False) and force setup, or ensure your finally: block always executes.
  2. Exact Error: RuntimeError: No access to /dev/mem. Try running as root!
    • Cause: You are running the script as a standard user on an older OS build, or the gpio group permissions are misconfigured in /etc/udev/rules.d/.
    • Fix: Execute with sudo python3 fan_control.py or add your user to the gpio group: sudo usermod -aG gpio $USER.
  3. Exact Error: RuntimeError: Conflicting edge detection already enabled for this GPIO channel
    • Cause: You called GPIO.add_event_detect() twice on the same pin without calling GPIO.remove_event_detect() or GPIO.cleanup() in between.

The "First Three" Debugging Checklist:
When the fan won't spin or the RPM reads zero, check these three things immediately:
1. Numbering Mode: Did you use GPIO.setmode(GPIO.BCM) but wire to Physical Pin 17 instead of BCM 17 (Physical 11)? This is the #1 beginner mistake.
2. The Pull-Down: Is the 10kΩ gate pull-down resistor physically seated? If the gate is floating, the MOSFET may be partially conducting, stalling the fan motor.
3. Tach Pull-Up: Measure BCM 27 with a multimeter. It must read ~3.3V when the fan is disconnected. If it reads 0V, your pull-up resistor is missing or the 3.3V rail is dead.

Extending and Simplifying the Build

How to Simplify

If you do not need RPM feedback and want to avoid the RPi.GPIO deprecation warnings on newer OS versions, strip the tachometer wiring and use the gpiozero library. The PWMOutputDevice class handles cleanup automatically on exit and abstracts the BCM/BOARD numbering confusion entirely. You will lose the ability to detect a stalled fan, but the code footprint drops to under 10 lines.

How to Extend

To turn this into a closed-loop thermal management system, add an I2C temperature sensor like the BME280 or TMP102. Wire the sensor's SDA/SCL to Physical Pins 3 and 5 (BCM 2 and 3). Implement a PID (Proportional-Integral-Derivative) control loop in Python: read the SoC temperature via vcgencmd measure_temp, calculate the error from your target setpoint (e.g., 55°C), and dynamically adjust the pwm.ChangeDutyCycle() value. This prevents the fan from hunting (rapidly speeding up and slowing down) and keeps the Pi 3 whisper-quiet during light workloads.