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.

[参考译文] TMS320F280049C:I2C_getStopConditionStatus 始终返回 true

Guru**** 2524040 points


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

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1272822/tms320f280049c-i2c_getstopconditionstatus-always-returns-true

器件型号:TMS320F280049C

我有  使用 I2C_INT_STOP_Condition 和 2C_INT_NO_ACK 中断的 I2C 代码。

在中断处理程序中、当我获取 2C_INT_NO_ACK 时、我 会调用 I2C_sendStopCondition、以便接下来获取 I2C_INT_STOP_Condition 中断。

我这样做是为了在单点(停止条件)处理消息的每一端并启动新的传输。

现在、 NACKed 消息后下一次传输失败的时间大约有一半。  

为了解决这个问题、我尝试 在中断处理程序中添加一个 while 循环、在它启动新的(有时失败)消息之前轮询 I2C_getStopConditionStatus。

这解决了问题、但是、对于其他 I2C 器件、有时这种 while 循环会卡住、因为 I2C_getStopConditionStatus 在某些情况下似乎总是返回 true。

什么会导致 I2C_getStopConditionStatus 从不返回 FALSE?

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

    您好、Kustaa、

    根据参考手册对 I2CMDR 寄存器的说明(这是 I2C_getStopConditionStatus 函数使用的内容):

    您能告诉我您的 I2C 配置吗? F28004x I2C 是设置为控制器还是目标? 是接收还是传输? 它使用哪种串行格式模式?

    此致、

    阿米尔·奥马尔

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

    您好!

    以下是初始化 I2C 控制器的方式:

    void init_i2ca() {
        Interrupt_disable(INT_I2CA);
        Interrupt_disable(INT_I2CA_FIFO);
    
        I2C_disableInterrupt(I2CA_BASE, I2C_INT_NO_ACK);
        I2C_disableInterrupt(I2CA_BASE, I2C_INT_STOP_CONDITION);
    
        g_i2cbus_endp.m_trnx_idx = 0;
        g_i2cbus_endp.m_receive = false;
    
        I2C_disableModule(I2CA_BASE);
    
        I2C_initMaster(I2CA_BASE, DEVICE_SYSCLK_FREQ, 100000, I2C_DUTYCYCLE_50);
        I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE);
    
        I2C_setDataCount(I2CA_BASE, 0);
        I2C_setBitCount(I2CA_BASE, I2C_BITCOUNT_8);
    
        I2C_disableFIFO(I2CA_BASE);
        I2C_enableFIFO(I2CA_BASE);
    
        I2C_setFIFOInterruptLevel(I2CA_BASE, I2C_FIFO_TXFULL, I2C_FIFO_RXFULL);
    
        I2C_enableModule(I2CA_BASE);
    
    
        Interrupt_register(INT_I2CA_FIFO, &i2c_FIFO_ISR);
        Interrupt_register(INT_I2CA, &i2c_ISR);
    
        Interrupt_enable(INT_I2CA);
    
        I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_NO_ACK | I2C_INT_STOP_CONDITION | I2C_INT_ARB_LOST);
        I2C_enableInterrupt(I2CA_BASE, I2C_INT_NO_ACK | I2C_INT_STOP_CONDITION | I2C_INT_ARB_LOST);
        i2c_start_next_transfer();
    }
    

    这是我的中断处理程序:

    __interrupt void i2c_ISR(void) {
        uint32_t istat = I2C_getInterruptStatus(I2CA_BASE);
        if (istat & I2C_INT_STOP_CONDITION) {
            GPIO_togglePin(39);
            I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_STOP_CONDITION);
            i2c_handle_received_data();
            i2c_start_next_transfer();
            GPIO_togglePin(39);
        }
        if (istat & I2C_INT_NO_ACK) {
            GPIO_togglePin(39);
            I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_NO_ACK);
            I2C_clearStatus(I2CA_BASE, I2C_STS_NO_ACK);
            I2C_disableFIFO(I2CA_BASE);
            I2C_enableFIFO(I2CA_BASE);
            I2C_sendStopCondition(I2CA_BASE);
            GPIO_togglePin(39);
        }
        if (istat & I2C_INT_ARB_LOST) {
            I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_ARB_LOST);
    
        }
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP8);
    }
    

    这用于处理在获取停止条件中断时接收/接收新消息:

    void i2c_start_next_transfer() {
    
        I2C_Trxn_t *trxn = get_next_transfer(&g_i2cbus_endp);
    
        if (trxn) {
            while(I2C_getStopConditionStatus(I2CA_BASE))
            GPIO_togglePin(39);
            //g_debug_x = trxn->m_debug;
            I2C_disableFIFO(I2CA_BASE);
            I2C_enableFIFO(I2CA_BASE);
            if (trxn->m_send) {
                I2C_setSlaveAddress(I2CA_BASE, trxn->m_addr);
                I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE);
                I2C_setDataCount(I2CA_BASE, trxn->m_data_len);
                uint16_t i;
                for (i = 0; i < trxn->m_data_len; i++) {
                    I2C_putData(I2CA_BASE, trxn->m_data[i]);
                }
                //I2C_setFIFOInterruptLevel(I2CA_BASE, I2C_FIFO_TXEMPTY, I2C_FIFO_RXFULL);
            } else {
                I2C_setSlaveAddress(I2CA_BASE, trxn->m_addr);
                I2C_setConfig(I2CA_BASE, I2C_MASTER_RECEIVE_MODE);
                I2C_setDataCount(I2CA_BASE, trxn->m_data_len);
                //I2C_setFIFOInterruptLevel(I2CA_BASE, I2C_FIFO_TXFULL, (I2C_RxFIFOLevel) trxn->m_data_len);
            }
            I2C_sendStartCondition(I2CA_BASE);
            I2C_sendStopCondition(I2CA_BASE);
        } else {
            I2C_disableInterrupt(I2CA_BASE, I2C_INT_NO_ACK);
            I2C_disableInterrupt(I2CA_BASE, I2C_INT_STOP_CONDITION);
        }
    
    }

    它是在上面的 int  

    while (I2C_getStopConditionStatus (I2CA_BASE))

    代码有时会卡住。

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

    您好、Kustaa、

    它是在上面的 int  

    while (I2C_getStopConditionStatus (I2CA_BASE))

    代码有时会卡住。

    [/报价]

    根据寄存器描述、STP 位在停止条件生成后自动清零。 我不确定为什么 在您的设备上有时不会清除它。 就从器件发送的有效传输而言、您是否在示波器上验证了这一点?  发送完成后应立即产生停止条件(见下文):

     也要确保 I2C 外设未处于复位状态(我不确定这里是否会发生这种情况、但这 会阻止 I2C 外设检测启动/停止条件)。

    此致、

    阿米尔·奥马尔

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

    您说停止条件的一部分取决于我要通信的总线上的器件?  
    因此、在中断服务例程中、像我这样的(可能)无限循环是不可接受的?
    我的思维模型是停止条件由 I2C 控制器单独生成、因此始终会发生、环路将会退出。
    除了实现超时之外、是否有办法检查总线是否处于"不良"状态、以及是否应终止循环?

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

    您好、Kustaa、

    为了有一个停止条件、SDA 和 SCL 线路的控制器需要将它们升高到高电平(如之前的图像所示)。 如果 您指定数据和时钟线路的范围、但没有发生这种情况、则将不会获得停止条件、并且 STP 位也不会被清除。

    除了实现超时之外,是否有其他方法可以检查总线是否处于"坏"状态以及是否应终止循环?
    [/报价]

    您可以向 while 循环添加一些逻辑来确定此情况、例如、如果需要、通过运行带有 CPU 计时器的计数器来创建某种超时。 我不认为有这样的硬件、因此您需要进行软件实施。

    此致、

    阿米尔·奥马尔