radxa / kernel

BSP kernel source
Other
153 stars 179 forks source link

Rock Pi S: Two simultaneous accesses to the same i2c device breaks the bus #292

Open BigMuscle85 opened 8 months ago

BigMuscle85 commented 8 months ago

I came into weird issue. We have Rock Pi S (kernel 6.1.68-1-stable, image buitl with rbuild) and connected SHT31 temperature/humidity sensor to I2C1 (address 0x44). It works correctly when reading with our C++ application. But when we (e.g. accidentally) run the application twice, I2C bus gets completely broken. Then it is not possible to access I2C bus anymore, neither after restarting the application, neither after "sudo reboot". We must completely disconnect the power from the board to make it work again.

When this happens, kernel log starts to be filled with the same error message infinitely even after reboot:

[ 445.386506] rk3x-i2c ff050000.i2c: timeout, ipd: 0x80, state: 1 [ 446.410279] rk3x-i2c ff050000.i2c: timeout, ipd: 0x80, state: 1 [ 447.434433] rk3x-i2c ff050000.i2c: timeout, ipd: 0x80, state: 1 [ 448.458403] rk3x-i2c ff050000.i2c: timeout, ipd: 0x80, state: 1 [ 449.482364] rk3x-i2c ff050000.i2c: timeout, ipd: 0x80, state: 1 [ 450.506431] rk3x-i2c ff050000.i2c: timeout, ipd: 0x80, state: 1 [ 451.530476] rk3x-i2c ff050000.i2c: timeout, ipd: 0x80, state: 1 [ 453.546436] rk3x-i2c ff050000.i2c: timeout, ipd: 0x80, state: 1 [ 455.562499] rk3x-i2c ff050000.i2c: timeout, ipd: 0x80, state: 1

It happens every time when the sensor on I2C is accessed by two applications at the same time. I understand that more simultaneous accesses won't work but it should not break the I2C bus completely.

I tried unbind/bind via "echo ff050000 | sudo tee /sys/bus/platform/drivers/rk3x-i2c/unbind" but it does not help. Any ideas? Or at least, how to fix the problem without the need to disconnect the power?

RadxaYuntian commented 8 months ago

Sounds like a kernel bug to me. Do you have a simple C program to help us reproduce this issue?

RadxaYuntian commented 8 months ago

https://patchwork.ozlabs.org/project/linux-i2c/patch/20210826174632.91887-1-t.schramm@manjaro.org/ https://github.com/torvalds/linux/commit/19cde9c92b8d3b7ee555d0da3bcb0232d3a784f4 Might be related. @RadxaMitchell

BigMuscle85 commented 8 months ago

This is a simple example (designed for SHT31 on address 0x44) that breaks it immediately by accessing the same device in two threads at the same time.

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <thread>
#include <unistd.h>

#include <linux/i2c-dev.h>
#include <sys/ioctl.h>

void OpenI2C() {
    int fd = open("/dev/i2c-1", O_RDWR);
    if(fd != -1) {
        if(ioctl(fd, I2C_SLAVE, 0x44) != -1) {
            while(true) {
                // Send high repeatability measurement command
                // Command msb, command lsb(0x2C, 0x06)
                char config[2] = { 0 };
                config[0] = 0x2C;
                config[1] = 0x06;
                write(fd, config, 2);
                sleep(1);               

                // Read 6 bytes of data
                // temp msb, temp lsb, temp CRC, humidity msb, humidity lsb, humidity CRC               
                char data[6] = { 0 };
                if (read(fd, data, 6) != 6) {
                    printf("Error reading data (%d)\n", errno);
                }
                sleep(1);                               
            }
        }
    }
}

int main() {
    auto tFunc = []() { OpenI2C(); };   

    std::thread t1(tFunc);
    std::thread t2(tFunc);

    t1.join();
    t2.join();

    return 0;
}
RadxaMitchell commented 8 months ago

@BigMuscle85 I tried the sample program you posted to communicate with an i2c device via i2c-1, but I didn't reproduce the i2c bus being corrupted. You can also try this software version (the kernel is also version 6.1.68): https://github.com/radxa-build/rock-pi-s/releases/download/b40/rock-pi-s_debian_bookworm_cli_b40.img. xz

BigMuscle85 commented 8 months ago

@RadxaMitchell I'll try to figure out what the problem might be. But now I can say that the same problem appears even with RPi3B+ so definitely not Radxa/Rockchip issue. Even after reboot only a bunch of errors:

[   26.791952] i2c-bcm2835 3f804000.i2c: i2c transfer timed out
[   28.871968] i2c-bcm2835 3f804000.i2c: i2c transfer timed out
[   30.391991] i2c-bcm2835 3f804000.i2c: i2c transfer timed out
[   32.471944] i2c-bcm2835 3f804000.i2c: i2c transfer timed out

The board has several DS18B20 (onewire) sensors and one SHT31 connected. I cannot say if it happens for other I2C devices too.