Fundamentals 13 min read

Why I2C Needs Pull‑Up Resistors and How to Choose the Right Value

This article explains the open‑drain nature of I2C, why pull‑up resistors are essential for providing a high level, ensuring signal integrity and enabling wired‑AND logic, and offers practical formulas, recommended resistor ranges for different speeds, STM32 configuration examples, and debugging tips.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Why I2C Needs Pull‑Up Resistors and How to Choose the Right Value

1. I2C Bus Working Principle

I2C is a half‑duplex, synchronous serial protocol that uses only two wires—SCL (clock) generated by the master and SDA (data) for bidirectional data transfer.

SCL : Clock line driven by the master.

SDA : Data line for transmitting bits.

1.1 Open‑Drain Output Characteristics

I2C devices use open‑drain (or open‑collector) outputs, meaning each GPIO pin contains only an NMOS transistor that can either pull the line low or remain in a high‑impedance state; it cannot actively drive a high level.

1.2 Why Use Open‑Drain?

Open‑drain prevents a short circuit when multiple masters try to drive the bus simultaneously: if one master pulls the line low while another tries to drive it high, the line is simply pulled low without damaging the drivers. This "wired‑AND" behavior enables multi‑master communication and clock stretching.

2. Role of Pull‑Up Resistors

Because open‑drain outputs cannot drive high, external pull‑up resistors connected to VCC pull the bus high when no device is pulling it low.

2.1 Providing a High Level

When all devices are in high‑impedance, the pull‑up resistor raises the bus to VCC, representing logical "1".

Device pulls low → bus is low (0).

No device pulls low → pull‑up raises bus to high (1).

2.2 Ensuring Signal Integrity

The resistor creates a defined charging path for the bus capacitance, allowing fast, stable transitions and preventing the line from floating.

2.3 Enabling Wired‑AND Functionality

Any device pulling low forces the bus low.

Only when all devices release the line does the pull‑up make it high.

This property supports clock stretching and arbitration in multi‑master setups.

3. Selecting Pull‑Up Resistor Values

The value must balance rise time, power consumption, and driver capability.

3.1 Problems with Too Large a Value

Slow charging → sluggish rising edges, limiting communication speed or causing failures.

Weak drive → poor noise immunity.

3.2 Problems with Too Small a Value

Higher static power when devices pull low.

Increased driver stress, possibly exceeding the chip's sink capability.

3.3 Calculation Formula

The RC time constant determines the maximum allowable resistor:

where tr is the allowed rise time and Cbus is the total bus capacitance.

Example: for a 100 pF bus at 400 kbps (Fast mode) with a 300 ns rise‑time limit, the resistor should be less than about 3.5 kΩ.

3.4 Common Recommended Values

Standard mode (100 kbps) : 4.7 kΩ–10 kΩ for short bus, 2.2 kΩ–4.7 kΩ for longer bus.

Fast mode (400 kbps) : 2.2 kΩ–4.7 kΩ for short bus, 1 kΩ–2.2 kΩ for longer bus.

Fast‑plus (1 Mbps) : typically around 1 kΩ.

In practice, 4.7 kΩ is the most commonly used value and works well for many designs.

4. STM32 I2C Configuration Example

Below is a HAL‑based STM32 code snippet that configures I2C1 in fast mode (400 kbps) with external pull‑ups.

I2C_HandleTypeDef hi2c1;

void MX_I2C1_Init(void)
{
    hi2c1.Instance = I2C1;
    hi2c1.Init.ClockSpeed = 400000;  // 400 kbps Fast mode
    hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
    hi2c1.Init.OwnAddress1 = 0;
    hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c1.Init.OwnAddress2 = 0;
    hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    if (HAL_I2C_Init(&hi2c1) != HAL_OK)
    {
        Error_Handler();
    }
}

void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    if (i2cHandle->Instance==I2C1)
    {
        __HAL_RCC_GPIOB_CLK_ENABLE();
        __HAL_RCC_I2C1_CLK_ENABLE();
        // PB6: I2C1_SCL, PB7: I2C1_SDA
        GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;   // Open‑drain
        GPIO_InitStruct.Pull = GPIO_NOPULL;      // No internal pull‑up
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    }
}

uint8_t I2C_ReadByte(uint8_t DevAddress, uint8_t RegAddress)
{
    uint8_t data;
    // Write register address
    HAL_I2C_Master_Transmit(&hi2c1, DevAddress, &RegAddress, 1, 100);
    // Read data
    HAL_I2C_Master_Receive(&hi2c1, DevAddress, &data, 1, 100);
    return data;
}

Key points: GPIO_MODE_AF_OD: configures open‑drain mode. GPIO_NOPULL: disables internal pull‑ups because external resistors are used.

External pull‑up resistors (typically 4.7 kΩ) must be placed on both SCL and SDA lines.

5. Practical Debugging Experience

5.1 Common Issues and Checks

Forgot to add pull‑up resistors.

Pull‑up value too large.

Excessive bus capacitance.

Solution: Observe SCL/SDA with an oscilloscope and verify rise time.

5.2 Oscilloscope Observation Points

Rise time : must meet protocol limits (Standard < 1000 ns, Fast < 300 ns).

Level amplitude : high ≈ VCC, low ≈ GND.

Signal integrity : clean waveform without ringing or overshoot.

If rise time is too slow, the pull‑up is likely too large or bus capacitance too high; ringing indicates impedance mismatch or interference.

6. Summary

Pull‑up resistors provide the high level required for I2C logic.

They improve signal quality and ensure reliable communication.

They enable the wired‑AND behavior that supports multi‑master operation and clock stretching.

Choosing the resistor value involves balancing communication speed, bus capacitance, and power consumption. A 4.7 kΩ resistor works well for most applications, but designers should verify rise times with an oscilloscope and adjust as needed.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

embedded systemshardware designSTM32I2Cbus communicationpull-up resistor
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.