Raspberry Pi GPIO: Pin Reference, gpiozero Guide, and Protocol Overview

Using Gpio Pins For Projects With Raspberry Pi (1)

Raspberry Pi GPIO pins are the physical interface between the Pi’s processor and external hardware: LEDs, buttons, sensors, motors, displays, and communication modules. The 40-pin header on Pi 2 through Pi 5 provides digital I/O, hardware PWM, I2C, SPI, and UART on specific pins. All GPIO pins operate at 3.3V. This guide covers the complete pin reference, controlling hardware with gpiozero in Python, enabling and using I2C, SPI, and UART, level shifting for 5V devices, and a project roadmap with links to the specialist guides for each hardware category.

Last reviewed: Raspberry Pi OS Bookworm Lite 64-bit | May 2025 | Raspberry Pi 4 Model B (4GB) | gpiozero 2.0, Python 3.11, pigpio 79

Key Takeaways

  • All Raspberry Pi GPIO pins operate at 3.3V with a maximum safe input of 3.3V and a maximum drive current of 8mA per pin (16mA total for all GPIO simultaneously). Applying 5V to a GPIO pin can permanently damage the BCM SoC. Use a resistor voltage divider or a dedicated logic level converter when interfacing with 5V devices or microcontrollers.
  • WiringPi was deprecated by its author in 2019 and does not correctly support Pi 4 or Pi 5. Do not use it for new projects. For Python, use gpiozero. For C/C++, use lgpio (the successor library from the same author as pigpio, maintained for Pi 4 and Pi 5 on Bookworm).
  • gpiozero uses the modern Linux GPIO character device interface (/dev/gpiochipN) via its default pin factory on Bookworm. The old /sys/class/gpio sysfs interface was deprecated in kernel 4.8 and should not be used in new code. gpiozero handles this automatically.

Raspberry Pi GPIO Pin Reference: Numbering, Voltage, and Functions

Raspberry pi gpio reference

The Pi’s 40-pin header contains 26 usable GPIO pins, 2x 3.3V power pins, 2x 5V power pins, 8x GND pins, and 2 special-purpose pins (GPIO2/3 with fixed pull-ups, GPIO14/15 for UART). GPIO pins are referenced by two numbering systems: BCM numbering uses the Broadcom SoC’s internal GPIO numbers (GPIO17, GPIO27, etc.) and is what gpiozero and most Python code use. Board numbering uses the physical pin position on the header (pin 11, pin 13, etc.). Never mix the two in a single script.

Gpio 1

The official pin diagram is at raspberrypi.com/documentation. The pinout command on Raspberry Pi OS prints an ASCII pin diagram in the terminal, useful for quick reference without leaving the SSH session:

pinout

The 3.3V electrical constraints in practice: a standard LED on a GPIO pin needs a 330-ohm current-limiting resistor. An HC-SR04 ultrasonic sensor’s ECHO pin outputs 5V and must be divided down before connecting to GPIO. A 1k/2k resistor voltage divider reduces 5V to approximately 3.3V. A logic level converter (bidirectional BSS138-based module) is cleaner and handles I2C correctly where resistor dividers cause issues. The Pi’s 3.3V rail can supply approximately 50mA total for external components.

Controlling Raspberry Pi GPIO with gpiozero

gpiozero is pre-installed on Raspberry Pi OS Desktop. On Lite, install it:

sudo apt install -y python3-gpiozero

gpiozero provides named classes that describe the hardware component rather than raw pin operations. Common output and input classes:

ClassUseKey methods / properties
LED(pin)Digital output, single LED.on() .off() .blink() .toggle()
PWMLED(pin)PWM LED brightness.value (0.0–1.0) .pulse()
RGBLED(r,g,b)RGB LED.color tuple (r,g,b) 0.0–1.0
Buzzer(pin)Passive buzzer.on() .off() .beep()
Servo(pin)Servo motor.value (−1 to 1) .min() .max()
Motor(fwd, bwd)DC motor via H-bridge.forward() .backward() .stop()
Button(pin)Push button input.is_pressed when_pressed callback
MotionSensor(pin)PIR motion sensor.motion_detected when_motion callback
DistanceSensor(echo,trig)HC-SR04 ultrasonic.distance in metres
LightSensor(pin)LDR light sensor.light_detected .value

Event-driven pattern (the correct approach for responsive hardware projects):

from gpiozero import LED, Button, MotionSensor
from signal import pause

led = LED(17)
btn = Button(4, pull_up=True, bounce_time=0.05)
pir = MotionSensor(18)

# Button toggles LED
btn.when_pressed  = led.on
btn.when_released = led.off

# PIR blinks LED while motion detected
pir.when_motion   = lambda: led.blink(0.2, 0.2)
pir.when_no_motion = led.off

pause()  # Block main thread; hardware runs in background

Expected result: The LED turns on when the button is pressed and off when released. When the PIR detects motion the LED blinks rapidly and stops when motion ends. All hardware runs in background threads; pause() keeps the script alive without consuming CPU. Ctrl+C exits cleanly and gpiozero releases all GPIO resources automatically.

For the HC-SR04 DistanceSensor class specifically: gpiozero’s implementation expects the ECHO pin to be safe for 3.3V GPIO. The HC-SR04 outputs 5V on ECHO. Use a voltage divider (1kΩ from ECHO to GPIO, 2kΩ from GPIO to GND) or a logic level converter before connecting ECHO to any GPIO pin. The TRIG pin (an input to the sensor) can connect directly since GPIO outputs 3.3V which is sufficient to trigger the sensor. For a full wiring and safety guide, see Raspberry Pi Robot Basics: The Complete Beginners Guide.

GPIO Protocols: I2C, SPI, and UART on Raspberry Pi

The Pi’s communication protocols are disabled by default on Raspberry Pi OS Lite. Enable each one through raspi-config:

sudo raspi-config
# Interface Options > I2C > Yes
# Interface Options > SPI > Yes
# Interface Options > Serial Port:
#   Login shell: No  (must disable console)
#   Serial hardware: Yes

On Raspberry Pi OS Desktop, these are toggled in the Raspberry Pi Configuration application under the Interfaces tab.

I2C uses two wires: SDA (GPIO2, pin 3) and SCL (GPIO3, pin 5). It supports multiple devices on the same two pins, each addressed by a unique 7-bit address. Scan for connected I2C devices after wiring:

sudo apt install -y i2c-tools
i2cdetect -y 1

A connected device shows its address (e.g., 0x76 for a BME280). If nothing shows, verify SDA/SCL wiring and that the device has the correct pull-up resistors (most breakout boards include these). GPIO2 and GPIO3 have fixed internal pull-ups to 3.3V. Do not add additional external pull-ups on these pins.

SPI uses four wires: MOSI (GPIO10), MISO (GPIO9), SCLK (GPIO11), and one or more CE/CS pins (GPIO8 for CE0, GPIO7 for CE1). SPI is faster than I2C and suited for displays, ADC chips, and flash memory. The Python spidev library provides SPI access:

sudo apt install -y python3-spidev

UART uses TX (GPIO14, pin 8) and RX (GPIO15, pin 10) for serial communication with GPS modules, Bluetooth adapters, and microcontrollers. The serial console must be disabled before using UART for hardware. The raspi-config Serial Port section shown above handles this. After disabling the console and rebooting, the device is available at /dev/serial0. Install pyserial for Python access:

sudo apt install -y python3-serial
sudo usermod -aG dialout $USER

For the complete GPS UART setup including GPSD, chrony PPS time sync, and Python logging, see Raspberry Pi GPS: Module Setup, Python Logging, and Time Sync Guide.

Advanced Raspberry Pi GPIO: PWM, Interrupts, and Level Shifting

Hardware PWM on Pi 4 is available on GPIO12 (PWM0), GPIO13 (PWM1), GPIO18 (PWM0), and GPIO19 (PWM1). Hardware PWM produces a clean signal at any duty cycle without CPU involvement, making it correct for servo control, fan speed control, and LED dimming where flicker-free output matters. gpiozero’s PWMLED and Servo classes use hardware PWM on these pins automatically. For other GPIO pins, gpiozero falls back to software PWM via the pigpio daemon, which provides better software PWM than the default RPi pin factory:

sudo apt install -y pigpio python3-pigpio
sudo systemctl enable --now pigpiod

# Use pigpio pin factory for better software PWM:
from gpiozero import Device, PWMLED
from gpiozero.pins.pigpio import PiGPIOFactory
Device.pin_factory = PiGPIOFactory()

led = PWMLED(17)
led.pulse()

Interrupts and edge detection let the Pi respond to hardware events without polling. gpiozero implements this via the when_pressed, when_released, and when_activated callback pattern shown in the gpiozero section above. For lower-level interrupt access in Python, the lgpio library provides gpio_claim_alert() for rising/falling/both edge callbacks:

import lgpio
import time

h = lgpio.gpiochip_open(0)
lgpio.gpio_claim_input(h, 4)  # GPIO4 as input

def callback(chip, gpio, level, tick):
    print(f"GPIO{gpio} changed to {level} at {tick}")

lgpio.callback(h, 4, lgpio.BOTH_EDGES, callback)
time.sleep(30)
lgpio.gpiochip_close(h)

Level shifting for 5V devices. When connecting a 5V Arduino, 5V sensor, or 5V logic chip to Raspberry Pi GPIO, the voltage must be reduced before reaching the GPIO pin. Two approaches: a resistor voltage divider (1kΩ and 2kΩ to form a 1/3 voltage divider, reducing 5V to 3.3V) for unidirectional signals, or a bidirectional logic level converter (BSS138-based) for I2C or SPI buses where the signal travels both directions. The divider approach adds resistance that can cause I2C signal integrity problems; the dedicated converter is the correct solution for I2C.

Raspberry Pi GPIO Projects: Where to Go Next

The following guides on this site cover specific GPIO hardware categories with complete wiring diagrams, working code, and Bookworm-tested setups.

Hardware categoryProtocolGuide
LED control and PWM dimmingDigital / PWMRaspberry Pi LED Python Guide
GPS module and time syncUARTRaspberry Pi GPS Guide
Robot motors and sensorsDigital / PWM / I2CRaspberry Pi Robot Basics Guide
IoT sensors and MQTTI2C / SPI / DigitalRaspberry Pi IoT Projects Guide
Camera (CSI ribbon cable)CSI (not GPIO)Raspberry Pi Time-Lapse Camera Guide
GPIO in Python programsAllPython Raspberry Pi Guide
GPIO with Tkinter GUIDigital / PWMRaspberry Pi Tkinter Guide
HAT add-on boardsI2C / SPI / UARTRaspberry Pi HATs Guide
ESPHome sensors via WiFiWiFi (no GPIO wire)ESPHome Raspberry Pi Guide
Zigbee USB dongleUSB (not GPIO)Zigbee2MQTT Raspberry Pi Guide

FAQ

How many GPIO pins does Raspberry Pi have?

The 40-pin header on Pi 2 through Pi 5 contains 26 usable GPIO pins. The remaining 14 pins are power (2x 3.3V, 2x 5V) and ground (8x GND), plus 2 reserved pins. The original Pi 1 Model A/B had a 26-pin header with fewer GPIO pins. The Pico and Pico 2 microcontrollers have 26 multi-function GPIO pins in a different form factor and run MicroPython rather than Linux.

What is the maximum current a Raspberry Pi GPIO pin can supply?

8mA per GPIO pin is the safe maximum current. The total recommended current across all GPIO pins simultaneously is 16mA. For components that require more current (motors, relays, high-brightness LEDs), use a transistor or MOSFET as a switch driven by the GPIO pin, with the component powered from the 5V rail or an external supply rather than directly from the GPIO pin. Exceeding the 8mA limit risks damaging the BCM SoC permanently.

What is the difference between BCM and BOARD GPIO numbering?

BCM numbering (also called GPIO numbering) uses the Broadcom SoC’s internal GPIO designations: GPIO17, GPIO27, GPIO22, and so on. These are the numbers gpiozero uses. BOARD numbering uses the physical pin position on the 40-pin header: pin 11, pin 13, pin 15. GPIO17 is on physical pin 11; GPIO27 is on physical pin 13. Run pinout in the terminal to see both numbering systems side by side. Always check which system a guide or library expects before wiring.

Can I connect 5V sensors to Raspberry Pi GPIO?

Not directly. GPIO pins accept a maximum of 3.3V. Connecting a 5V signal to a GPIO pin can permanently damage the Pi’s SoC. For unidirectional signals (sensor output to Pi input), use a 1kΩ/2kΩ resistor voltage divider to reduce 5V to approximately 3.3V. For I2C or other bidirectional buses, use a dedicated BSS138-based bidirectional logic level converter. The HC-SR04 ultrasonic sensor’s ECHO pin is a common source of accidental GPIO damage because it outputs 5V.

Is WiringPi still a good GPIO library for Raspberry Pi?

No. WiringPi was deprecated by its author in 2019 and does not correctly support Pi 4 or Pi 5. The author’s current library is lgpio, which supports Pi 4 and Pi 5 on Bookworm for C/C++ GPIO projects. For Python, use gpiozero, which is maintained by the Raspberry Pi Foundation and pre-installed on Raspberry Pi OS Desktop. Do not start new projects with WiringPi.

References:


About the Author

Chuck Wilson has been programming and building with computers since the Tandy 1000 era. His professional background includes CAD drafting, manufacturing line programming, and custom computer design. He runs PidiyLab in retirement, documenting Raspberry Pi and homelab projects that he actually deploys and maintains on real hardware. Every article on this site reflects hands-on testing on specific hardware and OS versions, not theoretical walkthroughs.

Reviewed May 2025 against Raspberry Pi OS Bookworm Lite 64-bit on Raspberry Pi 4 Model B (4GB). gpiozero 2.0, Python 3.11, lgpio 0.2.