This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] F28M36P63C2:C2000 I2C主接收器模式超时。

Guru**** 2524550 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/655386/f28m36p63c2-c2000-i2c-master-receiver-mode-timing-out

部件号:F28M36P63C2

我正在为C2000 I2C总线编写文章,并且在主接收器操作模式中遇到一些问题。 我使用轮询而不是基于中断的方法。

从从属设备接收数据时,我的I2C通信每隔几分钟超时一次。  在下面代码的突出显示区域中超时,I2caRegs.I2CSTR.ALL == 0x2430 (NACKSNT, XSMT, SCD, XRDY)。 我不确定在从主发送器模式切换到主接收器模式时是否对寄存器进行了正确编程。 我从从属设备中看不到任何黑色。 仅在主传输模式下(未显示代码),我没有遇到任何问题。

计时器的时钟频率为150MHz,因此20万 周期为133毫秒超时,由于最大读取为6字节,超时时间非常长。

void I2C_read (UINT8 addr,UINT16 regPtr,UINT16 numBytes,UINT16 * data,enum I2C_DEF_error *错误, bool msbFirst,UINT32 timeoutMicroSecs)
{
*ERR = I2C_OK;
i2cMutex.Lock();

色调;
UINT32 lo = CtoMIpcRegs.MIPCCOUNTERL;
UINT32 HI = CtoMIPCRegs.MIPCOUNTERH;
EINT;
UINT32 timed_out = 0;

//主位将自动清除,因此等待以确保是一件好事
//总线是免费的,可以使用新的主中继器
while (I2caRegs.I2CMDR.bit.MST &&!(timed_out = I2C_timedout (lo,hi,2000万)){};

如果(超时)
{
DbgInfo("读取TX 1时超时。 状态:0x%x",I2caRegs.I2CSTR.ALL);
*ERR = I2C_ERROR_TIMEOUT;
i2cMutex.Unlock();
返回;
}

//I2caRegs.I2CMDR.bit.IRS = 0; //这有时是需要的,但我不想总是重置它

I2caRegs.I2CCNT = 1; //在非重复模式(RM =0)中,这表示要发送的字节数。 仅1个用于阅读(寄存器)
I2caRegs.I2CSAR =地址; //从设备的地址
I2caRegs.I2CDXR = regPtr; //要传输的第一个数据字节,即要寻址的远程寄存器
I2caRegs.I2CMDR.bit.TRX = 1; //向从属设备传输数据
I2caRegs.I2CMDR.Bit.MST = 1; //设置主位以启动SCL线。
I2caRegs.I2CMDR.bit.free = 1; //允许I2C在断点中运行
I2caRegs.I2CMDR.bit.stp = 0; //由于我们正在从从属设备接收数据,因此我们要执行重复启动,因此禁用停止位
I2caRegs.I2CMDR.bit.STT = 1; //开始新事务
I2caRegs.I2CMDR.bit.IRS = 1; //将I2C从复位中拉出

//等待寄存器空闲,然后开始事务的读取阶段
while (!I2caRegs.I2CSTR.bit.ARDY &&!(timed_out = I2C_timedout (lo,hi,2000万));

如果(超时)
{
DbgInfo("读取TX 2时超时。 状态:0x%x",I2caRegs.I2CSTR.ALL);
*ERR = I2C_ERROR_TIMEOUT;
i2cMutex.Unlock();
返回;
}

//检查我们是否收到"不确认"
IF (I2caRegs.I2CSTR.bit.nack)
{
DbgInfo("在READ TX. 状态:0x%x",I2caRegs.I2CSTR.ALL);

I2caRegs.I2CMDR.All = 0;
//I2caRegs.I2CMDR.bit.stp = 1;//在这种情况下,我们需要强制执行停止条件
I2caRegs.I2CSTR.bit.nack = 1;//清除nack位(通过向其写入1)

*err = I2C_nack;
i2cMutex.Unlock();
返回;
}

// I2caRegs.I2CMDR.All = 0;
I2caRegs.I2CCNT = numBytes; //在非重复模式(RM =0)中,这表示要读取的字节数。
I2caRegs.I2CMDR.bit.TRX = 0; //我们是主接收器,所以关闭传输位
I2caRegs.I2CMDR.Bit.MST = 1; //仍然是主服务器(可能不需要)
I2caRegs.I2CMDR.bit.free = 1; //允许I2C在断点中运行
I2caRegs.I2CMDR.bit.stp = 1; //停止位将在I2CCNT达到0后应用
I2caRegs.I2CMDR.bit.STT = 1; //对事务的接收部分重复开始
I2caRegs.I2CMDR.bit.IRS = 1; //将I2C从复位中拉出(可能不需要)

UINT16 I(0);

对于(i=0;i < numBytes;i++)
{
while (!(I2caRegs.I2CSTR.bit.RRDY || I2caRegs.I2CSTR.bit.ARDY)&&!(timed_out = I2C_TIMEDOUOUT (lo,hi,2000万)));

如果(超时)
{
DbgInfo("读取RX 1时超时。 状态:0x%x",I2caRegs.I2CSTR.ALL); 
*ERR = I2C_ERROR_TIMEOUT;
i2cMutex.Unlock();
返回;
}

//检查我们是否收到"不确认"
IF (I2caRegs.I2CSTR.bit.nack)
{
DbgInfo("在读取Rx中获得了nack. 状态:0x%x",I2caRegs.I2CSTR.ALL);

I2caRegs.I2CMDR.All = 0;
//I2caRegs.I2CMDR.bit.stp = 1;//在这种情况下,我们需要强制执行停止条件
I2caRegs.I2CSTR.bit.nack = 1;//清除nack位(通过向其写入1)

*err = I2C_nack;
中断;
}

//确保已触发接收就绪信号
while (!I2caRegs.I2CSTR.bit.RRDY &&!(timed_out = I2C_timedout (lo,hi,2000万));

如果(超时)
{
DbgInfo("读取RX 2时超时。 状态:0x%x",I2caRegs.I2CSTR.ALL);
*ERR = I2C_ERROR_TIMEOUT;
i2cMutex.Unlock();
返回;
}

//首先根据MSB/LSB将下一个数据字节读入相应的索引中的缓冲区。
__byte((int*)数据,(msbFirst)? numBytes - I -1 :I)= I2caRegs.I2CDRRRr;
}

i2cMutex.Unlock();
} 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Derek,

    我很遗憾听到您在I2C上遇到一些问题。 我不知道程序卡在哪条线路上。 您是否可以复制您在发布的代码片段中引用的行? 亮点没有实现。

    设置I2C后,我不建议继续写入除需要更改的配置位之外的配置位。也就是说,如果您只在主传输和主接收之间移动,则只需更改TRX位。

    超时后模块复位(切换IRS (IRS)位)是否解决了问题?
    应用程序是否始终在同一位置挂起? 即,在发送地址之后,但在主接收阶段?

    谢谢!
    标记
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    标记,

    以下是行:

    <span style="background-color:#ffff00;">DbgInfo("Got Timed out in Read RX 1. Status: 0x%x", I2caRegs.I2CSTR.all);</span>

    是否在代码段中突出显示功能不起作用?

    超时后,切换IRS (美国国家税务局)将正常工作,应用程序将继续几分钟后再出现另一个超时(其间有数千个I2C事务)。

    每次我看到应用程序时,它都在同一位置挂起(上次计数的几百次),状态寄存器始终是相同的:0x2430。

    关于不更改CMD寄存器位,我是否需要将STP位从0->1更改为重复开始工作? 此外,由于我每次启用一个CMFR寄存器中的位,我是否应该遵循任何顺序? 我在网上看到了一些例子,人们把所有的位都写在I2CMDR.All联合中,但很明显,这并不像正在设置的那样清楚。

    最后,如果我在主接收部分开始之前清除ICMDR (取消注释以下行)

       I2caRegs.I2CMDR.All = 0;
       I2caRegs.I2CCNT = numBytes;        //在非重复模式(RM =0)中,这表示要读取的字节数。

    我可以显著减少总线的超时时间,但我担心这不是正确的操作方式,特别是您的评论说不是一直都写配置位。

    Derek

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好,Derek,

    我目前没有发现您的代码有任何问题。 我没有任何理由相信重写配置位是错误的,如果您像示例一样一次或单独地向它们写入,那就不重要了。

    如果您执行I2caRegs.I2CMDR.bit.IRS = 0而不是I2caRegs.I2CMDR.All = 0,是否会有任何区别?

    获取超时时间时是否有典型值numBytes? 它是在第一个字节上超时还是变化?

    谢谢!
    Whitney
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好,Whitney,

    这是我当前运行得更好的代码,但我仍然偶尔会超时(但最不常见的是,48小时内只有4次超时)。 最大的变化是我把I2CDXR的设置移动到检查XRDY和Nack之后。 我还转到了一次写入所有寄存器,只是为了消除可能的错误位置。

    读取2个字节时会发生这种情况,但我不会记录第一个或第二个字节是否发生超时。 当我查看数据缓冲区时,它确实包含非零数据,因此我假定它至少被填充一次,但无法明确说明这一点。

    void I2C_read (UINT8 addr,UINT16 regPtr,UINT16 numBytes,UINT16 * data,enum I2C_DEF_error *错误, bool msbFirst,UINT32 timeoutMicroSecs)

    *ERR = I2C_OK;

    色调;
    UINT32 lo = CtoMIpcRegs.MIPCCOUNTERL;
    UINT32 HI = CtoMIPCRegs.MIPCOUNTERH;
    EINT;
    UINT32 timed_out = 0;

    //主位将自动清除,因此等待以确保是一件好事
    //总线是免费的,可以使用新的主中继器
    while (I2caRegs.I2CMDR.bit.MST &&!(timed_out = I2C_timedout (lo,hi,2000万)){};

    如果(超时)

    DbgInfo("读取TX 1时超时。 状态:0x%x",I2caRegs.I2CSTR.ALL);
    *ERR = I2C_ERROR_TIMEOUT;
    RESET_Bus();
    //i2cMutex.Unlock();
    返回;
    }

    i2cMutex.Lock();

    //I2caRegs.I2CMDR.bit.IRS = 0; //这有时是需要的,但我不想总是重置它

    I2caRegs.I2CCNT = 1; //在非重复模式(RM =0)中,这表示要发送的字节数。 仅1个用于阅读(寄存器)
    I2caRegs.I2CSAR =地址; //从设备的地址

    // I2caRegs.I2CMDR.bit.TRX = 1; //向从属设备传输数据
    // I2caRegs.I2CMDR.bit.MST = 1; //设置主位以启动SCL线。
    // I2caRegs.I2CMDR.bit.free = 1; //允许I2C在断点中运行
    // I2caRegs.I2CMDR.bit.stp = 0; //由于我们正在从从属设备接收数据,因此我们要执行重复启动,因此禁用停止位
    // I2caRegs.I2CMDR.bit.STT = 1; //开始新事务
    // I2caRegs.I2CMDR.bit.IRS = 1; //将I2C从复位中拉出
    I2caRegs.I2CMDR.All = 0x6620; //这一次性完成了上面的注释行

    while (!(I2caRegs.I2CSTR.bit.XRDY || I2caRegs.I2CSTR.bit.ARDY)&&!(timed_out = I2C_TIMEDOUOUT (lo,hi,2000万));

    //检查我们是否收到"不确认"
    IF (I2caRegs.I2CSTR.bit.nack)

    DbgInfo("获得了读取SAR TX的机会。 状态:0x%x",I2caRegs.I2CSTR.ALL);

    I2caRegs.I2CMDR.All = 0;
    //I2caRegs.I2CMDR.bit.stp = 1;//在这种情况下,我们需要强制执行停止条件
    I2caRegs.I2CSTR.bit.nack = 1;//清除nack位(通过向其写入1)

    *err = I2C_nack;
    i2cMutex.Unlock();
    返回;
    }

    如果(超时)

    DbgInfo("读取TX 2时超时。 状态:0x%x",I2caRegs.I2CSTR.ALL);
    *ERR = I2C_ERROR_TIMEOUT;
    I2caRegs.I2CMDR.All = 0;
    i2cMutex.Unlock();
    返回;
    }

    I2caRegs.I2CDXR = regPtr; //要传输的第一个数据字节,即要寻址的远程寄存器

    //等待寄存器空闲,然后开始事务的读取阶段
    while (!I2caRegs.I2CSTR.bit.ARDY &&!(timed_out = I2C_timedout (lo,hi,2000万));

    如果(超时)

    DbgInfo("读取TX时超时3. 状态:0x%x",I2caRegs.I2CSTR.ALL);
    *ERR = I2C_ERROR_TIMEOUT;
    I2caRegs.I2CMDR.All = 0;
    i2cMutex.Unlock();
    返回;
    }

    //检查我们是否收到"不确认"
    IF (I2caRegs.I2CSTR.bit.nack)

    DbgInfo("在READ TX. 状态:0x%x",I2caRegs.I2CSTR.ALL);

    I2caRegs.I2CMDR.All = 0;
    //I2caRegs.I2CMDR.bit.stp = 1;//在这种情况下,我们需要强制执行停止条件
    I2caRegs.I2CSTR.bit.nack = 1;//清除nack位(通过向其写入1)

    *err = I2C_nack;
    i2cMutex.Unlock();
    返回;
    }

    //I2caRegs.I2CMDR.All = 0;
    I2caRegs.I2CCNT = numBytes; //在非重复模式(RM =0)中,这表示要读取的字节数。
    // I2caRegs.I2CMDR.bit.TRX = 0; //我们是主接收器,所以关闭传输位
    // I2caRegs.I2CMDR.bit.MST = 1; //仍然是主服务器(可能不需要)
    // I2caRegs.I2CMDR.bit.free = 1; //允许I2C在断点中运行
    // I2caRegs.I2CMDR.bit.stp = 1; //停止位将在I2CCNT达到0后应用
    // I2caRegs.I2CMDR.bit.STT = 1; //对事务的接收部分重复开始
    // I2caRegs.I2CMDR.bit.IRS = 1; //将I2C从复位中拉出(可能不需要)
    I2caRegs.I2CMDR.All = 0x6C20; //这一次性完成了上面的注释行

    UINT16 I(0);

    对于(i=0;i < numBytes;i++)

    while (!(I2caRegs.I2CSTR.bit.RRDY || I2caRegs.I2CSTR.bit.ARDY)&&!(timed_out = I2C_TIMEDOUOUT (lo,hi,2000万)));

    如果(超时)

    DbgInfo("读取RX 1时超时。 状态:0x%x",I2caRegs.I2CSTR.ALL);
    *ERR = I2C_ERROR_TIMEOUT;
    I2caRegs.I2CMDR.All = 0;
    中断;
    }

    //检查我们是否收到"不确认"
    IF (I2caRegs.I2CSTR.bit.nack)

    DbgInfo("在读取Rx中获得了nack. 状态:0x%x",I2caRegs.I2CSTR.ALL);

    I2caRegs.I2CMDR.All = 0;
    //I2caRegs.I2CMDR.bit.stp = 1;//在这种情况下,我们需要强制执行停止条件
    I2caRegs.I2CSTR.bit.nack = 1;//清除nack位(通过向其写入1)

    *err = I2C_nack;
    中断;
    }

    //确保已触发接收就绪信号
    while (!I2caRegs.I2CSTR.bit.RRDY &&!(timed_out = I2C_timedout (lo,hi,2000万));

    如果(超时)

    DbgInfo("读取RX 2时超时。 状态:0x%x",I2caRegs.I2CSTR.ALL);
    *ERR = I2C_ERROR_TIMEOUT;
    I2caRegs.I2CMDR.All = 0;
    中断;
    }

    //首先根据MSB/LSB将下一个数据字节读入相应的索引中的缓冲区。
    __byte((int*)数据,(msbFirst)? numBytes - I -1 : I)= I2caRegs.I2CDRRR;
    }

    i2cMutex.Unlock();
    }
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    嗨,Derek,
    很抱歉回复延迟。 您是否能够了解此问题?

    标记
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    标记,

     我最近发布的一篇文章肯定让事情变得更好,但我仍然偶尔会遇到超时。 我可以接受这一点,因为我只需几毫秒后再尝试一次交易,这通常是可行的。 但是,在超时后,总线完全锁定时,我仍然会出现这种情况。 我尝试重置I2C模块并等待MST标志,但它从未自我清除。 所以我假设外部设备将SDA保持在低位。

    我不能在不重启电源的情况下可靠地释放SDA线路。 我仍在研究如何以自动方式实现这一目标。

    Derek

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Derek,

    关于这种I2C,需要记住的一点是,除了协议本身的内容之外,实际上没有内置的错误检测功能。 如果有一些超时,您可能会使用一个看门狗,只要有I2C活动就会重置。 这将有助于C2000 I2C执行模块重置,但我不确定您希望如何接近网络的其余部分。

    您的下一个步骤似乎是找到令人不快的I2C模块,将线路保持在低位,并尝试找出问题的最初发生方式。

    标记