I2C总线介绍
更新时间: 2026/02/13
在Gitcode上查看源码

基本概念

定义

I2C属于两线式串行总线,由飞利浦公司开发用于微控制器(MCU)和外围设备(从设备)进行通信的一种总线,属于一主多从(多住多从时,会进行主机仲裁,同一时间下的通信只会有一个主机)的总线结构,总线上的每个设备都有一个特定的设备地址,以区分同一I2C总线上的其他设备

物理结构

I2C总线上可以连接多个设备,各设备之间通过SDA总线(数据线)和SCL总线(时钟线)进行连接,支持多主设备和多从设备,多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线,拓扑结构如下图所示。SCL和SDA空闲状态均为高天平

通信协议核心机制

I2C总线通信时采用主从模式,即主设备发起和结束通信,总线上的从设备被动响应,是一种同步、半双工、串行通信协议

起始(START)与停止(STOP)信号

SCL为高天平时,主设备控制SDA从高->低跳变产生START信号;SCL为高电平时,主设备控制SDA从低->高跳变产生STOP信号

确认(ACK)与非确认(NACK)信号

每字节传输后,接收方在第9个时钟周期拉低SDA发出ACK信号,确认接收成功,若SDA保持高电平(相当于发出NACK)则发送方会停止传输

数据传输格式

主设备发起START信号 -> 主设备发送从设备地址+读写位 -> 从设备相应ACK -> 传输n个字节,每传输完一个字节,接收方均响应ACK -> 主设备发送STOP信号结束通信并释放总线

SDA总线数据生成与采样

主从设备各有一个移位寄存器用于数据传输,两者由主设备控制的SCL总线的时钟信号进行统一驱动,一个时钟周期完成一位数据的传输。时钟信号的下降沿会触发发送方将移位寄存器最高位(MSB)传输到SDA总线,并保证在时钟信号的低电平期间完成该动作并确保数据稳定(因为数据传输有延迟,发送方不能保证在时钟信号下降沿的一瞬间完成传输),同一时钟周期的时钟上升沿会触发接收方采样SDA总线的数据并存入移位寄存器,并在SCL高电平期间完成采样。在SCL高电平期间,不能让SDA信号跳变,否则会导致采样错误

时钟延展

从设备可以通过拉低SCL暂停时钟,延长低电平时间以处理数据。主设备检查到SCL被拉低后,等待其释放后再重新接管SCL总线

Restart机制

该机制的典型应用场景之一为切换读写方向,以读EEPROM特定地址数据为例说明该机制: 主设备发起START信号 -> 主设备发送从设备地址+写位 -> 从设备响应ACK (只有与主设备发出的地址匹配的从设备会响应) -> 主设备往eeprom设备写入一个字节的偏移地址(eeprom收到该地址后会设置内部读数据的地址指针,以供后续读取数据使用,每读一个字节,该指针会自动加1)-> 从设备响应ACK -> 主设备发送Restart信号 -> 无效数据+读位(每读取一个字节就需要写一个无效数据,硬件据此判断要读取的字节数,并据此决定发送ACK的数量)-> 从设备返回1字节数据,主设备响应ACK(读取几个字节就重复该步骤几次)-> 主设备发送STOP信号结束通信并释放总线

RESTART信号的产生:在SCL高电平时,主设备释放SDA跳变为高电平,然后迅速将SDA拉低为低电平,产生RESTART信号,为了避免被误判为STOP信号,SDA跳变过程中要缩短其高电平时间,确保快速完成SDA的电平跳变

I2C支持的器件

器件接口
Ads78bmc.kepler.Chip
bmc.kepler.Release.TraceChip
通用Chipbmc.kepler.Chip
bmc.kepler.Chip.BlockIO
bmc.kepler.Chip.Aggregate
bmc.kepler.Release.TraceChip
CpldChipbmc.kepler.Chip
bmc.kepler.Chip.BlockIO
bmc.kepler.Chip.BitIO
bmc.kepler.Release.TraceChip
CpldRegisterbmc.kepler.Chip
bmc.kepler.Release.TraceChip
Eeprombmc.kepler.Chip
bmc.kepler.Chip.BlockIO
bmc.kepler.EepromData
bmc.kepler.Release.TraceChip
Lm75bmc.kepler.Chip
bmc.kepler.Release.TraceChip
Pca9545、Pca9544bmc.kepler.Chip
bmc.kepler.Release.TraceChip
Pca9555bmc.kepler.Chip
bmc.kepler.Release.TraceChip
Rtcbmc.kepler.Chip
bmc.kepler.Chip.BlockIO
bmc.kepler.Release.TraceChip
Smcbmc.kepler.Chip
bmc.kepler.Chip.BlockIO
bmc.kepler.Chip.BitIO
bmc.kepler.Release.TraceChip
Vrdbmc.kepler.Chip
bmc.kepler.Chip.BlockIO
bmc.kepler.Chip.BitIO
bmc.kepler.Release.TraceChip
Inabmc.kepler.Chip
bmc.kepler.Chip.BlockIO
bmc.kepler.Chip.BitIO
bmc.kepler.Chip.PowerMeter.Ina
bmc.kepler.Release.TraceChip

问题定位

常见问题现象

/var/log/framework.log | grep error 在串口查看框架日志(或一键收集日志dump_info\LogDump\framework.log中),出现错误的调用函数可能不同,但如果打印:i2c read fail, ret: 5或i2c write fail, ret: 5的时候优先按以下方法定位

问题定位指南

  1. 关键字:i2c fail, ret: 5
  2. 定位手段:查看/var/log/linux_kernel_log的SDK日志(或一键收集日志dump_info\LogDump\linux_kernel_log中)
  3. 定位思路:在linux_kernel_log中搜索I2C-xx, 对应的I2C日志格式如下:

[I2C-bus-RT <xfer_ret|ret>] M <addr|flag|protocal|retries|timeout> L <wlen|rldn|cmd_len> C <wcnt|rcnt|outstanding> E <cmd_error|msg_error|status|abort_source> I <irq_status|irq_raw_status|irq_mask>

参数解释
bus出现问题的I2C通道
xfer_ret返回的错误码
ret返回的错误码
addr表示slave地址(7bit)例如:0x50,BMC侧调试I2C xfer接口传入地址0x50,调用其他接口使用传入0xA0(0x50 << 1),8bit地址
flag1 表示接收数据,0表示发送数据
protocal表示传输消息的协议类型,I2C协议为0, SMBus协议表示此处协议类型,例:8表示block write
retries可能的重传次数
timeoutBMC软件配置的传输超时时间(timeout * 10)ms
wlenI2C需要写的数据个数
rlenI2C需要读的数据个数
cmd_len不关注
wcnt软件写到芯片FIFO中的数据个数
rcnt软件读到芯片中的数据个数
outstanding软件还剩余的没有读到的数据个数
cmd_errorcmd错误码
msg_errorMsg错误码
status数据传输的状态
abort_source发生abort的原因
irq_status中断状态
irq_raw_status原始中断状态
irq_mask中断mask

主要关注点:

  1. 找到对应的I2C
  2. RT<-5 | 5>对应framework.log中的ret:5
  3. slave器件地址
  4. flag(0x1或0x0),分别对应接收数据或者发送数据
  5. 错误码(查找下方具体的错误码对应的错误信息排查
返回码错误码说明排查步骤
-50x1发生tx_abort错误,传输被中止,此时一般都是slave没有响应。
原因有:
slave地址错误;
slave不响应;
链路异常;
0x1可能和0x200,0x800一起出现,只要有0x1,请一定查阅此处

地址无响应:
abort_source=1;
1) 确认slave地址是否存在
2) 确认slave是否在活跃状态
3)确认硬件链路是否畅通,信号质量是否良好
数据无响应:
abort_source=0x8;
1) 确认slave是否在活跃状态
2) 确认硬件链路是否畅通
丢失总线控制权:
abort_source=0x1000;
1) 是否存在多master抢占?
2) 是否存在总线干扰?
3) I2C外接的slave器件是否过多
三种错误都寻求硬件帮忙测量波形搞定。
-50x2smbus时钟一直是低
原因有:
I2C的复用关系可能没有配置
1、首先联系硬件,确认该I2C通道被用作I2C功能;
2、联系SDK软件检查复用配置
-50x200或0x201发送FIFO中的有效数据个数不为0.
原因有:
接收数据过程中,从器件突然不响应;
总线干扰;
1、一般0x200会与0x1一起出现,即0x201,这时引起这样的错误的原因一般是从器件无响应导致的,请联系硬件同事排查slave不响应的原因。
2、只有0x200的情况,一般是存在总线干扰,请联系硬件同事进行总线排查
-50x800或0x801软件还有剩余的数据没有读到
原因有:
slave地址错误;
slave不响应;
链路异常;
1、一般0x800会与0x1一起出现,即0x801;或者与0x200、0x1一起出现,即0xa01,这时引起这样的错误的原因一般是从器件无响应导致的。请联系硬件同事排查slave不响应的原因。2、只有0x800的情况,或是0x800与0x200一起出现,即0xa00,一般是存在总线干扰,请联系硬件同事进行总线排查
-620x10001传输超时
原因有:
设置的超时时间较短;
从器件特性限制,在读写之间需要有一个延时;
总线挂死;
1、查看超时时间,和要读的数据长度,是否存在超时时间太短,但时间很长的情况?此时建议BMC增大超时时间重试
2、联系slave器件负责人,咨询slave器件的性质,是否存在需要在读写之间增加延时的情况?典型器件如PSU需要在读写之间增加10ms的延时
3、通过测量波形,发现状态一直保持高电平,可以尝试减小链路的上拉电阻2
-620x10000传输超时
原因有:中断被屏蔽,硬件无法发出信号。
1、查看超时时间,和要读的数据长度,是否存在超时时间太短,但时间很长的情况?此时建议BMC软件增大超时时间重试
2、联系slave器件负责人,咨询slave器件的性质,是否存在需要在读写之间增加延时的情况?典型器件如PSU需要在读写之间增加10ms的延时
3、查看此时是否有大量打印,print会屏蔽中断