Setting I2C bus speed on a Raspberry Pi via Device Tree

This tutorial is based on my previous article where we installed pure Debian 9 with a recent mainline/vanilla Linux kernel, and so differs from what would be done on a Raspbian Distribution with a Raspbian kernel. In this article, we will set the I2C bus speed on a Raspberry Pi. Here is my previous article:

Device Trees

The I2C bus on the Broadcom BCM283x chips found on Raspberry Pi’s is well and directly supported by the mainline/vanilla Linux kernel. Since with the Raspberry Pi we’re dealing with a System on a Chip (SoC), and not a regular PC, the hardware is configured with so-called device trees, which is a low-level description of the chip hardware compiled from text into binary format.

The
rpi23-gen-image script mentioned in my previous tutorial installs the binary device tree into
/boot/firmware/bcm2836-rpi-2-b.dtb. The U-Boot bootloader can read this file and pass it to the Linux kernel which interprets it and enables all the mentioned features in it.

The clock frequency for the I2C bus is configured in this .dtb file, and the default is 100kHz. There is a tool which allows you to inspect the .dtb file, outputting regular text. With this tool you also can make changes to the device configuration. Nowadays, this is the proper way to configure low-level devices on SoC’s!

Read the device tree

Shell

1

2

apt-getinstall device-tree-compiler

fdtdump/boot/firmware/bcm2836-rpi-2-b.dtb

This will output the decoded device tree as text. Regarding I2C, you will find i2c@-entries like this:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

i2c@7e205000 {

compatible = "brcm,bcm2835-i2c";

reg = <0x7e205000 0x0000005c>;

interrupts = <0x00000002 0x000000e9>;

clocks = <0x00000008 0x00000022>;

#address-cells = <0x00000001>;

#size-cells = <0x00000000>;

status = "okay";

clock-frequency = <0x000186a0>;

};

i2c@7e804000 {

compatible = "brcm,bcm2835-i2c";

reg = <0x7e804000 0x0000005c>;

interrupts = <0x00000002 0x000000e9>;

clocks = <0x00000008 0x00000022>;

#address-cells = <0x00000001>;

#size-cells = <0x00000000>;

status = "okay";

clock-frequency = <0x000186a0>;

};

Change the device tree

The clock-frequency value is what we want to change. The value is a raw binary unsigned 32-bit int stored big-endian, unreadable for humans.

In my case, I wanted to set the I2C bus to the slowest frequency, to compensate for long cable lengths. I found that one of the lowest supported I2C clock frequencies is 4kHz. With
fdtput you can set the clock-frequency property for each i2c device (there are 3 on the RPi):