Adventures in I2C: clock stretching on the Raspberry Pi

This is a bit complicated, technically, but I’ve been asked to document the issue just in case someone comes across it.

I was getting I2C read errors when using the new TE AmbiMate MS4 sensor board (review coming soon!) with the Raspberry Pi 4. I contacted TE about it and they asked me to try a Pi 3. So I did, and it worked absolutely fine.

It was an intermittent issue on the Pi 4 (everyone’s favourite sort of error!), and so I did some research and found some information on something called ‘clock stretching‘.

This apparently affects the Raspberry Pi and was documented in a lot of detail, back in 2013 by someone at Advamation. Here is that post.

Although I found evidence on the Raspberry Pi forums that it had been fixed on the Pi 4, this is apparently not the case as it was a Pi 4 I was getting the problem on.

I tried a good old-fashioned apt-get update and upgrade and tried it again. No joy.

I was pointed at this GitHub issue which implied that the problem still exists. It suggested adding a line to /boot/config.txt

dtoverlay=i2c-bcm2708

which forces the Pi to use the old I2C driver. This failed to work, in fact it made the problem worse because suddenly it wouldn’t read anything from the sensor. I reversed this.

I tried an rpi-update to get the latest firmware, just in case a fix had been implemented on a newer version. This again failed to work.

Eventually, after some searching around (good ol’ Google!) I came across this issue on GitHub which suggested that the problem was the speed at which I was trying to read the I2C bus. So, I added a config option to /boot/config.txt as follows to reduce the read speed from 100000 baud to 10000 baud:

dtparam=i2c_baudrate=10000

Miraculously, this worked and I received stable readings from all the sensors on the AmbiMate without the errors occurring.

I came across an alternative solution (which I haven’t tried). Apparently, the bug only affects hardware clock stretching. However, it is possible to use an alternate set of pins for I2C and use software clock stretching. This is documented on GitHub here. Here is the relevant bit:

Raspbian has a software I2C driver that can be enabled by adding the following line to /boot/config.txt:

dtoverlay=i2c-gpio,bus=3

This will create an I2C bus called /dev/i2c-3. SDA will be on GPIO23 and SCL will be on GPIO24 which are pins 16 and 18 on the GPIO header respectively.

I hope this is of some use to someone!

3 comments for “Adventures in I2C: clock stretching on the Raspberry Pi

  1. GeekyTim
    4 January 2020 at 9:43 pm

    Nice find!

  2. Richard Newsham
    14 January 2020 at 9:39 am

    Hi Michael
    Firstly thank you for your interesting posts.
    This was a while ago. It was the standard software, Raspbian, but what version I can’t remember.
    I had this issue when I tried talking with a Pi Zero to an Arduino over I2C. Why wouldn’t you use these too lovely products together. I was having major problems with intermittent comms errors. I looked into it and found it to be a clock stretching issue. I believe, I am no expert, that the Raspberry Pi, or part of what it uses, is at fault in that it doesn’t comply with the I2C specification. The Arduino used clock stretching.
    You have mentioned a fix “reduce the read speed from 100000 baud to 10000 baud” but could that be fully used in an industrial application guaranteeing no issue. For a maker it is perhaps okay. The fault with the Raspberry Pi has to be fixed ultimately!
    I decided that I could not rely on it so changed to good old tried and trusted Serial communication. It did put a downer on things.
    It worries me though when I see RPi interfacing with anything that utilizes I2C clock stretching. Have they put a temporary fix in that only might be 99% reliable. Some device don’t use clock stretching and I think their okay.
    I am no expert so please take my comments with a pinch of salt.
    regards
    Richard

  3. Shoe
    6 March 2020 at 1:55 pm

    I hit a similar issue once with devices which either clock stretch or otherwise take time before responding to a read request, causing SMBus to timeout. While rooting around for solutions I came across a library (linked below) which accesses the i2c bus as a Linux file descriptor instead of using the SMBus module. This approach pokes the i2c bus and then skips through the inevitable exception and continues working.

    I’ve no idea what the pros and cons of each approach are, but I didn’t know that you could do software i2c. I’ll have to give that a try. are there any indications of the reliability/speed of the software method vs the hardware?

    https://github.com/Gozem/am2320

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.