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.

[参考译文] TMS320F280025C:I2C 总线忙、未知占用总线的原因

Guru**** 2463330 points
Other Parts Discussed in Thread: C2000WARE

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

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1180923/tms320f280025c-i2c-bus-busy-unknow-reason-to-occupy-the-bus

器件型号:TMS320F280025C
主题中讨论的其他器件:C2000WARE

驱动程序库:C2000Ware 4.02.00

参考的示例:I2C_Ex5_MASTER_SLAVE_INTERRUPT

I2C 规范:100kHz、7位地址、8位数据格式。 使用 FIFO 和 FIFO 中断。

简介:

  • 0025C 作为从 站、使用 Microchip PICkit 串行分析器测试正常且稳定、也可以使用另一个 F280025C 控制卡实现 I2C 主站、这意味着 I2C 总线设置正确。
  • 使用 Linux 系统作为主系统并运行"i2cget"命令、有机会让0025将 SCL 保持在低电平、猜它会进入延时模式。 Linux 系统还没有超时机制。
  • 需要知道的是、代码不够快、无法处理 I2C 请求、或者一些中断被抢占的问题导致了这个问题。
  •  这个问题有点复杂...

尊敬的 TI 专家:  

正如我 之前在 I2C 上所做的工作、我将构建一 个中断主/从设备进行通信。

感谢 gurus 作为您、我知道 I2C 中断可以触发主器件/从器件来更改数据方向、并将角色从接收器更改为发送器。

考虑将 Linux 系统用作主系统、0025C 与 EEPROM 一样、 应 通过"i2cget"命令读取/写入寄存器(命令)。

问题是、当我使用数据分析器和另一个0025作为主器件来测试代码时、它非常稳定、快速且正确。

但是、当我将平台更改为自定义平台时、通过数据格式、电子特性是相同的、因此有机会让从器件保持 SCL 为低电平。

发生错误时对波形执行堆叠:

虽然逻辑分析仪显示 SCL 恢复为高电平、但出于某种原因、我使用示波器检查 SCL 是否为低电平(可能是它超出范围)。

我还检查总线上是否有其他器件导致了此问题、但 SCL 仅在我的器件连接到总线时拉低。

此时、我在 while 循环中设置了一个断点(不执行任何循环)、并按如下所示检查寄存器:

BB 位 为高电平、这会导致 I2C 模块的状态错误、从而中断有限状态机。

正如我所知、I2C 模块检测 到 STARTcondition 后、BB=1、直到检测到另一个停止条件。

因此、不可预测的 BB=1意味着两个感官:意外发生了开始或意外发生了停止、或者我错过了什么?

但 I2C 模块具有内置滤波器、我认为这不是噪声问题。

为了将这个死端作为从器件来解决、我不能通过发送启动/停止条件来将其复位、而是复位整个 I2C 模块。

下面是一些参考波形:

数据重新发送失败 、但 I2C 获得了正确的停止条件以复位 BB 位。

数据传输成功、它包含两个字节、并完美地停止位。

通过自定义 Linux 系统获得成功

使用串行数据分析器成功

代码如下所示

I2C FIFO ISR

我知道,当器件处于从站传输模式时,I2CCNT 值无关,要传输数据,只需使用 I2C_Put ()即可。

我希望只使用 I2C_FFTX_INT 一次、将两个字节的数据放入 FIFO 中进行循环。

I2C 模块应自动向外发送数据。

/* @brief   Process I2C FIFO interrupt source
 * @param   none
 * @return  none
 * @disc    FIFO ISR need to process RX data and send data back to master
 */
__interrupt void i2c_FIFO_isr(void)
{
    uint32_t intSource_FIFO = (uint32_t)I2C_getInterruptStatus(I2CA_BASE);

    // If RX FIFO interrupt flag is set, read command
    if((intSource_FIFO & I2C_INT_RXFF) != 0)
    {
        I2c_cmd = I2C_getData(I2CA_BASE);
        I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_RXFF);
    }

    // Slave transmitter mode, send back data asked by master
    if(((intSource_FIFO & I2C_INT_TXFF) && I2c_cmd) != 0 )
    {
        i2c_cmd_process(I2c_cmd);       // process the i2c command
        I2c_cmd = 0;
        I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_TXFF);
    /*  After sending data back to master, stop condition detected
     *  Then FIFOINT will be disabled,
     *  so the process should not go back to TXFFINT again.
     */
    }
    PieCtrlRegs.PIEACK.bit.ACK8 = 1;
}

I2C_cmd_process

此函数切换到不同的命令、发送不同的数据。

我认为这可能会减慢整个过程、因为它处于中断中?

void i2c_cmd_process(uint16_t cmd){
            uint16_t i;
            switch(cmd){
                case(Vin1_cmd):
                        sData[0] = (Vin1_adc_val >> 8) & 0x00ff;
                        sData[1] = (Vin1_adc_val) & 0x00ff;
                        for(i = 0; i < 2; i ++)
                            I2C_putData(I2CA_BASE, sData[i]);
                        break;

                 default:
                     // Unrecognize command, send 0x87 twice
                     for(i = 0; i < 2; i ++)
                         I2C_putData(I2CA_BASE, 0x87);
                         break;

            }
}

I2C INT ISR

只需调整数据方向、并在检测到停止条件时复位 FIFO。

另外、发生在其他器件通信上的停止位也会导致该中断、只需保持 FIFO 清零即可。

/* @brief   Process I2C interrupt source
 * @param   none
 * @return  none
 * @disc    As I2C slave, ISR happened when master call it, this will trigger AASINT.
 *          Also, when master stop communication, STPINT triggered, slave reset I2C FFINT.
 */
__interrupt void i2c_isr(void){
    I2C_InterruptSource intSource = I2C_getInterruptSource(I2CA_BASE);
    // Go into different interrupt case
    switch (intSource)
    {
    case I2C_INTSRC_ARB_LOST:
        break;

    case I2C_INTSRC_NO_ACK:
        break;

    case I2C_INTSRC_REG_ACCESS_RDY:
        break;

    case I2C_INTSRC_RX_DATA_RDY:
        break;

    case I2C_INTSRC_TX_DATA_RDY:
        break;

    case I2C_INTSRC_STOP_CONDITION:
        // Disable I2C interrupt when I2C communication stop
        I2C_disableInterrupt(I2CA_BASE, (I2C_INT_TXFF | I2C_INT_RXFF));
        // Reset FIFO
        I2C_disableFIFO(I2CA_BASE);
        I2C_enableFIFO(I2CA_BASE);
        break;

    case I2C_INTSRC_ADDR_SLAVE:
        // Slave called by master
        I2C_setFIFOInterruptLevel(I2CA_BASE, I2C_FIFO_TX2, I2C_FIFO_RX1);   // Prepare the FIFO level

        // When master call the salve in read mode
        if((I2C_getStatus(I2CA_BASE) & I2C_STS_SLAVE_DIR))
        {
            // Slave Transmitter (SDIR = 1)
            I2C_setConfig(I2CA_BASE, I2C_SLAVE_SEND_MODE);
            // Enable TX FIFO interrupt to send back data
            // Disable RXFF interrupt
            I2C_disableInterrupt(I2CA_BASE, I2C_INT_RXFF);
            I2C_enableInterrupt(I2CA_BASE, I2C_INT_TXFF);
            I2C_clearInterruptStatus(I2CA_BASE, (I2C_INT_TXFF|I2C_INT_RXFF));
        }
        // When master call the slave in write mode
        else
        {
            // Slave Receiver (SDIR = 0)
            I2C_setConfig(I2CA_BASE, I2C_SLAVE_RECEIVE_MODE);
            // Enable RX FIFO interrupt waiting command
            // Disable TXFF interrupt
            I2C_disableInterrupt(I2CA_BASE, I2C_INT_TXFF);
            I2C_enableInterrupt(I2CA_BASE, I2C_INT_RXFF);
            I2C_clearInterruptStatus(I2CA_BASE, (I2C_INT_TXFF|I2C_INT_RXFF));
        }
        break;

        default:
            ESTOP0;
        break;
    }
    PieCtrlRegs.PIEACK.bit.ACK8 = 1;
}

INIT_I2C

GPIO 设置和 I2C 模块设置

void Init_I2C(void)
{
    // Enable I2C-A on GPIO32 - GPIO33
    EALLOW;
    GpioCtrlRegs.GPBPUD.bit.GPIO32 = 0;    // Enable pull-up for GPIO32 (SDAA)
    GpioCtrlRegs.GPBPUD.bit.GPIO33 = 0;    // Enable pull-up for GPIO33 (SCLA)

    GpioCtrlRegs.GPBQSEL1.bit.GPIO32 = 3;  // Asynch input GPIO32 (SDAA)
    GpioCtrlRegs.GPBQSEL1.bit.GPIO33 = 3;  // Asynch input GPIO33 (SCLA)

    GpioCtrlRegs.GPBGMUX1.bit.GPIO32 = 0;   // Configure GPIO32 for SDAA operation
    GpioCtrlRegs.GPBGMUX1.bit.GPIO33 = 0;   // Configure GPIO33 for SCLA operation

    GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 1;    // Configure GPIO32 for SDAA operation
    GpioCtrlRegs.GPBMUX1.bit.GPIO33 = 1;    // Configure GPIO33 for SCLA operation

    GpioCtrlRegs.GPBODR.bit.GPIO32 = 0;
    GpioCtrlRegs.GPBODR.bit.GPIO33 = 0;
    EDIS;

    //  Initialize I2C (Slave receiver mode)
    I2caRegs.I2CMDR.bit.IRS = 0;             // Reset I2C module
    I2caRegs.I2COAR.all = 0x60;              // Configure I2C own address
    I2caRegs.I2CSAR.all = 0x0;               // Configure I2C slave address

    I2caRegs.I2CMDR.bit.MST = 0;            // Configure I2C as slave
    I2caRegs.I2CMDR.bit.TRX = 0;            // Configure I2C as receive mode
    I2caRegs.I2CMDR.bit.BC = 0;             // Set the bit count to 8 bits per data byte
    I2caRegs.I2CCNT = 1;                    // Set data count = 1 bytes

    // Setup TX FIFO
    I2caRegs.I2CFFTX.bit.TXFFRST = 0;       // Reset and hold TX FIFO
    I2caRegs.I2CFFTX.bit.I2CFFEN = 1;       // Enable I2C FIFO
    I2caRegs.I2CFFTX.bit.TXFFIENA = 0;      // Disable TXFF interrupt
    I2caRegs.I2CFFTX.bit.TXFFIL = 0;        // TX FIFO level = 0 bytes
    I2caRegs.I2CFFTX.bit.TXFFINTCLR = 1;    // Clear TXFF INT
    I2caRegs.I2CFFTX.bit.TXFFRST = 1;       // Enable TX FIFO

    // Setup RX FIFO
    I2caRegs.I2CFFRX.bit.RXFFRST = 0;       // Reset and hold RX FIFO
    I2caRegs.I2CFFRX.bit.RXFFIENA = 1;      // Enable RXFIFO interrupt
    I2caRegs.I2CFFRX.bit.RXFFIL = 1;        // RX FIFO level = 1 byte
    I2caRegs.I2CFFRX.bit.RXFFINTCLR = 1;    // Clear RXFF INT
    I2caRegs.I2CFFRX.bit.RXFFRST = 1;       // Enable RX FIFO

    // Setup interrupt source
    I2caRegs.I2CIER.bit.AAS =   1;          // Enable Address as slave interrupt
    I2caRegs.I2CIER.bit.SCD =   1;          // Enable Stop condition detected interrupt
    I2caRegs.I2CIER.bit.XRDY =  0;          // Enable Transmit-data-ready interrupt
    I2caRegs.I2CIER.bit.RRDY =  0;          // Enable Receive-data-ready interrupt
    I2caRegs.I2CIER.bit.ARDY =  0;          // Enable Register-access-ready interrupt
    I2caRegs.I2CIER.bit.NACK =  0;          // Enable Non-ack interrupt
    I2caRegs.I2CIER.bit.ARBL =  0;          // Enable Arbitration-lost interrupt

    I2caRegs.I2CEMDR.bit.BC = 0;
    // Clear interrupt flags
    I2caRegs.I2CSTR.all = 0xFFFF;               // Clear other I2C flags
    I2caRegs.I2CMDR.bit.IRS = 1;                // Release I2C module
    DELAY_US(100);
}

结论:

  1. 我想知道我的 TTXFFINT 使用是否良好、或者这个中断设计为逐字节传输数据?
  2. 我错过了什么会导致 I2C 总线冻结(BB =1)吗?
  3. 如果中断被其他更高优先级的 ISR (如 ADCA1)抢占、它会导致 I2C 中断?
  4. 这种问题很可能会导致 Linux 系统的问题很小、因为它可以正确读取其他设备。

感谢您的帮助!!  

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

    基于 Linux 的 I2C 很可能无法为停止条件提供足够的设置时间。

    对于标准模式、您需要至少4us 的设置时间才能检测到停止条件。

    对于快速模式、您至少需要0.6us 的设置时间才能检测到停止条件。 器件数据表中提到了这两个参数

    此致、

    曼诺伊

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

    感谢您的快速回复。

    通过采纳您的建议、我检查传输波形。

    我认为停止设置时间 可能不是主要原因、因为 当数据发送成功时、

    波形显示在100kHz 时钟下有8uS。

    当发生总线占线错误时、似乎缺少一些时钟、如下所示:

    P.S 最终状态超出范围时、SCL = 0、SDA = 1。

    然后、我使用示波器进行检查、连接 SCL 和 SDA 线路、发现时钟信号似乎"衰减"、或者被从器件拉低:

    小缩放有一些"纹波"波形、我们可以看到一些 SCL 信号的波形。

    我认为问题可能是由 Linux 系统驱动程序不支持延时功能引起的。

    但我仍然需要你对这个问题的看法。

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

    这里显示的噪声干扰是一个问题。 我想知道干扰是否会导致 I2C (目标/从设备)上出现此问题? 您是否能够可靠地重现此问题。

    您是否尝试在 I2C 引脚上添加串联电阻器和旁路电容器以减轻干扰噪声效应?

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

    感谢您的回复。

    我发现尖峰不是噪声、它应该是正常的 SCL、而是由从器件拉低。

    由于我使用的 Linux 驱动程序没有延长时间的能力、因此主器件会照常读取消息、而不会影响从器件是否需要等待。

    换言之、主器件忽略从器件的延时请求、因此盲目生成时钟信号、在预设时间后、它会停止延迟。

    但另一方面、从器件生成延时请求、因此它认为主器件将等待它直到它释放 SCL 线路、而不是释放 SCL 线路。

    因此在这种情况下、主器件会误读数据、从器件也会错误地分析总线状态、因此会导致此问题。

    此外、毛刺脉冲实际上是从器件释放正常时钟信号的时刻。

    我连接 GPIO 并分析有关 ISR 和 I2C 的关系。

    当 ISR 与传输不冲突时、它工作正常、CPU 可以完全处理 I2C 请求。

    当 ISR1或 ISR2与 I2C 转换过程发生冲突时、从器件拉低要求更多时间、但主器件没有等待、这会导致问题。

    这就是我发现的、

    感谢您的帮助、希望这能帮助他人。