https://www.raspberrypi.org/documentation/hardware/raspberrypi/peripheral_addresses.md https://github.com/raspberrypi/linux/commit/dcaaa86b92be6f8341326b6039084bf4efdb92f4
Introduction
Clock stretching is a mechanism used by the slave (any I2C sensor device) to make the I2C master (Raspberry Pi) wait for it to complete some time lenthy operations, this wait time may vary from a few tens of microseconds to a few hundred of miliseconds. Clock stretching is acheieved when the addressed slave device holds down the clock line (SCL) after receiving/sending a byte, this indicates that the slave device is not yet ready to process any more data, the master must wait until the slave releases the clock line (SCL) and the clock line (SCL) actually goes high. The clock stretch timeout is the maximum amount of time that the master can wait for the addressed slave that clock stretches the clock line (SCL), to finish it’s operations.
Clock stretch timeout register – CLKT
The TOUT
field from CLKT
register provides a timeout on how long the master(Raspberry Pi) waits for the slave(an I2C sensor device) to stretch the clock before deciding that the slave has hung, the default value for TOUT
is 0x40(64 decimal), it is 16 bit long, this is from BCM2835-ARM-Peripherals doc, BCM2711-ARM-Peripherals doc.
Calculating timeout for the default baudrate(100kbps) with the default TOUT
value:
timeout = TOUT
1/baudrate = 64 0.01ms = 0,64ms
This clock stretch timeout can be too small, for example when the I2C-HAT is requested to save a parameter in it’s 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
Starting with Buster(Raspberry Pi OS) the TOUT
is loaded with a vlaue of 3500 at boot, this corresponds to 35ms of clock stretch timeout.
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:
wget https://raw.githubusercontent.com/raspihats/raspihats/master/clk_stretch/i2c1_set_clkt_tout.c
wget https://raw.githubusercontent.com/raspihats/raspihats/master/clk_stretch/i2c1_get_clkt_tout.c
Compile and link source files into executables:
gcc -o i2c1_set_clkt_tout i2c1_set_clkt_tout.c
gcc -o i2c1_get_clkt_tout i2c1_get_clkt_tout.c
Run the getter first, to see the value of your CLKT.TOUT
, should be 64(default value):
sudo ./i2c1_get_clkt_tout
To set the 200ms desired clock stretching timeout run the following command:
sudo ./i2c1_set_clkt_tout 20000
This value will be used until next time Raspberry Pi boots.
Set 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 rc.local file.
sudo nano /etc/rc.local
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” and reboot.
sudo reboot
After reboot you should use the getter to check that the value for CLKT.TOUT is 20000
sudo ./i2c1_get_clkt_tout