raspi-config nonint do_i2c 1 hangs “forever”

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:

dtparam i2c_arm=off

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

image

in my case depending on the activity of the two apps (CO2 and BME688), the file could be open two times as well:

image

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)