最近我把一个测试环境命名成了USB TO I2C_(Excel)_Scan ---- 3400KHz总线速率测试_A,名字里信息量比较大:USB转I2C适配链路、Excel记录、I2C扫描,外加一个很扎眼的频率后缀3400KHz。这个环境要干的事也很直接——拿电脑上的USB转I2C适配器扫出总线上所有从机地址,把ACK结果整理成Excel矩阵,再单独把SCL时钟拉到接近3.4MHz这种高速档位做一轮压测,看看哪些器件真的扛得住。
做板级调试的人都知道,I2C绝大多数时候都在100k/400k的舒适区里跑,但现在的传感器、PMIC、EEPROM、触摸屏控制器不少都标注支持1MHz甚至3.4MHz高速模式。datasheet上写归写,实际在PCB或杜邦线环境里能不能稳定跑3.4M,完全是另一回事。这篇文章就是把这套环境从硬件选型、驱动模式、扫描逻辑到3.4M时序测量完整复盘一遍,重点讲我在高频下踩过的坑和排查思路。适合正在做嵌入式驱动、板级调试,或者准备选USB-I2C调试工具的朋友参考,尤其是想给低速总线做压力测试的人。
1. 为什么偏偏是3400KHz:I2C速率等级与压测动机
1.1 I2C的五个速率档位对照
I2C协议从80年代末到现在,速率档位一张表就能说清楚:
| 模式 | 速率上限 | 常见应用 |
|---|---|---|
| 标准模式 | 100k | EEPROM、RTC、老传感器 |
| 快速模式 | 400k | 大部分常规传感器、PMIC |
| 快速模式+ | 1M | 高速传感器、部分存储芯片 |
| 高速模式(Hs-mode) | 3.4M | 高频传感器、高吞吐存储 |
| 超快模式(UFm) | 5M | 单向传输场景,极少见 |
标题里的3400KHz就是3.4MHz,对应I2C高速模式的上限。很多工程师对I2C的认知停在400k,突然看到3.4M会有点不适应,觉得“这能稳定吗”。实际评估下来,新版的高精度ADC、光线传感器、触控IC,甚至某些安全芯片,确实要求在1M以上跑,否则内部采样吞吐跟不上。把总线速率贴上3.4M上限去压测,本质上是对信号完整性和从机兼容性的一次提前体检。
1.2 一个SCL周期到底有多紧张
3400KHz意味着SCL周期大约是294纳秒,算一下就是:
T = 1 / 3400000 ≈ 294 ns294纳秒是什么概念?一个普通MCU的GPIO翻转,如果靠软件bit-bang,一次输出高电平或低电平可能就要100纳秒以上,再加上函数调用、循环判断、IO读写延迟,实际搭出来的波形根本不像方波。这也是为什么标题里特别注明“USB TO I2C”,而不是“USB转串口”。普通USB转UART芯片(比如FT231X)内部没有I2C时序引擎,顶多把SCL/SDA当GPIO用软件模拟,这种方案跑到1M都很吃力,更别提3.4M。选适配器一定要盯准“原生硬件I2C控制器”或“MPSSE引擎”这类能力。
I2C在3.4M下还有一个关键点:上升沿必须足够短。总线上的上拉电阻和寄生电容组成RC,上拉太大、线缆太长,波形上升沿就会变缓。早期调试时我用4.7k上拉加30厘米杜邦线,3.4M下看到的SCL几乎是三角波,从机直接不响应。后文我会专门讲上拉电阻怎么选,这里先记住一句话:高速I2C对物理连接的要求,比协议本身苛刻得多。
1.3 为什么环境名写3400KHz而不是3.4MHz
有朋友问过我,名字里用3400KHz是不是为了避开3.4MHz整数?不是。实际原因是,USB转I2C适配器内部一般用锁相环分频产生SCL,得到的是一个近似频率,不是精确的3400000Hz。配置成3.4M之后,用示波器测出来的可能是3.389M、3.402M,总之会在3400KHz附近波动。测试环境命名直接采用实测值,既符合记录习惯,也提醒后人这个“3400KHz”是实测结果而非理论值。
把频率后缀写进环境名的另一个好处是:每次复测报告里,标题本身就是一组可追溯的参数。我们项目中同类环境还有400KHz总线速率测试_B、1MHz总线速率测试_C,回看Excel记录时,扫一眼标题就知道当时跑的是哪一档。这算是个团队约定,但对个人调试同样适用。
2. 硬件与上位机链路:USB转I2C怎么搭才能测高频
2.1 适配器选型:不是所有USB转I2C都能跑3.4M
如果只是扫个地址,随便一个USB转I2C小板都行,但要测3400KHz,选型就窄了很多。主流方案有FT232H、FT2232H、CH341、CY7C65215这类芯片做的适配器,它们之间差异很大:
| 适配器芯片 | USB速度 | I2C最高速率 | 是否适合3.4M测试 | 备注 |
|---|---|---|---|---|
| FT232H | USB 2.0 High Speed | 约3.4M | 适合 | MPSSE引擎,驱动成熟 |
| FT2232H | USB 2.0 High Speed | 约3.4M | 适合 | 双通道,可同时挂两路 |
| CH341A | USB 1.1/Full Speed | 通常400k~1M | 不适合 | 便宜,适合常规调试 |
| CY7C65215 | USB 2.0 High Speed | 视版本而定 | 部分可以 | 需要确认具体固件 |
我通常直接用带FT232H的适配器板,原因有几个。第一,FT232H内置MPSSE,可以自动化生成I2C的START、STOP、ACK检测时序,而不是纯软件模拟,稳定性和速度都有保障。第二,D2XX驱动支持批量FIFO传输,一次可以把一整包I2C字节下发给芯片,不用每字节来回USB控制传输,这对高频连续读写的吞吐影响很大。第三,FTDI的生态成熟,Windows/Linux都有库支持,后面接Python脚本或C程序都方便。
选型时我踩过一个小坑:买过一款号称支持I2C的USB转UART模块,芯片是FT231X,设备管理器里识别成“USB Serial Port”。它确实能用GPIO模拟I2C,但速率极限连100k都不稳定。这种方案适合临时点灯,不适合做“总线速率测试”。所以看适配器时不要只认“USB转I2C”这几个字,还要确认芯片型号和内部是否有硬件I2C控制器或MPSSE。
2.2 驱动模式:VCP和D2XX千万别搞混
FTDI芯片有两套驱动,这一点很多人会卡住。VCP驱动是把设备模拟成COM口,系统里出现“COMx”,方便普通串口工具使用。D2XX驱动则是直接访问FTDI设备,供libMPSSE-I2C、PyFTDI这类库调用。
做3.4M I2C测试时,如果你的USB转I2C适配器用的是FT232H,必须确保系统里加载的是D2XX模式,否则MPSSE操作会失败或者超时。早期我把适配器插上,设备管理器看到COM口就以为能用了,结果调用库一执行就报“device not found”,排查半天发现是驱动处于VCP模式。
切换驱动也不难。用FTDI提供的FT_PROG软件读取EEPROM配置,或者用驱动替换工具把设备驱动从VCP切到WinUSB/D2XX。切完需要重新拔插USB线,让系统重新枚举。
2.3 Excel在测试环境里到底记录什么
名字里的Excel部分,很多人以为只是个噱头,其实它承担了“在线记录本+对比基线”的角色。实际调试中,现场扫完地址,只打印到屏幕根本不好复盘,尤其要对比多个样品、多组频率时,Excel矩阵最直观。
我通常建两个Sheet。一个Sheet叫“地址扫描矩阵”,16列乘8行,横坐标是地址低四位,纵坐标是高三位,有ACK的地址在对应格子填0x48,没ACK的留空,一眼就能看出总线挂了几颗设备、有没有地址冲突。另一个Sheet叫“速率测试记录”,字段包括:
- 环境名称
- 适配器型号
- 目标从机地址
- 配置频率
- 实测SCL频率
- tHIGH / tLOW / 上升沿 / 下降沿
- 总线负载电容估算
- ACK是否正常
- 读写校验是否通过
- 备注
这些字段全部用文本和数字分开存,后续做回归对比时,脚本只需要读两个Sheet就能自动比较,不用来回翻日志。Excel处理框架其实很省事,扫描结果我用Python写成CSV,再导入Excel,既保留原始数据又能做透视表和分析公式。
3. 一步步实操:连线、扫地址再到3.4M压测
3.1 硬件连接与上拉电阻配置
硬件连线上,SCL、SDA、GND三根是必须的。如果从机模块是独立供电,还需要共地,否则参考电位不一致,I2C电平判断会乱。适配器这边如果有VCC输出,可以从适配器取电,但要先确认电平是否匹配——大部分FT232H适配器支持3.3V或5V跳线,别拿5V直接怼3.3V的传感器。
上拉电阻是高频测试的重灾区。I2C总线上一般要求SCL/SDA各有一个上拉电阻到电源,阻值决定上升沿速度。低频下4.7k甚至10k都能跑,但到3.4M,RC时间常数必须足够小。参考选择如下:
| 目标速率 | 上拉电阻建议 | 最大总线电容参考 |
|---|---|---|
| 100k | 4.7k~10k | 400pF |
| 400k | 2.2k~4.7k | 200pF |
| 1M | 1k~2.2k | 100pF |
| 3.4M | 1k左右 | 40pF以内 |
这里要特别强调:总线电容不只是线缆电容,还有每个从机引脚的输入电容、示波器探头电容、USB适配器引脚电容。3.4M下我建议用短线、直接焊接或者最少杜邦线,线长尽量控制在10厘米以内。实测中,4.7k上拉加30厘米杜邦线,3.4M波形基本没法看;改成1k上拉加5厘米短线后,波形才接近方波。
如果适配器输出电平和从机不在同一个电压域,中间要加电平转换。但注意,3.4M下别用那种带使能开关的双向电平转换模块,开关切换本身有延迟,高频下会出现毛刺。优先选择低延迟的双向电平转换芯片,或者干脆统一电平到3.3V。
3.2 I2C设备扫描原理与实现
扫描原理很简单:7位地址空间从0x03到0x77(0x00~0x02和0x78~0x7F是保留地址,用于广播、10位地址等特殊用途),主机对每个地址发送START、地址字节(方向为写)、等待ACK。如果从机存在并且自己的地址匹配,就会在第9个时钟把SDA拉低,产生一个应答位。主机检测到SDA被拉低,就认为该地址有设备。
要注意探测动作要“轻”。有的I2C设备对读操作有副作用,比如读寄存器会清中断标志、改变内部状态。所以扫描时尽量只发地址字节,不写寄存器地址,不写数据。如果库默认探测方式是“读一字节”,注意确认是否会造成影响。
我通常用PyFTDI在Windows下做扫描,逻辑大概这样:
import csv from pyftdi.i2c import I2cController i2c = I2cController() i2c.configure('ftdi://ftdi:232h/1') found = [] for addr in range(0x03, 0x78): ok = False try: port = i2c.get_port(addr) # 只做一个字节的读探测,确认ACK port.read(1) ok = True except Exception: ok = False if ok: found.append(addr) print('found devices:', [hex(a) for a in found]) # 写CSV,便于导入Excel with open('i2c_scan.csv', 'w', newline='', encoding='utf-8-sig') as f: w = csv.writer(f) w.writerow(['addr7', 'ack']) for a in found: w.writerow([f'0x{a:02X}', True])这段代码不做写操作,只是用读探测去看ACK是否存在。扫描结果写入CSV后,Excel直接打开就能生成矩阵。如果你在Linux环境下调试,也可以用i2cdetect -y -r 1,-r参数代表用读方式探测,减少对从机的副作用。
3.3 3400KHz总线速率测试方法
扫描完成只是第一步,真正硬核的是把SCL拉到3400KHz去压测。配置频率的接口很简单,以libMPSSE-I2C为例:
I2C_CLOCK_CONFIG config; config.ClockRate = 3400000; /* 目标3400kHz */ config.LatencyTimer = 255; config.flags = I2C_ENABLE_DRIVE; /* 根据硬件调整 */ I2C_Device_Init(handle, &config);配置完先别急着读写,第一步是拿示波器量SCL。测量四组参数:实际频率、高电平时间tHIGH、低电平时间tLOW、上升沿时间tr。示波器带宽建议至少100M,最好500M以上,探头用10x,地线用弹簧地线而不是长鳄鱼夹。3.4M下高电平时间和低电平时间都非常短,普通无源探头的地线夹会引入振铃,测试结果完全失真。
I2C规范里不同模式的时序要求差异很大,拿tHIGH来说,标准模式最小4微秒,快速模式最小0.6微秒,快速+模式最小0.26微秒,高速模式最小0.06微秒。3.4M周期约294ns,如果占空比按高电平:低电平约1:2算,tHIGH大约100ns左右,tLOW大约200ns左右,这已经接近很多适配器输出能力的极限。测量时如果发现tHIGH或者tLOW明显偏短,或者上升沿超过几十纳秒,后续传输会不稳定。
测完静态波形,再做实际载荷测试。我常用的载荷有三种:向EEPROM连续写一页256字节然后读回校验;连续读传感器数据寄存器1000次并统计结果;如果有多个从机,用适配器在两个地址之间反复切换读写,模拟真实调度。测试过程中把ACK异常次数、读取错误数、超时次数记下来,填进Excel的“速率测试记录”Sheet,这就是频率压测的核心产物。
这里有个概念要澄清:真正的I2C高速模式(Hs-mode)在进入高速传输前,主机需要先发送一个“主代码”(0000 1xxx)来唤醒支持高速模式的从机。很多USB转I2C适配器所谓的支持3.4M,只是把SCL时钟频率拉高,并不一定会发送主代码序列,因此严格来说它是在跑“高速时钟”而不是完整的Hs-mode协议。这意味着,某些只支持Hs-mode、普通快速模式不工作的从机,在普通适配器上可能依然无法通信。测试时我会用示波器抓START之后的第一个字节,确认主代码行为,再决定要不要把结果当“高速模式兼容性”来看。
4. 我在这个项目里踩过的五个坑
4.1 高频扫描误报NACK
第一次做3.4M全总线扫描,我把所有地址从0x03到0x77扫了一遍,结果大部分设备都NACK或者时有时无,一度怀疑适配器坏了。后来复盘发现原因很直白:很多从机压根不支持3.4M,它们在400k以下才响应,高频扫描自然全灭。另外,普通USB适配器没有发主代码,遇到真正高速模式才能工作的从机,也会失败。
这个教训让我把流程改成了两步走:先用100k或400k做常规扫描,拿到总线上所有从机地址;再挑出datasheet里明确支持1M或3.4M的器件,单独对单个地址做高频测试。全总线高频扫描只适合验证总线信号质量,不适合判断从机是否存在。
4.2 示波器测量值失真:地线夹的坑
有段时间我发现SCL波形总有振铃,频率越高越明显,高电平处有明显过冲。开始以为是适配器驱动能力问题,后来把探头上的长地线夹换掉,用弹簧地线直接点在GND焊盘上,振铃立刻减轻很多。原因是长地线夹形成一个大电感回路,高频下会和探头电容谐振,产出的振铃是测量系统自身的,不是总线真实波形。
测量3.4M信号时,探头尽量用10x档,1x档带宽不够,会把上升沿拉缓。如果条件允许,用有源探头或者差分探头,测量结果会更接近真实。还有,示波器采样率至少10倍于信号频率,即用1GHz采样率的示波器测3.4M非常充裕,但要小心显示正弦波,实际上是带宽不够造成的高频分量丢失。
4.3 USB链路拖后腿:SCL波形出现周期性缺口
3.4M压测时,我注意到示波器上SCL波形每隔一段时间会有一段明显拉长,就像被谁暂停了几十微秒。这种“缺口”不是I2C协议里的时钟拉伸,而是USB适配器和PC之间传输调度造成的。USB转I2C适配器本质上是个USB外设,CPU每次通过USB下发I2C数据,中间要经过USB协议栈、驱动缓冲、系统调度。如果代码是逐字节调API,每发一个字节都要等USB往返,SCL自然会出现间隙。
解决办法有几个。优先用D2XX模式的批量FIFO传输,一次下传一大包字节,让适配器对着一串缓存自动发完,减少USB交互次数。把FTDI的LatencyTimer配置调大,减少USB中断频率。另外,尽量避免把适配器识别为COM口后再来做I2C,COM口那套轮询机制本来就慢,走D2XX才能发挥MPSSE的真实速度。实测下来,逐字节发送时3.4M连续性很差,改成批量发送后,SCL波形才保持相对稳定。
4.4 驱动误判:把FT231X当FT232H用
这是一个比较隐蔽的选型坑。早期同事给我一块“USB转I2C”小板,芯片丝印FT231X,设备管理器里也装了VCP驱动,能看到COM口。我想当然以为能用MPSSE,结果调用I2C接口全部失败。后来查芯片手册才发现FT231X是USB转UART芯片,内部根本没有MPSSE,I2C只是部分玩家通过bit-bang硬凑出来的功能。
排查时先用设备管理器看硬件ID和芯片类型,也可以用FT_PROG读取芯片EEPROM确认型号。如果系统识别成“USB Serial Port”而不是“USB High-Speed I2C/SPI”,大概率是UART芯片,不是I2C适配器。遇到这种情况别浪费时间,直接换FT232H或FT2232H适配器。
4.5 Excel数据导入中的格式坑
扫描结果用CSV导入Excel时,地址如果写成纯数字48,后面做对比和公式处理时非常痛苦。因为Excel会把48当成数值,而I2C地址更适合用十六进制文本表示。我的经验是地址统一用文本格式,写成0x48,导入CSV时该列保持文本,或者导入后立即设成文本格式,避免被Excel隐性转数值。
另外CSV编码也有讲究。Python写CSV时用utf-8-sig(带BOM),Excel打开才不会乱码中文列名。如果你要快速把Markdown表格转成Excel,可以先把Markdown表格的竖线去掉、转成Tab分隔符,再粘贴到Excel里,比直接拉表格快捷很多。地址矩阵里留空格与“未检测”是两个含义,我一般留空表示无ACK,填ERR表示有设备但通信异常,这样后续筛选时能区分不同状态。
5. 高频I2C压测速查表与后续扩展建议
5.1 一页纸速查:3400KHz测试前过一遍
测试前最好先跑一遍下面的核对表,能省掉很多重复排查:
| 项目 | 建议值或注意事项 |
|---|---|
| 适配器芯片 | FT232H / FT2232H,确认有MPSSE |
| 驱动模式 | D2XX,设备管理器不是COM口 |
| 上拉电阻 | 1k左右,总线电容控制在40pF内 |
| 线缆长度 | 尽量10厘米以内,避免长杜邦线 |
| 示波器设置 | 500M带宽以上,10x探头,弹簧地 |
| 配置频率 | 3.4M附近,实测后记录实际值 |
| 扫描策略 | 先100k/400k扫全总线,再高频单测特定设备 |
| 载荷测试 | EEPROM写读回,或连续读寄存器1000次 |
| 主代码确认 | 抓START后首字节,判断是否进入Hs-mode |
| Excel记录 | 地址用文本格式,CSV用utf-8-sig |
Excel记录Sheet的字段建议固定下来,这样后续多个版本能自动对比。参考字段:环境名称、适配器型号、目标从机地址、配置频率、实测SCL频率、tHIGH、tLOW、tr、tf、负载电容估算、ACK是否正常、读写校验结果、备注。有时间戳的话,用毫秒时间戳字段,不要用HH:mm:ss,不然排序和间隔计算很麻烦。
5.2 后续还可以怎么扩展
这套环境做完以后,有几个很自然的扩展方向。一个是把扫描矩阵和速率测试记录做成自动回归:每次改完驱动、固件或硬件连接,重新跑一遍,脚本对比两次Excel,标出新增、消失、异常的地址,就能快速定位问题器件。
另一个方向是给自己的高速从机写个仿真模型。之前有人搜“i2c读写eeprom代码 verilog”,如果手里有FPGA开发板,完全可以在FPGA里写一个支持3.4M的I2C从机模型,挂在适配器上,用这套环境验证适配器在高速下的信号质量。Verilog从机模型的好处是你可以精确控制ACK时序、时钟拉伸行为,比真实芯片更容易暴露主机的时序缺陷。
如果测试中遇到大量I2C事务压测,还可以结合USB抓包工具,分析适配器和PC之间的USB枚举、批量传输间隔,定位是不是USB层成为了瓶颈。高频I2C的问题经常是“总线看起来对,USB传输背锅”,抓包以后能直观看到每一笔USB请求的间隔和延迟。
最后一个小建议:环境名里的“_A”这种后缀,代表同一频率下的第一轮回归。后续可以把相同频率的多次测试做成_B、_C,Excel里也多建一个“汇总对比”Sheet,每次跑完自动追加一行。这样累计几轮后,任何一次环境改动导致的速率退化都会在表里留下痕迹。
整体做下来,我最大的体会是:3.4M的I2C测试,瓶颈往往不在I2C协议本身,而在物理连接、测量方法、USB传输调度和驱动模式这些外围环节。先低速扫描确认从机名单,再高压测特定设备,是一种更稳妥的项目推进方式。这套环境现在已经成为我们团队做总线兼容性验证的标配,每次硬件改版后跑一轮,Excel里的矩阵和时序记录就是最直接的回溯依据。如果你正在折腾USB转I2C适配器,或者被高速I2C信号搞得头大,不妨按这个流程搭一套环境,把结果量化下来,问题会清晰很多。