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.

[参考译文] TM4C1294NCZAD:I2C I2CMasterTimeoutSet 不工作

Guru**** 2508425 points


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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1288418/tm4c1294nczad-i2c-i2cmastertimeoutset-not-working

器件型号:TM4C1294NCZAD

您好、TI!

我想让 MasterTimeoutSet 函数在 I2C 模块上工作、但我没好运。

无论我尝试如何设置它、I2C_MCLKOCNT 寄存器都保持在0x00000000

我已经尝试使用 driverlib - I2CMasterTimeoutSet (I2C0_BASE、0x7D);

我已经尝试了直接寄存器操作- HWREG (I2C0_BASE + I2C_O_MCLKOCNT)= 0x7D;

在这两种情况下、I2C_MCLKOCNT 寄存器不发生变化。  我在这里做了严重的错误吗?

我已经在 while 循环中完成写入以进行确认、但 while 循环绝不会退出。

SysCtlPeripheralDisable(SYSCTL_PERIPH_I2C0);
SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_I2C0));
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
GPIOPinConfigure(GPIO_PB2_I2C0SCL);
GPIOPinConfigure(GPIO_PB3_I2C0SDA);
GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
I2CMasterInitExpClk(I2C0_BASE, SysFreq, false); //False = 100kbs, True = 400kbs
while ((HWREG(I2C0_BASE + I2C_O_MCLKOCNT) & 0xFF) != 0x7D) {
    HWREG(I2C0_BASE + I2C_O_MCLKOCNT) = 0x7D;
}
I2CMasterGlitchFilterConfigSet(I2C0_BASE, I2C_MASTER_GLITCH_FILTER_16);

您能告诉我如何获取该寄存器以进行实际设置吗?

谢谢!

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

    我还要补充一点、我已经确认 SCL 超时不起作用。  将 SCL 保持为低电平绝不会导致 I2C_MCS_CLKTO 变为高电平。

    我还尝试了在 MasterInitExpClk 之前和之后设置 Timeout 和 GlitchFilter。

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

    尊敬的 Ben:

     我目前正在旅行。 我会在下周再来的时候再仔细看一下。 您是如何强制外部从器件将 SCL 拉低的?

    18.3.1.6时钟低电平超时(CLTO)
    I2C 从器件可以将时钟周期性地拉低以创建一个慢位、从而延长事务
    原因。 I2C 模块有一个12位的可编程计数器、该计数器被用来跟踪
    时钟已经被保持在低电平。 通过以下公式可以对计数值的高8位进行软件编程:
    I2C 主机时钟低电平超时计数寄存器(I2CMCLKOCNT)。 低四位没有
    用户可见、为0x0。 必须将 I2CMCLKOCNT 寄存器中编程的 CNTL 值设置为
    大于0x01。 应用程序可以对计数器的八个最高有效位进行编程、
    反映事务中可接受的累计低电平时间。 计数在开始时加载
    条件、并在主机内部总线时钟的每个下降沿进行倒计数。 注意、
    即使 I2C 的速度已经设定、为此计数器生成的内部总线时钟也能继续以设定的速度运行
    在总线上保持低电平时。 在达到终端计数时、主状态机强制中止
    在 SCL 和 SDA 释放时发出停止条件来在总线上对总线进行重置。
    作为一个示例、如果一个 I2C 模块正以100 kHz 的速度运行、编辑 I2CMCLKOCNT
    寄存器0xDA 将转换为值0xDA0、因为低四位设置为0x0。 这个
    换言之、也就是3488个时钟周期、即在34.88 ms 时、
    100 kHz

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

    Charles

    非常感谢。  我们有一个板带有一个简单的 PIC 微控制器、其上用作 I2C 从设备。  它可以将 SCL 保持在低电平以实现时钟延展、我们使用此函数进行测试。  无论我们拉伸多长时间、TM4C1294都不会超时、并且实际上都会返回正常的数据。  即使数秒的时钟拉伸也不会触发超时。

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

    尊敬的 Benjamin:

     似乎寄存器在写入后会返回零。 我发现这个帖子具有相同的报告。  

    https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/682698/tm4c129encpdt-i2cmclkocnt---default-value-does-not-meet-documented-requirements

     您可以启用时钟超时中断吗?

     如果被置位了、您是否可以观察 I2CMRIS 寄存器中的 CLKRIS 位?

     当您拉伸 SCL 时、是在主器件写入还是主器件读取期间?  我提出这个问题的原因是、如果主器件向从器件写入数据、从器件拉伸时钟来等待主器件是有意义的。  

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

    Charles

    我们已尝试在读取和写入时扩展时钟、无论哪种情况下都不会发生超时  

    虽然我们不使用中断、但我已确认 CLKTO 或 CLKRIS 都没有设置。

    现在、我找到了一项新信息。  似乎如果我们在每个 I2C 外设的第一个 I2C 事务之后写入超时寄存器(MCLKOCNT)、那么它会针对后续事务正常工作。  只是通过一种非常偶然的方式发现了这一点。

    这基本上解决了我们的问题,当然,除非第一次交易超时-这是不可能的。  因此、这不是完美的解决方案。

    今天稍后我将进行更深入的探索、看看是否有特定的执行指令、然后可以写入时钟超时-现在、我确定的是、如果发生了一个完整的事务(在本例中为单字节读取)、 然后、我们可以设置时钟超时、从该点开始它就能按预期工作。

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

    Charles

    经过进一步的调查、我已经找到了 I2CMasterTimeoutSet 实际设置的最早点。  每个 I2C 总线上的第一个事务是读取、这就是我提出的问题。

        //The Slave Address for Write Mode
        I2CMasterSlaveAddrSet(I2CBase, slave_addr, false);
    
        //Specify the register to read
        I2CMasterDataPut(I2CBase, reg);
    
        //Start Transaction
        I2CMasterControl(I2CBase, I2C_MASTER_CMD_BURST_SEND_START);
    
        //Delay because TM4C I2C is broken
        SysCtlDelay(1000);
    
        //Wait for Master to finish
        while (I2CMasterBusy(I2CBase)) { }
    
        //Check for errors
        if (I2CMasterErr(I2CBase)) {
            I2CMasterControl(I2CBase, I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
            I2C_Log_Error(I2CBase, false);
            return 0x00;
        }
    
        //Now switch to a read
        I2CMasterSlaveAddrSet(I2CBase, slave_addr, true);
    
        //Set a reasonable timeout
        HWREG(I2CBase + I2C_O_MCLKOCNT) = I2C_TIMEOUT;
    
        //Begin first read
        I2CMasterControl(I2CBase, I2C_MASTER_CMD_SINGLE_RECEIVE);
        
        //Delay because TM4C I2C is broken
        SysCtlDelay(1000);
    
        //Wait for Master to finish
        //Return Error if Timeout
        while (I2CMasterBusy(I2CBase)) {
            if (I2CMasterTimeout(I2CBase) == true) {
                I2CMasterControl(I2CBase, I2C_MASTER_CMD_BURST_RECEIVE_ERROR_STOP);
                *I2CErr = 6;
                I2C_Log_Error(I2CBase, false);
                return 0x00;
            }
        }
    
        //Check for errors
        if (I2CMasterErr(I2CBase)) {
            I2CMasterControl(I2CBase, I2C_MASTER_CMD_BURST_RECEIVE_ERROR_STOP);
            *I2CErr = 7;
            I2C_Log_Error(I2CBase, false);
            return 0x00;
        }
    
        //Get Data from first byte
        return I2CMasterDataGet(I2CBase);

    如果我们在第一个事务期间将其设置在此处、那么它将能够持续工作并持续工作。

    有什么想法?  我很想将第一个事务包装在它自己的软件超时中、然后让硬件超时来完成。

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

    尊敬的 Ben:

     根据数据表、超时计数器应在启动条件的开始处启动。 这意味着当您在第8行开始第一个事务时、计数器应该开始向下计数。  

    应用程序可以对计数器的八个最高有效位进行编程、
    反映事务中可接受的累计低电平时间。 计数在开始时加载
    条件、并在主机内部总线时钟的每个下降沿进行倒计数。 注意、
    即使 I2C 的速度已经设定、为此计数器生成的内部总线时钟也能继续以设定的速度运行
    在总线上保持低电平时。 在达到终端计数时、主状态机强制中止
    在 SCL 和 SDA 释放时发出停止条件来在总线上对总线进行重置。
    作为一个示例、如果一个 I2C 模块正以100 kHz 的速度运行、编辑 I2CMCLKOCNT
    寄存器0xDA 将转换为值0xDA0、因为低四位设置为0x0。 这个
    换言之、也就是3488个时钟周期、即在34.88 ms 时、
    100kHz。
    当时钟稳定时、I2C 主机原始中断状态寄存器(I2CMRIS)的 CLKRIS 位被置位
    达到超时周期、允许主器件启动纠正措施以解析远程从器件
    状态。 另外、I2C 主机控制/状态(I2CMCS)寄存器的 CLKTO 位也被置位;这个位
    在发送停止条件时或 I2C 主器件复位期间清除。 原始 SDA 的状态
    软件可以通过 I2C 主总线的 SDA 和 SCL 位读取 SCL 信号
    帮助确定远程从机状态的监视(I2CMBMON)寄存器。

    在边注上、您可以在以下行的任何地方添加额外的 while (! I2CMasterBusy(I2CBase){}

    替换:

    while (I2CMasterBusy(I2CBase){}

    其中:

    while (! I2CMasterBusy(I2CBase){}//添加此行

    while (I2CMasterBusy(I2CBase){}//仍保留此行

    也许您没有遇到此帖子中提出的问题、但添加建议的解决方法可以避免比赛问题。 请参阅 Ralph 回答的这篇文章。 这与您的 SCL 超时问题无关。  

    https://e2e.ti.com/support/power-management-group/power-management/f/power-management-forum/844446/tpsm846c23evm-806-why-ic2-needs-certain-delay-in-tpsm846c23evm-806-for-every-data-byte-transmission

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

    Charles

    我们最初有 while (! I2CMasterBusy(I2CBase){}在那里,但由于我们正在运行 RTOS ,它导致了问题。

    如果周期发生在 I2CMasterControl(...) 和 while (!I2CMasterBusy (...) {},它最终会停留在那里。

    替换 while (! MasterBusy)通过静态延迟解决了该问题。

    I2CMasterControl(I2CBase, I2C_MASTER_CMD_SINGLE_RECEIVE);
    
    //Delay because TM4C I2C is broken
    SysCtlDelay(1000);
    
    //Wait for Master to finish
    while (I2CMasterBusy(I2CBase)) { }

    至于超时、是的、我明白它应该是如何工作的。  如果在 I2C 初始化期间对其进行了设置、则不会这样做。

    我已经很好地解决了这个问题、接下来我继续。  我已经以软件超时方式包装了每个 I2C 外设上的第一个 I2C 事务、从那时起、硬件超时按预期工作。