I2C clock stretching timeout on the Raspberry PI

Clock stretch timeout register – CLKT

The TOUT field from CLKT register provides a timeout on how long the master waits for the slave to stretch the clock before deciding that the slave has hung,  the default value for TOUT is 0x40(64 decimal), this is from BCM2835-ARM-Peripherals doc.

TOUT field is 16 bit long.

Calculating timeout for the default baudrate(100kbps):

timeout = TOUT * 1/baudrate = 64 * 0.01ms = 0,64ms

During normal operation this clock stretch timeout can be too small, for example when the I2C-HAT is requested to save a parameter in on-board flash, like DigitalOutputs Safety Value, PowerOn Value or the Communication Watchdog Period Value, the flash saving operation may imply a mass erase operation which has the longest duration of the flash operations, about 40ms on STM32 micro present on the I2C-HAT, this is why the default clock stretch timeout value of 0,64ms is too small.

Clock stretching is also heavily used during I2C-HAT firmware update, also implying mass erase.

An appropriate value for the clock stretching timeout should be 200ms, it’s selected to be 5 times greater than 40ms, just for safety.

TOUT = 200ms / 0.01ms =  20000(0x4E20), for the default baudrate of 100kbps

Some C code

The next two pieces of C code are used to set/get the clock stretching timeout value on the Raspberry PI

Open a terminal on Raspberry Pi, go to the desired folder and download the two files:

Compile and link source file into executable

Run first the get to see the value of your CLKT.TOUT, should be 64.

To set the 200ms desired clock stretching timeout run the following command:

This value will be used until next time Raspberry PI boots.

Set desired clock stretching timeout at boot

You probably want to automatically set the clock stretching timeout every time Raspberry PI boots. To do this you must edit your /etc/rc.local. More on runnig a script on startup you can find here 

I’m using nano for editing the file.

Add the following line just before “exit 0”:

/home/pi/workspace/i2c1_set_clkt_tout 20000

You should modify /home/pi/workspace/ path to point where you’ve build the executable with gcc.

Don’t forget to save the file using “Ctrl + O” than “Enter”. Exit nano with “Ctrl + X”

Reboot and use the get to make sure that the value for CLKT.TOUT is 20000

Not so elegant

Of course there are multiple ways to set the CLKT.TOUT value, some more elegant than others. A device tree overlay to set the timeout value would be the way to do it, the I2C driver may have to be modified, I’m not sure, I have little experience with device tree and drivers.

Leave a Reply

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