Since the underlying issue with I2C clock stretching on a Raspberry Pi is the hardware I2C peripheral, another option is to simply not use it. Instead, use a software based implementation. On a Raspberry Pi, this is available via the i2c-gpio device tree overlay.
There is a little more work to be done with this approach. An additional library must be installed and some minor code changes need to be done to user code.
The same information is also likely on the Pi itself under /boot/overlays/README
. This is a large README that covers all of the overlays. Search for "i2c-gpio" to find the entry for the software I2C overlay. It should look like this:
This describes the general syntax used to enable the overlay (the Load: line) as well as the four parameters that can be used to customize the resulting behavior.
Enabling the i2c-gpio Overlay
To enable the i2c-gpio overlay, the /boot/config.txt
is updated to add a line that enables it and optionally configures settings.
To use the defaults settings, the line can simply be:
dtoverlay=i2c-gpio
To specify specific pins, for example 16
and 20
, use:
dtoverlay=i2c-gpio,i2c_gpio_sda=16,i2c_gpio_scl=20
After rebooting, the resulting I2C interface will show up as a /dev/i2c* entry. A number will automatically be assigned at boot time. To specify a specific bus number, for example 8
, use:
dtoverlay=i2c-gpio,bus=8
The parameters can be combined as needed. For example, to specify specific pins and a fixed bus number, use:
dtoverlay=i2c-gpio,i2c_gpio_sda=16,i2c_gpio_scl=20,bus=8
Finding the I2C Port
After editing /boot/config.txt
to add the i2c-gpio overlay, and rebooting, run the following command:
ls /dev/i2c*
This will list all of the I2C buses created. Here is example output using the configuration from the previous section:
[email protected]:~ $ ls /dev/i2c* /dev/i2c-1 /dev/i2c-20 /dev/i2c-21 /dev/i2c-8
There are several entries shown. The /dev/i2c-8
entry is the one created via the i2c-gpio overlay. The number 8
is a result of using the bus=8
parameter.
Extended Bus Library
This is the first bit of extra work that needs to be done to allow using the i2c-gpio overlay. The main Blinka installation works with known specific hardware I2C ports and pins. It's not aware of any additional I2C ports that may be setup using the i2c-gpio overlay. To access these, the following library is needed:
It can be installed like any other Python/CircuitPython library using pip:
pip3 install adafruit-extended-bus
Update Code
The next bit of work needed is to modify code to use the Python Extended Bus library to access the software I2C port. The changes are limited to the initial setup part of the code. Once the I2C port has been created in code, it can be used in the same manner as the typical hardware I2C port.
Here is a brief summary of the two main lines needed:
# import the library from adafruit_extended_bus import ExtendedI2C as I2C # access the I2C port by bus number i2c=I2C(8)
The library is imported and then the I2C bus is created. It is referenced using the bus number, 8
in this example. This number may be different for different setups and should be changed as needed. See previous section for details.
Now the i2c
instance can be used in the same manner as the regular hardware i2c instance seen in most example code.