TMS320C672x DSP I2C总线驱动开发:从寄存器配置到硬件设计实践
1. 项目概述与I2C总线核心价值在嵌入式系统开发尤其是像TMS320C672x这类高性能浮点DSP的应用中如何高效、可靠地连接和管理外围芯片是一个永恒的课题。你可能需要连接一个EEPROM来存储配置参数或者驱动一个音频编解码器CODEC又或者读取多个传感器的数据。面对这些需求你会立刻想到几种常见的串行总线SPI、UART和I2C。今天我想重点聊聊I2C这个看似简单却充满细节的“两线制”总线。为什么在资源相对丰富的DSP系统中我们依然要重视I2C答案在于其极简的硬件连接和强大的寻址能力。仅凭SDA数据线和SCL时钟线两根线你就能挂载上百个设备这对于PCB空间紧张、需要连接多个同类传感器例如多个温度传感器分布在板卡不同位置的系统来说是SPI通常需要4根线以上且片选线随设备数量增加而增加难以比拟的优势。TMS320C672x系列DSP内部集成了两个完全独立的I2C模块I2C0和I2C1这为系统架构设计提供了极大的灵活性。在我的一个多声道音频处理项目中我就曾将I2C0专门用于配置板上的音频ADC/DAC、数字音频接口接收器等核心音频芯片而I2C1则用来管理OLED显示屏、温度监控芯片等“辅助”设备。这种物理隔离避免了总线冲突也简化了软件驱动层的任务划分。C672x的I2C模块完全兼容Philips I2C规范2.1版支持标准模式100 Kbps和快速模式400 Kbps并且贴心地内置了可编程的噪声滤波器可以有效滤除小于50ns的毛刺这对于工作在复杂电磁环境下的工业设备至关重要。不过手册里也特别用“CAUTION”标出了一点C672x的I2C引脚使用的是标准的±8 mA LVCMOS缓冲器而非I2C规范中定义的慢速I/O缓冲器。这意味着在硬件设计时你可能需要在SDA和SCL线上串联一个小电阻比如几十到几百欧姆来抑制信号振铃和过冲这是确保长距离或多设备通信稳定性的一个关键实践细节很多初次接触的工程师容易忽略。2. I2C模块整体架构与寄存器地图解析要驾驭C672x的I2C模块不能只停留在调用API的层面必须深入其寄存器。你可以把整个I2C模块想象成一个精密的自动化车间而寄存器就是控制这个车间的各个开关、仪表和指令面板。从用户提供的资料中的框图可以看出模块结构清晰主要分为几个功能集群总线时钟生成、核心控制、数据收发、中断/DMA控制以及引脚控制。总线时钟生成是通信速率的基础。它由三部分协同工作首先是预分频器I2CPSC它对DSP的内核时钟SYSCLK2进行第一次“粗调”。假设你的SYSCLK2是150MHz而你想得到一个大致的12MHz模块输入时钟就可以将预分频值设置为12实际写入I2CPSC寄存器的值为11因为分频系数 寄存器值 1。预分频后的时钟进入位时钟发生器这里由**时钟高位分频寄存器I2CCLKH和时钟低位分频寄存器I2CCLKL**进行“精调”它们共同决定了SCL时钟高电平和低电平的持续时间最终合成符合I2C时序要求的SCL信号。计算具体速率时公式为I2C 时钟频率 模块输入时钟频率 / [(I2CCLKH 5) (I2CCLKL 5)]。这里的“5”是硬件的一个固定偏移量。例如要产生400kHz的快速模式时钟若模块输入时钟为12MHz则需要满足12MHz / (H L 10) 0.4MHz即H L 20。你可以设置I2CCLKH7I2CCLKL8此时H12 L13总和25实际频率约为480kHz或者通过调整预分频值来获得更灵活的配比。核心控制寄存器是模块的大脑。自身地址寄存器I2COAR定义了当DSP作为从设备时的7位或10位地址。从设备地址寄存器I2CSAR则在DSP作为主设备时指定你要访问的从设备地址。模式寄存器I2CCMDR是最关键的寄存器没有之一。它的一位MST决定主从模式一位TRX决定发送或接收还有位用于产生起始STT和停止STP条件、使能重复起始RS、选择地址模式XA、选择自由数据格式FDF等。扩展模式寄存器I2CEMDR则用于使能数字回环DLB测试、选择时钟模式等高级功能。数据计数寄存器I2CCNT在DMA或中断模式下非常有用你可以预设要传输的数据字节数当计数器减到0时模块会自动产生停止条件或中断。数据收发部分是车间的流水线。数据发送寄存器I2CDXR是你放待发送数据的地方写入后硬件会自动将其移入发送移位寄存器I2CXSR并一位一位地发送出去。数据接收寄存器I2CDRR则是你从接收移位寄存器I2CRSR读取已接收数据的地方。这里有个重要的实操细节在读取I2CDRR之前必须通过查询中断状态寄存器I2CSTR的ICRDY位接收数据就绪或等待相应中断确保数据已经有效否则读到的将是旧数据或不确定值。中断与DMA控制是提高效率的关键。中断使能寄存器I2CIER允许你按需开启各种中断源例如仲裁丢失AL、无应答NACK、接收就绪ICRDY、发送就绪ICXRDY等。中断状态寄存器I2CSTR则显示了当前哪些中断事件已经发生。中断源寄存器I2CSRC在同时使能多个中断时可以快速判断是哪个事件触发了中断向量方便进行分支处理。对于大数据量传输一定要利用好DMA事件它可以解放CPU让数据在I2C和内存之间自动搬运。最后是引脚控制寄存器组I2CPFUNC, I2CPDIR等。当I2C引脚不作为I2C功能使用时可以通过这些寄存器将其配置为通用输入/输出GPIO。这在调试阶段或者引脚复用场景下非常有用。例如你可以先将SDA、SCL配置为GPIO输出高电平用软件模拟I2C时序来验证外围设备的基本响应然后再切换到硬件I2C模式进行全速操作。为了方便查阅我将I2C0和I2C1的主要寄存器地址、名称和功能整理如下表。请注意这些地址是字节地址在C语言编程中我们通常将其定义为指向volatile unsigned int类型的指针并进行相应的地址对齐。寄存器名称描述I2C0 字节地址I2C1 字节地址I2COAR自身地址寄存器0x4900 00000x4A00 0000I2CIER中断使能寄存器0x4900 00040x4A00 0004I2CSTR中断状态寄存器0x4900 00080x4A00 0008I2CCLKL时钟低电平时间分频寄存器0x4900 000C0x4A00 000CI2CCLKH时钟高电平时间分频寄存器0x4900 00100x4A00 0010I2CCNT数据计数寄存器0x4900 00140x4A00 0014I2CDRR数据接收寄存器0x4900 00180x4A00 0018I2CSAR从设备地址寄存器0x4900 001C0x4A00 001CI2CDXR数据发送寄存器0x4900 00200x4A00 0020I2CCMDR模式寄存器0x4900 00240x4A00 0024I2CISRC中断源寄存器0x4900 00280x4A00 0028I2CEMDR扩展模式寄存器0x4900 002C0x4A00 002CI2CPSC预分频寄存器0x4900 00300x4A00 00303. 关键寄存器深度配置与操作流程理解了寄存器地图后我们进入实战环节如何配置这些寄存器来完成一次完整的I2C通信。这个过程就像编写一个乐谱每一步都必须准确无误。我将以DSP作为主设备Master向一个7位地址的EEPROM假设地址0x50写入一个字节数据0xAB为例拆解整个流程。3.1 初始化配置搭建通信舞台在开始任何通信之前必须对I2C模块进行初始化。这主要包括引脚功能、时钟和中断的配置。第一步引脚功能配置。虽然上电复位后I2C引脚通常默认就是I2C功能但显式配置是一个好习惯。通过设置引脚功能寄存器I2CPFUNC将对应引脚例如I2C0_SDA和I2C0_SCL的功能选择位设置为1使其工作在I2C模式。同时引脚方向寄存器I2CPDIR在I2C模式下应由硬件自动管理但我们通常将其设置为输入方向或者忽略因为SDA线是双向的。第二步时钟配置。这是保证通信速率合规的核心。假设我们的SYSCLK2 100 MHz目标I2C时钟频率为400 kHz快速模式。首先配置预分频器I2CPSC。我们希望模块输入时钟IPSC_CLK在10-12MHz左右以获得较好的时序分辨率。计算分频系数I2CPSC SYSCLK2 / IPSC_CLK - 1。若取IPSC_CLK 10 MHz则I2CPSC 100/10 - 1 9。向I2CPSC寄存器写入9。接着配置I2CCLKH和I2CCLKL。根据公式IPSC_CLK / [(I2CCLKH 5) (I2CCLKL 5)] 目标频率。代入得10 MHz / (HL10) 0.4 MHz所以HL 15。我们需要根据I2C规范要求的高、低电平最小时间快速模式下高电平至少0.6us低电平至少1.3us来分配。IPSC_CLK周期为0.1us。因此高电平至少需要0.6us / 0.1us 6个IPSC_CLK周期。考虑到公式中的5I2CCLKH至少为6 - 5 1。同理低电平至少需要1.3us / 0.1us 13个周期I2CCLKL至少为13 - 5 8。取I2CCLKH 2I2CCLKL 8则实际高电平时间为 (25)*0.10.7us低电平时间为(85)*0.11.3us满足要求且总周期为 (2585)*0.1 2.0us即500kHz。这略高于400kHz但仍在快速模式允许的范围内且留有一定余量。在实际应用中你可以根据示波器实测波形进行微调。第三步中断配置如果使用。清除中断状态寄存器I2CSTR的所有状态位。然后在中断使能寄存器I2CIER中使能你关心的事件例如发送就绪ICXRDY、接收就绪ICRDY或传输完成ARDY。如果使用查询方式则可以跳过此步。3.2 主设备发送模式执行单字节写入操作配置好舞台现在开始演奏。我们的目标是向地址0x50的EEPROM的某个位置假设内部地址0x00写入数据0xAB。这是一个典型的“主发送-写”序列。第一步设置从设备地址和模式。将目标从设备地址0x50 1因为I2C协议中地址字节的最低比特是读写位写操作时为0写入从设备地址寄存器I2CSAR。因为我们作为主设备所以自身地址寄存器I2COAR在此模式下可以忽略或设置为一个不冲突的值。第二步准备并启动传输。这是最需要小心顺序的操作。向数据发送寄存器I2CDXR写入第一个字节即EEPROM的内部存储地址0x00。注意此时数据并不会被发送。配置模式寄存器I2CCMDR。这是一个需要一次性写入多个控制位的操作。我们需要构建一个命令字MST 1主模式。TRX 1发送模式。STT 1产生起始条件。STP 0先不产生停止条件因为我们还要发送数据字节。XA 07位地址模式。FDF 0非自由数据格式。其他位如IRSI2C模块复位后使能应已在上一步初始化中设置为1。 将构建好的命令字写入I2CCMDR寄存器。写入这个寄存器的瞬间硬件I2C状态机被激活开始控制总线首先产生起始条件S然后发送从设备地址写位0xA0等待并接收从设备的应答ACK接着发送我们预先放在I2CDXR中的第一个数据字节0x00。第三步发送数据字节并结束。在发送第一个字节地址期间我们需要等待发送就绪。可以通过查询I2CSTR寄存器的ICXRDY位当该位为1时表示发送缓冲器I2CDXR为空可以写入下一个数据或者等待ICXRDY中断。一旦检测到可以发送下一个数据立即向I2CDXR写入真正的数据字节0xAB。紧接着我们需要修改模式寄存器以产生停止条件。但是你不能直接读写一个正在控制总线的寄存器。正确的做法是在写入最后一个数据字节0xAB到I2CDXR之后立即在同一个操作或紧接的下一个操作中向I2CCMDR写入一个新的命令字。这个新命令字与之前基本相同但关键是将STP位设置为1。这意味着“在完成当前字节0xAB的传输后产生一个停止条件”。硬件会在发送完0xAB并收到从设备的应答后自动在总线上产生停止条件P结束本次传输。关键提示STT和STP位的操作非常讲究。STT位是“边缘触发”的写1启动后硬件会将其清零。而STP位是“电平触发”的在传输序列结束前必须保持为1才能产生停止条件。在多次重复起始Repeated Start的操作中需要在适当的时候清除STP位并设置新的STT位。3.3 主设备接收模式读取操作与重复起始读取操作稍微复杂因为它通常涉及一个“写-读”序列中间用重复起始条件Repeated Start Sr连接而不是停止条件。假设我们要从刚才写入的地址0x00读回数据。第一步发送设备地址和内部存储地址写周期。这个过程和上述写入操作的前两步完全一样设置I2CSAR为0xA0写写入内部地址0x00到I2CDXR配置I2CCMDRMST1 TRX1 STT1 STP0启动传输。这个阶段发送了从设备地址写和内部地址。第二步发送重复起始条件和读地址。在第一个写周期发送内部地址0x00结束后我们不产生停止条件而是产生一个重复起始条件。等待第一个写周期完成查询I2CSTR的ARDY位或等待中断。重新配置I2CCMDR。此时TRX位要改为0接收模式STT位再次置1以产生重复起始条件STP位仍然为0。同时需要更新I2CSAR为读地址0x50 1 | 1 0xA1。注意有些实现中可以在不改变I2CSAR的情况下仅通过改变I2CCMDR的TRX位和重新置位STT来发起读操作但为了清晰建议重新写入I2CSAR。写入新的I2CCMDR命令字。硬件会先产生一个重复起始条件Sr然后发送从设备地址读位0xA1。第三步接收数据并结束。发送读地址后从设备会开始回送数据。作为主设备我们需要在接收每个字节前通过I2CCMDR的RM位重复模式或通过手动控制来提供时钟。对于单字节读取一种简单方法是在启动读地址发送后等待接收就绪ICRDY位。当ICRDY置起从I2CDRR读取数据。在读取最后一个字节之前我们需要告诉从设备“这是最后一个字节”方法是在读取倒数第二个字节后由主设备发送一个“非应答NACK”。在C672x中这通过设置I2CCMDR寄存器的NACKMOD位来实现。通常我们在启动读传输的命令中就设置STP1和NACKMOD1。这样硬件会在接收到最后一个字节后自动发送NACK并紧接着产生停止条件。因此对于单字节读取我们可以在发送读地址并启动接收的命令中直接设置STP1和NACKMOD1。硬件会自动完成发送Sr - 发送读地址 - 接收数据字节 - 发送NACK - 发送停止条件。整个“写-读”序列的流程可以概括为S 从地址(写) ACK 内部地址 ACK Sr 从地址(读) ACK 数据字节 NACK P。理解并能在寄存器层面实现这个序列是掌握I2C主设备操作的关键。4. 中断与DMA应用策略在轮询Polling模式下CPU需要不断查询I2CSTR寄存器效率低下且会阻塞其他任务。对于实时性要求高的DSP应用使用中断或DMA是必然选择。4.1 中断驱动编程模型中断方式将CPU从轮询中解放出来。你需要完成以下步骤初始化中断系统配置DSP的全局中断控制器将I2C中断向量映射到你的中断服务程序ISR并使能该中断。配置I2C中断源在I2CIER寄存器中精确使能你需要的事件。例如在发送多字节数据时使能ICXRDY发送缓冲空和ARDY传输结束在接收时使能ICRDY接收缓冲满。务必避免使能不必要的中断以减少中断响应开销和潜在的冲突。编写中断服务程序ISR在ISR中首先读取中断源寄存器I2CSRC来确定是哪个具体事件触发了中断。然后根据状态进行相应的操作如果是ICXRDY则从应用程序缓冲区取下一个字节写入I2CDXR。如果是ICRDY则从I2CDRR读取数据并存入应用程序缓冲区。如果是ARDY则表示一次传输序列可能包含多个字节完成可以设置一个标志位通知主程序。如果是NACK无应答或AL仲裁丢失则说明通信出错需要进行错误处理如重试、记录日志。清除中断标志在ISR结束前必须通过向I2CSTR寄存器的相应位写1来清除已处理的中断标志位。否则退出中断后会立即再次进入。一个常见的陷阱是中断嵌套或重入。I2C中断服务程序应尽可能短小高效只做必要的数据搬运和状态更新复杂的处理应放到主循环中基于标志位进行。另外确保对共享数据如应用程序缓冲区指针、状态标志的访问是原子操作或受保护的。4.2 DMA传输的高效实现当需要传输大量数据例如从I2C接口的EEPROM中加载固件或向I2C DAC发送连续的波形数据时DMA是终极解决方案。C672x的I2C模块可以产生发送和接收DMA事件与片上的dMAX控制器配合实现无人值守的数据搬运。配置流程如下配置dMAX通道为I2C发送或接收事件分配一个dMAX通道。设置源地址对于发送是内存中的数据缓冲区对于接收是I2CDRR的地址、目的地址对于发送是I2CDXR的地址对于接收是内存中的缓冲区、传输数据量字节数以及传输模式通常是自动递增。配置I2C模块以配合DMA设置数据计数寄存器I2CCNT。这个寄存器定义了在产生停止条件或中断之前要传输的数据字节数。当与DMA联用时I2CCNT通常设置为DMA要传输的总字节数。在模式寄存器I2CCMDR中确保STP和STT位根据你的传输序列正确设置。对于多字节连续传输通常只在启动时设置STT在配置I2CCMDR启动传输时将STP位设为1并设置I2CCNT。这样硬件会在传输完I2CCNT个字节后自动产生停止条件。使能DMA事件。这通常涉及设置I2C模块的某个控制位可能在其他相关控制寄存器中具体请参考器件TRM以允许其在发送缓冲空或接收缓冲满时触发DMA请求。启动传输先启动dMAX通道然后像往常一样通过配置I2CCMDR设置STT1等启动I2C传输序列。之后硬件I2C和dMAX就会协同工作自动完成所有数据的搬移。传输完成后dMAX通道会产生完成中断或者I2C模块的ARDY中断会标志整个序列结束。使用DMA的最大好处是极低的CPU占用率。CPU只需要在传输开始前进行配置在传输结束后处理完成事件即可期间可以全力处理其他任务如音频算法运算。这对于C672x这种以计算能力见长的DSP来说意义重大。5. 硬件设计要点与电气时序考量再好的软件也建立在可靠的硬件之上。C672x的I2C模块电气特性要求我们必须仔细对待硬件设计。上拉电阻的选择I2C总线是开漏输出必须依赖外部上拉电阻Rp将线路拉到高电平。电阻值的选择是一个权衡电阻值不能太大太大会导致上升沿时间tr过长可能违反快速模式下的最大上升时间要求300ns。上升时间由总线电容Cb和上拉电阻决定tr ≈ 0.8473 * Rp * Cb对于VDD3.3V。假设总线总电容包括所有器件引脚和走线为200pF要求tr300ns则Rp应小于约1.8kΩ。电阻值不能太小太小会导致低电平时电流过大可能超过引脚驱动能力虽然C672x是8mA LVCMOS但也要考虑功耗和噪声。同时过小的电阻在总线仲裁多个主设备同时拉低时会产生更大的电流冲突。典型值对于3.3V系统在标准模式100kHz下常用4.7kΩ或10kΩ。在快速模式400kHz下为了满足更快的边沿要求常使用2.2kΩ或1kΩ。我的经验是在C672x系统中如果总线设备不多5个走线不长10cm使用2.2kΩ是一个在速度和驱动能力之间比较好的折中。务必使用示波器测量SCL和SDA信号的上升沿确保其平滑且时间符合规范。噪声滤波与串联电阻如前所述C672x的I2C引脚是LVCMOS缓冲器输出边沿较陡。这容易引起信号振铃尤其是在长走线或高电容负载时。手册建议的“串联电阻”通常放置在DSP的I2C引脚输出端值在22Ω到100Ω之间。这个电阻与总线电容构成一个低通滤波器可以减缓边沿减少过冲和振铃。你可以在PCB上将其设计为0欧姆电阻的位号根据实测波形决定是否焊接以及焊接多大阻值。时序参数计算与验证手册中的Table 4-36和Table 4-37给出了严格的时序参数。我们之前的时钟配置计算I2CCLKH I2CCLKL就是为了满足这些参数。例如快速模式下tw(SCLL)SCL低电平脉宽最小1.3us。我们配置的(I2CCLKL5)*IPSC_CLK周期 13*0.1us 1.3us刚好满足最小值。tw(SCLH)SCL高电平脉宽最小0.6us。我们配置的(I2CCLKH5)*IPSC_CLK周期 7*0.1us 0.7us满足要求。tsu(SDA-SCLH)SDA数据在SCL上升沿前的建立时间最小100ns。这个由硬件I2C模块在生成SCL时钟和数据时保证只要时钟配置正确通常都能满足。th(SDA-SCLL)SDA数据在SCL下降沿后的保持时间最小0ns。同样由硬件保证。布局布线建议将上拉电阻靠近主设备C672x放置这样可以提供最强的驱动源。SDA和SCL走线应等长、平行、靠近以减少信号 skew。如果空间允许在它们之间布一根地线可以提供更好的噪声屏蔽。远离高频噪声源如开关电源、时钟线、数字总线等。如果无法远离考虑在I2C走线下方铺设完整的地平面。对于更恶劣的环境可以在SDA/SCL线上靠近从设备端增加对地的几十皮法电容构成RC滤波但要注意这会增加总线电容影响上升时间。6. 调试技巧与常见问题排查实录即使按照手册精心设计和编程在实际调试中依然会遇到各种问题。下面是我在多个项目中总结出的常见故障现象、排查思路和解决方法。问题一通信完全无响应用逻辑分析仪或示波器看不到任何起始信号。排查步骤检查基本配置确认I2C模块的时钟是否使能相关外设时钟门控寄存器PSC。确认I2C引脚的复用功能是否已正确设置为I2C模式I2CPFUNC寄存器。检查硬件连接测量SDA和SCL线电压。空闲时它们应该被上拉到高电平如3.3V。如果一直是低电平可能有设备引脚损坏或短路。检查软件流程是否在写入I2CCMDR启动传输前已经正确配置了I2CSAR和I2CDXR是否忘记了将I2CCMDR的IRS位模块内部复位后使能置1这个位必须在任何操作前置1否则模块处于复位状态。检查总线是否被锁死如果从设备在通信中途异常可能会将SDA线持续拉低导致总线死锁。尝试将I2C引脚临时配置为GPIO输出模式先后拉高SCL和SDA模拟几个时钟脉冲来“解锁”总线这是一个非常实用的技巧。问题二能检测到起始信号和地址字节但收不到应答NACK或后续数据出错。排查步骤确认从设备地址这是最常见的问题。确保写入I2CSAR的地址是7位左移1位后的值即(slave_addr 1) | rw_bit。许多从设备的数据手册给出的是7位地址编程时容易忘记左移。检查从设备电源和就绪有些设备如EEPROM在写操作后需要几毫秒的写入周期Write Cycle Time在此期间不会应答。必须等待足够时间或查询其就绪状态。用逻辑分析仪解码这是最直接的诊断工具。查看发送的地址字节、数据字节以及ACK/NACK位是否与预期完全一致。特别注意数据的MSB和LSB顺序。检查时序测量SCL频率是否在从设备支持的范围内特别是有些老器件只支持100kHz标准模式。测量建立时间和保持时间是否满足从设备要求可能比I2C标准更严格。问题三使用中断或DMA时程序跑飞或数据丢失。排查步骤中断服务程序ISR效率ISR是否执行时间过长是否在ISR内进行了耗时的操作如打印日志这可能导致丢失后续中断。确保ISR尽可能精简。中断标志清除是否在ISR中清除了正确的状态标志读取I2CDRR会自动清除ICRDY吗在C672x中读取I2CDRR并不会自动清除ICRDY位你必须手动向I2CSTR寄存器的ICRDY位写1来清除它。这是一个容易遗漏的细节会导致中断持续触发。DMA配置错误检查dMAX通道的源/目的地址、传输数量、地址递增模式是否正确。特别是目的地址为I2CDXR时地址是否对齐传输数量单位是字节、半字还是字必须与I2C的数据宽度8位匹配。缓冲区管理确保应用程序的缓冲区足够大且DMA/ISR更新缓冲区索引时主程序访问该索引是安全的考虑使用volatile变量或关中断保护。问题四通信不稳定偶尔出错尤其在长时间运行后。排查步骤电源噪声用示波器观察I2C总线上的电源纹波。大的噪声毛刺可能导致逻辑误判。确保为I2C总线上的所有器件提供干净、稳定的电源。信号完整性观察SDA/SCL波形是否有严重的过冲、振铃或回沟ringback。尝试增加之前提到的串联电阻或稍微增大上拉电阻但需重新评估上升时间。软件容错在驱动层增加重试机制。例如连续收到NACK后尝试发送一个停止条件延时再重新开始整个传输序列。对于关键数据可以实现简单的校验和或重读验证。总线负载总线上设备是否过多总线电容是否过大测量总线电容如果超过400pF快速模式上限需要考虑使用I2C缓冲器如PCA9515来分割总线。调试I2C逻辑分析仪几乎是必备工具。它能直观地展示整个通信过程包括起始、地址、数据、应答和停止是定位问题最快的方式。当没有逻辑分析仪时用示波器双通道分别抓取SDA和SCL通过光标测量关键时间参数也能解决大部分时序相关问题。最后养成在代码中增加详细状态打印和错误计数的习惯对于追踪间歇性故障非常有帮助。