I2C is a popular communication protocol in embedded systems. When interfacing with the slave device a pull-up resistor is needed on each bi-directional line. One common question that arises is "what size pull-up resistor should I use?". Instead of going through a bunch of theory and calculations I thought it would be easier to show what happens to the signals when different resistor values are used.
Since the Arduino is a popular micro-controller among hobbyists we'll use it for the following examples. We'll interface the Arduino to a DS3231 Real Time Clock, which is a 5 volt device. We'll also look at the effects on the signal with varying speeds of I2C (100 and 400kHz clock signals).
We'll set up our oscilloscope to measure rise time, frequency and peak voltage. Frequency? Why do we want to measure frequency, I thought the clock frequency was running at 100kHz...well let's just see what the scope says. Since the capacitance is roughly the same for the SDA (data) and SCL (clock) lines we'll only vary the resistance on the SCL line and keep a standard 4.7k ohm resistor on the SDA line. It's just easier to analyze a repetitive clock signal on the oscilloscope than a data pattern.
Let's take an initial reading using just the Arduino's internal pull-up resistors. As you can see in Figure 1 the clock signal has a very long rise and only reaches a maximum voltage of 3.76 volts before falling back to zero. While the circuit does function I wouldn't want to rely on it outside the lab. As you can see the frequency measured is closer to 87kHz due to the slow rise time. The circuit still works but if your application is time sensitive it's not generally a good idea to use the internal pull-up resistors. Anyway let's disable the Arduino's internal pull-up resistors and install our own pull-ups and see how they affect the signal. We'll start with a 68k ohm resistor followed by 47k, 33k, 10k, 6.8k,4.7k, 3.3k, 2.2k and finally 1.5k. As you can see in Figure 2, the signal eventually takes on a square shape which is what we like to see. Notice how the measured frequency approaches our desired clock frequency between 33k and 10k ohms. You can also see how the rise time decreases as our resistance decreases. As you can see, 4.7k yields a good looking signal with a rise time around 1 microsecond . You'll find that 4.7k is a pretty common resistance used in a lot of single slave setups. Of course as you add more and more devices to the lines the bus capacitance will increase and that means you'll have to start decreasing your resistance (t = RC) if you want to maintain your signal integrity. Each design will be unique and the capacitance referenced in the datasheet is not guaranteed so it's always good practice to look at the signals on an oscilloscope. So why not just use a very low resistor to start off with, shouldn't that reduce the rise time to give us the squarest signal possible? Well yes and no. The I2C standard sets some limits that need to be followed, luckily these limits help us narrow the range of resistance values. A simple formula for calculating the smallest pull-up resistor is Rp = (Vcc - 0.4)/3mA, which for a 5V system comes out to be about 1.5k ohms. The formula for calculating the largest resistor is actually based off a maximum rise time for standard mode (100kHz) which is 1 microsecond and that formula is Rp = 1us/Cb, where Cb is the total bus capacitance for one signal line. So for our example the total bus capacitance would be about 20pF (Arduino is 10pF, per the datasheet, and the DS3231 is also 10pF per the datasheet), which yields a high side value of 50k ohms. Obviously adding more DS3231 RTC's to the line will change the largest allowable resistor that we should use (1 more drops it down to 33.3k, another one drops it to 25k, etc...). It's important to note that each I2C device will have it's own capacitance so always look at the datasheet so you know what that value is.
Next, we'll use the same circuit, but this time let's switch from Standard mode to Fast mode (400kHz). As you can see is Figure 3 the rise time is very slow with respect to the clock frequency. The frequency of the clock is measured at around 171kHz, which is significantly slower than the desired 400kHz. Also notice how the peak voltage only reaches 3.28V before switching to the second half of the duty cycle. We're going to repeat the same test from above using the same resistors. Before we begin let's take a look at the calculations for determining upper and lower pull-up resistor values. The calculation for the lowest value pull-up resistor is the same as above, yielding 1.5k on the low side, however the maximum rise time for Fast mode is reduced from 1 microsecond to 300 nanoseconds. As you can see, using the formula and substituting the maximum bus capacitance of 400pF results in an upper limit resistance of 750 ohms which is actually lower than the lowest value resistor from the first calculation. For this reason the maximum recommended bus capacitance is dropped down to about 200pF with a 5 volt system. So make sure you keep close watch on the total bus capacitance as you're building your circuit. So lets install the resistors and see how they affect the signal quality (Figure 4). Notice how the measured clock frequency doesn't approach 400kHz until we transition from 6.8k to 4.7k ohms. You can also see how the signal takes on a good shape once we transition from 2.2k to 1.5k ohms.