ARTICLE DETAIL

资讯详情

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

USB转I2C批量扫描实战:1000KHz高速模式与Excel测试管理

USB转I2C批量扫描实战:1000KHz高速模式与Excel测试管理 1. 项目缘起与整体测试思路USB转I2C这个方向做嵌入式的人多少都碰过。手头有个传感器、EEPROM或者小屏主控板还没画好或者板子上的I2C总线被占满了最省事的办法就是拿个USB转I2C的小模块插电脑上先用上位机把器件跑通再说。这次要聊的就是这么一件事用USB转I2C模块配合Excel表格做批量扫描把总线速率拉到1000KHz看看在这个速率下器件还能不能稳定应答。标题里的“Excel”不是让你用Excel去算I2C时序而是指测试用例、寄存器地址、扫描结果都用Excel来组织。这个做法在实际项目里非常常见尤其是做产线测试或者器件兼容性验证的时候几百个寄存器地址不可能手敲用表格管理最直观。1000KHz这个速率也就是1MHz属于I2C的Fast Mode Plus档位标准模式是100KHz快速模式是400KHz再往上就是1MHz甚至3.4MHz的高速模式。很多器件手册标称支持400KHz但实际跑1MHz也能凑合有些则直接丢包。所以这个测试的核心目的就一个在1000KHz总线速率下用USB转I2C方案做一轮完整的扫描确认哪些地址能通、哪些不通、通的时候数据对不对。适合看这篇内容的人大概分三类。第一类是嵌入式软件工程师手头有USB转I2C工具想快速验证器件第二类是硬件工程师想了解I2C在1MHz下的实际表现评估上拉电阻和走线的影响第三类是测试岗需要一套可复现的扫描流程用Excel管理测试向量。不管哪一类核心诉求都是“别跟我讲太多理论告诉我怎么接、怎么配、怎么跑、跑不通怎么查”。我自己的设备组合是这样的一个FT231X芯片的USB转串口模块外挂一个I2C桥接芯片整体作为一个USB转I2C适配器用。上位机跑的是Windows环境用Python写脚本调用适配器的DLLExcel负责存地址表和结果。为什么不用现成的图形化工具因为批量扫描的时候图形界面点一次读一个地址几百个地址点下来手就废了脚本化是唯一出路。下面就把整个思路拆开从方案选型到实操细节再到踩过的坑一条一条说清楚。2. 方案选型与核心原理拆解2.1 为什么选USB转I2C而不是USB转串口加MCU很多人第一反应是拿个STM32或者Arduino写个I2C扫描程序通过USB转串口把结果打到串口助手上。这个方案不是不行但有几个麻烦。第一你得有块板子还得烧程序改一次扫描范围就要重新编译下载。第二串口打印的速度有限115200波特率下一行结果几十个字节扫256个地址要等好几秒。第三时序受MCU主频和中断影响1MHz下抖动不好控制。USB转I2C适配器的优势在于I2C时序由适配器内部的硬件状态机生成上位机只管发命令收数据。FT231X这类芯片本身是USB转串口但配合I2C桥接芯片后上位机通过USB批量传输把I2C读写请求发下去桥接芯片负责把串行数据转成I2C波形。这样做的好处是时序稳定1MHz下的时钟占空比和建立保持时间都由硬件保证不受电脑操作系统调度影响。坏处是灵活性差一点比如想发一个非标准的起始条件或者时钟拉伸得看适配器固件支不支持。我选这个方案核心原因是可脚本化和时序一致性。Excel里存好地址列表Python脚本读一行发一条I2C读命令结果写回Excel。整个过程不需要人工干预跑完一轮直接看表格里哪些地址有应答。对于1000KHz这种高速率硬件生成时序比软件模拟靠谱得多。2.2 I2C在1000KHz下的电气约束I2C总线速率提到1MHz不是改个配置就完事。标准模式和快速模式的上拉电阻取值逻辑在1MHz下要重新算。I2C总线的上升时间由RC时间常数决定R是上拉电阻C是总线电容。标准模式100KHz下上升时间要求小于1000ns快速模式400KHz下小于300ns到了1MHz上升时间要求更严具体数值看器件手册一般要求小于120ns到150ns。假设总线电容C是100pF这是PCB走线加器件引脚的典型值。上升时间t约等于2.2RC要满足t小于120ns算下来R要小于545欧姆。实际常用的4.7K上拉在100KHz下没问题400KHz就勉强1MHz下上升沿会明显变缓波形变成圆角器件可能识别不到高电平。所以1MHz测试时上拉电阻要换到1K甚至更小同时要确认适配器和从机器件能不能承受这个灌电流。还有一个容易忽略的点是总线电容。每加一个器件引脚电容大概10pF走线每厘米大概1pF到2pF。如果总线上挂了五六个器件电容轻松超过100pF。这时候就算上拉电阻降到1K上升时间也可能超标。解决办法要么减少挂载器件要么用I2C缓冲器做总线分段。我在测试时只挂了一个EEPROM和一个传感器总线电容控制在50pF以内上拉用1.5K1MHz下波形还算干净。2.3 Excel在测试中的角色定位Excel在这个项目里不是计算工具而是测试向量管理器和结果记录表。具体用法是这样第一个工作表存器件地址列表从0x00到0x7F共128行每行有地址、预期器件类型、备注。第二个工作表存寄存器地址针对特定器件比如EEPROM存0x0000到0x00FF。第三个工作表存测试结果Python脚本每扫一个地址就把应答状态、读到的数据、耗时写进去。为什么用Excel而不是CSV或者JSON因为调测试的时候经常要临时改地址范围、加备注、标红异常项。Excel的筛选、排序、条件格式用起来最顺手。而且硬件工程师和测试工程师都能直接打开看不需要装额外的工具。Python这边用openpyxl库读写xlsx文件兼容性好格式也不会丢。注意openpyxl读写大文件时内存占用较高如果地址表超过几千行建议拆成多个文件或者改用pandas加xlsxwriter。我这次只扫128个地址openpyxl完全够用。3. 硬件连接与适配器配置实操3.1 适配器识别与驱动安装FT231X芯片在Windows下需要装VCP驱动装好之后设备管理器里会出现一个COM口。但这个COM口是给串口用的I2C桥接芯片是挂在FT231X的某个GPIO或者I2C接口上的上位机要通过DLL调用不能直接开COM口发数据。我用的适配器厂商提供了一个DLL文件里面封装了I2C读写函数Python用ctypes加载这个DLL。驱动安装有个坑有些FT231X模块的VID和PID是默认值Windows自动装的驱动可能不匹配。这时候要在设备管理器里手动更新驱动指向厂商提供的inf文件。装好之后用厂商自带的上位机工具先试一下能不能扫描到I2C器件确认硬件通路没问题再上Python脚本。如果设备管理器里出现“未知设备”或者带黄色感叹号先检查USB线是不是只供电不传数据的那种。有些便宜的USB线只有电源线没有D和D-插上去设备能亮灯但电脑识别不到。换一根确认能传数据的线问题基本就解决了。3.2 I2C总线接线与上拉电阻选择接线本身很简单适配器的SDA接器件的SDASCL接SCLGND共地。但1MHz下接线长度要尽量短杜邦线超过10厘米就开始出现振铃和反射。我测试时用20厘米的杜邦线1MHz下波形已经有明显过冲后来剪短到5厘米波形干净很多。上拉电阻的接法有两种一种是适配器板上自带上拉通常是4.7K或者10K这种在1MHz下偏大另一种是自己外接上拉把适配器上的上拉跳线断开在SDA和SCL上各接一个1.5K电阻到3.3V。我选的是外接上拉因为要精确控制阻值。总线速率典型上拉电阻上升时间要求总线电容上限100KHz4.7K1000ns400pF400KHz2.2K300ns200pF1000KHz1K-1.5K120ns100pF这个表里的数值是经验值具体要看器件手册。有些器件在1MHz下要求上拉更小比如820欧姆但灌电流会增大要确认适配器的IO口能不能承受。我用的适配器IO口灌电流能力是3mA1.5K上拉在3.3V下灌电流约2.2mA留了余量。3.3 适配器固件配置与速率设置适配器上电后默认速率可能是100KHz。要跑到1000KHz得通过上位机发配置命令。厂商DLL里一般有SetI2CSpeed或者类似的函数传入速率参数。有些适配器用分频系数比如系统时钟48MHz分频48就是1MHz。具体看DLL文档。配置命令发下去之后最好用示波器或者逻辑分析仪抓一下SCL波形确认频率确实是1MHz。我遇到过配置成1MHz但实际输出只有800KHz的情况原因是适配器内部时钟源不是精确的48MHz有偏差。这时候要么接受这个偏差要么换一个时钟精度更高的适配器。逻辑分析仪抓I2C波形时采样率至少要10倍于总线速率1MHz总线建议用20MHz以上采样率。我用的逻辑分析仪是24MHz采样率抓1MHz波形刚好够用能看到起始条件、地址字节、ACK位和数据字节。如果采样率不够波形会混叠看不出时序细节。4. Python脚本驱动与Excel交互实现4.1 DLL加载与I2C读写函数封装Python通过ctypes加载DLL先定义函数原型。假设DLL里有两个核心函数I2C_Write和I2C_Read参数是设备地址、寄存器地址、数据缓冲区指针、长度。封装成Python函数之后调用起来就方便了。import ctypes from ctypes import c_uint8, c_uint16, POINTER dll ctypes.CDLL(i2c_adapter.dll) dll.I2C_Write.argtypes [c_uint8, c_uint16, POINTER(c_uint8), c_uint16] dll.I2C_Write.restype c_uint8 dll.I2C_Read.argtypes [c_uint8, c_uint16, POINTER(c_uint8), c_uint16] dll.I2C_Read.restype c_uint8 def i2c_write(dev_addr, reg_addr, data): buf (c_uint8 * len(data))(*data) ret dll.I2C_Write(dev_addr, reg_addr, buf, len(data)) return ret def i2c_read(dev_addr, reg_addr, length): buf (c_uint8 * length)() ret dll.I2C_Read(dev_addr, reg_addr, buf, length) if ret 0: return list(buf) else: return None返回值0表示成功非0表示失败。失败码具体含义要看DLL文档常见的有超时、NACK、总线忙等。脚本里要把失败码记下来写到Excel的备注列方便后续排查。4.2 Excel地址表读取与结果写入用openpyxl读地址表遍历每一行调用i2c_read把结果写回结果工作表。这里有个细节I2C扫描时对每个地址发一个读命令如果器件存在会回ACK如果不存在会回NACK。适配器DLL一般会把NACK作为失败返回所以脚本里判断返回值就能知道器件在不在。import openpyxl wb openpyxl.load_workbook(i2c_scan.xlsx) addr_sheet wb[地址表] result_sheet wb[扫描结果] result_sheet[A1] 地址 result_sheet[B1] 状态 result_sheet[C1] 读回数据 result_sheet[D1] 耗时(ms) row_idx 2 for row in addr_sheet.iter_rows(min_row2, values_onlyTrue): addr row[0] if addr is None: continue start time.perf_counter() data i2c_read(addr, 0x00, 1) elapsed (time.perf_counter() - start) * 1000 if data is not None: result_sheet.cell(rowrow_idx, column1, valuehex(addr)) result_sheet.cell(rowrow_idx, column2, valueACK) result_sheet.cell(rowrow_idx, column3, valuehex(data[0])) else: result_sheet.cell(rowrow_idx, column1, valuehex(addr)) result_sheet.cell(rowrow_idx, column2, valueNACK) result_sheet.cell(rowrow_idx, column3, value) result_sheet.cell(rowrow_idx, column4, valueround(elapsed, 2)) row_idx 1 wb.save(i2c_scan_result.xlsx)这段代码跑一遍128个地址大概几秒钟。1MHz下每个地址的读操作包括起始条件、地址字节、ACK、寄存器地址、ACK、重复起始、地址字节、读数据、NACK、停止条件总共大概几十个时钟周期算下来一个地址不到100微秒。128个地址理论上十几毫秒但USB传输和DLL调用有开销实际几秒是正常的。4.3 速率测试与耗时统计要测1000KHz下的实际速率不能只看配置值得用逻辑分析仪抓波形算时间。具体做法是让脚本连续读同一个地址100次逻辑分析仪抓SCL波形测量100次读操作的总时间除以100就是单次操作时间。再用单次操作的时钟周期数除以时间就是实际总线速率。我实测下来配置成1000KHz时逻辑分析仪测到的SCL频率是980KHz左右偏差2%。这个偏差来自适配器内部时钟源的精度属于可接受范围。单次读操作耗时约85微秒100次读操作8.5毫秒加上USB传输开销脚本里测到的单次耗时约120微秒。这个数据说明USB传输本身有大约35微秒的固定开销在批量扫描时这个开销会累积所以扫描速度不能只看I2C速率。实操心得如果扫描速度是瓶颈可以把多个读操作合并成一个批量命令。有些适配器DLL支持一次发多个I2C事务中间不插入USB传输这样能省掉大部分USB开销。我用的DLL不支持批量所以只能一个一个来。5. 1000KHz下的典型问题与排查记录5.1 器件不应答但波形正常这是最常见的情况。逻辑分析仪抓波形起始条件、地址字节、ACK位都正常但器件就是不回ACK。原因通常有三个地址不对、器件没上电、器件不支持1MHz。地址不对的情况最多。I2C的7位地址在波形上占一个字节的高7位最低位是读写位。比如器件地址是0x50写操作时波形上的字节是0xA0读操作是0xA1。脚本里传的地址是7位地址DLL内部会左移一位加上读写位。如果传错了比如传了8位地址就会扫不到。器件没上电或者电压不对也会导致不应答。用万用表量一下器件的VCC和GND确认电压在手册范围内。有些器件在1.8V下工作适配器输出3.3V直接接上去可能烧器件或者不工作需要电平转换。器件不支持1MHz的情况查手册确认。如果手册只写了400KHz那1MHz下不应答是正常的。这时候要么降速到400KHz要么换支持1MHz的器件。5.2 数据读回错误或全为0xFF地址能应答但读回的数据不对全是0xFF或者随机值。0xFF通常意味着总线被拉高没有器件驱动可能是读的寄存器地址不存在或者器件在1MHz下时序不满足导致数据错位。先降速到100KHz试一下如果100KHz下数据正确说明是速率问题。检查上拉电阻是否合适波形上升沿是否太缓。用逻辑分析仪看数据位的建立保持时间1MHz下数据在SCL高电平期间必须稳定如果数据变化太晚器件可能采到错误的值。还有一种可能是寄存器地址宽度不对。有些器件寄存器地址是8位有些是16位。脚本里如果按8位发16位地址的器件就会解析错。查手册确认地址宽度改脚本里的寄存器地址长度。5.3 USB传输超时或DLL返回错误脚本跑着跑着报USB超时或者DLL返回一个非零错误码。先检查USB线是不是松了换一个USB口试试。有些电脑的USB口供电不足适配器工作不稳定换到主板直出的USB口会好一些。如果错误码是“总线忙”说明上一次I2C操作还没完成下一次就发下去了。脚本里要在每次读写之间加一个小延时比如1毫秒给适配器留出处理时间。1MHz下I2C操作本身很快但USB传输和DLL内部处理需要时间不加延时容易冲突。还有一种情况是适配器固件版本太老不支持1MHz。联系厂商要最新固件或者换一个明确标称支持1MHz的适配器。我一开始用的适配器只支持400KHz配置成1MHz后直接返回错误换了适配器才跑通。现象可能原因排查方法解决措施器件不应答地址错误核对7位地址修正脚本地址器件不应答器件不支持1MHz查手册速率参数降速或换器件数据全0xFF寄存器地址不存在查手册寄存器表修正寄存器地址数据错位上拉电阻过大逻辑分析仪看上升沿换1K-1.5K上拉USB超时USB口供电不足换USB口用主板直出USB口DLL报错固件不支持1MHz查适配器规格升级固件或换适配器5.4 多器件挂载时的地址冲突总线上挂多个器件时如果两个器件地址相同就会冲突。I2C器件一般有地址选择引脚通过拉高或拉低来改地址。测试前要确认所有器件的地址不重复。我遇到过两个EEPROM地址都是0x50的情况其中一个的A0引脚悬空导致地址不确定。把A0接地后地址变成0x51冲突解决。还有一种情况是器件地址在1MHz下发生变化。有些器件在高速模式下地址会多一位比如标准模式7位地址高速模式变成8位。查手册确认高速模式下的地址格式脚本里要相应调整。6. 测试结果分析与速率优化建议6.1 1000KHz扫描结果解读我这次扫了128个地址实际应答的只有两个0x50和0x68。0x50是EEPROM0x68是实时时钟芯片。其他地址全是NACK符合预期。EEPROM在1MHz下读写正常读回的数据和之前用100KHz写入的一致。实时时钟芯片在1MHz下也能应答但读回的时间寄存器数据偶尔有跳变降速到400KHz后稳定。这个结果说明不是所有标称支持400KHz的器件都能跑1MHz。EEPROM这类存储器件时序余量大1MHz下没问题。实时时钟芯片内部有分频和计数逻辑1MHz下可能采样窗口不够导致数据不稳定。所以1000KHz测试不能只看能不能应答还要看数据对不对、稳不稳。6.2 从1000KHz降到400KHz的取舍如果1MHz下数据不稳定降到400KHz是最直接的办法。400KHz下上拉电阻可以用2.2K总线电容容忍度更高走线长度也可以放宽。代价是扫描时间变长128个地址在400KHz下大概要十几秒1MHz下几秒。对于产线测试几秒和十几秒的差别可能影响节拍但对于研发调试稳定性优先。我的建议是先用1MHz扫一遍记录哪些器件能通、哪些不能。能通的器件再跑一轮数据校验确认数据正确。不能通或者数据不稳的器件单独降到400KHz再测。这样兼顾速度和稳定性。6.3 批量扫描的脚本优化方向现在的脚本是单线程顺序执行一个地址一个地址读。如果地址多可以改成多线程但I2C总线是共享的多线程同时读写会冲突所以多线程不适合I2C扫描。更好的优化方向是减少USB传输次数把多个I2C事务打包成一个USB包发下去。这需要适配器DLL支持批量命令我用的DLL不支持所以没做。另一个优化是结果缓存。如果同一个地址连续读多次可以把结果缓存起来避免重复USB传输。但扫描场景下每个地址只读一次缓存意义不大。还有一个方向是用更快的USB适配器比如USB 2.0 High Speed的芯片USB传输开销从毫秒级降到微秒级。但I2C总线速率本身是瓶颈1MHz下USB开销占比不大换高速USB提升有限。7. 实操心得与避坑清单7.1 上拉电阻不要照搬手册手册上写的上拉电阻值通常是标准模式100KHz下的推荐值比如4.7K。到了1MHz这个值必须改。我一开始偷懒没改波形上升沿超过200ns器件偶尔应答偶尔不应答查了半天以为是地址问题。后来用逻辑分析仪看波形发现上升沿太缓换成1.5K上拉后立刻稳定。所以1MHz下上拉电阻一定要重新算不能照搬手册。7.2 逻辑分析仪是必备工具没有逻辑分析仪1MHz下的问题基本靠猜。波形上升沿、时钟占空比、数据建立保持时间这些参数用万用表看不出来。我用的逻辑分析仪是入门款24MHz采样率抓1MHz波形够用。如果预算够买采样率100MHz以上的能看到更细的时序细节。7.3 Excel文件要加版本号测试过程中经常要改地址表、加备注、调格式。如果不加版本号改乱了想回退都找不到旧文件。我的做法是文件名带日期和版本比如i2c_scan_20250101_v3.xlsx。每次大改之前先另存一份改坏了直接回退。7.4 脚本里加超时和重试USB传输偶尔会超时尤其是电脑负载高的时候。脚本里要对每个I2C操作加超时判断超时后重试一次。重试还失败就记录到Excel里继续扫下一个地址。不要因为一个地址失败就整个脚本崩掉那样跑一半的结果全丢了。7.5 器件手册的速率参数要仔细看有些器件手册写“支持400KHz”但小字备注“在特定条件下”。比如电源电压3.3V时支持400KHz1.8V时只支持100KHz。测试前把手册的速率参数和测试条件看清楚避免白忙活。7.6 总线电容要估算每加一个器件总线电容增加。如果总线上挂了多个器件就算上拉电阻降到1K上升时间也可能超标。测试前估算一下总线电容走线长度加器件引脚电容超过100pF就要考虑用I2C缓冲器或者减少挂载器件。7.7 适配器固件版本要确认不同批次的适配器固件版本可能不同对1MHz的支持也不一样。拿到适配器先读一下固件版本确认支持1MHz再往下做。我遇到过同一型号的适配器旧固件不支持1MHz新固件支持升级固件后问题解决。7.8 测试结果要交叉验证脚本扫出来的结果最好用示波器或者逻辑分析仪交叉验证一下。比如脚本说0x50应答逻辑分析仪抓波形确认地址字节确实是0xA0ACK位确实是低电平。脚本和波形对不上说明脚本或者DLL有问题要先解决再继续。8. 从单次测试到可复用测试框架这套东西跑通之后可以整理成一个可复用的测试框架。Excel模板固定下来地址表、寄存器表、结果表三个工作表。Python脚本封装成命令行工具传入Excel文件路径和适配器配置自动跑完输出结果。适配器DLL的加载和函数封装做成一个模块换适配器时只改这个模块。框架搭好之后新器件测试只需要改Excel里的地址表和寄存器表脚本不用动。产线测试时把Excel模板发给测试员填好地址范围跑脚本看结果。整个过程不需要写代码降低了门槛。后续还可以扩展加一个自动降速功能1MHz下不应答的地址自动降到400KHz重试加一个数据校验功能读回的数据和预期值对比不一致的标红加一个报告生成功能把结果表导出成PDF或者HTML方便归档。我个人在实际操作中的体会是USB转I2C做1000KHz扫描硬件上最关键是上拉电阻和走线软件上最关键是脚本的容错和结果记录。把这两块做好剩下的就是体力活。踩过的坑主要集中在波形问题和地址问题上逻辑分析仪和器件手册是排查的两大法宝。这套流程跑顺之后再测新器件就是改改Excel的事效率提升非常明显。
返回列表