I'm using a Raspberry Pi 4B to read pressure sensors via I2C, with Python 3.7.3 and the SMBus library. I ran into the Broadcom clock-stretching bug, so I switched to software-based I2C (brief description here: https://github.com/fivdi/i2c-bus/blob/master/doc/raspberry-pi-software-i2c.md). This helped me significantly; the reads on hardware-based I2C were highly oscillatory and unreliable.
Unfortunately, it introduced a new problem: the clock speed. The sensors only support a max of 100 kHz, and the Pi is running at ~140 kHz, as measured on a scope. The problem presents as the bus getting stuck intermittently, with the clock and data lines getting pulled low and unable to bounce back to high until the sensor is physically disconnected from the Pi. I think the stuck bus is due to the clock speed being too fast (the sensors work very well with NI LabVIEW, which uses a clock speed of 100 kHz), so that's what I'm trying to address.
I don't think software I2C clock speed is controlled in the same way as hardware, but I tried several settings nonetheless. The main things I tried:
- Adding
dtparam=i2c_arm=on,i2c_arm_baudrate=100000
in config.txt sudo modprobe i2c_bcm2708 baudrate=100000
- Creating a .conf file in /etc/modprobe.d/ with the content
options i2c_bcm2708 baudrate=100000
- Editing
/etc/modules
to contain:i2c-bcm2708 baudrate=400000 i2c-dev
None of these had any effect on the clock speed. Is there a special way to control the clock speed for software-based I2C?
In case it's helpful, I also looked at vcgencmd measure_clock arm
while the Pi is at rest, is reading sensors successfully, and has the stuck bus. These are different values than the scope readings for clock frequency, so I'm not quite sure how to interpret them, but they certainly show a difference:
- Idling: ~600,000,000
- Successfully reading: ~700,000,000-800,000,000
- Stuck bus: ~1,500,000,000
If I can't fix the clock speed, some other ideas I've had which I've briefly looked into are:
- Try using the GPCLK functionality of one of the other GPIO pins--although figuring out how to set those pins to be clocks, let alone editing their specific frequency, seems to be quite challenging
- Look into headers for converting SPI to I2C, and use SPI functionality on the Pi
- Switch from Pi to an alternative platform
I'd welcome other options to investigate as well.
-
Are you sure that the RPi 4b still has the clock stretching hardware bug? I don't think so.vanthome– vanthome2024年03月30日 20:46:26 +00:00Commented Mar 30, 2024 at 20:46
1 Answer 1
The software I2C bus settings are documented in /boot/overlays/README
.
Name: i2c-gpio
Info: Adds support for software i2c controller on gpio pins
Load: dtoverlay=i2c-gpio,<param>=<val>
Params: i2c_gpio_sda GPIO used for I2C data (default "23")
i2c_gpio_scl GPIO used for I2C clock (default "24")
i2c_gpio_delay_us Clock delay in microseconds
(default "2" = ~100kHz)
bus Set to a unique, non-zero value if wanting
multiple i2c-gpio busses. If set, will be used
as the preferred bus number (/dev/i2c-<n>). If
not set, the default value is 0, but the bus
number will be dynamically assigned - probably
3.
I suggest you try with an i2c_gpio_delay_us
of 3.
-
1Thank you so much! This has solved my problem. My delays vs clock speed were: 3 us --> 105 kHz, 4 us --> 85 kHz, 5 us --> 75 kHz. This is exactly what I needed, thanks!curiousInCali– curiousInCali2022年01月05日 17:27:45 +00:00Commented Jan 5, 2022 at 17:27