Stretching Time: The I2C Black Hole

For the Raspberry Pi to communicate reliably using I2C to the DI/ModRobotics Inertial Measurement Unit (IMU), which is Bosch BNO055 based, the Raspberry Pi must implement I2C clock stretching.

It has been reported that the Raspberry Pi does not implement the clock stretching fully, and indeed I found that trying to use the Raspberry Pi hardware I2C to communicate with either the DI/BNO055 IMU or the Ivensense MPU-9250 IMU will fail miserably.

Supposedly users can make it work by configuring a slower I2C clock speed as in https://learn.adafruit.com/circuitpython-on-raspberrypi-linux/i2c-clock-stretching

DI/ModRobotics has supplied interface code that automagically implements the clock stretching in software in di_I2c.py and extends the I2C bus onto the two configurable connectors AD1 and AD2. The DI IMU interface defaults to the AD1 connector.

There will still be some soft errors so users should use a try/except block to catch the errors and retry the operation. (If you see a zero temperature value when running the DI IMU example a soft error occurred.)

P.s. This concludes the full extent of my knowledge on this clock stretching issue.

1 Like

I wonder if the Pi-4 and/or its latest firmware have addressed this issue, since the Pi-4 includes significant hardware improvements in the SOC.

Do you have some kind of simple script that I could “plop in place” on Charlie and run against the IMU, (the picky sensor), from either of the interfaces, (both hardware and software i2c) so that I can try to verify your results? on the Pi-4 platform?

Something that I could plop in place, sudo the heck out of it, let it run for a while, and look at a log somewhere to see what, if anything, is happening?

I might be tempted to make a small modification that would cause Dex’s eyes to light different colors while the test is running to indicate the presence or absence of errors.

Thanks!

Sure:

HW and SW I2C Stress Suite (download tgz)

Suite consists of:

  • HWDistanceSensor.py - requests DI Distance Sensor I2C-mutex-protected reading roughly 10 times a second
  • SW_I2C_Stress_with_IMU.py - requests set of four DI IMU I2C-mutex-protected component readings roughly 10 times a second
  • test_HW_and_SW_I2C.sh - starts both test programs as background processes, with known log file names
  • monitor_HW_and_SW_logs.sh - tails both test logs with {uptime, processor temperature, and soft I2C error count} in a loop
  • Also SWDistanceSensor.py - tests Distance Sensor using SW I2C (This use to fail quickly - have not tried it lately.)
     

REQUIREMENTS:

  • GoPiGo3
  • DI Distance Sensor wired to IC1 or IC2 connector
  • DI Inertial Measurement Unit wired to AD1 connector

 

USAGE:

  1. ./test_HW_and_SW_I2C.sh

  2. ./monitor_HW_and_SW_logs.sh

  3. cntrl-c to stop monitor log loop

  4. ps -ef | grep -v grep | grep -E “SW_I2C_Stress_with_IMU|HWDistanceSensor”

Note the process numbers, then kill the listed python3 processes with"

  • kill <left_most_PID>"
  • kill <left_most_PID>"
     

NOTES:

  • SW I2C soft errors will be noted in the log and count displayed in the monitor script
  • SW I2C program issues four separate I2C-mutex-protected requests (mag, gyro, accel, euler) roughly 10 times per second
  • Log Files:
    • HW_I2C_during_SW_I2C_Stress.log logs every tenth distance reading
    • SW_I2C_Stress.log logs every tenth set of four component readings

 

RESULT

On my (unaspirated) Pi3B, the tests result:

  • 0.8 to 1.0 15 minute usage (4 = all four cores busy)
  • around 55 degC
  • approximately 10 HW and 10 (x4) SW I2C requests every 2-3 seconds
  • roughly 16 soft SW I2C errors in a combined 3.2 million HW and SW I2C readings
  • No fatal / hard I2C errors in 24/7 testing for 9 days with over 5 million combined I2C readings
     

Can also bring it down with:

curl https://github.com/slowrunner/Carl/raw/master/systests/I2C/testsuite.tgz

The suite is here:

1 Like