If your search history is full of "raspberry pi pines," don't worry—autocorrect and typos frequently turn "pins" into "pines." You are looking for the 40-pin GPIO (General Purpose Input/Output) header. The physical pins on a Raspberry Pi are the bridge between your Python scripts and the physical world, but misinterpreting the pinout is the number one cause of fried boards and silent I2C failures.
The direct answer for most beginners: Pin 1 is 3.3V, Pin 2 is 5V, and Pin 6 is Ground. However, when writing code, you must decide whether to reference the Physical Board Number (1-40) or the BCM (Broadcom) GPIO Number (e.g., GPIO17). Mixing these two numbering systems is responsible for 90% of embedded debugging headaches.
In this guide, we will wire an I2C environmental sensor, write robust Python code with proper error handling, and break down the exact troubleshooting steps for the most common I2C bus errors.
The 40-Pin Header: Physical vs. BCM Numbering
The Raspberry Pi uses two distinct numbering schemes. The Physical (Board) scheme simply counts pins 1 through 40, starting from the 3.3V pin nearest the SD card slot. The BCM (Broadcom) scheme refers to the internal chip designations (e.g., GPIO2, GPIO3). Libraries like gpiozero default to BCM, while physical wiring diagrams use Board numbers.
| Physical Pin | BCM GPIO | Function / Name | Project Connection |
|---|---|---|---|
| 1 | - | 3.3V Power | BME280 VCC (Red wire) |
| 2 | - | 5V Power | Do not use for 3.3V I2C sensors |
| 3 | GPIO 2 | I2C1 SDA | BME280 SDA (Blue wire) |
| 5 | GPIO 3 | I2C1 SCL | BME280 SCL (Yellow wire) |
| 6 | - | Ground (GND) | BME280 GND (Black wire) |
| 11 | GPIO 17 | General Purpose I/O | Status LED Anode (via 330Ω resistor) |
| 9 | - | Ground (GND) | Status LED Cathode |
Project Build: I2C Environmental Monitor
We are building a headless temperature, humidity, and pressure logger using a BME280 sensor and a status LED. This build teaches I2C bus initialization, BCM pin mapping, and runtime exception handling.
Parts List & Exact Variants
- Board: Raspberry Pi 4 Model B (4GB RAM) — Code targets this variant; fully compatible with Pi 3B+ and Pi 5.
- Sensor: Adafruit BME280 I2C Breakout (Product ID: 2652) or generic 3.3V BME280 module.
- Indicator: Standard 5mm Red LED + 330Ω through-hole resistor.
- Wiring: Female-to-female jumper wires (use standard color coding: Red=3.3V, Black=GND, Blue=SDA, Yellow=SCL).
Wiring Steps
- De-energize: Unplug the Raspberry Pi from the USB-C power supply before touching the GPIO header.
- Enable I2C: Boot the Pi, open terminal, run
sudo raspi-config→ Interface Options → I2C → Enable. - Wire Power: Connect BME280
VINto Pi Physical Pin 1 (3.3V). Connect BME280GNDto Pi Physical Pin 6. - Wire Data: Connect BME280
SDAto Pi Physical Pin 3. Connect BME280SCLto Pi Physical Pin 5. - Wire LED: Connect the 330Ω resistor to Pi Physical Pin 11 (BCM 17), then to the LED anode (long leg). Connect the LED cathode to Pi Physical Pin 9 (GND).
- Verify: Power on the Pi. Run
i2cdetect -y 1. You should see76or77in the grid output.
Complete Python Code with Error Handling
Before running this script, install the required dependencies via terminal: pip3 install smbus2 RPi.bme280 gpiozero.
This script explicitly defines pin mappings at the top, uses try/except blocks to catch hardware disconnects, and cleans up the GPIO state on exit.
import smbus2
import bme280
from gpiozero import LED
from time import sleep
import sys
import logging
# --- HARDWARE CONFIGURATION ---
# Target Board: Raspberry Pi 4 Model B (4GB)
I2C_PORT = 1
# Adafruit BME280 defaults to 0x76; some generic clones use 0x77
BME280_ADDR = 0x76
STATUS_LED_BCM = 17 # Maps to Physical Pin 11
# Configure logging for headless debugging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def main():
# Initialize GPIO LED (defaults to BCM numbering in gpiozero)
status_led = LED(STATUS_LED_BCM)
status_led.blink(on_time=0.5, off_time=0.5, background=True)
logging.info(f"Status LED active on BCM {STATUS_LED_BCM}.")
# Initialize I2C Bus and Sensor Calibration
try:
bus = smbus2.SMBus(I2C_PORT)
calibration_params = bme280.load_calibration_params(bus, BME280_ADDR)
logging.info("BME280 calibration loaded successfully.")
except OSError as e:
logging.error(f"I2C Hardware Error: {e}")
logging.error("Check: 1) Is I2C enabled in raspi-config? 2) Is SDA/SCL wired to Pins 3/5?")
sys.exit(1)
except Exception as e:
logging.error(f"Unexpected setup error: {e}")
sys.exit(1)
# Main Telemetry Loop
try:
while True:
data = bme280.sample(bus, BME280_ADDR, calibration_params)
temp_c = data.temperature
humidity = data.humidity
pressure = data.pressure
logging.info(f"Temp: {temp_c:.2f}C | Hum: {humidity:.1f}% | Press: {pressure:.1f}hPa")
sleep(2)
except KeyboardInterrupt:
logging.info("Script terminated by user (Ctrl+C).")
except OSError as e:
# Catches mid-run physical disconnects or bus lockups
logging.error(f"I2C Communication lost during runtime: {e}")
finally:
# Always clean up GPIO and I2C resources
status_led.off()
bus.close()
logging.info("LED off, I2C bus closed. Exiting cleanly.")
if __name__ == "__main__":
main()
Debugging: "Remote I/O Error" and Common I2C Failures
When working with the Raspberry Pi pins for I2C communication, you will inevitably encounter bus errors. The most infamous is the Remote I/O error.
Exact Error String: OSError: [Errno 121] Remote I/O error
This error means the Pi's I2C controller sent a clock pulse and address request, but the slave device (your sensor) did not acknowledge (ACK) it. Here are the first three things to check, ranked by probability:
- Verify the I2C Address (Most Likely): Run
i2cdetect -y 1in the terminal. If your sensor shows up at77but your Python code definesBME280_ADDR = 0x76, the bus will throw Errno 121. Update your code to match the hex output fromi2cdetect. - Check Physical Wire Seating: Dupont female connectors wear out. A loose SCL (clock) wire will cause intermittent Errno 121 failures. Swap your jumper wires or crimp new connectors. Measure continuity from the Pi header to the sensor breakout with a multimeter.
- Verify I2C Interface is Enabled: If
i2cdetectreturns an empty grid or says "command not found", you haven't enabled the hardware overlay. Runsudo raspi-configand enable I2C under Interface Options, then reboot.
Extending and Simplifying the Build
Once you have the baseline telemetry running, you can adapt the hardware to fit your specific project constraints.
How to Extend (Add More Sensors)
The I2C bus supports multiple devices, provided they have unique addresses. If you want to add a second BME280 (e.g., for indoor vs. outdoor monitoring), you must change the I2C address of the second breakout board. On Adafruit modules, this involves scraping a tiny trace and soldering a jumper pad to shift the address from 0x76 to 0x77. For generic boards without address jumpers, use a TCA9548A I2C Multiplexer (approx. $6) to route the Pi's single I2C bus into 8 independent channels.
How to Simplify (Headless Logging)
If you don't need real-time terminal output and just want a low-power data logger, strip out the gpiozero LED code and replace the logging.info print statements with standard Python file I/O. Open a CSV file in append mode ('a') and write the timestamped sensor readings. You can then schedule the script via cron to run every 5 minutes, allowing the Pi to sleep in between to reduce thermal noise affecting the temperature sensor.
Frequently Asked Questions
Why are my Raspberry Pi pins not outputting 5V?
The Raspberry Pi is a 3.3V logic device. While Physical Pin 2 and Pin 4 supply 5V power directly from the USB-C input (useful for powering 5V relays or LED strips), the actual data pins (GPIO) only output 3.3V HIGH. If you need to drive a 5V logic component (like an older Arduino or a 5V shift register), you must use a logic level converter (like the Texas Instruments SN74LVC8T245) or an optocoupler to safely bridge the 3.3V Pi pins to 5V logic.
Can I use the Raspberry Pi pins for analog inputs?
No. Unlike the Arduino Uno or ESP32, the Broadcom SoC on the Raspberry Pi does not have a built-in Analog-to-Digital Converter (ADC) on its GPIO pins. The pins are strictly digital (HIGH/LOW). To read analog sensors (like a potentiometer, MQ-2 gas sensor, or LDR), you must wire an external ADC chip to the Pi's I2C or SPI pins. The ADS1115 (16-bit, 4-channel I2C ADC, approx. $10) is the industry standard for adding analog read capabilities to the Pi.
How do I safely shut down the Pi using a physical GPIO pin button?
Pulling the power cord corrupts the SD card. You can wire a momentary pushbutton between Physical Pin 5 (GPIO 3) and Physical Pin 6 (GND). The Pi's bootloader has a hardcoded feature: if Pin 5 is pulled LOW while the Pi is halted, it will wake up and boot. To make this button trigger a safe shutdown when running, add dtoverlay=gpio-shutdown,gpio_pin=3,active_low=1,gpio_pull=up to the bottom of your /boot/config.txt file. This delegates the hardware interrupt to the OS, ensuring a clean filesystem unmount before power-off.






