1. 项目概述:当I2C需要“长途跋涉”时
在嵌入式系统开发,尤其是汽车电子、工业视觉和安防监控领域,我们经常需要用一个主控制器去配置和管理分布在系统各个角落的传感器或外设。I2C总线因其简洁的两线制(SCL时钟线和SDA数据线)和灵活的寻址方式,成为了这种场景下的首选。然而,当传感器被安装在距离主控板几米甚至十几米远的地方时,比如车载环视摄像头、工厂产线上的工业相机,传统的I2C总线就力不从心了。信号衰减、电磁干扰和长线缆带来的电容效应,都会严重限制通信距离和可靠性。
这时,我们就需要一种“桥梁”技术,它能把本地的I2C信号“打包”,通过一条抗干扰能力强、传输距离远的链路发送出去,在远端再“解包”还原成标准的I2C信号。德州仪器(TI)的FPD-Link III技术,配合DS90UB913(串行器)和DS90UB914(解串器)芯片组,就是为解决这个问题而生的。这套方案最巧妙的地方在于,它在传输高速视频数据的同时,还嵌入了一个全双工、低延迟的双向控制通道。这个通道原生兼容I2C协议,允许主机像访问本地设备一样,透明地访问链路另一端的I2C从设备。
简单来说,你可以把FPD-Link III的BCC想象成一条I2C信号的“专属高速公路”。本地的主机(比如车机SoC)发出I2C命令,DS90UB914(解串器)作为“本地收费站”,识别命令并将其封装,通过这条高速公路发送给远端的DS90UB913(串行器)——“远端收费站”。DS90UB913再负责把命令还原,并以其自身的名义在远端I2C总线上执行,充当一个“代理主设备”。整个过程中,主机完全感知不到中间复杂的串行化/解串行化过程,它只知道自己成功读写了一个I2C地址。这对于需要远程配置摄像头传感器参数、读取温度传感器数据或控制马达驱动器的工程师来说,无疑是一个既优雅又强大的解决方案。
2. 核心概念与寄存器精解:理解BCC的运作基石
在深入配置之前,我们必须先厘清几个核心概念和关键的寄存器,这是理解整个系统如何“欺骗”I2C主机和从设备的基础。
2.1 关键定义:物理地址与逻辑别名
在DS90UB913/914的语境下,理解“地址”需要分两层来看:
设备ID:这是芯片的物理I2C地址,通常由硬件引脚(ID[x])在上电时设定。例如,DS90UB913的默认地址是0x58,DS90UB914是0x60。这个地址用于主机直接与本地连接的串行器或解串器本身进行通信,配置其内部寄存器。
设备别名:这是一个逻辑地址,由软件写入特定寄存器来定义。它的核心作用是地址重映射。当主机想要访问一个远程设备时,它并不直接使用该设备的物理地址,而是使用一个预先配置好的“别名”地址。本地芯片(代理从设备)会截获这个别名地址的通信,将其转换为目标的物理地址,再通过BCC转发出去。
重要提示:在芯片的寄存器中,I2C地址值通常以左移1位后的形式存储。这是因为在标准的I2C 7位地址后,需要跟一个读写位(R/W# bit),构成一个完整的8位字节。例如,物理地址0x50(二进制101 0000)在写入寄存器时,需要写作
0x50 << 1 = 0xA0(二进制1010 0000)。在阅读数据手册和配置时,务必注意这个转换,这是新手最容易混淆和出错的地方。
2.2 核心寄存器详解
DS90UB913/914提供了一系列寄存器来管理BCC的I2C功能。下表是这些核心寄存器的概要:
| 寄存器功能 | DS90UB914 地址 | DS90UB913 地址 | 说明 |
|---|---|---|---|
| I2C Device ID | 0x00 | 0x00 | 本地芯片自身的I2C地址。可被ID引脚覆盖。 |
| SER ID | 0x06 | 不适用 | 自动加载的远程串行器物理地址(左移1位后)。 |
| SER Alias | 0x07 | 不适用 | 为远程串行器定义的逻辑别名地址。 |
| DES ID | 不适用 | 0x06 | 自动加载的远程解串器物理地址(左移1位后)。 |
| DES Alias | 不适用 | 0x07 | 为远程解串器定义的逻辑别名地址。 |
| Slave ID[0-7] | 0x08-0x0F | 0x08 | 远程I2C从设备(如摄像头传感器)的物理地址。 |
| Slave Alias[0-7] | 0x10-0x17 | 0x09 | 为对应远程从设备定义的逻辑别名地址。 |
| SCL High Time | 0x40 | 0x11 | 配置代理主设备输出的SCL高电平时间。 |
| SCL Low Time | 0x41 | 0x12 | 配置代理主设备输出的SCL低电平时间。 |
| I2C Pass Through | 0x03[3] | 0x03[2] | 使能通过BCC与已定义别名的远程设备通信。 |
| I2C Pass Through All | 0x21[7] | 0x03[3] | 使能所有非寻址本地芯片的通信都通过BCC转发。 |
寄存器操作精要:
- 自动加载机制:
SER ID和DES ID寄存器在链路建立(RX Lock)后,会自动从对端芯片读取并填充。这是一个非常便利的功能,意味着你通常不需要手动去配置对端芯片的地址。除非有特殊需求(如固定地址),才需要写入并冻结(Freeze Device ID)它。 - 别名地址的必要性:
SER/DES Alias和Slave Alias寄存器必须被配置为一个非零值,相应的远程设备才能被访问(除非启用Pass Through All模式)。这是实现地址重映射的关键。 - 通道控制:
I2C Pass Through位是远程通信的“总开关”。而I2C Pass Through All是一个更宽松的模式,它允许所有不匹配本地Device ID的通信都尝试通过BCC转发,这在调试初期或简单系统中可能有用,但在多设备系统中容易引起地址冲突,需谨慎使用。
3. 实战配置解析:主机在解串器侧的典型场景
最常见的应用场景是:主控制器(如处理器)与DS90UB914解串器在同一侧(本地),而DS90UB913串行器与摄像头传感器在另一侧(远程)。此时,DS90UB914作为本地I2C总线上的从设备,DS90UB913则作为远程I2C总线上的代理主设备。
3.1 场景一:与本地解串器通信
这是最简单的情况。主机直接使用DS90UB914的Device ID(例如默认的0x60)进行读写。由于通信没有跨越串行链路,因此不需要BCC参与,也没有额外的延迟。这通常用于配置解串器本身的参数,如视频链路配置、BCC使能等。
操作步骤:
- 主机发起START条件。
- 发送从设备地址:
0x60 << 1 | R/W#(例如写操作:0xC0)。 - 后续发送寄存器地址和数据字节。
- 通信完全在本地I2C总线上完成。
3.2 场景二:与远程串行器通信
主机需要配置或读取远程DS90UB913串行器本身的寄存器。假设串行器的物理地址是默认的0x58。
方法A(推荐,使用别名):
- 查询/确认SER ID:主机先读取DS90UB914的
SER ID寄存器(0x06)。链路正常时,这里会自动加载为0x58 << 1 = 0xB0。 - 配置别名:向DS90UB914的
SER Alias寄存器(0x07)写入一个值,例如0x59 << 1 = 0xB2。这个值就是主机后续用来访问远程串行器的“门牌号”。 - 发起通信:此后,当主机想访问远程串行器时,不再使用地址0x58,而是使用地址0x59。DS90UB914会识别到这个别名地址,将整个I2C事务通过BCC转发给地址为0x58的远程DS90UB913。
方法B(使用Pass Through All):
- 将DS90UB914的
I2C Pass Through All位(0x21[7])置1。 - 此时,主机发送给任何**不等于DS90UB914自身Device ID(0x60)**的地址的通信,都会被尝试转发到远程串行器。
- 主机可以直接使用远程串行器的物理地址0x58进��通信。
实操心得:强烈推荐使用方法A(别名法)。
Pass Through All模式虽然方便,但在系统中有多个远程设备时,会带来严重的地址冲突和通信混乱。别名法则清晰、可控,是构建稳健多设备系统的基石。
3.3 场景三:与远程从设备(如摄像头)通信
这是最核心的应用。假设远程摄像头传感器的物理I2C地址是0x50。
配置与通信流程:
- 配置物理地址:向DS90UB914的一个
Slave ID寄存器(例如0x08)写入摄像头的物理地址左移1位后的值:0x50 << 1 = 0xA0。 - 配置逻辑别名:向对应的
Slave Alias寄存器(0x10)写入一个别名,例如0x51 << 1 = 0xA2。这意味着我们告诉DS90UB914:“以后看到发往地址0x51的I2C命令,都帮我转发给那个物理地址为0x50的设备”。 - 发起远程访问:主机现在可以使用地址0x51来读写摄像头传感器。DS90UB914会完成地址转换和协议转发。
- 时钟拉伸:请注意!由于通信需要经过BCC,存在往返延迟。因此,当DS90UB914(作为主机的从设备)收到主机发往0x51的命令后,它需要时间通过串行链路与远端交互。在此期间,它会通过时钟拉伸(将SCL线拉低)来让主机等待,直到收到远端的响应。这就要求主机I2C控制器必须支持从设备时钟拉伸功能,否则通信会失败。
3.4 场景四与五:处理重复地址的系统
在复杂的多摄像头系统中,经常会遇到多个同型号传感器具有相同I2C地址的情况。传统I2C总线无法区分它们,但BCC的别名机制完美解决了这个问题。
系统拓扑:两个独立的FPD-Link III链路(Link1和Link2)。每个链路的远端都有一个DS90UB913和一个地址为0x50的摄像头。两个DS90UB913的地址可能相同(默认都是0x58),两个摄像头的地址肯定相同(0x50)。本地有两个DS90UB914(DES1地址0x60,DES2地址0x61)连接在同一主I2C总线上。
解决方案:
- 区分串行器:虽然两个远程串行器物理地址都是0x58,但我们可以为它们配置不同的别名。
- 在DES1上,设置
SER Alias = 0x57。 - 在DES2上,设置
SER Alias = 0x59。 - 这样,主机用0x57访问Link1的串行器,用0x59访问Link2的串行器。
- 在DES1上,设置
- 区分摄像头:两个摄像头的物理地址都是0x50,我们同样为它们配置不同的别名。
- 在DES1上,设置
Slave ID[0] = 0xA0 (0x50<<1),Slave Alias[0] = 0xA2 (0x51<<1)。 - 在DES2上,设置
Slave ID[0] = 0xA0 (0x50<<1),Slave Alias[0] = 0xA4 (0x52<<1)。 - 这样,主机用0x51访问Link1的摄像头,用0x52访问Link2的摄像头。
- 在DES1上,设置
通过这套别名系统,主机I2C总线上看似有四个独一无二的设备(0x57, 0x59, 0x51, 0x52),完美实现了对物理地址重复的远程设备的独立寻址。
4. 代理主设备SCL时钟配置:掌控远程总线速率
当DS90UB913或DS90UB914作为代理主设备在远端I2C总线上发起通信时,它需要自己产生SCL时钟。这个时钟的频率由本地主机通过配置SCL High Time和SCL Low Time寄存器来控制。
计算原理: 寄存器的值代表时间片的个数,每个时间片在标称振荡器频率下为50ns。
- SCL高电平时间 =
SCL High Time寄存器值 × 50ns - SCL低电平时间 =
SCL Low Time寄存器值 × 50ns - SCL周期 = 高电平时间 + 低电平时间
- SCL频率 = 1 / SCL周期
例如,默认值0x82(十进制130):
- 高/低电平时间 = 130 × 50ns = 6.5µs
- 周期 = 13µs
- 频率 ≈ 1 / 13µs ≈ 77 kHz
配置示例: 假设远程摄像头传感器支持标准模式(100kHz)和快速模式(400kHz)。我们需要根据其数据手册中的时序要求(特别是t_{LOW},t_{HIGH},t_{SU:DAT}等参数)来配置。
目标:100kHz远程SCL
- 周期应为10µs。通常高低电平各占约5µs。
- 寄存器值 = 期望时间 / 50ns = 5µs / 0.05µs = 100 (十进制) = 0x64 (十六进制)。
- 因此,设置
SCL High Time = 0x64,SCL Low Time = 0x64。
目标:400kHz远程SCL
- 周期为2.5µs。高低电平时间需满足传感器最短要求,假设各需至少0.6µs和1.3µs。
- 我们可以配置为高电平0.6µs,低电平1.9µs。
- 高电平寄存器值 = 0.6µs / 0.05µs = 12 = 0x0C。
- 低电平寄存器值 = 1.9µs / 0.05µs = 38 = 0x26。
- 注意:必须同时满足芯片本身的最小高低电平时间(DS90UB913/914数据手册规定)和从设备的要求。
注意事项:
SCL Low Time还有一个重要作用,它同时被用作BCC通信中,从设备在SCL上升沿之前准备数据(SDA建立时间)的窗口。设置过小的SCL Low Time可能导致从设备数据建立时间不足,从而通信失败。在高速通信时,需要仔细权衡。
5. 数据吞吐量分析与BCC延迟影响
通过BCC进行I2C通信并非没有代价,其主要开销来自于BCC延迟。理解这个延迟对评估系统性能和设置超时时间至关重要。
5.1 BCC延迟从何而来?
BCC通道以83.33kHz的帧率(周期12µs)工作,将I2C命令打包成30位的帧在反向通道上传输。这意味着:
- 本地代理从设备(如DS90UB914)收到主机的I2C字节后,需要等待下一个BCC帧起始点才能发送。
- 数据在串行链路上传输需要时间(前向通道延迟,约1µs)。
- 远端代理主设备(如DS90UB913)收到BCC帧后,需要解析并在远程总线上执行I2C操作。
- 响应数据再经历同样的过程返回。
因此,一次远程I2C字节传输的典型往返延迟在12µs到24µs之间。这远大于本地I2C总线上的一个位时间。
5.2 有效比特率计算
应用报告给出了一个估算有效比特率的公式:有效比特率 = 9 bits / [(Host_bit * 9) + (Remote_bit * 9) + FCdelay + BCCdelay]
Host_bit: 主机I2C总线一位的时间(1/频率)。Remote_bit: 远程I2C总线一位的时间。FCdelay: 前向通道延迟,约1µs。BCCdelay: 双向控制通道延迟,典型值12µs。9 bits: 一个I2C字节(8位)加上一个应答位。
举例计算:主机100kbps,远程77kbps(默认)。
- Host_bit = 10µs, Remote_bit ≈ 13µs。
- 有效比特率 = 9 / (910µs + 913µs + 1µs + 12µs) = 9 / (90+117+1+12)µs = 9 / 220µs ≈ 41 kbps。
可以看到,由于BCC延迟的固定开销,有效吞吐量远低于本地或远程总线的标称速率。下表对比了不同配置下的典型性能:
| 主机速率 | 远程SCL速率 | SCL High Time | SCL Low Time | 近似有效比特率 | 适用场景 |
|---|---|---|---|---|---|
| 100 kbps | 77 kHz (默认) | 0x82 | 0x82 | ~41 kbps | 默认配置,兼容性好 |
| 100 kbps | 100 kHz | 0x64 | 0x64 | ~47 kbps | 平衡延迟与远程速率 |
| 400 kbps | 100 kHz | 0x64 | 0x64 | ~72 kbps | 主机快,远程设备慢时优化 |
| 400 kbps | 400 kHz | 0x19 | 0x19 | ~155 kbps | 高速批量配置 |
5.3 优化吞吐量的实战技巧
- 使用突发传输:I2C协议中,每次传输都有起始条件、地址字节、停止条件等开销。通过使用重复起始条件进行连续读写(即I2C的“块传输”模式),可以显著减少这些开销占总传输时间的比例,从而提升有效数据吞吐量。在配置传感器时,尽量将多个寄存器的读写合并为一次突发操作。
- 主机速率与远程速率匹配:上表显示,当主机速率(400kbps)远高于远程速率(100kbps)时,有效速率受限于远程端。适当提升远程SCL速率能带来更大收益。但前提是远程从设备支持。
- 权衡延迟与速率:盲目提高远程SCL频率可能减少
SCL Low Time,导致从设备数据建立时间不足。务必以从设备数据手册的时序要求为第一准则。 - 超时设置:由于时钟拉伸的存在,主机I2C控制器必须设置合理的超时时间。这个时间应大于
2 * BCCdelay + 远程设备响应时间。对于典型12µs BCC延迟,建议主机超时时间至少设置在50-100ms量级,以容纳多次重试和远端设备的处理时间。
6. 常见问题排查与调试实录
在实际硬件调试中,BCC I2C通信失败是常见问题。以下是我在项目中总结的一套排查流程和常见坑点。
6.1 通信完全失败(无ACK)
现象:主机发送地址字节后,收不到ACK(应答)。
排查步骤:
- 检查物理链路:首先确认FPD-Link III视频链路是否已经锁定(检查
RX_LOCK引脚或状态寄存器)。没有视频链路,就没有BCC。 - 确认本地通信:尝试与本地解串器(DS90UB914)本身通信,读写其一个已知寄存器(如0x00的Device ID)。这可以验证主机到本地芯片的I2C通路是否正常。
- 验证BCC使能:检查本地和远端芯片的配置寄存器,确保BCC功能已使能(通常涉及
BCC_CONFIG等寄存器,需查阅具体数据手册)。 - 检查别名配置:确认你试图访问的“别名”地址,是否已经在本地芯片的
SER Alias或Slave Alias寄存器中正确配置(非零值),并且对应的Slave ID寄存器也正确填写了远程设备的物理地址(左移1位后)。 - 检查Pass Through位:确保
I2C Pass Through位(DS90UB914的0x03[3]或DS90UB913的0x03[2])已被设置为1。 - 确认远程设备地址:如果可能,暂时将远程从设备直接连接到主I2C总线,验证其物理地址是否正确,以及它是否正常工作。
6.2 通信不稳定或数据错误
现象:偶尔能成功,但经常出现NACK或读回数据错误。
排查步骤:
- 检查电源与地:确保本地和远端芯片的电源干净、稳定,两地之间的地参考电位差在允许范围内。长距离传输时,地环路噪声是常见干扰源。
- 检查SCL/SDA上拉电阻:BCC两端的I2C总线都需要上拉电阻。确认阻值是否合适(通常3.3V系统用4.7kΩ,长线或高速时可能需要更小,如2.2kΩ),并且电阻已正确连接。
- 审视SCL时序配置:这是高频发区。使用逻辑分析仪或示波器,测量远端I2C总线上的SCL/SDA波形。
- 检查SCL频率是否与配置相符。
- 重点检查SDA的建立时间:在SCL上升沿之前,SDA上的数据必须稳定一段时间(
t_{SU:DAT})。这个时间由远程代理主设备的SCL Low Time决定。如果从设备数据准备慢,就需要增大SCL Low Time寄存器值。 - 检查从设备要求的保持时间(
t_{HD:DAT})是否满足。
- 主机时钟拉伸支持:百分之百确认你的主机I2C控制器驱动或硬件支持从设备时钟拉伸。很多MCU的I2C外设在默认配置下不支持,需要特别开启。通信失败时,用示波器看主机的SCL线是否在地址字节后一直被拉低(被DS90UB914拉伸),如果是,而主机却超时复位了总线,那就是主机不支持拉伸。
- 降低速率:尝试将主机和远程的I2C速率都降到最低(如10kHz),看通信是否稳定。如果稳定,再逐步提高,找到系统的稳定边界。
6.3 多设备系统中的地址冲突
现象:配置多个链路后,对某个别名的操作会错误地影响到其他设备。
排查步骤:
- 检查别名唯一性:确保在同一主I2C总线下,所有本地芯片(多个DS90UB914)上配置的所有
SER Alias和Slave Alias值都是唯一的。不能有两个芯片使用相同的别名。 - 慎用Pass Through All:确保除了调试目的,不要使能
I2C Pass Through All位。该模式下,任何未匹配本地Device ID的地址都会被转发,极易导致命令发错链路。 - 验证自动加载的ID:在复杂系统中,确认每个本地芯片的
SER ID寄存器自动加载的值是否符合预期。有时链路干扰可能导致加载错误地址。
6.4 调试工具与技巧
- 逻辑分析仪是你的最佳伙伴:同时抓取主机侧和远程侧的I2C波形进行对比,是定位问题最直接的方法。你可以清晰看到命令是否被转发、延迟有多大、远端响应是否正常返回。
- 善用芯片状态寄存器:DS90UB913/914有丰富的状态寄存器,可以报告BCC错误、CRC错误、链路状态等。在通信失败后读取这些寄存器,能获得宝贵的诊断信息。
- 分步测试法:
- 第一步:只连一个链路,确保基础通信正常。
- 第二步:配置与远程串行器通信。
- 第三步:配置与一个远程从设备通信。
- 第四步:再增加第二个链路和从设备。 这种递进的方式能有效隔离问题。
- 编写健壮的初始化代码:初始化流程应包括:等待链路锁定 -> 读取并验证自动加载的远程ID -> 配置别名寄存器 -> 使能Pass Through -> 进行简单的远程寄存器读写测试(如读取远端芯片的ID寄存器)以确认整个通路畅通,然后再进行应用层操作。