While developing PiCockpit, and trying to allow the user to turn I2C off from the webinterface, I have run into crashes and problems.
I am using raspi-config in non-interactive mode (I’ve written about this before) to control I2C from the PiCockpit client.
While debugging the issue, I noted that – if something was busy accessing the I2C bus, the command (raspi-config) would freeze.
Investigating with ps aux, I noticed that another command had been started but did not finish to execute:
This is a compiled binary, no script. But it has a verbose mode.
running this manually, in verbose mode, while something else would be accessing the I2C bus:
17:32:55 root@Avalon:/home/pi # dtparam -v i2c_arm=off
DTOVERLAY[debug]: using platform ‘bcm2711’
DTOVERLAY[debug]: overlay map loaded
run_cmd: which dtoverlay-pre >/dev/null 2>&1 && dtoverlay-pre
run_cmd: dtc -I fs -O dtb -o ‘/tmp/.dtoverlays/base.dtb’ /proc/device-tree 1>/dev/null 2>&1
DTOVERLAY[debug]: loading file ‘/tmp/.dtoverlays/base.dtb’
DTOVERLAY[debug]: found override i2c_arm
DTOVERLAY[debug]: override i2c_arm: string target ‘status’
DTOVERLAY[debug]: wrote 166 bytes to ‘/tmp/.dtoverlays/69_dtparam.dtbo’
DTOVERLAY[debug]: wrote 179 bytes to ‘/sys/kernel/config/device-tree/overlays/69_dtparam/dtbo’
run_cmd: which dtoverlay-post >/dev/null 2>&1 && dtoverlay-post
would hang before the last command (highlighted in yellow).
Once the other application had released the I2C bus, dtparam would finish it’s job and show the last line.
How can you find out which applications are accessing the i2c bus?
Easily, with lsof:
sudo lsof /dev/i2c-1
lsof: WARNING: can’t stat() fuse.gvfsd-fuse file system /run/user/1000/gvfs
Output information may be incomplete.
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
python3 24772 root 13u CHR 89,1 0t0 285423 /dev/i2c-1
in my case depending on the activity of the two apps (CO2 and BME688), the file could be open two times as well:
My recommendation is, since there does not seem to be a workaround for dtparam hanging (and thus raspi-config hanging) when I2C is being accessed / open, to check the state of the file descriptors first, and show the user an error message if this is the case (that they will need to disable the applications first for this to work).
NB: for Python’s SMBus, you can simply use bus.close() (if you called your SMBus instance bus)