ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

I2C物理层深度解析:开漏输出、上拉电阻与两线制通信原理

I2C物理层深度解析:开漏输出、上拉电阻与两线制通信原理 1. 从一次诡异的通信失败说起几年前调一块传感器板子主控和从设备离得不到三厘米走线短得不能再短按道理这种距离下I2C应该稳如老狗。结果上电之后逻辑分析仪抓出来的波形让我愣了半天SCL时钟干干净净SDA数据线却像被人用手按住了一样始终趴在一个不高不低的电平上既不是明确的高也不是明确的低。主控发地址没回应读数据全是0xFF。我第一反应是器件坏了换了一片一样。又怀疑是地址配错翻手册确认了三遍没问题。最后拿万用表一量SDA对地的电阻才发现问题所在——这条线上挂了一个推挽输出的器件它只要一拉高就和另一个器件的下拉形成了硬碰硬的对拉两条低阻抗通路直接顶在一起电平自然卡在中间。那次之后我才真正把I2C为什么必须开漏这件事从考试会考变成了肌肉记忆。这篇就围绕两线制物理层这个最底层的话题把I2C的开漏结构、上拉电阻、时序约束、常见故障一次讲透。不管你是刚接触I2C的新手还是调过很多板子但没系统梳理过物理层的老手这篇都值得从头看一遍——因为绝大多数I2C通信问题根子都埋在这一层。2. 两线制到底两在哪SDA与SCL的角色分工2.1 一根线传数据一根线定节拍I2C全称Inter-Integrated Circuit物理层上只有两根信号线SDASerial Data负责承载数据位和地址位SCLSerial Clock负责提供同步时钟。加上地线一个最简的I2C连接就是三根线SDA、SCL、GND如果从设备需要供电再加一根VCC四根线搞定。这种极简的连线方式是I2C最大的卖点。对比一下UART点对点至少要TX、RX两根加地线而且只能一对一SPI要四根线SCLK、MOSI、MISO、CS每多一个从设备就多一根片选而I2C用两根线就能挂一整个总线上的几十个器件靠的是地址寻址而不是片选线。这就是为什么板级低速外设——EEPROM、温度传感器、加速度计、IO扩展芯片、PMBus电源管理——几乎清一色选I2C。但两线这个设计不是没有代价的。正因为两根线要同时承担多个器件共享和双向通信两个职责物理层就必须解决一个核心矛盾多个器件怎么在同一根线上和平共处而不互相打架。这个矛盾的答案就是开漏输出加外部上拉。2.2 总线是线与逻辑不是或逻辑理解I2C物理层最关键的一句话是I2C总线上的电平是所有挂载器件输出的线与wired-AND结果。什么叫线与就是只要有一个器件把线拉低整条线就是低只有当所有器件都不拉低都释放总线时线才通过上拉电阻变成高。这跟或逻辑正好相反——或逻辑是有一个拉高就是高。这个特性直接决定了I2C能做时钟同步和总线仲裁。比如两个主设备同时发起传输它们各自输出的SCL周期可能不同但因为线与实际SCL是高电平最短的那个决定谁先把线拉低谁说了算低电平最长的那个决定最终两个主设备会自动同步到一个共同时钟上。仲裁也是同理谁发的数据是1释放而别人发的是0拉低谁就立刻知道自己输了主动退出。如果换成推挽输出一个器件拉高、另一个拉低就是电源到地的低阻通路轻则电平错乱重则烧器件。所以线与逻辑是I2C多设备共享的物理基础而开漏是实现线与的唯一手段。3. 开漏输出的内部结构一颗MOS管撑起的双向总线3.1 开漏的漏指的是什么开漏Open-Drain这个名字来自MOSFET的结构。一个N沟道MOS管有三个主要端子栅极Gate、源极Source、漏极Drain。开漏输出就是把漏极直接引到引脚上不接任何内部上拉源极接地栅极由内部驱动电路控制。工作逻辑非常简单栅极给高电平MOS管导通漏极被拉到地引脚输出低电平栅极给低电平MOS管截止漏极悬空高阻态引脚不输出任何电平此时靠外部上拉电阻把线拉到高电平。注意这里的关键开漏输出只能主动拉低不能主动拉高。高电平是被动来的是外部上拉电阻给的。这就是为什么I2C必须外接上拉电阻——没有上拉线永远悬空读到的永远是无效电平。3.2 为什么不是开集Open-Collector老一点的资料里会提到开集电极输出那是双极型晶体管BJT时代的说法集电极开路。原理完全一样三极管导通时集电极拉低截止时集电极悬空。现在CMOS工艺下用MOS管就叫开漏。两者在逻辑行为上等价只是器件类型不同。你在看一些老芯片手册时看到open-collector不用慌理解成开漏就行。3.3 双向引脚是怎么实现的I2C的SDA是双向线同一个引脚既要输出又要输入。开漏结构天然支持这一点输出级只有一个下拉MOS管输入级是一个高输入阻抗的缓冲器接在引脚上。当器件要读总线时把自己的下拉管关掉释放总线此时引脚对外呈现高阻输入缓冲器就能读到线上其他器件或上拉电阻决定的电平。这种输出时只管拉低、读的时候先释放的机制是I2C能做应答ACK/NACK和时钟拉伸Clock Stretching的根本。从设备收到一个字节后在第九个时钟把SDA拉低表示ACK这个拉低动作就是通过它自己的开漏管完成的主设备此时已经释放了SDA所以不会冲突。4. 推挽输出为什么在I2C上会出事4.1 推挽的结构与它的强势推挽Push-Pull输出内部有一对互补的MOS管上面一个P沟道管接VCC下面一个N沟道管接地。输出高时上管导通、下管截止引脚被主动拉到VCC输出低时下管导通、上管截止引脚被主动拉到地。推挽的优点是驱动能力强、上升沿陡峭、速度快所以SPI、UART这些点对点或带片选的协议都用推挽。但它的强势恰恰是I2C的灾难它不允许别人插手输出高就是硬拉到VCC输出低就是硬拉到地。4.2 两个推挽器件对拉会发生什么假设总线上有两个推挽器件A和B。A输出高上管导通引脚接VCCB输出低下管导通引脚接地。此时从VCC经过A的上管、再经过B的下管到地形成一条完整的低阻通路。这条通路的电流只受两个MOS管的导通电阻限制可能达到几十甚至上百毫安。后果分几档情况现象导通电阻较大电平卡在中间值逻辑判断混乱通信失败导通电阻较小大电流持续流过芯片发热长期可能烧毁多器件同时冲突电流叠加最坏情况直接冒烟这就是我开头那次踩坑的本质。那个推挽器件只要一输出高就和总线上其他拉低的器件顶上了牛。4.3 开漏与推挽的对比特性开漏输出推挽输出高电平来源外部上拉电阻内部上管主动拉高能否主动拉高不能能多器件共享同一线可以线与不可以会冲突上升沿速度受上拉电阻和线容限制较慢快典型应用I2C、SMBus、PMBus、部分中断线SPI、UART、普通GPIO是否需要外部上拉必须不需要看到这张表I2C选开漏的理由就一目了然了它要共享就必须放弃主动拉高的能力把拉高的活儿交给上拉电阻从而保证任何时刻都不会出现两个器件对拉。5. 上拉电阻不是随便焊一个就行5.1 上拉电阻决定了上升沿开漏输出的高电平是被动建立的靠的是上拉电阻给总线电容充电。总线电容包括PCB走线电容、器件引脚电容、连接器电容典型值在几十到几百皮法。上升时间由RC充电常数决定t_r ≈ 0.847 × R_pullup × C_bus这个0.847来自RC充电从0.3VDD到0.7VDD的时间I2C标准定义的上升沿测量区间。举个例子C_bus 200pFR_pullup 4.7kΩ那么t_r ≈ 0.847 × 4700 × 200e-12 ≈ 0.8μs。对于100kHz标准模式周期10μs这个上升时间完全够用但如果跑400kHz快速模式周期2.5μs0.8μs的上升沿就偏大了可能逼近时序极限。5.2 上拉电阻的上下限怎么算上拉电阻不是越小越好也不是越大越好它被两个约束夹在中间。下限由灌电流决定。器件拉低时电流从VCC经上拉电阻灌入器件的开漏管。I2C标准规定标准模式和快速模式下器件的灌电流能力至少3mA所以R_min (VDD - V_OL_max) / I_OL_max以VDD3.3V、V_OL_max0.4V、I_OL3mA计算R_min (3.3-0.4)/0.003 ≈ 967Ω。也就是说上拉电阻不能小于约1kΩ否则灌电流超标器件可能拉不到足够低的电平。上限由上升时间和漏电流决定。电阻太大上升沿太慢还没充到高电平下一个时钟就来了同时总线漏电流在电阻上产生的压降也可能让高电平达不到VIH_min。经验上R_max ≈ t_r_max / (0.847 × C_bus)还是以400kHz、C_bus200pF、允许t_r300ns为例R_max ≈ 300e-9/(0.847×200e-12) ≈ 1771Ω。这就有点尴尬了下限967Ω、上限1771Ω可选范围很窄。5.3 常用取值与场景对照总线速率总线电容推荐上拉说明100kHz100pF4.7kΩ~10kΩ板内短走线最常见100kHz100~200pF2.2kΩ~4.7kΩ多器件或稍长走线400kHz100pF2.2kΩ~4.7kΩ快速模式400kHz100~200pF1kΩ~2.2kΩ需权衡灌电流1MHz50pF1kΩ左右高速模式通常需专用缓冲提示很多开发板默认焊4.7kΩ是因为板子小、器件少、电容小这个值在100kHz下几乎万能。但一旦你把总线引到排线、接上多个模块4.7kΩ可能就偏大了波形上升沿会明显变缓。5.4 上拉电阻小了不通信的反直觉现象热词里有个i2c上拉电阻小了不通信这确实存在而且很多人想不通——电阻小不是上升更快吗怎么会不通信原因在于灌电流。电阻太小器件拉低时灌入的电流超过它的额定能力开漏管的V_OL被抬高可能超过VIH_max低电平上限通常0.3VDD。主设备读到的低不够低就被判成高数据全错。另外如果总线上有多个器件同时拉低电流叠加更严重。所以上拉电阻是够用就好不是越小越猛。6. 从时序图看物理层的硬约束6.1 起始与停止条件为什么这么定义I2C的起始条件START是SCL为高时SDA由高变低停止条件STOP是SCL为高时SDA由低变高。为什么这么定义因为在正常数据传输期间SDA只在SCL为低时变化SCL为高时SDA必须稳定。所以SCL高时SDA跳变就成了一个不会在数据中出现的特殊模式天然适合做帧边界标志。这个定义对物理层有要求SDA从高到低的跳变必须足够快、足够干净否则主设备可能误判。而SDA的上升沿又受上拉电阻限制所以起始条件之后紧接着的第一个时钟SDA必须已经稳定在高电平——这就把上拉电阻的上限又收紧了一点。6.2 建立时间与保持时间I2C标准对时序有明确要求以标准模式100kHz为例参数含义最小值单位t_HD;STA起始条件保持时间4.0μst_LOWSCL低电平时间4.7μst_HIGHSCL高电平时间4.0μst_SU;DAT数据建立时间250nst_HD;DAT数据保持时间0nst_SU;STO停止条件建立时间4.0μst_r上升时间1000ns最大t_f下降时间300ns最大注意t_r最大1000ns这就是上拉电阻和总线电容必须满足的硬指标。下降时间t_f由开漏管的导通能力决定通常比上升快得多因为拉低是主动的、低阻的。6.3 时钟拉伸从设备的暂停键时钟拉伸是I2C一个很实用的机制。从设备如果处理不过来可以在ACK之后把SCL拉低主设备发现SCL没按预期变高就知道从设备还没准备好于是等待。这个拉低动作也是通过从设备的开漏管完成的——如果从设备是推挽输出它拉低SCL时主设备可能正在拉高又是对拉。时钟拉伸对物理层的要求是主设备的SCL输出也必须是开漏并且主设备要能检测SCL的实际电平而不是只看自己输出什么。很多用GPIO模拟I2C的代码在这里翻车就是因为只写不读没做SCL回读。7. 实战排查I2C不通时先看物理层7.1 用逻辑分析仪抓什么逻辑分析仪是调I2C的标配。抓波形时重点看四件事空闲电平SDA和SCL在不通信时是否都是高。如果有一条是低说明有器件在死拉总线或者上拉电阻没焊/虚焊。上升沿形状是不是明显的RC充电曲线。如果上升沿很缓说明上拉电阻偏大或总线电容偏大。起始条件SCL高时SDA有没有干净的下降沿。ACK位第九个时钟SDA是否被从设备拉低。如果一直是高说明从设备没应答可能是地址错、器件没上电、或者物理层电平不达标。7.2 万用表能查出的物理层问题逻辑分析仪看动态万用表看静态。断电测电阻SDA对VCC的电阻应该等于上拉电阻值如果只有一个上拉SDA对地的电阻应该是无穷大除非有器件内部有下拉SDA和SCL之间不应该有低阻通路。上电测电压空闲时SDA、SCL都应该是VCC附近如果某条线只有1V多说明上拉电阻太大或有强下拉。7.3 常见故障对照表现象可能原因排查方向空闲时SDA为低器件死拉、上拉缺失、短路逐个断开器件定位上升沿极缓上拉电阻过大、电容过大减小上拉、缩短走线低电平不够低上拉电阻过小、灌电流超标增大上拉通信偶尔成功时序临界、干扰降速、优化上拉完全无应答地址错、器件没上电、物理层断查地址、查供电、查连线多器件时冲突有推挽器件混入确认所有器件都是开漏7.4 一个容易被忽略的坑电平不匹配3.3V主控接5V从设备或者反过来是另一个高频坑。I2C的开漏结构其实给电平转换提供了便利只要上拉电阻接到目标电压开漏管拉低时两边都能拉到地高电平由各自的上拉决定。但前提是器件的开漏管耐压要够而且不能有内部钳位二极管把电压倒灌回去。稳妥做法是用专用的I2C电平转换芯片或者用MOS管做双向电平转换不要图省事直接上拉到了事。8. 几个延伸问题的一次性说清8.1 I2C、SMBus、PMBus的物理层关系SMBus是I2C的一个子集物理层几乎一样都是开漏加两线但SMBus对时序、电平、超时要求更严比如它有35ms的超时机制防止从设备死拉总线。PMBus又建立在SMBus之上主要面向电源管理物理层沿用。所以你在PMBus和I2C之间纠结时物理层可以认为是一致的差异在协议层。8.2 为什么I2C速率上不去I2C标准模式100kHz、快速模式400kHz、快速加模式1MHz、高速模式3.4MHz。相比SPI动辄几十MHzI2C慢得明显。根子就在开漏加RC充电上升沿是被动建立的速率越高允许的上升时间越短对上拉电阻和总线电容的要求越苛刻。到了高速模式往往需要专门的缓冲器或电流源上拉普通电阻上拉已经力不从心。8.3 多主设备的仲裁为什么不会损坏总线因为所有主设备都是开漏。仲裁时一个主设备输出高释放另一个输出低拉低线与结果是低输出高的那个读回发现自己发的是高但线上是低就知道自己输了立刻退出并释放总线。整个过程没有任何对拉因为谁都不会主动拉高。这就是开漏对多主架构的天然支持。9. 我在实际项目里总结的几条经验第一画原理图时上拉电阻一定要画而且标注清楚阻值和位置。我见过太多人以为芯片内部有上拉就不画结果芯片内部上拉往往是弱上拉几十kΩ跑100kHz都勉强。外部上拉是必须的内部上拉只能算锦上添花。第二上拉电阻尽量靠近主设备或总线中点不要放在总线末端。放在末端的话上拉电流要流过整条走线才能给远端器件充电等效电容更大上升沿更慢。第三调试时先降速。通信不稳时先把速率从400kHz降到100kHz如果降速后稳定了基本可以确定是物理层时序余量不够重点查上拉和电容。这个方法能帮你快速区分物理层问题和协议层问题。第四多器件总线要逐个上电验证。新板子第一次调试不要一次把所有从设备都焊上。先焊一个通了再加下一个这样一旦出问题能立刻定位到是哪个器件引入的。我吃过一次亏八个器件一起焊结果一个器件的地址和另一个冲突查了一下午。第五逻辑分析仪的解码功能要用起来。光看波形容易漏细节开启I2C解码后地址、数据、ACK一目了然。很多分析仪还能直接标出时序违规比人眼靠谱。第六注意总线的分布电容。走线越长、挂的器件越多、连接器越多电容越大。如果总线要引出板外一定要把上拉电阻相应减小或者加总线缓冲器。我有个项目总线引到排线接了四个模块4.7kΩ上拉直接跑不动换成1.5kΩ才稳。把这些物理层的细节吃透你会发现后面调协议、调驱动时心里特别有底——因为你知道问题大概率出在哪一层也知道该拿什么工具去验证。I2C看着简单但它的简单是建立在物理层精心设计之上的开漏加线与就是这套设计的灵魂。
返回列表