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.

[参考译文] CCS/TMS320F28069M:从 AM4096获取数据时出现 I2C 问题

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

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/896973/ccs-tms320f28069m-i2c-issue-getting-data-from-am4096

器件型号:TMS320F28069M

工具/软件:Code Composer Studio

大家好、

我正在尝试从磁传感器(PN:AM4096)获取数据、并且遇到了问题。 代码在同一总线上与温度传感器配合使用良好。 作为一种方式、我在第一次获得有效数据、但当我第二次尝试时、代码会挂起、以在 read_Bytes 函数中查找 I2caRegs.I2CMDR.bit.STT 标志以进行清除。

UINT16 AM4096class::GetAbsoluteAngle (void)
{
uint8数据[2];
int16结果= I2C_Success;

AM4096class::SetRegisterAddress (32);
结果= I2C.Read_Bytes ((AM4096_address_code |(AM4096class::Address))、sizeof (data)、data);
AM4096class::data_union.data_Registers.data_ADDR_33.all = data[1]<<8+data[0];
返回结果;
}

uint16 I2Cclass::read_Bytes (uint16 slave_address、uint16 count、uint8 *out)
{
uint16 i、ret;
GpioDataRegs.GPADAT.bit.GPIO21=0;
I2Cclass::start (slave_address);
GpioDataRegs.GPADAT.bit.GPIO21=1;

//发出重复启动
I2caRegs.I2CMDR.bit.STT = 1;

//等待重复开始到结束
I2Cclass::timeout=0;
while (I2caRegs.I2CMDR.bit.STT!= 0)
{
I2Cclass::I2Cclass::timeout++;
if (I2Cclass::I2Cclass::timeout>timeout_limit)
{
返回 I2C_ERROR;
}
}

//非重复模式
I2caRegs.I2CMDR.bit.RM = 0;

//设置数据计数
I2caRegs.I2CCNT =计数;

//在数据计数器递减到0时生成停止条件
I2caRegs.I2CMDR.bit.STP= 1;

//接收器模式
I2caRegs.I2CMDR.bit.TRX = 0;

对于(i = 0;i < count;+i)
{
//等待数据接收寄存器准备好读取
I2Cclass::timeout=0;
while (I2cRegs.I2CSTR.bit.RRDY!= 1)
{
I2Cclass::timeout++;
if (I2Cclass::timeout>timeout_limit)
返回 I2C_ERROR;

}
OUT[i]= I2caRegs.I2CDRR;
}

返回 I2C_SUCCESS;
}
UINT16 I2Cclass::start (UINT16 SLAVE_ADDRESS)
{
//加载从器件地址
I2caRegs.I2CSAR =从器件地址;

//等待停止条件
I2Cclass::timeout=0;
while (I2caRegs.I2CMDR.bit.STP!= 0)
{
I2Cclass::timeout++;
if (I2Cclass::timeout>timeout_limit)
返回 I2C_ERROR;

}

//主控模式
I2caRegs.I2CMDR.bit.MST = 1;

//生成起始条件
I2caRegs.I2CMDR.bit.STT = 1;

返回 I2C_Success
;} 

下面的图片是第一个请求。 它返回正确的值。

第二幅图显示了 I2C 总线挂起。 它能够发送从器件和寄存器地址。

此图像是从 Arduino 运行传感器时的图像。 它每次都能正常工作。

有人能不能就此发出一些光? 谢谢!

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

    在按照以下 wiki 页面上的建议重新配置 I2C 以进行重复启动之前、是否可以尝试检查 ARDY 位?

    https://processors.wiki.ti.com/index.php/I2C_Tips#Repeated_Start

    惠特尼

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

    这是通道3上 ARDY 的波形图(每1us 更新一次)。 当第一个数据包完成后、ARDY 看起来永远不会清除。 您认为我在缓冲区中还有另一个字节吗?

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

    如果我在函数的开始处清除 ARDY、我不会卡住:  

    uint16 I2Cclass::read_Bytes (uint16 slave_address、uint16 count、uint8 *out)
    {
    uint16 i、ret;
    uint8垃圾[16];
    
    
    I2caRegs.I2CSTR.bit.ARDY = 1;
    
    I2Cclass::start (slave_address); 

    不过、不要认为这是一个解决方案。 为什么在第一个数据包的末尾不清除 ARDY?

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

    要进行澄清、您应该等待 ARDY 置1、而不是清零。 该位置位时表明寄存器已准备好更新、因为之前的配置已经被使用。 那么、ARDY 是否不再升高、或者它只是在您最近的屏幕截图中切断?

    惠特尼

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

    明白了。 问题是、ARDY 在传输成功后从不会清除(发出停止位)

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

    我反复阅读了所提到的链接、但运气不好。 我重新编写了代码以与建议的代码匹配、在检查 ARDY 时仍然卡住。

    uint16 I2Cclass::read_block (uint16 slave_address、uint16 read_address、uint16 count、uint8 *out)
    {
    uint16 i、ret;
    
    I2Cclass::timeout=0;
    while (I2cRegs.I2CSTR.bit.BB);
    
    I2caRegs.I2CMDR.ALL = 0;//在配置期间禁用 I2C 模块
    
    I2caRegs.I2CSAR =从器件地址;//设置器件地址
    
    I2caRegs.I2CMDR.ALL = 0x2620;
    
    I2Cclass::timeout=0;
    while (((!I2cRegs.I2CSTR.bit.XRDY));//||(!I2cRegs.I2CSTR.bit.ARDY));
    
    if (I2caRegs.I2CSTR.bit.nack)
    {
    I2caRegs.I2CMDR.ALL = 0;//复位 I2C 以便 SCL 不被保持在低电平返回 RRET__FAIL;
    返回 I2C_Nack_error;
    }
    I2caRegs.I2CDXR = READ_ADDRESS; //写入寄存器地址
    
    I2Cclass::timeout=0;
    //***我被卡在这里!***//
    while (!I2caRegs.I2CSTR.bit.ARDY);//等待 ARDY 被清除
    
    //设置数据计数
    I2caRegs.I2CCNT =计数;
    
    I2caRegs.I2CMDR.ALL = 0x2C20;
    
    对于(i = 0;i < count;+i)
    {
    //等待数据接收寄存器准备好读取
    I2Cclass::timeout=0;
    while ((!I2cRegs.I2CSTR.bit.RRDY)||(!I2cRegs.I2CSTR.bit.ARDY));
    if (I2caRegs.I2CSTR.bit.nack)
    {
    I2caRegs.I2CMDR.ALL = 0;//复位 I2C 以便 SCL 不被保持在低电平返回 RRET__FAIL;
    返回 I2C_Nack_error;
    }
    OUT[i]= I2caRegs.I2CDRR;
    }
    返回 I2C_Success
    ;}
    

    下面的数据显示了我正在监控的一些控制线。

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

    当 I2CMDR.RM 为0时、ARDY 不会再次变为高电平、直到字节计数递减到零-但在发送读取地址之前、您绝不会设置字节计数。 如果您将字节计数设置为1、ARDY 是否会在适当的时间变为高电平?

    惠特尼

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

    尊敬的惠特尼:

    我发现了这个问题。 我现在可以使用代码、但如果我在下面的两个位置检查 ARDY、它将锁定。 但是、它们位于您提到的参考代码中。

    uint16 I2Cclass::read_block (uint16 slave_address、uint16 read_address、uint16 count、uint8 *out)
    {
    uint16 i;
    
    I2Cclass::timeout=0;
    while (I2cRegs.I2CSTR.bit.BB);
    {
    I2Cclass::timeout++;
    if (I2Cclass::timeout>timeout_limit)
    返回 I2C_ERROR;
    }
    
    I2caRegs.I2CMDR.ALL = 0;
    I2caRegs.I2CSAR =从器件地址;//设置器件地址
    I2caRegs.I2CCNT = 1; //仅发送一个字节(寄存器地址)
    I2caRegs.I2CMDR.ALL = 0x2620; //开始传输
    
    
    I2Cclass::timeout=0;
    //<<< >>
    while (((!I2cRegs.I2CSTR.bit.XRDY));//||(!I2cRegs.I2CSTR.bit.ARDY));
    {
    I2Cclass::timeout++;
    if (I2Cclass::timeout>timeout_limit)
    返回 I2C_ERROR;
    }
    
    if (I2caRegs.I2CSTR.bit.nack)
    {
    I2caRegs.I2CMDR.ALL = 0;//复位 I2C 以便 SCL 不被保持在低电平返回 RRET__FAIL;
    返回 I2C_Nack_error;
    }
    I2caRegs.I2CDXR = READ_ADDRESS; //写入寄存器地址
    
    I2Cclass::timeout=0;
    while (!I2caRegs.I2CSTR.bit.ARDY);//等待 ARDY 被清除
    {
    I2Cclass::timeout++;
    if (I2Cclass::timeout>timeout_limit)
    返回 I2C_ERROR;
    }
    
    //设置数据计数
    I2caRegs.I2CCNT =计数;
    
    I2caRegs.I2CMDR.ALL = 0x2C20;
    
    对于(i = 0;i < count;+i)
    {
    //等待数据接收寄存器准备好读取
    I2Cclass::timeout=0;
    //<<< >>
    while (((!I2cRegs.I2CSTR.bit.RRDY));//||(!I2cRegs.I2CSTR.bit.ARDY));
    {
    I2Cclass::timeout++;
    if (I2Cclass::timeout>timeout_limit)
    返回 I2C_ERROR;
    
    }
    if (I2caRegs.I2CSTR.bit.nack)
    {
    I2caRegs.I2CMDR.ALL = 0;//复位 I2C 以便 SCL 不被保持在低电平返回 RRET__FAIL;
    返回 I2C_Nack_error;
    }
    OUT[i]= I2caRegs.I2CDRR;
    }
    返回 I2C_Success
    ;}
    

    下面是信号在信号分析器中的表现。

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

    您好 Fabio、

    对于您所说的内容、您是否正确回答了以下问题? 如果是、我看不出为什么它会卡住。

    //<<< >>
    while (((!I2cRegs.I2CSTR.bit.XRDY));//||(!I2cRegs.I2CSTR.bit.ARDY)); 
    可能还应尝试在 I2CMDR 线路中启用 FREE MODE 位。 这似乎是您代码中的一个差异、但我不知道为什么这会改变任何内容 .
    I2caRegs.I2CMDR.ALL = 0x4620; //开始传输 
    最棒的
    Kevin
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    这实际上会使它变得更糟糕。 代码将始终锁定在:

    I2caRegs.I2CDXR = READ_ADDRESS; //写入寄存器地址
    
    I2Cclass::timeout=0;
    while (!I2caRegs.I2CSTR.bit.ARDY);//等待 ARDY 被清除
    {
    I2Cclass::timeout++;
    if (I2Cclass::timeout>timeout_limit)
    返回 I2C_ERROR;
    } 

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

    因此、当它未注释时、语句如下所示:

    while ((!I2cRegs.I2CSTR.bit.XRDY)||(!I2cRegs.I2CSTR.bit.ARDY)); 

    在中断循环之前、是否等到 XRDY 和 ARDY 都设置完毕? 我认为示例代码表示等待这两个代码中的任何一个。

    while (!(I2cRegs.I2CSTR.bit.XRDY || I2cRegs.I2CSTR.bit.ARDY)); 

    此外,是否忘记删除;添加超时代码是故意的?

    惠特尼

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

    尊敬的惠特尼:

    感谢您抓住;错误。 这不是有意的、但不应影响我的问题。

    您提议的 while 语句在逻辑上是合理的、但我不太理解参考指南中的语句、即我必须等待 ARDY 进行清除。 当运行此代码时、我现在可以运行而不会锁定。 但是、由于 XRDY 是中断此 while 循环的标志、因此 ARDY 并不总是被清除。

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

    以下是我最新代码的副本、供参考:

    uint16 I2Cclass::read_block (uint16 slave_address、uint16 read_address、uint16 count、uint8 *out)
    {
    uint16 i;
    
    I2Cclass::timeout=0;
    while (I2cRegs.I2CSTR.bit.BB)
    {
    I2Cclass::timeout++;
    if (I2Cclass::timeout>timeout_limit)
    返回 I2C_ERROR;
    }
    
    I2caRegs.I2CMDR.ALL = 0;
    I2caRegs.I2CSAR =从器件地址;//设置器件地址
    I2caRegs.I2CCNT = 1; //仅发送一个字节(寄存器地址)
    I2caRegs.I2CMDR.ALL = 0x2620; //开始传输
    
    
    I2Cclass::timeout=0;
    //<<< >>
    while (!(I2cRegs.I2CSTR.bit.XRDY || I2cRegs.I2CSTR.bit.ARDY))
    {
    I2Cclass::timeout++;
    if (I2Cclass::timeout>timeout_limit)
    返回 I2C_ERROR;
    }
    
    if (I2caRegs.I2CSTR.bit.nack)
    {
    I2caRegs.I2CMDR.ALL = 0;//复位 I2C 以便 SCL 不被保持在低电平返回 RRET__FAIL;
    返回 I2C_Nack_error;
    }
    I2caRegs.I2CDXR = READ_ADDRESS; //写入寄存器地址
    
    I2Cclass::timeout=0;
    while (!I2cRegs.I2CSTR.bit.ARDY)//等待 ARDY 清除
    {
    I2Cclass::timeout++;
    if (I2Cclass::timeout>timeout_limit)
    返回 I2C_ERROR;
    }
    
    //设置数据计数
    I2caRegs.I2CCNT =计数;
    
    I2caRegs.I2CMDR.ALL = 0x2C20;
    
    对于(i = 0;i < count;+i)
    {
    //等待数据接收寄存器准备好读取
    I2Cclass::timeout=0;
    //<<< >>
    while (!(I2cRegs.I2CSTR.bit.RRDY || I2cRegs.I2CSTR.bit.ARDY))
    {
    I2Cclass::timeout++;
    if (I2Cclass::timeout>timeout_limit)
    返回 I2C_ERROR;
    
    }
    if (I2caRegs.I2CSTR.bit.nack)
    {
    I2caRegs.I2CMDR.ALL = 0;//复位 I2C 以便 SCL 不被保持在低电平返回 RRET__FAIL;
    返回 I2C_Nack_error;
    }
    OUT[i]= I2caRegs.I2CDRR;
    }
    返回 I2C_Success
    ;} 

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

    如果您共享的最后一个屏幕截图在代码更新后仍然有效、我认为 ARDY 行为符合预期。 您可以看到、由于 STP = 0、因此在发送读取地址后它会变为高电平。 您仍然需要在其他循环中检查它、以便在发生 NACK 时将其断开、但如果它未被设置、这并不一定意味着某件事是错误的。

    您是否同意或认为仍有问题?

    惠特尼

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

    好的。 谢谢。 我认为我现在很好。 感谢您的帮助!