Raspberry Pi: Nominal vs. Actual I2C Speeds

Two lines in /boot/config.txt enable the I2C hardware and set the I2C bus speed:


However, the actual SCL frequency comes from dividing the CPU’s core clock by an even integer, so you can’t always get what you want. The Pi 3 ticks along at 1.2 GHz (actually 1.1 GHz, because marketing) from a core clock of 550 MHz, so a 200 kHz clock calls for a 2750 divider: 550 MHz / 2750 = 200 kHz.

Actually measuring the SCL frequencies suggests something else is going on:

I2C 200kHz - actual 125kHz
I2C 200kHz – actual 125kHz

D0, the bottom trace, is SCL, D1 is SDA, and D2 is a trigger output not used in this setup. The yellow analog trace is the current in the SCL line between the Pi and the BNO055, about which more later.

So a 200 kHz nominal frequency produces a 125 kHz actual frequency.

The BNO055 pulls the clock low (“clock stretching”), which can (and does) cause problems, but it’s not active during the main part of the transfer where the Pi determines the SCL frequency.

More measurement along those lines produces a table:

CPU Core Clock: 550 MHz
Nominal Ratio Actual Ratio
250 2200 156.20 3521
200 2750 125.00 4400
150 3667 92.59 5940
125 4400 78.12 7040
100 5500 62.50 8800
50 11000 31.25 17600
25 22000 15.63 35189
10 55000 6.25 88000

Apparently, the code converting the nominal I2C rate in config.txt uses a table of divider values intended for another CPU core clock. AFAICT, the boot code could divide the actual core clock by the desired I2C frequency to produce the appropriate value.

I have no particular desire to Use The Source to figure out what’s going on …

[Update: Perhaps this comes along with CPU clock throttling due to temperature. For completeness, I should dump the temperature and actual clock speed.]

One thought on “Raspberry Pi: Nominal vs. Actual I2C Speeds

Comments are closed.