You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于STM32的I2C总线主动嗅探:外部中断模式可行性问询

I2C总线收发器/开关实现方案疑问解答

问题背景

我有一块定制开发板,采用STM32微控制器作为I2C主设备,与3个I2C从设备进行通信(如图1所示)。
图1


我可通过逻辑分析仪嗅探I2C总线,获取设备地址与寄存器信息,从而自主实现相关功能(这实际是一个逆向工程项目,如图2所示)。
图2


目前我需要在项目中新增一款微控制器来嗅探I2C总线,但并非作为逻辑分析仪这类被动设备,而是充当类似TCA9545A的收发器或开关(如图3所示)。
图3


我的问题是:能否通过如下所示的简单外部中断模式实现该功能?

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    uint8_t datum;

    if (GPIO_Pin == SCL_IT_Pin) {
        // 时钟触发;接收到位数据
        datum = HAL_GPIO_ReadPin(SDA_GPIO_Port, SDA_Pin);
    } else if (HAL_GPIO_ReadPin(SCL_GPIO_Port, SCL_Pin)) { // 必定是SDA引脚触发的中断
        // 起始或停止条件
        // 'A'代表起始信号,'B'代表停止信号
        datum = HAL_GPIO_ReadPin(SDA_IT_GPIO_Port, SDA_IT_Pin) ? 'B' : 'A';
    } else {
        // 无有效事件,直接返回
        return;
    }

    buffer[bufferPos] = datum; // 将接收到的位数据存入缓冲区

    bufferPos = (bufferPos + 1) % I2C_BUFFER_SIZE;
    if (bufferPos == bufferStart) printf("ERROR! I2C缓冲区过小!\r\n"); // 缓冲区溢出!
}

解答

这种方案能实现基础的I2C总线嗅探,但距离充当TCA9545A这类收发器/开关的需求还有很大差距,具体分析如下:

1. 仅能被动嗅探,无法主动介入总线

当前代码只是通过外部中断捕获SCL时钟沿和SDA的起始/停止信号,只能被动收集总线数据,无法像TCA9545A那样主动切换总线通路、转发或修改I2C数据——而后者才是“收发器/开关”的核心功能。如果需求只是嗅探,这个方案有基础可行性,但要做开关/转发,完全不够。

2. 现有嗅探逻辑存在缺陷

  • SDA中断判断不严谨:代码假设非SCL中断就是SDA触发,若GPIO外部中断配置不当(比如其他引脚绑定EXTI)会导致误判;另外,未区分重复起始信号(Repeated Start),会把它当成普通起始信号存储,后续解析I2C帧时会出错。
  • 位数据存储方式低效易出错:直接将单个bit存入缓冲区,后续需手动拼接成字节,且未处理ACK/NACK位、读写方向位等I2C协议细节,最终缓冲区数据无法直接解析为有效I2C帧。
  • 中断响应时序风险:STM32外部中断存在响应延迟,若I2C总线速率较高(如400kHz快速模式),可能错过SCL时钟沿导致采样错误;且中断回调中直接调用printf会大幅增加响应时间,加剧时序问题。

3. 实现类似TCA9545A功能的调整方向

  • 放弃单纯外部中断方案,改用STM32的I2C外设 Slave 模式监听,或用两个I2C外设分别连接主端与从端,实现总线转发(类似网桥);
  • 实现I2C协议完整解析:识别设备地址、读写方向、寄存器地址、数据帧、ACK/NACK等,才能在合适时机介入总线(如切换通路、修改数据);
  • 做开关功能需额外GPIO控制通路切换,同时保证总线切换时序合规,避免总线挂死;
  • 中断中禁止调用printf这类耗时函数,改用环形缓冲区缓存数据后在主循环处理输出。

总的来说,你给出的代码只能作为I2C嗅探的雏形,但完全达不到TCA9545A这类收发器/开关的功能要求,需要重构核心逻辑。

内容的提问来源于stack exchange,提问作者Nima Azad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 05:17:22