3. 总线仲裁原理:线与逻辑、仲裁过程、仲裁丢失检测
多主模式,说白了就是多个设备都能当老大。但问题来了——如果两个老大同时抢总线,谁说了算?
我刚开始接触I2C多主时,总觉得这事儿挺玄乎。后来调了几个月板子,才真正理解背后的机制。其实核心就三个词:线与逻辑、仲裁过程、仲裁丢失检测。
3.1 线与逻辑:硬件层面的“投票机制”
I2C总线的物理层有个关键设计——开漏输出。每个设备的SDA和SCL引脚都是开漏结构,只能拉低,不能主动拉高。拉高靠上拉电阻。
这就形成了所谓的“线与”逻辑:
- 只要有一个设备拉低总线,总线就是低电平
- 所有设备都释放(不拉低),总线才回到高电平
你想想看,这像不像一个“一票否决”机制?谁想拉低都能拉低,但想拉高得所有人都同意。
核心结论:线与逻辑是I2C仲裁的物理基础。没有开漏+上拉,就没有仲裁这回事。
我在项目中遇到过一种情况:某次调试时发现总线一直低,查了半天,原来有个从机的SDA引脚内部短路到地。这就是“线与”的副作用——一个坏设备能拖死整条总线。
3.2 仲裁过程:谁的数据“0”多,谁赢
仲裁发生在SDA线上,SCL由所有主机共同同步(时钟同步我们下一节细讲)。过程其实很简单:
- 多个主机同时发出START信号
- 它们各自在SDA上逐位输出自己的数据(地址或数据位)
- 每个主机在发送每个位后,会回读SDA的实际电平
- 如果自己发送的是1(释放总线),但读到的是0(被其他设备拉低),说明仲裁失败
- 仲裁失败的主机立即释放SDA和SCL,转为从机模式
我习惯用一个比喻来理解:谁先输出0,谁就赢。因为0是主动拉低,1是释放。你输出1,别人输出0,总线就是0,你自然就输了。
| 主机A发送位 | 主机B发送位 | SDA实际电平 | 仲裁结果 |
|---|---|---|---|
| 1(释放) | 1(释放) | 1 | 继续 |
| 0(拉低) | 1(释放) | 0 | 主机B输 |
| 0(拉低) | 0(拉低) | 0 | 继续 |
| 1(释放) | 0(拉低) | 0 | 主机A输 |
注意,仲裁不仅发生在地址阶段,也发生在数据阶段。我曾经调试过一个系统,两个主机往同一个从机写数据,结果数据阶段仲裁了,数据被破坏。嗯,这就是设计上的坑——多主模式下,地址要唯一,数据阶段也要避免冲突。
实战技巧:用示波器抓SDA波形时,如果看到地址阶段有“毛刺”或非完整波形,大概率是多个主机在仲裁。这时候数一下地址位,看谁输了。
3.3 仲裁丢失检测:输了怎么办?
仲裁丢失检测,是每个I2C主机必备的“认输”机制。检测到仲裁丢失后,主机会做以下几件事:
- 立即释放SDA和SCL:不再驱动总线,避免干扰胜出的主机
- 设置仲裁丢失标志位:通常是一个状态寄存器位,软件可以查询
- 停止当前传输:不再继续发送剩余的位
- 可选:产生中断:通知CPU重新调度
我曾经踩过一个坑:某款MCU的I2C外设,仲裁丢失后不会自动释放SCL,导致总线卡死。后来在中断服务里手动释放才解决。所以,不要完全相信硬件手册,实际测一下才放心。
避坑指南:我曾经遇到一个案例,主机A和主机B同时访问同一个从机,地址相同,数据也相同。结果仲裁一直不触发,因为双方发的位一模一样。这种情况下,总线不会卡死,但数据可能重复或丢失。解决方案是给每个主机分配不同的地址范围,或者用软件令牌机制。
3.4 仲裁与时钟同步的关系
仲裁和时钟同步是孪生兄弟。仲裁发生在SDA上,时钟同步发生在SCL上。没有时钟同步,多个主机的SCL节奏不一致,仲裁就没法逐位比较。
简单说:时钟同步让所有主机步调一致,仲裁在这个统一节拍下逐位决胜负。
3.5 实战:如何用示波器观察仲裁
纸上谈兵没意思,咱们说说怎么实际抓仲裁波形。
- 触发设置:用SDA下降沿触发,捕获START条件
- 观察地址阶段:看前8个SCL周期内的SDA波形
- 找异常位:如果某个位SDA不是完整的方波,而是“中间变低”,那就是仲裁点
- 确认失败方:仲裁失败的主机在仲裁位之后会释放SDA,波形会变“干净”
关键波形特征:仲裁发生时,SDA在SCL高电平中间出现“额外”的下降沿。这是因为失败方在回读时发现总线被拉低,主动释放了输出。
我记得有一次调一个双主机的系统,两个主机地址分别是0x50和0x51。抓波形发现地址阶段总是0x50赢,0x51从来没赢过。后来一查,0x50的地址最后一位是0,0x51是1。这不就应了那句话吗——谁先输出0,谁赢。
3.6 本章小结
| 概念 | 核心要点 | 常见误区 |
|---|---|---|
| 线与逻辑 | 开漏输出+上拉电阻,谁拉低谁控制总线 | 以为总线高电平是设备主动拉高的 |
| 仲裁过程 | 逐位比较,输出0的赢,输出1的输 | 以为仲裁只发生在地址阶段 |
| 仲裁丢失检测 | 释放总线、设标志、停止传输 | 以为硬件会自动恢复,实际需要软件介入 |
仲裁这事儿,说白了就是硬件层面的“谦让”机制。谁的数据更“强势”(0多),谁就占住总线。输了的自动退让,不吵不闹。这种设计思想,其实挺值得我们在软件架构中借鉴的。