Raspberry Pi I2C Slave Read (clock stretching) Problem
Raspberry Pi I2C Slave Read (clock stretching) Problem
Note: If you have a second rev Raspberry Pi, the I2C is on port 1 not 0 as shown in this tutorial
Some slower I2C devices use a method called clock stretching to allow it to get ready to send the data back to the requesting master I2C device (i.e. the Raspberry Pi). Although the Raspberry Pi hardware can support this clock stretching feature, it seems that the current I2C drivers don't currently support it.
If the slave device can't respond fast enough, it seems that the Raspberry Pi sends an I2C Stop command. This is then received by the slave device which does as it is told and stops. So no data is received.
In the following image an I2C read command is sent to a slave at address 0x28. Zooming in to Image 2 shows what happens more clearly. The request is received by the slave, which acknowledges the command, but before it can send any data, a Stop command is received.
This is the command
i2cget -y 0 0x28 0x01 b
Image 1 - I2C Read request fails
Image 2 - I2C Read request failure (zoom into details showing Stop command)
How to fix it
Well, there is no real cure until the I2C drivers are updated to fully support clock stretching.
However, there is a hack that can be done to effectively slow down the clock speed for slow slave devices. This gives the device more time to send the data and avoid the Stop command being sent.
Details of this hack can be found and downloaded from the byvac website http://doc.byvac.com/index.php5?title=RPI_I2C
Unfortunately, the code as it stands didn't work for the device i was testing. The I2C bus needed slowing down a little bit more than the standard code. Fortunately this is easy to do. I modified the code to create two small programs, one slows the I2C bus down and one sets it back to normal.
i2c_slow |
Run this to slow down the I2C bus speed sudo ./i2c_slow |
i2c_fast |
Run this to set the I2C bus speed back to normal sudo ./i2c_fast |
These two programs can be downloaded in file rpi_i2c.zip. Download the zip file and extract the two programs. Copy these to the Raspberry Pi. We have included the byvac program in this download so you can modify the code if required.
You can download the zip file on your Raspberry Pi if it is connected to the internet.
wget http://www.hobbytronics.co.uk/download/rpi_i2c.zip
Extract the files using
unzip rpi_i2c.zip
Then make the files executable with
chmod +x i2c_fast i2c_slow
The image below shows the same data request at the slower I2C speed. This time data is received (0x67)
Our complete request is thus
sudo ./i2c_slow
i2cget -y 0 0x28 0x01 b
sudo ./i2c_fast