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.

[参考译文] EK-TM4C123GXL:I2C SCL 线路保持低电平?

Guru**** 2939240 points

Other Parts Discussed in Thread: TMP117

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1126124/ek-tm4c123gxl-i2c-scl-line-remaining-low

器件型号:EK-TM4C123GXL
主题中讨论的其他器件:TMP117

我使用 Tiva 开发板(TM4C123G)从 该 Adafruit 温度传感器读取 I2C。   我正在从温度传感器的寄存器0x0F 中读取一个2字节值。  它正常工作、预期值是我接收到的值(0x0117)、但 我想知道为什么在 我写入温度传感器地址的第一次写入位置后 SCL 线路保持低电平。  以下是我使用逻辑分析仪捕获的内容:

我正在使用的代码看起来正确、并且对于写入寄存器 然后读取两个字节来说非常简单:

    // Set up the slave address with write transaction
    MAP_I2CMasterSlaveAddrSet(i2cChannelInfo[channel].i2cBase, slaveAddress, false);
    WAIT_ON_I2C_BUS_BUSY(channel);

    // Store the command data in I2C data register
    MAP_I2CMasterDataPut(i2cChannelInfo[channel].i2cBase, registerAddress);
    WAIT_ON_I2C_BUS_BUSY(channel);

    // Start the I2C transaction
    MAP_I2CMasterControl(i2cChannelInfo[channel].i2cBase, I2C_MASTER_CMD_BURST_SEND_START);
    WAIT_ON_I2C_BUS_BUSY(channel);

    // Set the data direction to true since the I2C Master is initiating a read from the slave
    MAP_I2CMasterSlaveAddrSet(i2cChannelInfo[channel].i2cBase, slaveAddress, true);
    WAIT_ON_I2C_BUS_BUSY(channel);

    // Start receiving data in burst mode
    MAP_I2CMasterControl(i2cChannelInfo[channel].i2cBase, I2C_MASTER_CMD_BURST_RECEIVE_START);
    WAIT_ON_I2C_BUS_BUSY(channel);

    // Get the first byte
    *outputWord = (MAP_I2CMasterDataGet(i2cChannelInfo[channel].i2cBase) & 0xFF) << (byteOrder == I2C_LSB_FIRST ? 0 : 8);
    WAIT_ON_I2C_BUS_BUSY(channel);

    // Request the second (and final) byte
    MAP_I2CMasterControl(i2cChannelInfo[channel].i2cBase, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
    WAIT_ON_I2C_BUS_BUSY(channel);

    // Read the second byte of data
    *outputWord |= (MAP_I2CMasterDataGet(i2cChannelInfo[channel].i2cBase) & 0xFF) << (byteOrder == I2C_LSB_FIRST ? 8 : 0);
    WAIT_ON_I2C_BUS_BUSY(channel);

宏 WAIT_ON_I2C_BUS_BUS_BUSY 宏定义为:

#define WAIT_ON_I2C_BUS_BUSY(CHANNEL) if(I2CWaitOnMasterBusy(CHANNEL) == false) { EndCriticalSection(); return false; }

有人有什么想法吗?

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

    尊敬的 Terence:

    我想这是因为您使用 了 I2C_MASTER_CMD_BURST_SEND_START、但仅发送一个字节。

    对于此用例、我建议您只使用 I2C_MASTER_CMD_SINGLE_SEND 发送一个字节。

    此致、

    Ralph Jacobi

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

    您好 Ralph -感谢您的快速回复。  实际上、 我最初使用 的是 I2C_MASTER_CMD_SINGLE_SEND、而不是  I2C_MASTER_CMD_BURST_SEND_START、但我注意到在使用 I2C_MASTER_CMD_SINGLE_SEND 时 、写入后显示"停止"、我 担心会使从器  件混乱、因为我仍然需要从寄存器进行读取。

    以下是使用 I2C_MASTER_CMD_SINGLE_SEND 时的事务:

    这是代码。  我所做的就是将 I2C_MASTER_CMD_BURST_SEND_START 更改为  I2C_MASTER_CMD_SINGLE_SEND:

        // Make sure the bus isn't busy before trying to start the transaction
        WAIT_ON_I2C_BUS_BUSY(channel);
    
        // Set up the slave address with write transaction
        MAP_I2CMasterSlaveAddrSet(i2cChannelInfo[channel].i2cBase, slaveAddress, false);
        WAIT_ON_I2C_BUS_BUSY(channel);
    
        // Store the command data in I2C data register
        MAP_I2CMasterDataPut(i2cChannelInfo[channel].i2cBase, registerAddress);
        WAIT_ON_I2C_BUS_BUSY(channel);
    
        // Start the I2C transaction
        MAP_I2CMasterControl(i2cChannelInfo[channel].i2cBase, I2C_MASTER_CMD_SINGLE_SEND);
        WAIT_ON_I2C_BUS_BUSY(channel);
    
        // Set the data direction to true since the I2C Master is initiating a read from the slave
        MAP_I2CMasterSlaveAddrSet(i2cChannelInfo[channel].i2cBase, slaveAddress, true);
        WAIT_ON_I2C_BUS_BUSY(channel);
    
        // Start receiving data in burst mode
        MAP_I2CMasterControl(i2cChannelInfo[channel].i2cBase, I2C_MASTER_CMD_BURST_RECEIVE_START);
        WAIT_ON_I2C_BUS_BUSY(channel);
    
        // Get the first byte
        *outputWord = (MAP_I2CMasterDataGet(i2cChannelInfo[channel].i2cBase) & 0xFF) << (byteOrder == I2C_LSB_FIRST ? 0 : 8);
        WAIT_ON_I2C_BUS_BUSY(channel);
    
        // Request the second (and final) byte
        MAP_I2CMasterControl(i2cChannelInfo[channel].i2cBase, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
        WAIT_ON_I2C_BUS_BUSY(channel);
    
        // Read the second byte of data
        *outputWord |= (MAP_I2CMasterDataGet(i2cChannelInfo[channel].i2cBase) & 0xFF) << (byteOrder == I2C_LSB_FIRST ? 8 : 0);
        WAIT_ON_I2C_BUS_BUSY(channel);

    此外、我还找到 了这个关于 与 Tiva 进行 I2C 通信的 DigiKey 教程、它使用 I2C_MASTER_CMD_BURST_SEND_START  在进行 I2C 读取时向从器件发送单个寄存器寄存器。  请参阅标题为"I2C 接收功能"的部分。

    遗憾  的是、TivaWare 外设库文档(SW-TM4C-DRL-UG.2.1.3.156)或示例代码中没有多字节读取示例。  

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

    尊敬的 Terence:

    因此、我在 I2C 器 件方面的典型经验是、正确的用法是使用 I2C_MASTER_CMD_SINGLE_SEND、它会在数据读取完成之前生成停止条件。 尽管如此、我一直在查看 TMP117的数据表、并且可以看到采用这种方法引起关注的原因、因为这是如何概述通信的。 传输 结束时应发出唯一停止条件。

    使用单次发送与突发式命令的过程实际上被设置为指示何时 发送启动和停止条件、因此您编写代码的方式将在何时 发送启动和停止条件方面与 TMP117数据表相匹配。

    这就提出了为什么 SCL 线路在该时间段内为低电平的问题。 它不受 TMP117控制、因为数据表明确指出器件不会驱动 SCL 线路、因此它是 TM4C、它将其保持在低电平。

    我猜、由于外设等待清晰的下一步操作、SCL 线路被保持在低电平。 如果需要发出停止条件、SCL 需要保持在最后一个时钟的低电平。 因此、状态机会在预期情况下将其保持在较低的水平、直到它收到有关下一步应执行的指令。 我看不到这方面的任何根本问题、因为当时正在进行通信、您已经确认通信正常。

    关于多个 bye Read 示例、我们确实在这方面存在差距、但在 TivaWare 2.2.0中、我们发布了一个新的简化 I2C 示例、涵盖了这类用例。 然而、所述传感器的工作原理与此基本不同、即主器件触发读取、然后在延迟后读取结果。 以下是我们用于供您参考的 API:

    //*****************************************************************************
    //
    // This function sends the specified command to the I2C slave device.
    //
    //*****************************************************************************
    void
    I2CWriteCommand(uint32_t ui32Command)
    {
        //
        // Set up the slave address with write transaction.
        //
        MAP_I2CMasterSlaveAddrSet(I2C3_BASE, SHT21_I2C_ADDRESS, false);
    
        //
        // Store the command data in I2C data register.
        //
        MAP_I2CMasterDataPut(I2C3_BASE, ui32Command);
    
        //
        // Start the I2C transaction.
        //
        MAP_I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_SINGLE_SEND);
    
        //
        // Wait until the I2C transaction is complete.
        //
        while(MAP_I2CMasterBusy(I2C3_BASE))
        {
        }
    }

    //*****************************************************************************
    //
    // This function will read three 8-bit data from the I2C slave.  The first
    // two 8-bit data forms the humidity data while the last 8-bit data is the
    // checksum. This function illustrates three different I2C burst mode
    // commands to read the I2C slave device.
    //
    //*****************************************************************************
    void
    I2CReadCommand(uint32_t * pui32DataRx)
    {
        //
        // Modify the data direction to true, so that seeing the address will
        // indicate that the I2C Master is initiating a read from the slave.
        //
        MAP_I2CMasterSlaveAddrSet(I2C3_BASE, SHT21_I2C_ADDRESS, true);
    
        //
        // Setup for first read.  Use I2C_MASTER_CMD_BURST_RECEIVE_START
        // to start a burst mode read.  The I2C master continues to own
        // the bus at the end of this transaction.
        //
        MAP_I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START);
    
        //
        // Wait until master module is done transferring.
        //
        while(MAP_I2CMasterBusy(I2C3_BASE))
        {
        }
    
        //
        // Read the first byte data from the slave.
        //
        pui32DataRx[0] = MAP_I2CMasterDataGet(I2C3_BASE);
    
        //
        // Setup for the second read.  Use I2C_MASTER_CMD_BURST_RECEIVE_CONT
        // to continue the burst mode read.  The I2C master continues to own
        // the bus at the end of this transaction.
        //
        MAP_I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
    
        //
        // Wait until master module is done transferring.
        //
        while(MAP_I2CMasterBusy(I2C3_BASE))
        {
        }
    
        //
        // Read the second byte data from the slave.
        //
        pui32DataRx[1] = MAP_I2CMasterDataGet(I2C3_BASE);
    
        //
        // Setup for the third read.  Use I2C_MASTER_CMD_BURST_RECEIVE_FINISH
        // to terminate the I2C transaction.  At the end of this transaction,
        // the STOP bit will be issued and the I2C bus is returned to the
        // Idle state.
        //
        MAP_I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
    
        //
        // Wait until master module is done transferring.
        //
        while(MAP_I2CMasterBusy(I2C3_BASE))
        {
        }
        
        //
        // Note the third 8-bit data is the checksum byte.  It will be
        // left to the users as an exercise if they want to verify if the
        // checksum is correct.
        pui32DataRx[2] = MAP_I2CMasterDataGet(I2C3_BASE);
    }

    这是使用的应用代码:

            //
            // Write the command to start a humidity measurement.
            //
            I2CWriteCommand(TRIGGER_RH_MEASUREMENT);
    
            //
            // Per SHT21 sensor datasheet, the humidity measurement
            // can take a maximum of 29ms to complete at 12-bit
            // resolution.  Here we will wait for 33ms.
            //
            MAP_SysCtlDelay(MAP_SysCtlClockGet() / (30 * 3));
    
            //
            // Read the humidity measurements.
            //
            I2CReadCommand(&pui32DataRx[0]);

    希望所有这些信息都能澄清您看到的内容、并确认您正在为所涉及的特定传感器使用适当的 API。

    此致、

    Ralph Jacobi

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

    感谢 的全面回应。  非常感谢。