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.

MSP430F5242: I2C Driverlib, repeated start condition

Part Number: MSP430F5242

Hello!

I was trying to switch to the USCI_B I2C Driverlib and i noticed i couldn't reproduce a clean repeated start condition (e.g. for reading a byte from the slave). If i watch the waveforms with the oscilloscope i can see the SDA line rising and falling without even reaching 3V3 level. maybe it's enough for the i2c slave i'm using (it works, i receive the right bytes) but I'm trying to figure out if this represents a potential error cause or not.

Here are the snippets (with and without driverlib):

   

// Test RGB (manuf. ID = 0xE0)
    USCI_B_I2C_setSlaveAddress(USCI_B0_BASE, RGBFR_ADDR);

    if(USCI_B_I2C_masterSendSingleByteWithTimeout(USCI_B0_BASE, MANUFACTURER_ID, 20000))
    {
        if(USCI_B_I2C_masterReceiveSingleStartWithTimeout(USCI_B0_BASE, 20000))
        {
            receivedMsg = USCI_B_I2C_masterReceiveSingle(USCI_B0_BASE);
        }
    }
    if(receivedMsg==0xE0) peripherals |= RGB_FRECCE;
    receivedMsg=0;

here is the function i made without driverlib, called as "I2C_Receive_Single_Byte(RGBFR_ADDR, MANUFACTURER_ID)

char I2C_Receive_Single_Byte(char Slave_Address, char RegAddr)
{
    char received_data=0x00;

    UCB0I2CSA = Slave_Address;                      // Address Assignment
    UCB0IFG &=~ UCTXIFG;                            // Flag Clear
    UCB0CTL1 |= UCTR + UCTXSTT;                     // I2C TX, start condition
    while(!(UCB0IFG&UCTXIFG));                      // While Flag=0 (UCTXIFG=1 when START is generated, data can be written)
    UCB0IFG &=~ UCTXIFG;                            // Flag Clear

    UCB0TXBUF = RegAddr;                            // Data (register to read) load

    while((UCB0CTL1&UCTXSTT))                       // While start not ack'ed
    {
        if(UCB0IFG&UCNACKIFG)                       // if NACK, issue stop and exit
        {
            UCB0IFG &=~ UCNACKIFG;
            UCB0CTL1 |= UCTXSTP;
            return 1;
        }
    }

    UCB0CTL1 &=~ UCTR;              // Prepare to receive
    UCB0IFG &=~ (UCTXIFG+UCRXIFG);  // Flag Clear
    UCB0CTL1 |= UCTXSTT;            // Issue repeated start


    while(UCB0CTL1&UCTXSTT)         // While start not ack'ed
    {
        if(UCB0IFG&UCNACKIFG)       // if NACK, issue stop and exit
        {
            UCB0CTL1 |= UCTXSTP;
            return 1;
        }
    }

    UCB0CTL1 |= UCTXSTP;
    while(!(UCB0IFG&UCRXIFG));      // While a byte is not received
    received_data = UCB0RXBUF;      // Read and save

    __delay_cycles(10000);
    return received_data;           // Self descripting
}

should i introduce some kind of extra polling in the driverlib? Am i worrying for nothing?

Thank you!

  • Hi,

    can you please share the oscilloscope plots? Usually the SDA line should have a1kOhm to 10kOhm pull-up resistor. Usually we recommend 4.7kOhm. If you say SDA does not reach 3.3V it seems there is too much capacitance on SDA. Can you please check? 

    What is your transmit frequency?

    What pull-ups do you have attached to your SDA/SCL?

    Please check our application note: " Solutions to Common eUSCI and USCI Serial Communication Issues on MSP430TM MCUs"

    Chapter 5 covers I2C communication. 

    Best regards,

    Andre

  • Sorry but at the moment i can't do the measures but i remember what i saw. I think the problem is that the driverlib function sets the STP bit and not the start bit, creating that strange tooth and not a repeated start condition.

    It's not a pull-up issue (4k7) as you can see, i'm probably misusing the driverlib

  • USCI_B_I2C_masterSendSingleByteWithTimeout() does a complete I²C transaction, i.e., it generates a stop condition.

    For a repeated start, you have to send the first byte(s) while pretending that more could follow (USCI_B_I2C_masterSendMultiByteStartWithTimeout()), and then, without doing a stop first, simply start receiving  (USCI_B_I2C_masterReceive*Start()).

  • Thank you Clemens! This code is working properly but i had to put a delay inside. Is there a polling that could work instead of the delay?

    if(USCI_B_I2C_masterSendMultiByteStartWithTimeout(USCI_B0_BASE, MANUFACTURER_ID, 20000))
    {
    dummy = 100;
    while(dummy-->5);
    if(USCI_B_I2C_masterReceiveSingleStartWithTimeout(USCI_B0_BASE, 20000))
    {
    receivedMsg = USCI_B_I2C_masterReceiveSingle(USCI_B0_BASE);
    }
    }

    if i remove the delay, the only waveforms coming out the i2c module are: START - 0x38(SlaveAddr) - 0xFF (????) - STOP; where 0xFF should be 0x92. I guess because the second USCI Driverlib function sets the start bit before data transmission is completed.

    Trying to poll UCBUSY does not work, neither using the USCI_B_I2C_isBusy(). Regarding this last function, weren't the flags set when the module could be accessed and not the opposite (like here)? I mean, if UCTXIFG is set, guides say that if it's set i can write another data byte in UCxTXBUF, but if i use this function without knowing what it does (it can happen to someone, i guess) i get in a situation that does the opposite of what i meant to do, like:

    if(USCI_B_I2C_masterSendMultiByteStartWithTimeout(USCI_B0_BASE, MANUFACTURER_ID, 20000))
    {
    while(USCI_B_I2C_isBusy());
    if(USCI_B_I2C_masterReceiveSingleStartWithTimeout(USCI_B0_BASE, 20000))
    {
    receivedMsg = USCI_B_I2C_masterReceiveSingle(USCI_B0_BASE);
    }
    }


    uint8_t USCI_B_I2C_isBusy (uint16_t baseAddress)
    {
    //Return the busy status.
    if ((HWREG8(baseAddress + OFS_UCBxIFG) & (UCTXIFG + UCRXIFG))){
    return (USCI_B_I2C_BUS_BUSY);
    } else {
    return (USCI_B_I2C_BUS_NOT_BUSY);
    }
    }

    Am i wrong? Thank you again,

    Mirco
  • Briefly, aren't the flags in the driverlib function inverted? I can't understand...

    Thanks!
    Mirco
  • Clearly, polling for uctxifg resolves this problem...
  • Setting UCTXSTT does not abort the current transmission (see figure 41-12 of the User's Guide).

    The isBusy() function indeed appears to be wrong.

    And there is no other function; the only way to wait for TXIFG is to do it manually. (Apparently, this is a case where the driverlib assumes that you are using interrupts.)
  • Understood!

    But why
    "if i remove the delay, the only waveforms coming out the i2c module are: START - 0x38(SlaveAddr) - 0xFF (????) - STOP; where 0xFF should be 0x92." then
  • Hello,


    I can't comment on the exact DriverLib configuration here, but if you are transmitting 0xFF instead of your desired data, then one of three things are happening.

    1) Your placing 0xFF in the TxBuff w/o realizing it
    2)You are transmitting too soon before filling the TxBuff properly and its transmitting the last thing it sent
    3)You are filling the TxBuff too soon and potentially corrupting the buffer before it gets sent out.

    As Clemens mentioned earlier, DriverLib assumes you are using interrupts for the I2C, so you need to wait until the TXIFG happens so you can fill TxBuff properly.
  • Hi Mirco,

    do you have further questions on this thread? If not, please click the "Resolved" button on the thread that resolved your question.

    Best regards,
    Andre