社区编辑申请
注册/登录
通信协议 I2C 子系统之 Debug
网络 通信技术
在应该收到 ACK 信号的时候没有收到 ACK 信号,i2c controller 就会产生一个 ACK error 的中断,告诉 i2c driver 发生了 ACK error。通常情况是 slave 本身的问题。

I2C 常见有两种错误:I2C ACK error、I2C timeout

一、I2C ACK error

在应该收到 ACK 信号的时候没有收到 ACK 信号,i2c controller 就会产生一个 ACK error 的中断,告诉 i2c driver 发生了 ACK error。通常情况是 slave 本身的问题。

图片

1、检查 device 是否存在,i2c bus number 和 device address 是否正确。示例如下:i2c number 为 6,addr 为 0x28:

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

2、检查 device 是否已经上电使能,以及正确的 init。

3、检查 i2c speed 是否适配,speed 大于 device 支持的 max speed 也会造成 ACK Error。降低速度,如果仍然可以工作的话就说明是 clk 相关问题。

4、检查 i2c device 信号电平是否与 AP 匹配。

5、GPIO check 以下几个部分:

  1. GPIO 电流驱动能力。
  2. GPIO 工作模式是否是 I2C 模式。
  3. GPIO 是否有内部上拉电阻。
  4. GPIO 默认电平状态。

从 i2c spec 看,如下情况 NACK 是正常的。

I2C 写

图片

主机向从机发送数据时,最后一个 Byte 数据时,从机可能应答也可能非应答,但不怎样主机都可以产生停止条件,如果主机在向从机发送数据(甚至包括从机地址在内)时检测到从机非应答,则会及时停止传输。

I2C 读

图片

主机从从机接收数据时,最后一个 Byte 数据时,主机不回应该从机,即 NACK。

二、I2C timeout

当 I2C 传输发生 timeout 时,一般 kernel log 会有类似如下打印:

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

图片

1、GPIO check 以下几个部分。

  1. GPIO 电流驱动能力。
  2. GPIO 工作模式是否是 I2C 模式。
  3. GPIO 是否有内部上拉电阻。
  4. GPIO 默认电平状态。

2、排查 slave 顺序。

  1. log 中第一个发生 timeout 的 slave。
  2. 有 power 控制和 reset 控制的 slave。
  3. other slave。

复现问题后,可以手动将相应外设去掉,确认是哪个外设将 i2c bus 拉住,再与供应商沟通,debug 一下该 IC 状态,理清拉住 i2c bus 原因。

三、i2c-tools

i2c-tools 也很好用,这个工具工具博主上次写过,参考以下文章:

​手把手教你使用 i2c-tools。​

四、常见问题

1、同一条 i2c bus 上所有的外设的 i2c addr 要不同

(1)相同 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

对应的错误码是 -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 */
......

可以执行 ls /sys/bus/i2c/devices 查看对应的 i2c-1 下是否已经有注册相同的 address 的外设。

若返回 -11,-EAGAIN。代表总线正忙,或无法申请到总线锁。如果总线正忙,请 retry 等待,或查看是哪个 device 一直在发送。如果无法申请到总线锁,请查看是否在中断函数或原子上下文调用了 i2c_transfer。

(2)隐藏的 i2c address,即外设存在多个 i2c addr 或外设 HW bug,导致 i2c 通讯异常。

示例:eeprom 在 i2c-1 上注册了 0x50 地址,而 type c 虽然注册到 0x60 地址,但对 0x50 也能产生响应,type c 拉低了 SDA ,从而 timeout 。

debug 方法:

  1. 软件上确认数据及对应的 driver 是否正确。
  2. 硬件上逐一去掉外设,确认是哪个外设导致。

2、示波器 ACK 的地方有毛刺

slave 在第 9 个 clk 产生 ACK 应答后,换成 mater 端来控制时产生的毛刺。此毛刺不会影响 I2C 总线读写时序,无需处理。

即 slave 和 master 控制总线切换间隔,没有人控制总线,带来的毛刺。

3、半高电平

在外接上拉电阻的情况下,有 enable 内部下拉电阻,导致总线上有半高电平。

4、总线上电平拉不到地

  1. master 端发送数据时电平拉不到地,可以增大驱动电流或者上拉电阻。
  2. slave 端拉不到地,可以咨询供应商看是否能增大 slave 端驱动电流或者上拉电阻。

5、RK 平台 I2C debug

来源于 firefly。

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

I2C 通信失败,出现 log: “timeout, ipd: 0x00, state: 1”

请检查硬件上拉是否给电。

调用 i2c_transfer 返回值为 -6?

返回值为 -6 表示为 NACK 错误,即对方设备无应答响应,这种情况一般为外设的问题,常见的有以下几种情况:

  1. I2C 地址错误,解决方法是测量 I2C 波形,确认是否 I2C 设备地址错误;
  2. I2C slave 设备不处于正常工作状态,比如未给电,错误的上电时序等;
  3. 时序不符合 I2C slave 设备所要求也会产生 Nack 信号。

当外设对于读时序要求中间是 stop 信号不是 repeat start 信号的时候,该如何处理?

这时需要调用两次 i2c_transfer, I2C read 拆分成两次,修改如下:

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;
}

相信以上的 I2C debug 方法已经能为大家解决大部分问题,如果还是没解决,一般是芯片问题或者原厂底层 code bug,可以找芯片原厂支持。

责任编辑:姜华 来源: 嵌入式Linux系统开发
相关推荐

2022-06-20 22:37:25

Linux操作系统命令

2022-06-16 17:02:49

微软智能云混合云Azure

2022-06-15 11:02:40

网络安全运营

2022-06-09 18:04:46

网络攻击网络安全

2022-06-22 09:19:55

HDC鸿蒙ADB命令

2022-06-15 11:51:14

Vue3开发避坑

2022-06-01 17:47:24

运维监控系统

2022-06-09 09:27:16

前端行业生存

2022-06-24 15:13:17

区块链数字资产加密货币

2022-06-22 05:53:49

城域网广域网VXLAN

2022-06-07 09:59:21

网络安全安全漏洞

2022-06-21 21:47:13

数据系统

2022-06-24 11:34:38

云计算应用安全

2022-06-02 15:28:42

网络安全信息通信数据保护

2022-06-16 11:33:57

物联网区块链科技

2022-06-23 12:30:03

物联网工业物联网IIoT

2022-06-23 11:42:22

MySQL数据库

2022-06-10 07:45:09

CentOS国产操作系统

2022-06-16 10:31:26

2022-06-23 06:43:55

异常数据上报异常监控sdk阿波罗移动端

同话题下的热门内容

CAP,能少了P?你知道吗?聊聊实现 6G 愿景所需技术进步的问题

编辑推荐

FTP与SFTP两者有什么区别你的手机支持5Gwifi吗?5G上网真的很快吗?VXLAN与EVPN的结合使用VXLAN技术介绍:三层的网络来搭建虚拟的二层网络什么是通信原理?原来这么简单
我收藏的内容
点赞
收藏

51CTO技术栈公众号