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.

MSP430FR5994: 使用库函数时硬件IIC主机接收多个数据问题。

Part Number: MSP430FR5994
Other Parts Discussed in Thread: LDC1612, TMP102,

我在使用库函数,430作为主机读取LDC1612从机的数据,当函数执行到EUSCI_B_I2C_masterReceiveMultiByteFinish(EUSCI_B2_BASE);时一直处于卡在    while (!(HWREG16(baseAddress + OFS_UCBxIFG) & UCRXIFG)) ;

我使用示波器查看了下,卡在这里时SCL一直处于拉低状态,但是我使用单个字节读取的函数一切是正常的。

以下是我的配置和正在调试的代码片段,其他的内容还包括一个UART和一个外部触发中断。

void IIC_init(void){ EUSCI_B_I2C_initMasterParam iic_param = {0}; iic_param.selectClockSource = EUSCI_B_I2C_CLOCKSOURCE_SMCLK; iic_param.i2cClk = CS_getSMCLK(); iic_param.dataRate = EUSCI_B_I2C_SET_DATA_RATE_400KBPS; iic_param.autoSTOPGeneration = EUSCI_B_I2C_NO_AUTO_STOP; iic_param.byteCounterThreshold = 1; EUSCI_B_I2C_initMaster(EUSCI_B2_BASE, & iic_param); //set slave address EUSCI_B_I2C_setSlaveAddress(EUSCI_B2_BASE, LDC_ADDRESS); //使能IIC EUSCI_B_I2C_enable(EUSCI_B2_BASE); //清除IIC中断 EUSCI_B_I2C_clearInterrupt(EUSCI_B2_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0 + EUSCI_B_I2C_BYTE_COUNTER_INTERRUPT + EUSCI_B_I2C_NAK_INTERRUPT); // //Enable master interrupt // EUSCI_B_I2C_enableInterrupt(EUSCI_B2_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0); while(EUSCI_B_I2C_isBusBusy(EUSCI_B2_BASE)); printf("I2C in Master mode initial finish!\r\n"); return; }

void IIC_Read_Bytes(uint8_t RegAddr, uint8_t length){ i2c_rx_buf_len = length; uint8_t data1,data2; while(EUSCI_B_I2C_isBusBusy(EUSCI_B2_BASE)); EUSCI_B_I2C_setMode(EUSCI_B2_BASE, EUSCI_B_I2C_TRANSMIT_MODE); EUSCI_B_I2C_masterSendSingleByte(EUSCI_B2_BASE, RegAddr); //receive EUSCI_B_I2C_setMode(EUSCI_B2_BASE, EUSCI_B_I2C_RECEIVE_MODE); //Init iic send data and stati EUSCI_B_I2C_masterReceiveStart(EUSCI_B2_BASE); data1 = EUSCI_B_I2C_masterReceiveMultiByteNext(EUSCI_B2_BASE); data2 = EUSCI_B_I2C_masterReceiveMultiByteFinish(EUSCI_B2_BASE); }

  • 上传代码的话,请您使用该回复框下的“插入”-->代码 来插入,以方便阅读

    另外您使用的是launchpad还是自己的板子?

    之前有类似的讨论,您也可以先看一下

    https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/437554/launchpad-msp430fr5969-i2c-driverlib-hangs-on-while-hwreg16-baseaddress-ofs_ucbxifg-ucrxifg 

  • 新技能get,我所使用的是FR5994 launchpad, 一部分原因我找到了,在配置IIC的IO口时,我使用的是:

    GPIO_setAsPeripheralModuleFunctionOuttPin(GPIO_PORT_P7, GPIO_PIN0+GPIO_PIN1, GPIO_PRIMARY_MODULE_FUNCTION);

    应该配置为

    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P7, GPIO_PIN0+GPIO_PIN1, GPIO_PRIMARY_MODULE_FUNCTION);

    现在问题中

    ->EUSCI_B_I2C_masterReceiveMultiByteFinish(EUSCI_B2_BASE);

    已经可以执行完成了,但是在执行完这一行后,我认为主机应当释放IIC总线控制权,但是此时SCL一直是拉低的,第二次执行读取任务的时候就会卡在IIC  BUSY的检测上。

    附现在调试的代码

    void IIC_Read_Bytes(uint8_t RegAddr, uint8_t length){ uint8_t data1,data2;

    while(EUSCI_B_I2C_isBusBusy(EUSCI_B2_BASE));

    EUSCI_B_I2C_setMode(EUSCI_B2_BASE, EUSCI_B_I2C_TRANSMIT_MODE);

    EUSCI_B_I2C_masterSendSingleByte(EUSCI_B2_BASE, RegAddr);

    //receive

    EUSCI_B_I2C_setMode(EUSCI_B2_BASE, EUSCI_B_I2C_RECEIVE_MODE);

    EUSCI_B_I2C_masterReceiveStart(EUSCI_B2_BASE);

    data1 = EUSCI_B_I2C_masterReceiveMultiByteNext(EUSCI_B2_BASE);

    data2 = EUSCI_B_I2C_masterReceiveMultiByteFinish(EUSCI_B2_BASE);

    printf("x%x,%x",data1,data2);

    return ;

    }

  • 请您看一下下面的链接,和您的问题相似

    https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/581257/ccs-msp430fr5969-problem-to-read-temperature-in-tmp102-using-i2c-usci_b?tisearch=e2e-sitesearch&keymatch=TMP102

    若还是不能解决问题,请附上相关的代码和时序波形,我们具体看一下

  • 您好,对于上面链接中提到的,我都进行了尝试,但是都不成功,总结一个最接近成功的例子。

    我使用MSP430FR5994读取LDC1612的manufacture_id,器件地址是0X2A,正常通信的话,第一个8bits返回0x54,第二个8bits返回0x49.

    IIC配置代码如下:

    void IIC_init(void){
    
        //set the I2C IO
        GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P7, GPIO_PIN0+GPIO_PIN1, GPIO_PRIMARY_MODULE_FUNCTION);
    
        EUSCI_B_I2C_initMasterParam iic_param = {0};
    
        iic_param.selectClockSource = EUSCI_B_I2C_CLOCKSOURCE_SMCLK;
        iic_param.i2cClk = CS_getSMCLK();
        iic_param.dataRate = EUSCI_B_I2C_SET_DATA_RATE_400KBPS;
        iic_param.autoSTOPGeneration = EUSCI_B_I2C_NO_AUTO_STOP;
        iic_param.byteCounterThreshold = 1;
    
        EUSCI_B_I2C_initMaster(EUSCI_B2_BASE, & iic_param);
    
        //set slave address
        EUSCI_B_I2C_setSlaveAddress(EUSCI_B2_BASE, LDC_ADDRESS);
    
        //使能IIC
        EUSCI_B_I2C_enable(EUSCI_B2_BASE);
    
        //清除IIC中断
        EUSCI_B_I2C_clearInterrupt(EUSCI_B2_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0 + EUSCI_B_I2C_BYTE_COUNTER_INTERRUPT + EUSCI_B_I2C_NAK_INTERRUPT);
    //
        //Enable master interrupt
    //    EUSCI_B_I2C_enableInterrupt(EUSCI_B2_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
        while(EUSCI_B_I2C_isBusBusy(EUSCI_B2_BASE));
    
        printf("I2C in Master mode initial finish!\r\n");
        return;
    }

    使用外部按键,以按键中断的方式读取一次数据。IIC的读取代码如下:

    uint16_t IIC_Read_Bytes(uint8_t RegAddr, uint8_t length){
    
        i2c_rx_buf_len = length;
        uint8_t data1,data2;
        uint16_t data_test;
    
        while(EUSCI_B_I2C_isBusBusy(EUSCI_B2_BASE));
    
        EUSCI_B_I2C_setMode(EUSCI_B2_BASE, EUSCI_B_I2C_TRANSMIT_MODE);
    
        EUSCI_B_I2C_masterSendSingleByte(EUSCI_B2_BASE, RegAddr);
    
        //receive
        EUSCI_B_I2C_setMode(EUSCI_B2_BASE, EUSCI_B_I2C_RECEIVE_MODE);
    
        EUSCI_B_I2C_masterReceiveStart(EUSCI_B2_BASE);
        while(EUSCI_B_I2C_isBusBusy(EUSCI_B2_BASE));
    
        data1 = EUSCI_B_I2C_masterReceiveMultiByteNext(EUSCI_B2_BASE);
        data2 = EUSCI_B_I2C_masterReceiveMultiByteFinish(EUSCI_B2_BASE);
        EUSCI_B_I2C_masterReceiveMultiByteStop(EUSCI_B2_BASE);
        EUSCI_B_I2C_masterIsStopSent(EUSCI_B0_BASE);
        while(EUSCI_B_I2C_isBusBusy(EUSCI_B2_BASE));
        data_test = data1<<8 | data2;
        return data_test;
    }

    我测试了下,会出现两种错误:

    此种状态下,第二帧数据直接不读取,但主机释放IIC,可以正常退出中断,读取的返回值是0x54,也就是只读取第一个8Bits数据。

    还可能出现一种错误:

    此种状态下,读取了第二帧数据,但是最后一帧的数据时钟缺两个,也没有NACK及STOP信号,IIC时钟直接没了,我打断点测试中间是卡在了这一行:    data2 = EUSCI_B_I2C_masterReceiveMultiByteFinish(EUSCI_B2_BASE);

    以上两种情况都可能发生

    其他的例如使用上面提到的自己成功的代码:

    uint16_t IIC_Read_Bytes(uint8_t RegAddr, uint8_t length){
    
        i2c_rx_buf_len = length;
        uint8_t data1,data2;
        uint16_t data_test;
    
        while(EUSCI_B_I2C_isBusBusy(EUSCI_B2_BASE));
    
        EUSCI_B_I2C_setMode(EUSCI_B2_BASE, EUSCI_B_I2C_TRANSMIT_MODE);
    
        EUSCI_B_I2C_masterSendSingleByte(EUSCI_B2_BASE, RegAddr);
    
        //receive
        EUSCI_B_I2C_setMode(EUSCI_B2_BASE, EUSCI_B_I2C_RECEIVE_MODE);
    
        EUSCI_B_I2C_masterReceiveStart(EUSCI_B2_BASE);
        while(EUSCI_B_I2C_isBusBusy(EUSCI_B2_BASE));
        data1 = EUSCI_B_I2C_masterReceiveSingle(EUSCI_B2_BASE);
        data2 = EUSCI_B_I2C_masterReceiveSingle(EUSCI_B2_BASE);
        EUSCI_B_I2C_masterReceiveMultiByteStop(EUSCI_B2_BASE);
        EUSCI_B_I2C_masterIsStopSent(EUSCI_B0_BASE);
        /*
        data1 = EUSCI_B_I2C_masterReceiveMultiByteNext(EUSCI_B2_BASE);
        data2 = EUSCI_B_I2C_masterReceiveMultiByteFinish(EUSCI_B2_BASE);
        EUSCI_B_I2C_masterReceiveMultiByteStop(EUSCI_B2_BASE);
        EUSCI_B_I2C_masterIsStopSent(EUSCI_B0_BASE);
        while(EUSCI_B_I2C_isBusBusy(EUSCI_B2_BASE));
        */
        data_test = data1<<8 | data2;
        return data_test;
    }
    

    第一种问题,接收的数据虽然是正常的,但是后面带尾巴,返回的数据不对。

    第二种情况:波形是正常的,但是单片机直接死机,按复位都不行,只能强制断电重启才可以。

    以上,IIC硬件使用4.7K电阻上拉。

  • 谢谢您的详细反馈。由于条件限制,我这周都无法在实验室测试。若是您比较急的话,请您直接在英文E2E发帖

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

  • 非常感谢您,我先在E2E上提问试试,再用别的MCU尝试下,如果有进展的话我也会及时在此问题下更新。

  • 谢谢您的理解,很抱歉未能帮到您。期待您的反馈!

  • hello,我来交作业来了。

    我再仔细的核对了下库函数和寄存器及例程,最后找到了一个比较稳定的解决方案。

    首先说明问题,我在配置IIC的时候,设置的是没有不会自动产生STOP信号,所以在byteCounterThreshold设置了1,逻辑上似乎是不会产生问题,但是就是因为这个问题导致的接收只接收了MSB的数据而丢失了LSB的数据。以下是我修改后的设置。

    void IIC_init(void){
    
        //set the I2C IO
        GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P7, GPIO_PIN0+GPIO_PIN1, GPIO_PRIMARY_MODULE_FUNCTION);
    
        EUSCI_B_I2C_initMasterParam iic_param = {0};
    
        iic_param.selectClockSource = EUSCI_B_I2C_CLOCKSOURCE_SMCLK;
        iic_param.i2cClk = CS_getSMCLK();
        iic_param.dataRate = EUSCI_B_I2C_SET_DATA_RATE_400KBPS;
        iic_param.autoSTOPGeneration = EUSCI_B_I2C_SEND_STOP_AUTOMATICALLY_ON_BYTECOUNT_THRESHOLD;
        iic_param.byteCounterThreshold = 0x02;
    
        EUSCI_B_I2C_initMaster(EUSCI_B2_BASE, &iic_param);
    
        //set slave address
        EUSCI_B_I2C_setSlaveAddress(EUSCI_B2_BASE, SLAVE_ADDRESS);
    
        //使能IIC
        EUSCI_B_I2C_enable(EUSCI_B2_BASE);
    
        //清除IIC中断
        EUSCI_B_I2C_clearInterrupt(EUSCI_B2_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0 + EUSCI_B_I2C_BYTE_COUNTER_INTERRUPT + EUSCI_B_I2C_NAK_INTERRUPT);
    //
        //Enable master interrupt
    //    EUSCI_B_I2C_enableInterrupt(EUSCI_B2_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
        while(EUSCI_B_I2C_isBusBusy(EUSCI_B2_BASE));
    
        printf("I2C in Master mode initial finish!\r\n");
        return;
    }

    主要改动点是设置为接收2帧数据后自动产生STOP信号。

    接收数据的代码修改为:

    uint16_t IIC_Read_Bytes(uint8_t RegAddr, uint8_t length){
    
        i2c_rx_buf_len = length;
        uint8_t data1,data2;
        uint16_t data_test;
    
        while(EUSCI_B_I2C_isBusBusy(EUSCI_B2_BASE));
    
        EUSCI_B_I2C_setMode(EUSCI_B2_BASE, EUSCI_B_I2C_TRANSMIT_MODE);
    
        EUSCI_B_I2C_masterSendSingleByte(EUSCI_B2_BASE, RegAddr);
    
        //receive
        EUSCI_B_I2C_setMode(EUSCI_B2_BASE, EUSCI_B_I2C_RECEIVE_MODE);
    
        EUSCI_B_I2C_masterReceiveStart(EUSCI_B2_BASE);
        while(EUSCI_B_I2C_isBusBusy(EUSCI_B2_BASE));
        data1 = EUSCI_B_I2C_masterReceiveSingle(EUSCI_B2_BASE);
        data2 = EUSCI_B_I2C_masterReceiveSingle(EUSCI_B2_BASE);
        EUSCI_B_I2C_masterReceiveMultiByteStop(EUSCI_B2_BASE);
        EUSCI_B_I2C_masterIsStopSent(EUSCI_B0_BASE);
        while(EUSCI_B_I2C_isBusBusy(EUSCI_B2_BASE));
    
        data_test = data1<<8 | data2;
        return data_test;
    }

    我试过将autoSTOPGeneration 设置为 EUSCI_B_I2C_NO_AUTO_STOP

    但是首次接收时,MSP多读取了一帧,虽然IIC释放了总线,但是后面读取的数据都是错误的。

    此问题虽然没能彻底搞清楚,但至少暂时能继续前进了,非常感谢Susan。

  • 很高兴您能解决问题,也非常感谢您的详细反馈!相信会对之后遇到类似问题的工程师有很大帮助