Back

I2C

Loading views...

I2C Protocol

Overview

I2C (Inter-Integrated Circuit) is a two-wire synchronous serial protocol invented by Philips. It supports multiple masters and multiple slaves on the same bus using 7-bit or 10-bit addressing. It is widely used for sensors, EEPROMs, RTCs, and display controllers in embedded systems.


1. Theory & Fundamentals

  • Problem solved: Connect multiple ICs with just 2 wires using addressing
  • Physical layer: Open-drain, requires pull-up resistors (typically 4.7kΩ)
  • Wires: SDA (data), SCL (clock)
  • Addressing: 7-bit (112 devices) or 10-bit (extended)
  • Speeds: Standard (100kHz), Fast (400kHz), Fast+ (1MHz), High-speed (3.4MHz)
  • Multi-master: Supported with arbitration

2. Frame / Packet Structure

START  ADDR(7-bit)  R/W  ACK  DATA(8-bit)  ACK  ...  STOP
  S    A6..A0       0/1   A   D7..D0        A         P
  • START: SDA falls while SCL is HIGH
  • STOP: SDA rises while SCL is HIGH
  • ACK: Receiver pulls SDA LOW on 9th clock
  • NACK: Receiver releases SDA (HIGH) — signals error or end

3. Protocol Mechanics

  • Clock stretching: Slave can hold SCL LOW to pause master
  • Arbitration: Multi-master — if two masters drive simultaneously, loser detects conflict and backs off
  • Repeated START: Change direction without releasing bus
  • ACK polling: Used with EEPROM write cycle completion check

4. Hardware Implementation

  • Pull-up resistors: 4.7kΩ for 100kHz, 2.2kΩ for 400kHz, 1kΩ for 1MHz
  • Level shifting: PCA9306 for mixed 3.3V/5V systems
  • Bus capacitance: Max 400pF limits cable length (~1–2m)
  • Common I2C ICs: 24LC256 (EEPROM), DS3231 (RTC), BMP280 (pressure), SSD1306 (OLED)
  • I2C mux: PCA9548A for multiple identical-address devices

5. Register-Level Programming (STM32)

// Init I2C1 at 100kHz, 8MHz APB1 clock
I2C1->CR2 = 8;         // APB1 freq in MHz
I2C1->CCR = 40;        // 100kHz: CCR = fAPB/(2*fSCL) = 8M/(2*100k)
I2C1->TRISE = 9;       // Max rise time: (1000ns / 125ns) + 1
I2C1->CR1 |= I2C_CR1_PE; // Enable I2C

// Write byte to slave
void I2C_Write(uint8_t addr, uint8_t reg, uint8_t data) {
    I2C1->CR1 |= I2C_CR1_START;
    while (!(I2C1->SR1 & I2C_SR1_SB));
    I2C1->DR = addr << 1;           // Write mode
    while (!(I2C1->SR1 & I2C_SR1_ADDR));
    (void)I2C1->SR2;                // Clear ADDR
    I2C1->DR = reg;
    while (!(I2C1->SR1 & I2C_SR1_TXE));
    I2C1->DR = data;
    while (!(I2C1->SR1 & I2C_SR1_BTF));
    I2C1->CR1 |= I2C_CR1_STOP;
}

6. Driver Development

uint8_t I2C_ReadReg(uint8_t addr, uint8_t reg) {
    // Write register address
    I2C_Start(); I2C_SendAddr(addr, WRITE); I2C_SendByte(reg);
    // Repeated START then read
    I2C_RepeatedStart(); I2C_SendAddr(addr, READ);
    uint8_t data = I2C_ReadByte(NACK);
    I2C_Stop();
    return data;
}

void I2C_ReadBurst(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len) {
    I2C_Start(); I2C_SendAddr(addr, WRITE); I2C_SendByte(reg);
    I2C_RepeatedStart(); I2C_SendAddr(addr, READ);
    for (int i = 0; i < len - 1; i++) buf[i] = I2C_ReadByte(ACK);
    buf[len-1] = I2C_ReadByte(NACK);
    I2C_Stop();
}

7. Debugging & Testing

  • Logic analyzer: Decode with correct I2C protocol, check address
  • Common issues:

- Missing pull-ups → no signal

- Wrong pull-up value → slow edges or bus lockup

- Address conflict → unexpected NACKs

- Clock stretching ignored → data corruption

- Bus lockup → SDA stuck LOW (clock 9 pulses to recover)

  • I2C scanner: Probe all 128 addresses to discover devices

8. Real-World Applications

  1. BMP280: Read temperature and pressure via I2C
  2. SSD1306 OLED: Send pixel commands over I2C
  3. DS3231 RTC: Read/write time registers
  4. 24LC256 EEPROM: Store configuration data with ACK polling
  5. MPU-6050 IMU: Stream 6-axis data via I2C with interrupt

9. Advanced Topics & Edge Cases

  • 10-bit addressing: Extended addressing for larger systems
  • SMBus: I2C superset with defined timeouts and protocols
  • I2C multiplexer: PCA9548A — expand to 8 sub-buses
  • Software I2C: Bit-bang on any GPIO when hardware I2C unavailable
  • I2C over long distance: Use active buffers (P82B96)
  • ACK polling for EEPROM: Retry after write until device responds

10. Standards & Variants

Mode Speed Use case
Standard 100kHz Sensors, EEPROMs
Fast 400kHz Most modern sensors
Fast+ 1MHz High-speed sensors
High-speed 3.4MHz Display drivers
Ultra-fast 5MHz Unidirectional only

💡 Practical Examples

Example 1: I2C Scanner

for (uint8_t addr = 1; addr < 127; addr++) {
    if (I2C_Probe(addr) == ACK)
        printf("Device at 0x%02X\n", addr);
}

Example 2: Read BMP280 temperature

uint8_t msb = I2C_ReadReg(0x76, 0xFA);
uint8_t lsb = I2C_ReadReg(0x76, 0xFB);
int32_t raw = (msb << 12) | (lsb << 4);
// Apply compensation formula...

Example 3: Bus recovery (stuck SDA)

void I2C_BusRecover(void) {
    // Clock 9 times to release any stuck slave
    for (int i = 0; i < 9; i++) {
        SCL_HIGH(); delay_us(5);
        SCL_LOW();  delay_us(5);
    }
    I2C_Stop(); // Generate STOP condition
}

🧪 Practice Questions

Beginner

  1. Why does I2C need pull-up resistors?
  2. What is the purpose of the ACK bit?
  3. How many devices can share one I2C bus?
  4. What is a repeated START condition used for?
  5. What is the difference between 7-bit and 10-bit addressing?

Intermediate

  1. How do you calculate the correct pull-up resistor value for 400kHz I2C?
  2. What causes I2C bus lockup and how do you recover?
  3. Write a burst read function for reading 6 bytes from MPU-6050.
  4. How does I2C multi-master arbitration work?
  5. Explain clock stretching and when a slave uses it.

Advanced

  1. Implement a complete EEPROM driver with page write and ACK polling.
  2. How would you use a PCA9548A to talk to 8 sensors with the same address?
  3. Design a software I2C implementation on bit-bang GPIO.
  4. What limits I2C bus speed and how do you push to 1MHz (Fast+)?
  5. How would you debug intermittent I2C NACKs in a noisy industrial environment?

Hands-on Projects

  1. Environmental Monitor: Read temp/humidity (SHT31) and pressure (BMP280) over I2C, display on SSD1306 OLED.
  2. I2C EEPROM Logger: Store timestamped data in 24LC256 with wear leveling.
  3. Multi-sensor Hub: Use PCA9548A to read 8 identical sensors on one bus.

Checklist

  • [ ] Draw I2C START, data, ACK, and STOP waveforms
  • [ ] Calculate pull-up resistor values for different speeds
  • [ ] Write bare-metal I2C master driver
  • [ ] Implement I2C scanner
  • [ ] Read multi-byte sensor data with burst read
  • [ ] Handle NACK and implement retries
  • [ ] Implement I2C bus recovery sequence
  • [ ] Use I2C with EEPROM including ACK polling
  • [ ] Debug I2C with logic analyzer
  • [ ] Implement software (bit-bang) I2C
  • [ ] Use I2C multiplexer (PCA9548A)
  • [ ] Configure I2C DMA for high-throughput sensors