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.

[参考译文] MSP430G2553:I2C 问题

Guru**** 2530350 points
Other Parts Discussed in Thread: LDC1614, MSP430G2553

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1053283/msp430g2553-i2c-problems

主题中讨论的其他器件:LDC1614MSP430G2553

您好!

我尝试在自己的 PCB 中使用 MSP430G2553 + LDC1614 + MPU6050、但在通过 I2C 通道与 LDC1614通信时遇到了一些问题。

PCB 配置:
拉高电阻10K
P1.6 > I2C SCL
P1.7 > I2C SDA
P2.4 > LDC1614 INTB
P2.5 > LDC1614 SD
LDC1614 ADDR > GND
LDC1614 CLKIN > GND

问题:
当 LDC1614为 I2C 从设备时、最后一个数据包不能发送。
假设有3个字节、代码每次发送一个字节作为数据包。
当第二个信号被成功发送时、IFG2的 UCB0TXIFG 将被清零。
然后、当示波器测量来自 SCL 引脚的信号时、将出现噪声。
2.MPU6050可与 MSP430G2553完美搭配、实现 PCB 中的 I2C 通信。
相同的代码可以很好地用于 Launch Pad (嵌入式 MSP430G2553)和 LDC1614 EVM 板。

int main(void)
{
    WDTCTL = WDTPW + WDTHOLD;   // Stop WDT
    BCSCTL1 = CALBC1_8MHZ;      //20201127   1M -> 8M
    DCOCTL  = CALDCO_8MHZ;
    BCSCTL2 |= DIVS_1;          //20201127   SMCLK / 2 = 4MHz
 
    __delay_cycles(10000);
 
    //reset EVM
    P2SEL &= ~BIT5;
    P2REN |= BIT5;
    P2DIR |= BIT5;              //P2.5 > SD
    P2OUT |= BIT5;
    __delay_cycles(480);
    P2OUT &= ~BIT5;
 
    I2C_init();
    EVM_init();
    MPU_init();
 
    for(;;)
    {
        sensor_mode();
        MPU_read();
    }
}
void MPU_init()
{
    UCB0CTL1 |= UCSWRST;        //20210927
    UCB0I2CSA = 0x68;
    UCB0CTL1 &= ~UCSWRST;       //20210927
    TX_Data[1] = 0x6B;
    TX_Data[0] = 0x00;
    TX_ByteCtr = 2;
    I2C_TX_DATA();
}
 
void MPU_read()
{
    UCB0CTL1 |= UCSWRST;        //20210927
    UCB0I2CSA = 0x68;
    UCB0CTL1 &= ~UCSWRST;       //20210927
    TX_Data[0] = 0x3B;
    TX_ByteCtr = 1;
    I2C_TX_DATA();
 
    RX_ByteCtr = 6;
    I2C_RX_DATA();
 
    xAccel = RX_Data[5] << 8 | RX_Data[4];
    yAccel = RX_Data[3] << 8 | RX_Data[2];
    zAccel = RX_Data[1] << 8 | RX_Data[0];
 
    __no_operation();
    __delay_cycles(600000);
}
 
void EVM_init()
{
    //LDC1614 INTB setup
    EVM_INT_DIR &= ~EVM_INT_BIT;           // INPUT
    EVM_INT_IE |= EVM_INT_BIT;             // interrupt enabled
    EVM_INT_IES |= EVM_INT_BIT;            // Hi->Lo Edge
    EVM_INT_IFG &= ~EVM_INT_BIT;          // Clear IFG
 
    Transmit(0x1C,0x8000);              //LDC13xx16xx_CMD_RESET_DEVICE
    Transmit(0x08,0xFFFF);              //LDC13xx16xx_CMD_REF_COUNT_CH0
    Transmit(0x0C,0x0000);              //LDC13xx16xx_CMD_OFFSET_CH0
    Transmit(0x10,0x044c);              //LDC13xx16xx_CMD_SETTLE_COUNT_CH0
    Transmit(0x14,0x1001);              //LDC13xx16xx_CMD_CLOCK_DIVIDERS_CH0
    Transmit(0x1E,0x8c40);              //LDC13xx16xx_CMD_DRIVE_CURRENT_CH0
    Transmit(0x1A,0x1d01);              //LDC13xx16xx_CMD_CONFIG
    Transmit(0x1B,0x020C);              //LDC13xx16xx_CMD_MUX_CONFIG
    Transmit(0x19,0x0001);              //LDC13xx16xx_CMD_ERROR_CONFIG
}
 
void sensor_mode()
{
    EVM_INT_IE |= EVM_INT_BIT;
    EVM_read();
}
 
void EVM_read()
{
    static unsigned int evmStatus;
 
    if(dataReady == 0)
    {
        if(evmStatus & 0x0048)
        {
            dataReady=1;
        }
    }
 
    if(dataReady==1)
    {
        Receive(LDC13xx16xx_CMD_STATUS,&evmStatus);
        Receive(LDC13xx16xx_CMD_DATA_MSB_CH0,&allData[0]);
        Receive(LDC13xx16xx_CMD_DATA_LSB_CH0,&allData[1]);
 
        uHcal(allData[0],allData[1]);
        dataReady=0;
    }
}
 
void Transmit(unsigned char code, unsigned int data)
{
    __disable_interrupt();
    UCB0CTL1 |= UCSWRST;                //20210927
    UCB0I2CSA = 0x2A;
    UCB0CTL1 &= ~UCSWRST;
    TX_Data[2] = code;
    TX_Data[1] = (data >> 8) & 0xFF;
    TX_Data[0] = data & 0xFF;
    TX_ByteCtr = 3;
    done = FALSE;
    I2C_TX_DATA();
}
 
void Receive(unsigned char code, unsigned int* data)
{
    UCB0CTL1 |= UCSWRST;                //20210927
    UCB0I2CSA = 0x2A;
    UCB0CTL1 &= ~UCSWRST;
 
    TX_Data[0] = code;
    I2C_TX_DATA();
 
    RX_ByteCtr = 2;
    I2C_RX_DATA();
}
 
void I2C_TX_DATA()
{
    __disable_interrupt();
    IE2 |= UCB0TXIE;
    while (UCB0CTL1 & UCTXSTP);
    UCB0CTL1 |= UCTR + UCTXSTT;
    if(UCB0I2CSA == 0x2A)
    {
        __bis_SR_register(GIE);
        __no_operation();
    }
    else
    {
        __bis_SR_register(CPUOFF + GIE);
        __no_operation();
    }
}
 
void I2C_RX_DATA()
{
    __disable_interrupt();
    IE2 |= UCB0RXIE;
    while (UCB0CTL1 & UCTXSTP);
    UCB0CTL1 &= ~UCTR;
    UCB0CTL1 |= UCTXSTT;
    __bis_SR_register(CPUOFF + GIE);
    __no_operation();
    IE2 &= ~UCB0RXIE;
}
 
// USCIAB0TX_ISR
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
    if(UCB0CTL1 & UCTR)     // TX mode (UCTR == 1)
    {
        if (TX_ByteCtr)     // TRUE if more bytes remain
        {
            TX_ByteCtr--;                           // Decrement TX byte counter
            UCB0TXBUF = TX_Data[TX_ByteCtr];        // Load TX buffer
        }
        else                                        // no more bytes to send
        {
            UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
            IFG2 &= ~UCB0TXIFG;                     // Clear USCI_B0 TX int flag
            __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
        }
    }
    else // (UCTR == 0)                             // RX mode
    {
        if (--RX_ByteCtr)                           // RxByteCtr != 0
        {
            RX_Data[RX_ByteCtr] = UCB0RXBUF;        // Get received byte
            if (RX_ByteCtr == 1)                    // Only one byte left?
            {
                UCB0CTL1 |= UCTXSTP;                // Generate I2C stop condition
            }
        }
        else                                        // RxByteCtr == 0
        {
            RX_Data[RX_ByteCtr] = UCB0RXBUF;        // Get final received byte
            IFG2 &= ~UCB0RXIFG;
            __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
        }
    }
}

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

    问题似乎是 G2553 可以单独与 MPU6050和 LDC1614搭配使用。 但在将这三个器件放在同一 I2C 总线上时会出现一些问题。

    您能给我展示一下您听到的噪音吗?

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

    I2C_TX_DATA 在检查 I2C 端口是否停止前禁用中断。 这会导致前一个事务在中间停止。 这将发生、因为它不会等待事务完成。 因此、用于初始化 EVM 的 transmit ()调用字符串只会使 EVM 产生一些麻烦。

    此外,receive()不对传递给它的缓冲地址执行任何操作。 在调用 I2C_TX_DATA 之前、它不会设置 TX 字节计数器、因此调用将无法按预期工作。 可能还有更多问题。

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

    更糟糕的是,Transmit ()禁用中断并重置 I2C 端口,而不会产生抖动,以检查它是否处于繁忙状态。 它将是什么。

    G2553的文档中并不清楚、但对于许多其他器件、您不必将端口置于复位状态即可更改 I2C 从器件地址。

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

    尊敬的 David:

    很抱歉,我有点困惑。  问题似乎出在软件配置和中断上?

    伊斯天

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

    大家好,伊斯安, 戴维,

    我尝试了捕获噪音、但遇到了新问题。

    MPU6050和 LDC1614现在无法正常工作。 无法生成 I2C 启动条件(SCL 无法拉低)

    我已经尝试修复了这个问题,在调用 I2C_TX_DATA 之前,我已经删除了所有“_disable_interrupt ()”、“UCB0CTL1 |= UCSWRST;”,然后更改 I2C 从地址并设置 TX 字节计数器。 但 I2C 仍然无法正常工作,并遇到新问题,I2C 启动条件无法生成(SCL 无法拉低)。

    我已尝试恢复代码,但问题仍然存在。 我是否错过了其他问题?

    int main(void)
    {
        WDTCTL = WDTPW + WDTHOLD;  // Stop WDT
        BCSCTL1 = CALBC1_8MHZ;     //8M
        DCOCTL  = CALDCO_8MHZ;
        BCSCTL2 |= DIVS_1;         //SMCLK / 2 = 4MHz
    
         __delay_cycles(10000);
    
        //reset EVM
        P2SEL &= ~EVM_SD_BIT;
        //P2REN |= EVM_SD_BIT;
        P2DIR |= EVM_SD_BIT;              //P2.5 > SD
        P2OUT |= EVM_SD_BIT;
        __delay_cycles(I2C_TOGGLE_DELAY);
        P2OUT &= ~EVM_SD_BIT;
    
        I2C_init();
        MPU_init();
        EVM_init();
    
        for(;;)
        {
        	sensor_mode();
    		MPU_read();
        }
    }
    
    void MPU_init()
    {
        //UCB0CTL1 |= UCSWRST;              
        UCB0I2CSA = MPU6050;
        //UCB0CTL1 &= ~UCSWRST;            
        TX_Data[1] = 0x6B;
        TX_Data[0] = 0x00;
        TX_ByteCtr = 1;
        I2C_TX_DATA();
    }
    
    void MPU_read()
    {
        //UCB0CTL1 |= UCSWRST;             
        UCB0I2CSA = MPU6050;
        //UCB0CTL1 &= ~UCSWRST;            
        TX_Data[0] = 0x3B;
        TX_ByteCtr = 1;
        I2C_TX_DATA();
    
        RX_ByteCtr = 6;
        I2C_RX_DATA();
    
        xAccel = RX_Data[5] << 8 | RX_Data[4];
        yAccel = RX_Data[3] << 8 | RX_Data[2];
        zAccel = RX_Data[1] << 8 | RX_Data[0];
    
        __no_operation();
        __delay_cycles(600000);
    }
    
    void EVM_init()
    {
        //LDC1614 INTB setup
        EVM_INT_DIR &= ~EVM_INT_BIT;           // INPUT
        EVM_INT_IE |= EVM_INT_BIT;             // interrupt enabled
        EVM_INT_IES |= EVM_INT_BIT;            // Hi->Lo Edge
        EVM_INT_IFG &= ~EVM_INT_BIT;           // Clear IFG
     
        Transmit(0x1C,0x8000);              //LDC13xx16xx_CMD_RESET_DEVICE
        Transmit(0x08,0xFFFF);              //LDC13xx16xx_CMD_REF_COUNT_CH0
        Transmit(0x0C,0x0000);              //LDC13xx16xx_CMD_OFFSET_CH0
        Transmit(0x10,0x044c);              //LDC13xx16xx_CMD_SETTLE_COUNT_CH0
        Transmit(0x14,0x1001);              //LDC13xx16xx_CMD_CLOCK_DIVIDERS_CH0
        Transmit(0x1E,0x8c40);              //LDC13xx16xx_CMD_DRIVE_CURRENT_CH0
        Transmit(0x1A,0x1d01);              //LDC13xx16xx_CMD_CONFIG
        Transmit(0x1B,0x020C);              //LDC13xx16xx_CMD_MUX_CONFIG
        Transmit(0x19,0x0001);              //LDC13xx16xx_CMD_ERROR_CONFIG
    }
    
    void sensor_mode()
    {
        EVM_INT_IE |= EVM_INT_BIT;
        EVM_read();
    }
    
    void EVM_read()
    {
        static unsigned int evmStatus;
    
        if(dataReady == 0)
        {
            if(evmStatus & 0x0048)
            {
                dataReady=1;
            }
        }
    
        if(dataReady==1)
        {
            Receive(LDC13xx16xx_CMD_STATUS,&evmStatus);
            Receive(LDC13xx16xx_CMD_DATA_MSB_CH0,&allData[0]);
            Receive(LDC13xx16xx_CMD_DATA_LSB_CH0,&allData[1]);
    
            uHcal(allData[0],allData[1]);
            dataReady=0;
       }
    }
    
    void Transmit(unsigned char code, unsigned int data)
    {
        //__disable_interrupt();
        //UCB0CTL1 |= UCSWRST;			
        UCB0I2CSA = LDC1614;
        //UCB0CTL1 &= ~UCSWRST;
        TX_Data[2] = code;
        TX_Data[1] = (data >> 8) & 0xFF;
        TX_Data[0] = data & 0xFF;
        TX_ByteCtr = 3;
        done = FALSE;
        I2C_TX_DATA();
    }
    
    void Receive(unsigned char code, unsigned int* data)
    {
        //UCB0CTL1 |= UCSWRST;			
        UCB0I2CSA = LDC1614;
        //UCB0CTL1 &= ~UCSWRST;
    
        TX_Data[0] = code;
        TX_ByteCtr = 1;
        I2C_TX_DATA();
    
        RX_ByteCtr = 2;
        I2C_RX_DATA();
        *data = RX_Data[0] | (RX_Data[1] << 8);
    }
    
    void I2C_TX_DATA()
    {
        //__disable_interrupt();
        IE2 |= UCB0TXIE;
        while (UCB0CTL1 & UCTXSTP);
        UCB0CTL1 |= UCTR + UCTXSTT;
    	__bis_SR_register(CPUOFF + GIE);
    	__no_operation();
    }
    
    void I2C_RX_DATA()
    {
        //__disable_interrupt();
        IE2 |= UCB0RXIE;
        while (UCB0CTL1 & UCTXSTP);
        UCB0CTL1 &= ~UCTR;
        UCB0CTL1 |= UCTXSTT;
        __bis_SR_register(CPUOFF + GIE);
        __no_operation();
        //IE2 &= ~UCB0RXIE;
    }
    
    // USCIAB0TX_ISR
    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    {
        if(UCB0CTL1 & UCTR)                          // TX mode (UCTR == 1)
        {
            if (TX_ByteCtr)                          // TRUE if more bytes remain
            {
                UCB0TXBUF = TX_Data[TX_ByteCtr--];   // Load TX buffer
            }
            else                                     // no more bytes to send
            {
            	UCB0TXBUF = TX_Data[TX_ByteCtr];     // Load TX buffer
                UCB0CTL1 |= UCTXSTP;                 // I2C stop condition
                IFG2 &= ~UCB0TXIFG;                  // Clear USCI_B0 TX int flag
                __bic_SR_register_on_exit(CPUOFF);   // Exit LPM0
            }
        }
        else // (UCTR == 0)                          // RX mode
        {
            //RX_ByteCtr--;                          // Decrement RX byte counter
            if (--RX_ByteCtr)                        // RxByteCtr != 0
            {
                RX_Data[RX_ByteCtr] = UCB0RXBUF;     // Get received byte
                if (RX_ByteCtr == 1)                 // Only one byte left?
                {
                    UCB0CTL1 |= UCTXSTP;             // Generate I2C stop condition
                }
            }
            else                                     // RxByteCtr == 0
            {
                RX_Data[RX_ByteCtr] = UCB0RXBUF;     // Get final received byte
                IFG2 &= ~UCB0RXIFG;
                __bic_SR_register_on_exit(CPUOFF);   // Exit LPM0
            }
        }
    }

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

    建议您移除 MPU6050和 LDC1614、以查看哪个器件使 SCL 无法拉取。

    这不应是软件问题。

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

    伊斯顿,你好,很抱歉回答得太晚了。

    我已经解决 了 SCL 无法拉低 的问题、MPU6050现在可以正常工作。因为在 LDC1614退出关断模式后 UCBBUSY 会设置1。

    但是 LDC1614仍然有问题,在我发送 START 条件之后,LDC1614将接收  NACK。 我尝试再次发送 STOP 和 START 条件、但 LDC1614仍接收 NACK。

    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    {
    	if(UCB0STAT & UCNACKIFG)
    	{
    		UCB0CTL1 |= UCTXSTP;
    		while(UCB0CTL1 & UCTXSTP);
    		UCB0CTL1 |= UCTXSTT;
    	}
    	else
    	{
    	    if(UCB0CTL1 & UCTR)                          // TX mode (UCTR == 1)
    	    {
    	        if (TX_ByteCtr)                          // TRUE if more bytes remain
    	        {
    	            TX_ByteCtr--;                        // Decrement TX byte counter
    	            UCB0TXBUF = TX_Data[TX_ByteCtr];     // Load TX buffer
    	            UCB0CTL1 |= UCTXSTT;
    	        }
    	        else                                     // no more bytes to send
    	        {
    	            UCB0CTL1 |= UCTXSTP;                 // I2C stop condition
    	            IFG2 &= ~UCB0TXIFG;                  // Clear USCI_B0 TX int flag
    	            __bic_SR_register_on_exit(CPUOFF);   // Exit LPM0
    	        }
    	    }
    	    else // (UCTR == 0)                          // RX mode
    	    {
    	        //RX_ByteCtr--;                          // Decrement RX byte counter
    	        if (--RX_ByteCtr)                        // RxByteCtr != 0
    	        {
    	            RX_Data[RX_ByteCtr] = UCB0RXBUF;     // Get received byte
    	            if (RX_ByteCtr == 1)                 // Only one byte left?
    	            {
    	                UCB0CTL1 |= UCTXSTP;             // Generate I2C stop condition
    	            }
    	        }
    	        else                                     // RxByteCtr == 0
    	        {
    	            RX_Data[RX_ByteCtr] = UCB0RXBUF;     // Get final received byte
    	            IFG2 &= ~UCB0RXIFG;
    	            __bic_SR_register_on_exit(CPUOFF);   // Exit LPM0
    	        }
    	    }
    	}
    }
    

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

    您能否检查是否可以在没有 MPU6050的情况下与 LDC1614进行通信? 您能否使用示波器捕获波形、以查看它是否满足 LDC1614的要求。