Hello! This Instructable is for a software only project that anyone with an Arduino UNO can perform. It is basically a modified capacitance meter sketch and is very useful to indicate the proper range of pull-up values that you can use in your I2C communication setup.
We made this as an answer to a common question that gets asked for paralleling I2C slave devices. In our case it was for a new high performance I2C laser distance sensor module we created called tinyLiDAR. For example you can make one Arduino UNO control many of these devices running in parallel for a single robot navigation setup as shown in the picture above.
Step 1: Theory
There are basically two ways to determine the I2C pull-ups: the DC approach and AC approach.
For the DC approach, you can simply calculate the minimum pull-up resistance value based on the I2C standard and your supply voltage level. But this approach also dissipates the maximum power in your design.
The AC approach yields the maximum practical pull-up resistance for which you can run your design properly at minimum power dissipation. To use this, you will need to measure the capacitance of your wiring and add to this the actual number of devices you will be using.
Most designers either stick to the DC only approach or use a guesstimate for what their system capacitance is. Hence they are always on the low side and therefore dissipate more power than necessary in the I2C bus.
This sketch will provide both values. As mentioned above, it was designed for tinyLiDAR but you can simply set "tinyLiDAR_capacitance" to zero or change it out for your particular I2C slave devices.
Let's run through some of the theory, starting with the simplest.
The DC Approach:
The I2C standard provides limits for thresholds and rise time.
For our application at 100KHz clock rate, the important limits are as follows:
IoL, LOW-level output current = 3mA min
VoL, LOW-level output voltage = 0.4V max.
The Arduino supply voltage, VDD = 5V nominal, so we get the following for net pull-up resistance Rp:
Rp= (VDD - VoL)/IoL
Rp = (5-0.4)/3mA
Rp = 1.53K
The AC Approach:
For this method, we need to minimize the rise time (Tr) of the signal based on actual bus loading. Refer to Figure 1 for terms. Rise time is affected by the net capacitive loading of the bus and the net resistance used for the pull-ups.
The I2C standard specifies the input voltage thresholds as ViL = 0.3VDD to ViH = 0.7VDD levels. It also specifies a maximum rise time, Tr = 1000ns for a 100KHz clock rate.
Generally, the voltage on a charging capacitor is defined as shown in green in Figure 1. Hence we need to ensure the rise time is below 1000ns while the voltage rises between the two input voltage thresholds for our capacitive bus loading.
Solving for the input voltage levels, we can see that it will take a time of 0.3567RC to charge up to ViL and 1.2040RC to charge to ViH. The difference is our required rise time of 0.8473RC.
Knowing this, we can find Rp = Tr/(0.8473*C).
Step 2: Sketch
Our sketch will measure C and automatically add the parasitic capacitance as required for the number of I2C modules you have connected. Just enter how many you are using and press enter to run the sketch. It displays the results on the Arduino IDE terminal at 115200 baud as shown in the screen shot above.
Note that the above methods provide the net pull-up resistance. Each tinyLiDAR has 0603/1608 size SMD pads for two pull-up resistors - one for SDA and one for SCL, hence the sketch provides a range of pull-up resistor values for these resistors to be placed on each and every board used in your setup.
Enjoy the sketch and please visit our Indiegogo campaign for tinyLiDAR soon if you like this kind of stuff. tinyLiDAR is basically a gereral purpose laser distance sensor board that simplifies access to the VL53L0X chip and gives better performance than a software only approach. We just started the campaign on July 14th and need everyone's help to bring tinyLiDAR to life.