Raspberry Pi I2C Basics

I2C is a simple two-wire bus that lets your Raspberry Pi talk to many sensors and displays at once, each identified by its own address.

What Is I2C?

I2C (Inter-Integrated Circuit) is a communication protocol that lets a single controller — your Raspberry Pi — exchange data with many peripheral chips over just two shared wires. Instead of wiring a separate connection to every sensor or display, every device taps into the same pair of lines and listens for its own unique address. When the Pi wants to talk to a specific chip, it starts by sending that chip's address on the bus, and only the matching device responds; everything else stays silent.

  • SDA (Serial Data) carries the actual bits back and forth
  • SCL (Serial Clock) keeps both sides synchronized to the same timing
  • Each device on the bus has its own 7-bit address, so dozens of chips can share the same two wires
  • Standard mode runs at 100 kHz and Fast mode at 400 kHz, both far slower than SPI
  • Pull-up resistors on SDA and SCL are required for the bus to work reliably
  • Widely used by temperature/pressure sensors, real-time clocks, small OLED displays, and I/O expanders

Wiring and Enabling I2C

On every Raspberry Pi model, the primary I2C bus is exposed on physical pin 3 (GPIO2 / SDA) and physical pin 5 (GPIO3 / SCL), with ground available on several nearby pins. Because the Pi's GPIO header runs at 3.3V logic, make sure any module you connect is 3.3V-tolerant. I2C is disabled by default, so open a terminal and run sudo raspi-config, then choose Interface Options > I2C > Yes, or enable it without the menu using sudo raspi-config nonint do_i2c 0. Either way, reboot afterwards. Then install the tools used throughout this page with sudo apt update && sudo apt install -y i2c-tools python3-smbus2.

Scanning the Bus with i2cdetect

With the tools installed, run i2cdetect -y 1 (bus 1 is the standard user-facing I2C bus on modern Raspberry Pi boards). You'll see a 16x16 grid of two-digit hexadecimal addresses. Most cells show --, meaning nothing answered at that address, while a value such as 3c means a device responded there. A cell showing UU means a kernel driver has already claimed that address, which is common for a HAT's onboard identification chip.

DeviceTypical I2C Address
BMP280 temperature/pressure sensor0x76 or 0x77
MPU6050 accelerometer/gyroscope0x68 (or 0x69)
SSD1306 OLED display0x3C (or 0x3D)
DS3231 real-time clock0x68
PCF8591 ADC/DAC0x48

Example

from smbus2 import SMBus

BUS_NUMBER = 1

with SMBus(BUS_NUMBER) as bus:
    found = []
    for address in range(0x03, 0x78):
        try:
            bus.read_byte(address)
            found.append(hex(address))
        except OSError:
            pass

print("Devices found:", found)

Reading and Writing Registers with smbus2

Example

from smbus2 import SMBus

BMP280_ADDRESS = 0x76
CHIP_ID_REGISTER = 0xD0

with SMBus(1) as bus:
    chip_id = bus.read_byte_data(BMP280_ADDRESS, CHIP_ID_REGISTER)
    print(f"Chip ID: {hex(chip_id)}")

    # Writing a single configuration byte to a register
    CONTROL_REGISTER = 0xF4
    bus.write_byte_data(BMP280_ADDRESS, CONTROL_REGISTER, 0x27)
Note: If two devices on the bus default to the same address (an MPU6050 and a DS3231 RTC module can both default to 0x68, as shown in the table above), you'll need a module that lets you change its address with a solder jumper, or move one device to a second I2C bus. Also double-check wiring: SDA and SCL are easy to swap by mistake, and boards without built-in pull-up resistors may need external 4.7 kΩ resistors to 3.3V for reliable communication.