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: I2C Problem with ADS112C04

Part Number: MSP430FR5994
Other Parts Discussed in Thread: ADS112C04

Hello,

I am trying to read data from a ADS112C04. Therefore I have written functions that basically work like corresponding functions from eusci_b_i2c library but with repeated start conditions. The initialisation of the ADC works fine and I can write all the registers, the IDAC current will be switched on and the PGA also works. I am also receiving the first measurement correctly. But when sending the RDATA command for the second measurement the code gets stuck.

The measurement is triggered by TimerB four times per second and this is the complete sequence:

TimerB Interrupt -> Send START_SYNC Command (function ADS112C04_Measure) -> DRDY falling edge IRQ -> Send RDATA and switch to receive (see function ADS112C04_receive) -> I2C RX IRQ -> process measurement data

This cycle works one time in the beginning and gets stuck the second time (see source):

bool ADS112C04_init(void)//(uint8_t eUSCI_MODULE)
{
    uint8_t i;
    const uint16_t delay = 80; 
    const uint8_t regSend[8] = {CMD_WREG0, REG0, CMD_WREG1, REG1, CMD_WREG2, REG2, CMD_WREG3, REG3};

    // I2C_ Init
    EUSCI_B_I2C_initMasterParam i2c_master_init = {
       EUSCI_B_I2C_CLOCKSOURCE_SMCLK,
       CS_getSMCLK(),
       EUSCI_B_I2C_SET_DATA_RATE_100KBPS,       
       0,                                       
       EUSCI_B_I2C_NO_AUTO_STOP                 
    };

    ADS112C04_powerOn();

    EUSCI_B_I2C_initMaster(AFE_USCI_BASE, &i2c_master_init);

    EUSCI_B_I2C_clearInterrupt(AFE_USCI_BASE, UCRXIE); // neu

    EUSCI_B_I2C_setSlaveAddress(AFE_USCI_BASE, ADS112C04_ADDRESS);

    EUSCI_B_I2C_setMode(AFE_USCI_BASE,EUSCI_B_I2C_TRANSMIT_MODE);

    EUSCI_B_I2C_enable(AFE_USCI_BASE);

    HWREG16(AFE_USCI_BASE + OFS_UCBxCTLW0) |= UCTXSTT;

    while(HWREG16(AFE_USCI_BASE + OFS_UCBxCTLW0) & UCTXSTT); 

    for (i=0; i<8; i++)
    {
        HWREG16(AFE_USCI_BASE + OFS_UCBxTXBUF) = regSend[i];
        while ((!(HWREG16(AFE_USCI_BASE + OFS_UCBxIFG) & UCTXIFG)) && --timeout);
		if (timeout == 0) return (STATUS_FAIL);
        __delay_cycles(delay); 
    }

    HWREG16(AFE_USCI_BASE + OFS_UCBxCTLW0) |= UCTXSTP;

    EUSCI_B_I2C_clearInterrupt(AFE_USCI_BASE, UCRXIE); 
    EUSCI_B_I2C_enableInterrupt(AFE_USCI_BASE, UCRXIE);

    GPIO_selectInterruptEdge(AFE_EOC_PIN, GPIO_HIGH_TO_LOW_TRANSITION);
    GPIO_clearInterrupt(AFE_EOC_PIN);
    GPIO_enableInterrupt(AFE_EOC_PIN);

    return (STATUS_SUCCESS);
}


bool ADS112C04_sendCmd(uint8_t command)
{
    bool timeoutError = false;

    if (!EUSCI_B_I2C_masterSendSingleByteWithTimeout(AFE_USCI_BASE, command, ADS112C04_TIMEOUT)) return (STATUS_FAIL);

    return (STATUS_SUCCESS);
}

bool ADS112C04_measure(void)
{
    bool error = false;

    error = ADS112C04_sendCmd(CMD_START_SYNC);

    return (error);
}

bool ADS112C04_receive(void) // RDATA
{
    uint32_t timeout = ADS112C04_TIMEOUT;

    uint16_t txieStatus = HWREG16(AFE_USCI_BASE + OFS_UCBxIE) & UCTXIE; //Store current transmit interrupt enable

    HWREG16(AFE_USCI_BASE + OFS_UCBxIE) &= ~(UCTXIE); //Disable transmit interrupt enable

    HWREG16(AFE_USCI_BASE + OFS_UCBxCTLW0) |= UCTR +  UCTXSTT; //Send start condition.

    while ((!(HWREG16(AFE_USCI_BASE + OFS_UCBxIFG) & UCTXIFG)) && --timeout); //Poll for transmit interrupt flag
    
    if (timeout == 0) return (STATUS_FAIL); //Check if transfer timed out
    
    HWREG16(AFE_USCI_BASE + OFS_UCBxTXBUF) = CMD_RDATA;//Send single byte data

	timeout = ADS112C04_TIMEOUT; //Reset timeout
	
	/* !!!!!!!
	 THE CODE GETS STUCK IN THE LOOP BELOW
	!!!!!!!! */
    
    while ((!(HWREG16(AFE_USCI_BASE + OFS_UCBxIFG) & UCTXIFG)) && --timeout);//Poll for transmit interrupt flag.
    
    if (timeout == 0) return (STATUS_FAIL); //Check if transfer timed out
    
    HWREG16(AFE_USCI_BASE + OFS_UCBxIFG) &= ~(UCTXIFG); //Clear transmit interrupt flag before enabling interrupt again

    HWREG16(AFE_USCI_BASE + OFS_UCBxIE) |= txieStatus;//Reinstate transmit interrupt enable

     __delay_cycles(64); 

	// Receive

    bytesExpected = 2;
    i2cRxByteCount = 0;
	
    EUSCI_B_I2C_setMode(AFE_USCI_BASE, EUSCI_B_I2C_RECEIVE_MODE);

    HWREG16(AFE_USCI_BASE + OFS_UCBxCTLW0) |= UCTXSTT; // Start

    return(STATUS_SUCCESS);
}

#pragma vector =  AFE_IRQ_VECT 
__interrupt void EUSCI_B_ISR(void)
{
    switch(__even_in_range(AFE_IRQ_REG, USCI_I2C_UCBIT9IFG)) //NEU
    {
        case USCI_NONE:          break;     // Vector 0: No interrupts
        case USCI_I2C_UCALIFG:   break;     // Vector 2: ALIFG
        case USCI_I2C_UCNACKIFG: break;     // Vector 4: NACKIFG
        case USCI_I2C_UCSTTIFG:  break;     // Vector 6: STTIFG
        case USCI_I2C_UCSTPIFG:  break;     // Vector 8: STPIFG
        case USCI_I2C_UCRXIFG3:  break;     // Vector 10: RXIFG3
        case USCI_I2C_UCTXIFG3:  break;     // Vector 12: TXIFG3
        case USCI_I2C_UCRXIFG2:  break;     // Vector 14: RXIFG2
        case USCI_I2C_UCTXIFG2:  break;     // Vector 16: TXIFG2
        case USCI_I2C_UCRXIFG1:  break;     // Vector 18: RXIFG1
        case USCI_I2C_UCTXIFG1:  break;     // Vector 20: TXIFG1
        case USCI_I2C_UCRXIFG0:             // Vector 22: RXIFG0

            if (bytesExpected > 0)
            {
                if (i2cRxByteCount == bytesExpected - 1)
                {
                    // EUSCI_B_I2C_masterReceiveMultiByteFinish
                    HWREG16(AFE_USCI_BASE + OFS_UCBxCTLW0) |= UCTXSTP; // Stop-Bedingung setzen
                }

                i2cRxBuf[i2cRxByteCount] = HWREG16(AFE_USCI_BASE + OFS_UCBxRXBUF);
                i2cRxByteCount++;

                if (i2cRxByteCount == bytesExpected)
                {
                    bytesExpected = 0;
                    i2cRxFlag = true;
                    __bic_SR_register_on_exit(LPM3_bits | GIE);
                }
            }

            break;
        case USCI_I2C_UCTXIFG0:  break;     // Vector 24: TXIFG0
        case USCI_I2C_UCBCNTIFG: break;     // Vector 26: BCNTIFG
        case USCI_I2C_UCCLTOIFG: break;     // Vector 28: clock low timeout
        case USCI_I2C_UCBIT9IFG: break;     // Vector 30: 9th bit
        default: break;
    }
}

  • From your description I suspect you're issuing a (new) Start while a Stop-request is pending, which causes trouble with the I2C unit. You're waking up main() while the (n+1)th byte is being received, so the UCTXSTP latency could be up to (9+1)/100k=100usec.

    I suggest you add something like this to the beginning of your _receive():

    >     while(HWREG16(AFE_USCI_BASE + OFS_UCBxCTLW0) & UCTXSTP); // make sure previous operation is complete.

  • Thank you for your fast answer. I added your suggested polling for stop with no success. The stop bit is already cleared when it comes to that point. Also I am already sending the stop condition before receiving the last byte (see line 138) as it is recommended in SLAU208.  

    The problem is that after sending the RDATA byte which should make the ADC send its conversion result, the TX polling loop in line 93 will timeout or if you remove the timeout it will loop forever. And I can really see no reason for that.

  • To answer your question: [Ref User Guide (SLAU367P) Fig 32-12] The first TXIFG comes "for free", before the Start is issued. There's almost nothing that can go wrong before then. The next TXIFG only appears after (1) the Start has completed (2) the SLA has been ACK-ed, so things can go wrong.

    The usual suspects: (a) Something wrong with the bus, preventing issuing the Start (missing pullups, slave clock-stretching, slave holding SDA low for some reason) (b) NACK from the SLA byte (c) a Start was requested while a Stop was pending. 

    We can probably discount pullups/NACK since prior operations succeeded, and the slave data sheet claims it never clock-stretches. The other failures originate in the previous operation which is (I missed this before) the Start/Synch command. I'll just mention here that sendSingleByte doesn't wait for its UCTXSTP to complete.

    You mention that some operations are triggered by IRQ(s). Are you issuing the I2C operations inside the ISR(s)?

**Attention** This is a public forum