serial-bench / I²C / msg #5
A board with eleven I²C devices - sensors, an expander, a small display controller - behaved perfectly at 100 kHz. Moved to 400 kHz it read back a corrupted value from the farthest sensor on roughly two per cent of transfers. Nobody had touched the addresses or the driver.
I²C is the bus where I have made the most embarrassing mistakes, because its failures are analogue and its documentation is digital. There is no driver fighting you here. There is an RC circuit, and you either budgeted for it or you did not.
A falling edge on I²C is driven by a transistor and is fast. A rising edge is not driven at
all - the device releases the line and the pull-up resistor charges everything hanging off it.
That makes the rising edge an exponential with time constant R × C, where
C is every pin, every trace and every centimetre of ribbon on the segment.
Fast mode allows the signal 300 ns to get from 0.3 VDD to 0.7 VDD. Standard mode at 100 kHz allows 1 000 ns. That single difference is the whole reason a segment can be solid at one speed and marginal at the next one up.
You do not need to know the capacitance of each part. Put a resistor of known value on the
line, measure the 30 %–70 % rise time on the scope, and invert the exponential. Between those
two points the elapsed time is R × C × ln(0.7 / 0.3), and the logarithm is
0.847, so:
C = t_rise / (0.847 × R)
With the 1.8 kΩ resistors that were fitted, I measured 473 ns on SDA at the far device, averaged over sixteen rising edges. That gives 310 pF. Eleven devices and about 0.9 m of ribbon is entirely consistent with that figure, and I deliberately did not try to attribute it part by part - the total is the quantity the resistor sees, and the total is what I can measure.
473 ns against a 300 ns allowance. The segment had been out of specification since the day it was assembled; at 100 kHz the limit is 1 000 ns, so nothing complained.
Rearranged the other way, the requirement is R ≤ 300 ns / (0.847 × 310 pF),
which is 1 142 Ω. The cost of going lower is current: the device pulling the line down has to
sink VDD / R and still hold VOL under 0.4 V.
| Pull-up | trise 30–70 % | Fast-mode limit 300 ns | Sink current |
|---|---|---|---|
| 4.7 kΩ | 1 235 ns | 4.1× over | 0.70 mA |
| 2.2 kΩ | 578 ns | 1.9× over | 1.50 mA |
| 1.8 kΩ (as built) | 473 ns | 1.6× over | 1.83 mA |
| 1.0 kΩ | 263 ns | pass, 12 % margin | 3.30 mA |
| 680 Ω | 179 ns | pass, 40 % margin | 4.85 mA |
I fitted 1.0 kΩ. Every device on that segment is specified to sink 3 mA while holding VOL below 0.4 V, and after the change the lowest level I could find anywhere on the bus was 0.18 V, so the margin is real rather than nominal. I did not fit 680 Ω: the extra timing margin is pleasant, but 4.85 mA is above what two of these parts promise, and a bus that is out of specification in a different direction is not an improvement.
Two details that were not obvious to me at the start.
The failures concentrated at the physically most distant sensor because the pull-ups sit at one end of the ribbon. The device at the far end sees the same capacitance but also the series resistance of the copper, so its view of the rising edge is the slowest on the segment. The near parts were reading a line that had already crossed their input threshold.
And the corruption landed on the acknowledge bit of the last byte because that is where a rising edge has the least room. The ninth clock pulse has a minimum high time of 600 ns in fast mode; a 473 ns rising edge eats most of it, and the master samples SDA while the voltage is still climbing towards the 2.31 V input threshold. Sometimes it crossed in time. Two per cent of the time it did not, and an acknowledge was read as its opposite.
The number worth memorising is 0.847. One rise-time measurement and one known resistor give you the capacitance of a bus you did not design, in thirty seconds, with a scope you already own. Everything else on this page is division.