Debug of communication protocol I2C subsystem

2022.06.25
Debug of communication protocol I2C subsystem

If the ACK signal is not received when the ACK signal should be received, the i2c controller will generate an ACK error interrupt to tell the i2c driver that an ACK error has occurred. Usually the problem is the slave itself.

There are two common errors in I2C: I2C ACK error, I2C timeout

1. I2C ACK error

If the ACK signal is not received when the ACK signal should be received, the i2c controller will generate an ACK error interrupt to tell the i2c driver that an ACK error has occurred. Usually the problem is the slave itself.

picture

1. Check whether the device exists and whether the i2c bus number and device address are correct. The example is as follows: i2c number is 6, addr is 0x28:

[31.092951][xxx]i2c i2c-6:addr:0x28,ACK error
  • 1.

2. Check whether the device has been powered on and enabled, and the correct init.

3. Check whether the i2c speed is suitable. If the speed is greater than the max speed supported by the device, an ACK Error will also be caused. Slow down, if it still works then it's a clk related issue.

4. Check whether the i2c device signal level matches the AP.

5. GPIO check the following parts:

  1. GPIO current drive capability.
  2. Whether the GPIO working mode is I2C mode.
  3. Whether the GPIO has an internal pull-up resistor.
  4. GPIO default level state.

From the i2c spec, NACK is normal in the following cases.

I2C write

picture

When the master sends data to the slave, the slave may or may not respond when the last Byte of data is received, but the master can generate a stop condition, if the master is sending data to the slave (even including the slave address) When it is detected that the slave is not responding, it will stop the transmission in time.

I2C read

picture

When the master receives data from the slave, the master does not respond to the slave, that is, NACK when the last byte of data is received.

2. I2C timeout

When a timeout occurs in the I2C transmission, the general kernel log will print something like the following:

[48.197718][xxx]i2c i2c-1: addr:0xa,transfer timeout
  • 1.

picture

1. GPIO check the following parts.

  1. GPIO current drive capability.
  2. Whether the GPIO working mode is I2C mode.
  3. Whether the GPIO has an internal pull-up resistor.
  4. GPIO default level state.

2. Check the slave order.

  1. The first slave with timeout in the log.
  2. There are slaves with power control and reset control.
  3. other slaves.

After the problem is reproduced, you can manually remove the corresponding peripherals, confirm which peripheral is pulling the i2c bus, and then communicate with the supplier to debug the IC status and clarify the reason for pulling the i2c bus.

3. i2c-tools

i2c-tools is also very useful. The blogger of this tool tool wrote last time. Please refer to the following articles:

​​Teach you how to use i2c-tools.

4. Frequently Asked Questions

1. The i2c addr of all peripherals on the same i2c bus should be different

(1) Conflicts when registering with the same address.

[2.059184][xxx]i2c i2c-1:Failed to register i2c client 24c02 at 0x51(-16) 
[2.059189][xxx]i2c i2c-1:Can't create device at 0x51
  • 1.
  • 2.

The corresponding error code is -16.

/kernel-5.10/include/uapi/asm-generic/errno-base.h
#define EPERM   1 /* Operation not permitted */
#define ENOENT   2 /* No such file or directory */
#define ESRCH   3 /* No such process */
#define EINTR   4 /* Interrupted system call */
#define EIO   5 /* I/O error */
#define ENXIO   6 /* No such device or address */
#define E2BIG   7 /* Argument list too long */
#define ENOEXEC   8 /* Exec format error */
#define EBADF   9 /* Bad file number */
#define ECHILD  10 /* No child processes */
#define EAGAIN  11 /* Try again */
#define ENOMEM  12 /* Out of memory */
#define EACCES  13 /* Permission denied */
#define EFAULT  14 /* Bad address */
#define ENOTBLK  15 /* Block device required */
#define EBUSY  16 /* Device or resource busy */
......
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

You can execute ls /sys/bus/i2c/devices to check whether there are peripherals registered with the same address under the corresponding i2c-1.

If -11 is returned, -EAGAIN. It means that the bus is busy, or the bus lock cannot be applied for. If the bus is busy, retry and wait, or see which device has been sending. If the bus lock cannot be obtained, please check whether i2c_transfer is called in the interrupt function or atomic context.

(2) Hidden i2c address, that is, there are multiple i2c addr or peripheral HW bugs in the peripheral, resulting in abnormal i2c communication.

Example: eeprom registers 0x50 address on i2c-1, and although type c is registered to 0x60 address, it can also respond to 0x50, type c pulls down SDA, thus timeout.

debug method:

  1. Confirm whether the data and the corresponding driver are correct on the software.
  2. Remove the peripherals one by one on the hardware to confirm which peripheral is causing it.

2. There are glitches where the oscilloscope ACK

The glitch generated when the slave switches to the mater side to control after the ninth clk generates an ACK response. This glitch does not affect the I2C bus read and write timing and does not need to be addressed.

That is, the slave and master control the bus switching interval, and no one controls the bus, resulting in glitches.

3. Half high level

In the case of an external pull-up resistor, there is an enable internal pull-down resistor, resulting in a half-high level on the bus.

4. The level on the bus cannot be pulled to ground

  1. When the master side sends data, the level cannot be pulled to ground, and the drive current or pull-up resistor can be increased.
  2. If the slave terminal cannot pull the ground, you can consult the supplier to see if the drive current or pull-up resistor of the slave terminal can be increased.

5. RK platform I2C debug

From firefly.

https://wiki.t-firefly.com/zh_CN/Firefly-RK3399/driver_i2c.html
  • 1.

I2C communication failed, log: "timeout, ipd: 0x00, state: 1"

Please check whether the hardware pull-up is powered.

Calling i2c_transfer returns a value of -6?

The return value of -6 indicates a NACK error, that is, the other device has no response. This situation is generally a peripheral problem. The common situations are as follows:

  1. The I2C address is wrong, the solution is to measure the I2C waveform to confirm whether the I2C device address is wrong;
  2. The I2C slave device is not in normal working state, such as no power supply, wrong power-on sequence, etc.;
  3. Timing that does not meet the requirements of the I2C slave device will also generate a Nack signal.

When the peripheral requires the read timing to be a stop signal instead of a repeat start signal, how should it be handled?

At this time, i2c_transfer needs to be called twice, and the I2C read is split into two, and the modification is as follows:

static int i2c_read_bytes(struct i2c_client *client, u8 cmd, u8 *data, u8 data_len) {struct i2c_msg msgs[2];
     int ret;
     u8 *buffer;
     buffer = kzalloc(data_len, GFP_KERNEL);
     if (!buffer)
         return -ENOMEM;
     msgs[0].addr = client->addr;
     msgs[0].flags = client->flags;
     msgs[0].len = 1;
     msgs[0].buf = &cmd;
     ret = i2c_transfer(client->adapter, msgs, 1);
     if (ret < 0) {
      dev_err(&client->adapter->dev, "i2c read failed\n");
            kfree(buffer);
       return ret;
      }
      msgs[1].addr = client->addr;
      msgs[1].flags = client->flags | I2C_M_RD;
      msgs[1].len = data_len;
      msgs[1].buf = buffer;
      ret = i2c_transfer(client->adapter, &msgs[1], 1);
      if (ret < 0)
          dev_err(&client->adapter->dev, "i2c read failed\n");
      else
        memcpy(data, buffer, data_len);
      kfree(buffer);
      return ret;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • twenty one.
  • twenty two.
  • twenty three.
  • twenty four.
  • 25.
  • 26.
  • 27.
  • 28.

I believe that the above I2C debug method can solve most of the problems for you. If it still does not solve the problem, it is usually a chip problem or a bug in the original code. You can find the original chip support.