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 错误处理

Guru**** 2511985 points
Other Parts Discussed in Thread: TM4C1294NCZAD

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1262945/tm4c1294nczad-i2c-error-handling

器件型号:TM4C1294NCZAD

您好、TI!

我必须对旧版产品进行一些小的更新。  遗憾的是、我无法访问其中的 JTAG 端口、并且只能使用引导加载程序更新固件。  无调试。

该器件会与整个基于 I2C 的不同传感器通信、并且大部分情况下运行良好。  唯一的问题是、如果从 I2C 器件没有响应(缺失、损坏等)、TM4C 会锁定在 I2CSend 例程中的某个位置。

熟悉外设库的人能否建议我可以向此代码添加哪些内容来处理缺少的/无响应的 I2C 从器件?

非常感谢!

P.S.我实际上发布了一个类似的问题,关于这个确切的问题几年前,从来没有真正想出一个完整的修复.  早在那时、我们就有这个器件的开发版本(具有 JTAG 访问权限)、但多年来它们一直被弃用、因此这就变得更加困难了。

uint32_t I2C3Send(uint8_t slave_addr, uint8_t num_of_args, ...)
{
    uint8_t i;

    // Tell the master module what address it will place on the bus when
    // communicating with the slave.
    I2CMasterSlaveAddrSet(I2C3_BASE, slave_addr, false);

    //stores list of variable number of arguments
    va_list vargs;

    //specifies the va_list to "open" and the last fixed argument
    //so vargs knows where to start looking
    va_start(vargs, num_of_args);

    //put data to be sent into FIFO
    I2CMasterDataPut(I2C3_BASE, va_arg(vargs, uint32_t));

    //if there is only one argument, we only need to use the
    //single send I2C function
    if(num_of_args == 1)
    {
        //Initiate send of data from the MCU
        I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_SINGLE_SEND);

        // Wait until MCU is done transferring.
        while(!I2CMasterBusy(I2C3_BASE));
        while(I2CMasterBusy(I2C3_BASE));

        if(I2CMasterErr(I2C3_BASE)) return 0;

        //"close" variable argument list
        va_end(vargs);

    }

    //otherwise, we start transmission of multiple bytes on the
    //I2C bus
    else
    {
        //Initiate send of data from the MCU
        I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_BURST_SEND_START);

        // Wait until MCU is done transferring.
        while(!I2CMasterBusy(I2C3_BASE));
        while(I2CMasterBusy(I2C3_BASE));

        if(I2CMasterErr(I2C3_BASE)) return 0;

        //send num_of_args-2 pieces of data, using the
        //BURST_SEND_CONT command of the I2C module
        for(i = 1; i < (num_of_args - 1); i++)
        {
            //put next piece of data into I2C FIFO
            I2CMasterDataPut(I2C3_BASE, va_arg(vargs, uint32_t));
            //send next data that was just placed into FIFO
            I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);

            // Wait until MCU is done transferring.
            while(!I2CMasterBusy(I2C3_BASE));
            while(I2CMasterBusy(I2C3_BASE));

            if(I2CMasterErr(I2C3_BASE)) return 0;

        }

        //put last piece of data into I2C FIFO
        I2CMasterDataPut(I2C3_BASE, va_arg(vargs, uint32_t));
        //send next data that was just placed into FIFO
        I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
        // Wait until MCU is done transferring.
        while(!I2CMasterBusy(I2C3_BASE));
        while(I2CMasterBusy(I2C3_BASE));

        if(I2CMasterErr(I2C3_BASE)) return 0;

        //"close" variable args list
        va_end(vargs);

    }
    return 1;
}

SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C3);
SysCtlPeripheralReset(SYSCTL_PERIPH_I2C3);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOR);
GPIOPinConfigure(GPIO_PK4_I2C3SCL);
GPIOPinConfigure(GPIO_PR5_I2C3SDA);
GPIOPinTypeI2CSCL(GPIO_PORTK_BASE, GPIO_PIN_4);
GPIOPinTypeI2C(GPIO_PORTR_BASE, GPIO_PIN_5);
I2CMasterInitExpClk(I2C3_BASE, SysCtlClockGet(), true); //False = 100kbs, True = 400kbs
HWREG(I2C3_BASE + I2C_O_FIFOCTL) = 80008000;

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

    尊敬的 Benjamin:

    除了您报告的问题外、I2C 完全可以正常工作、我感到非常惊讶。 它存在于您的第二个代码片段中。 使用 SysCtlClockGet ()。 此 API 只能用于 TM4C123 MCU、不能用于 TM4C129。 这与您为此线程选择的器件型号 TM4C1294NCZAD I2C 错误处理不符。 我希望您确实在使用 TM4C123。 当您使用错误的器件型号创建该主题时、这只是一个错误。  

    I2CMasterInitExpClk (I2C3_base、SysCtlClockGet ()、true);//False = 100kbs、True = 400kbs

    Unknown 说:
    该器件与基于 I2C 的各种传感器发生了巨大的冲突、而且大多情况下运行良好。  唯一的问题是、如果从 I2C 设备没有响应(缺失、损坏等)、TM4C 会锁定在 I2CSend 例程中的某个位置。

    现在、让我们回到 您的问题。  

    首先、我 不能真正看到 I2C3Send ()出现问题 、而不是 SysCtlClockGet。  如果使用 TM4C123、SysCtlClockGet 将不是问题。 但是、如果您确实使用了 TM4C1294NCZAD、那么首先要修复的问题将是。  

     您是否检查了从机不响应时遇到的错误类型?  

      出现任何错误时、SDA 线路的状态是怎样的? 如果您得到的噪声会在 SCL 或 SDA 上产生额外转换、则从器件和主器件将不同步。 例如、从器件等待另一个 SCL 时钟、但主器件认为它已经发送完 。解决方案是使用 SCL 作为数字 I/O、并在从器件释放 SDA 之前对它进行位次触发、即低/高。 反之亦然,情况也可能发生。  

     我建议您首先检查 SCL 和 SDA 线路的状态。 如果从器件将 SDA 保持为低电平、使从器件脱离此状态的唯一方法是 SCL 上的边沿。 由于 I2C 模块将其视为保持总线的不同主器件、因此它不会尝试驱动 SCL。 位拆裂是唯一可以使你摆脱锁定的解决方案。 复位模块或主机超时不会改变从机的状态、因为从机无法知道主机已复位。  

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

    Charles

    抱歉-我们正在使用 TM4C1294、但 SysCtlClockGet ()函数已被正确返回频率的函数替代。  I2C 经示波器确认在预期频率下运行。

    在 SCL/SDA 保持低电平方面、我正在处理的特定测试用例是 I2C 器件缺失或损坏、并且根本没有响应。  基本而言、假设没有从器件将 SCL/SDA 保持为低电平。

    我想我的问题确实可以归结为 I2CMasterBusy ()的运行。  在从器件根本不响应的情况下、该函数是会一直返回零、还是会继续无限期地使 MasterBusy 生效?  我曾尝试对这些函数进行详细描述、但我所遇到的一切都是相当高的。

    while (I2CMasterBusy (..));是我可以看到代码可能卡在循环中的唯一位置。  还有其他我还应该检查的东西吗?
    while (I2CMasterBusy)&& (I2CMasterErr ))),例如?

    此外、当 I2CMasterErr 返回错误时、在执行另一个 I2C 事务之前清除错误的正确方法是什么?

    谢谢!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我想我的问题确实可以归结为 I2CMasterBusy()的操作。  [/报价]

    您是否可以在第30行放置一个断点, 检查 I2CMasterBusy()之后的行? 是否继续行30? 如果它是这样,那么它没有挂起由于 I2CMasterBusy()。  I2CMasterBusy()在 I2C 内核正在发送时返回 true。 虽然从器件可能没有响应、但从主器件的角度来看、尽管从器件没有以 ACK 响应、但它在发送命令字节后应清除 BUSY 位。 在本例中、您应该会得到一个 ACK 错误。 请检查是否设置了 NACKRIS。

    此外、当 I2CMasterErr 返回错误时、在执行另一个 I2C 事务之前清除错误的正确方法是什么?

    [/报价]

    通过向 I2CMICR 寄存器写入1来清除相应的错误位 您可以使用 I2CMasterIntClear ()或 I2CMasterIntClearEX ()清除错误标志,并可能禁用相应的 I2C 模块,这样它就不会再次访问从器件,因为从器件不存在。  

    [/quote]