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.

[参考译文] TMS320F2.8069万M:I2C主控制器-如何终止传输(例如,传输时间过长)?

Guru**** 2561530 points


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

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/632654/tms320f28069m-i2c-master---how-to-terminate-the-transmission-ex-if-the-transfer-takes-too-long

部件号:TMS320F2.8069万M

您好,

我终于实现了I2C驱动程序,但是我希望有一个超时控制,以防传输时间过长。

我将当前代码发布在下面。 如果XRDY寄存器未准备好太长时间,我只想让传输停止并释放总线。 我尝试重置模块,从硬件角度看它工作正常(总线已简单释放),但软件不发送停止条件,因此无法传输下一个字节( I2CMDR的STP位未就绪)。 如何强制停止条件?

I2C_Error_e I2C_writeData (I2C_handle i2cHandle,Int16_t地址,uint16_t数据[],uint16_t bytesToSend_no)
{
静态Int16_t iByte,cntTimeout = 0;

//检查总线是否未等待停止状态
IF (i2cHandle->I2CMDR.bit.stp ==1)
{
返回I2C_Error_StpNotReady;
}

//检查总线是否繁忙
IF (i2cHandle->I2CSTR.bit.BB ==1)
{
返回I2C_Error_Busy
;}

//设置从属地址
I2C_setSlaveAddress (i2cHandle,地址);

//设置要发送的字节数
I2C_setDataBytesNumber (i2cHandle,bytesToSend_no);

//在生成停止条件后,将主模式设置为自动切换为从属模式
I2C_setMode (i2cHandle,I2C_Mode_Master_Transmitter);

//准备在传输结束后发送的停止条件
I2C_STOP (i2cHandle);

//发送启动条件
I2C_START (i2cHandle);

for (iByte = 0;iByte<bytesToSend_no;iByte++)
{ 
//在巴士免费之前不做任何事情 while ( i2cHandle->I2CSTR.bit.XRDY ==0) { IF (cntTimeout++> 1000)//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 在此处松开总线 { I2C_RESET (i2cHandle); I2C_ENABLE (i2cHandle); 返回I2C_Error_timeout; } }; //将数据发送到传输寄存器 i2cHandle->I2CDXR =数据[iByte]; } 返回I2C_Error_NoError; }

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

    感谢您的帖子。 您的线程已分配给C2000专家,应很快得到解答。

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

    你好,Jakub,

    我认为必须发送停止条件以正确结束传输并防止I2C模块出现任何混淆。 按照您设置I2C模块的方式,您似乎必须等待I2CCNT寄存器达到零,然后才能发送停止条件。

    另一种可能是让从属设备在您要发送的最后一个字节之后发送nack。 如果发现错误,f2.8069万M应该能够正确发送停止条件。 有关更多信息,请参阅设备用户指南的I2C部分 ,http://www.ti.com/lit/ug/spruh18g/spruh18g.pdf

    希望这能有所帮助,

    Kevin

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

    您好,Kevin:

    感谢您的见解,并对我的延迟回复表示抱歉,我不得不将此主题搁置一段时间。 但现在我有一个不同的问题。

    EDIT (3):问题似乎在于发送数据的频率。 我在EEPROM示例中检查了它(只是将地址更改为我的从属设备),当我试图太快地发送另一部分数据时(100Hz似乎是我的代码的限制),也会发生同样的情况。 为什么会出现这种情况?如何使我的代码在这种情况下保持强健? 如果I2C总线像这样损坏,我该如何重置它?

    问题:SCL信号被锁定在第7位数据上(然后SDA永远保持低电平)。 在逻辑分析器上可以看到它,如下面的屏幕截图所示。 下图显示了正确的传输,上部的传输是故障传输。

    这种情况经常发生,而且总是第7个SCL位的数据被锁定,所以它看起来像是主(MCU)的故障。 但原因何在?

    我正在使用的从属设备是 FTDI UMFT200XD-01芯片,它是一个I2C-USB桥。 我正在通过I2C将数据发送到此芯片,该芯片随后会显示在我的PC上。

    Logic analyzer\

    更新:问题似乎是I2C总线上的电阻过小-将其增加到9千欧后,传输正常工作。

    更新2:不再...问题不断出现,使用新的电阻值时可能不是很频繁。

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

    你好,Jakub,

    有关最大/最小上拉电阻计算,您可以查看此应用手册:  

    很难从波形上真正判断到底发生了什么,但它看起来就像SDA线被其中一个设备保持在低位。 您可以在F2.8069万一侧检查的是查看I2CFR (I2C状态寄存器),并比较传输工作时间和不工作时间。

    有关每个寄存器位的含义的信息,请查看F2806x TRM:  

    希望这能有所帮助,

    Kevin

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

    谢谢你,Kevin,我将查看这些材料。 状态寄存器仅显示BB标志和XRDY的差异,这似乎是合乎逻辑的。

    还有一个问题-即使这种I2C损坏是由从属设备引起的,如果在没有我控制的情况下(在实际应用中)发生这种情况,我该怎么办? 是否有办法完成CLK信号并强制停止条件以重新启动总线? 我的设备将在不同的条件下工作,我希望使其也适用于外部事件。

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

    您之前提到过"100Hz似乎是我的代码的限制",您是否说SCL只能以100Hz运行? 这真的很低,您的意思是100KHz吗?

    您可能需要检查I2C时钟模块的设置,它需要在7-12 MHz范围内。 检查您的设备TRM有关详细信息,IPSC寄存器是一个很好的起点。

    关于I2C腐败处理的主要问题,我相信您可以尝试一些方法。 查看以下Wiki页面的"外部从属设备通过保持SDA低电平悬挂总线"部分: processors.wiki.ti.com/.../I2C_Tips

    它讨论了使用GPIO时钟SCL的问题,以强制时钟信号,并在总线挂起时重置从属设备上的I2C模块。

    希望这能有所帮助,

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

    我指的是向I2C写入数据的频率,而不是总线频率-抱歉误解。  但我终于找到了问题的真正根源... 我当时使用的是这种I2C-USB桥接器,但我不是直接将它连接到PC,而是使用1.5 m USB扩展电缆。  这可能为I2C网桥与PC通信造成了一些问题,导致它阻塞I2C线路。 直接连接设备后,一切都完美无瑕。

    不过,我还要问你一件事。

    这是我在I2C ISR中使用的代码的一部分:

    IntSource = halHandle->i2cHandle->I2CISRC.all;
    
    //中断源=检测到停止条件
    IF (IntSource == I2C_SCD_ISRC)
    {
    //通知消息已检测到停止条件
    I2C_lastMessageHandle->status = I2C_MsgStatus_SCD;
    
    //在传输过程中,我们是否可以检测到一个nack?
    if(halHandle->i2cHandle->I2CSTR.bit.nack ==1){
    ASM(" ESTOP0");
    }
    }
    //中断源=寄存器访问就绪
    否则IF (IntSource == I2C_ARDY_ISRC)
    {
    
    IF (halHandle->i2cHandle->I2CSTR.bit.nack == 1)
    {
    //如果未收到ACK,则生成停止条件
    halHandle->i2cHandle->I2CMDR.bit.stp =1;
    
    //清除nack中断位
    halHandle->i2cHandle->I2CSTR.bit.nack =1;
    }
    
    //清除ARDY中断位
    halHandle->i2cHandle->I2CSTR.bit.ARDY =1;
    } //注册结束访问准备就绪 

    有一个Estop命令,我认为当其中一个数据字节被堆叠时应该可以到达,但它不是(我在逻辑分析器上看到过这样的情况)。 在这种情况下,什么清除了nack位(并且可能会在总线上发出停止条件)?  根据我的理解,第二 个(ARDY)条件仅与地址字节相关,因此它不会对数据字节传输过程中发生的情况产生任何影响。

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

    很棒! 很高兴听到现在有事情在为您工作。

    与您的nack问题相关,您能否确认在输入STOP CONFIRM IF语句时,在状态寄存器中看到nack?

    我认为在停止条件之后不会出现nack,这意味着状态寄存器位在该IF语句中始终为零。

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

    您好,

    我尝试更深入地研究本模块,我认为我需要澄清几件事,然后再继续。

    正如您在我的ISR代码中看到的那样,ARDYINT用于触发中断。 现在,看一下文档(表14-10 of spruh18g),我读了:

    "在非重复模式下(I2CMDR中的RM = 0):如果I2CMDR中的STP = 0,则当时设置ARDY位
    内部数据计数器计数降至0。  如果STP =1,则ARDY不受影响 (而是I2C模块
    当计数器达到0时生成停止条件。"

    即使 I2CCNT 设置为再接收几个字节,在收到nack后,ISR如何立即生成?

    类似的问题涉及在ISR内生成停止条件。 文档显示:

    "STP已被设备设置为在I2C模块的内部数据计数器倒计时到0时生成停止条件。"

    但是,我可以看到停止条件发生在相同的字节(NACKED)之后。 它是否应该等到其余字节被传输后再进行?


    我还想在ARDY_INT中使用nack_INT和检查nack bit有什么区别? I2C模块设置为主发送器,非重复模式,禁用FIFO。

    这正是我所说的情况。 接受地址字节,发送大量数据字节,其中一个被置入( 在I2CCNT寄存器中定义了更多数据字节)。 之后立即设置停止条件(在我停止程序时未在此处看到):

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

    你好,Jakub,

    您描述的是C2000侧的主-发送器还是主-接收器模式?

    我认为I2C中的标准是使传输结束,并且通常(如果不是总是)会出现停止条件。  nack意味着接收器不想或不能接收更多的字节,或者出现了错误(即线路断开,或未正确接收字节)。

    据说I2CCNT可能被忽略或在看到一个nack时设置为0。

    希望这能有所帮助,

    Kevin