Why change clock speed

So why you would want to change speed of your I2C interface?

You might just need to probe your sensors more often.

You might also want to get around long standing I2C stretching bug, which caused that by default I2C stretching on rPi I2C controller is disabled.

What is I2C stretching? In short, it's a mechanism where slower device (in this case I2C slave), "stretches" the clock cycle by holding it down for longer (I2C is open-drain bus with pullups so any device can do that), and in that case other device is supposed to wait and probe data once the clock is back up. Some I2C devices rely on that behaviour if bus is too fast for them and not supporting it might cause those devices to read wrong. And slowing down clock is workaround for that

How to check clock speed?

Clock speed is read from /sys/class/i2c-adapter/i2c-*/of_node/clock-frequency, where i2c-* is one of the I2C buses device has.

You can get their names from (rPi3)

1# i2cdetect -l
2i2c-1	i2c       	bcm2835 I2C adapter             	I2C adapter
3i2c-2	i2c       	bcm2835 I2C adapter             	I2C adapter
4i2c-0	i2c       	bcm2835 I2C adapter             	I2C adapter

That is how it looks on rPi4:

1root@rpi4:~# i2cdetect -lrpi4:~# i2cdetect -l
2i2c-3	i2c       	bcm2835 (i2c@7e804000)          	I2C adapter
3i2c-1	i2c       	Broadcom STB :                  	I2C adapter
4i2c-2	i2c       	bcm2835 (i2c@7e205000)          	I2C adapter
5i2c-0	i2c       	Broadcom STB :                  	I2C adapter

SDA0/SCL0 appears to be bus i2c-3 so to check its current speed we run

1xxd /sys/class/i2c-adapter/i2c-3/of_node/clock-frequency
200000000: 0001 86a0                                ....

which gives us 0x0186a0 or 100 000 Hz in dec

i2c-0/1 appears to be video chip busses, so I'd advice leaving those alone

How to change clock speed?

Previous iterations of Raspberry Pi used a i2c-bcm2708 driver that could accept the speed parameter either via module parameters or dtparam in config.txt, like this:

1dtparam=i2c_arm=on
2dtparam=i2c1_baudrate=25000

This appears to not be the case on newer kernels on rPi4:

1root@rpi4:~# lsmod |grep i2c
2i2c_dev                24576  0
3i2c_bcm2835            20480  0
4root@rpi4:~# uname -a
5Linux rpi4 5.10.0-13-arm64 #1 SMP Debian 5.10.106-1 (2022-03-17) aarch64 GNU/Linux

Instead, you need to modify device tree. Device tree is configuration structure that tells Linux kernel what devices are present and how they should be set up.

First, we need to apt-get install device-tree-compiler. Then we can look at the device tree via fdtdump /boot/firmware/bcm2711-rpi-4-b.dtb.

To find entry that we're interested in, first we need to find right i2c interface. Let's say we're interested in changing i2c-3

Go into /sys/class/i2c-adapter/i2c-3 and look at symlinks:

1root@rpi4:~# ls -la /sys/class/i2c-adapter/i2c-3/of_node
2lrwxrwxrwx 1 root root 0 Apr 28 16:33 /sys/class/i2c-adapter/i2c-3/of_node -> ../../../../../firmware/devicetree/base/soc/i2c@7e804000

the /soc/i2c@7e804000 is the "magical" number we care about. We can then see whether we got the right guy:

1root@rpi4:~# fdtget /boot/firmware/bcm2711-rpi-4-b.dtb /soc/i2c@7e804000 clock-frequency
2100000

Then we change it

1root@rpi4:~# fdtput /boot/firmware/bcm2711-rpi-4-b.dtb /soc/i2c@7e804000 clock-frequency 10000
2root@rpi4:~# reboot

Changes will be applied after reboot

i2c-2 seems to be other bus, so try that one if your device doesn't see the change in speed. Historically that numbering has been a bit of a mess (from Adafruit page: "The Raspberry Pi designers swapped over I2C ports between board releases. Just remember: 512M Pi's use i2c port 1, 256M ones use i2c port 0!" ). So if something doesnt work try the other one

The busses that show up as "Broadcom STB" are between broadcom chips so I wouldn't touch settings on those.