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.

I2C master receiver mode on a MSP430F5438A

Other Parts Discussed in Thread: MSP430F5438A

Hello,

Using MSP430F5438A UCB3 as a I2C master receiver. Problem is that the UCSTPIFG bit gets set immediately after I set the UCTXSTT (send start condition bit). No where in the MSP430F5XX Users Guide (slau208m.pdf June 2008 Revised Feb 2013) does it say why the UCSTPIFG bit would get set under these conditions; so I cannot figure out how to remedy the problem. Figure 36-13 on page 963 does not show any condition that would cause the UCSTPFG bit to get set.

I do not see the UCRXIFG bit get set in my code and I do not see the UCNACKIFG get set either. So I am assuming that the slave device is acknowledging its address being sent out by the MSP430 when the start condition is enabled by my software.

Will greatly appreciate if someone can provide suggestions/answers by the UCSTPIFG bit is getting set and why I may not be seeing any data from the slave device (lack of UCRXFG).

Thanks in advance.

  • AFAIK, nothing will ever set UCTXSTP by itself. It will clear after a stop ahs been sent, but it will never been set by the hardware. So most certainly you’re doing something wrong in your code, maybe a racing condition with an ISR or something like that.

    Hint: posting your code will help analyzing what's wrogn with it.

  • Hi,

    The code is below. Two very simple functions. I call InitEEPROM first and then EEPROMRead from my main. As you can see, I have commented out the writing of the starting address from where I want to read from the EEPROM slave (Microchip 24LC128). I have also commented out the section that checks for NACK from the slave. So, the code simply asserts the UCTXSTT bit and then goes to the for loop where it waits to a receive interrupt before reading the receive buffer reg. I put a breakpoint on the delay_cycles right above the UCTXSTT bit set line and then another breakpoint on the for statement. Only thing happening between the two breakpoints is the UCTXSTT bit getting set. Looking at the UCB3IFG register in debugger. Definitely see the UCSTPIFG bit getting set on the second breakpoint and it was a zero 0 on the first breakpoint.

    I agree that most likely it is something in the code. But what? Has me completely stumped.

    Thanks for looking into this for me.


    int InitEEPROM() {
    //init the i2c port for the eeprom
    P10SEL |= 0x06; // Assign I2C pins to USCI_B3
    UCB3CTL1 |= UCSWRST; // Enable SW reset
    UCB3CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
    UCB3CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
    UCB3BR0 = 12; // fSCL = SMCLK/12 = ~100kHz; with val =3 , fSCL = SMCLK/3 = ~400kHz
    UCB3BR1 = 0;
    UCB3I2CSA = 0x50; // Slave Address is 050h
    UCB3CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
    uci3cNumBytesToXmit = 0; // Load TX byte counter
    uci3cNumBytesToRecv = 0;
    uci3cRXByteCtr = 0;
    UCB3CTL1 &= ~UCTR; //set up as receiver

    return (0);
    }

    int EEPROMRead(char *pcBuf, int iNumBytesToRead, unsigned int uiPageToRead) {
    int i;
    unsigned int uiStartAddr;

    if (iNumBytesToRead > 64) return (-1);
    uiStartAddr = 64*uiPageToRead;

    #if 0
    UCB3CTL1 |= UCTR + UCTXSTT; //I2C TX, start condition
    while((UCB3IFG&0x0002)==0x00); //check for transmit interrupt flag

    __delay_cycles(100);

    UCB3TXBUF = (unsigned char) ((uiStartAddr)>>8);
    __delay_cycles(100);
    while(UCB3CTL1&UCTXSTT); //Send the start condition
    while((UCB3IFG&0x0002)==0x00); //check for transmit interrupt flag
    UCB3TXBUF = (unsigned char)uiStartAddr;
    // UCB3CTL1 |= UCTXSTP;

    // while(UCB3CTL1&UCTXSTP); //Send the stop condition

    while(UCB3CTL1&UCTXSTT); //Send the start condition
    __delay_cycles(100);
    while((UCB3IFG&0x0002)==0x00); //check for transmit interrupt flag

    ShortDelay(100);
    #endif

    UCB3CTL1 &= ~UCTR; //make it receiver

    __delay_cycles(1000);

    //NACK polling as per eeprom datasheet
    #if 0
    while (1) {
    UCB3CTL1 |= UCTXSTT; // I2C TX, start condition
    // ShortDelay(1);
    if (UCB3IFG&0x0020) {
    continue; //if NACK received
    } else if (UCB3IFG&0x0008) {
    continue; //if STOP asserted by eUSCI
    } else break;
    }
    #else
    UCB3CTL1 |= UCTXSTT; // I2C TX, start condition
    #endif

    for(i=0;i<(iNumBytesToRead-1);i++) {
    while((UCB3IFG&0x0001)==0x00); //check for receive interrupt flag
    *pcBuf = UCB3RXBUF;
    pcBuf++;
    }

    UCB3CTL1 |= UCTXSTP;
    while((UCB3IFG&0x0001)==0x00); //check for receive interrupt flag
    *pcBuf = UCB3RXBUF;
    while(UCB3CTL1&UCTXSTP); //Send the start condition

    return 0;
    }

  • Hi ketan,

     You commented the I2C start condition also. you need to enable i2c start condtion then you try.

  • With the "#if 0" code blocks removed, the code looks like this:

    int InitEEPROM() {
        //init the i2c port for the eeprom
        P10SEL |= 0x06; // Assign I2C pins to USCI_B3
        UCB3CTL1 |= UCSWRST; // Enable SW reset
        UCB3CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
        UCB3CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
        UCB3BR0 = 12; // fSCL = SMCLK/12 = ~100kHz; with val =3 , fSCL = SMCLK/3 = ~400kHz
        UCB3BR1 = 0;
        UCB3I2CSA = 0x50; // Slave Address is 050h
        UCB3CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
        uci3cNumBytesToXmit = 0; // Load TX byte counter
        uci3cNumBytesToRecv = 0;
        uci3cRXByteCtr = 0;
        UCB3CTL1 &= ~UCTR; //set up as receiver
    
        return (0);
    }
    
    int EEPROMRead(char *pcBuf, int iNumBytesToRead, unsigned int uiPageToRead) {
        int i;
        unsigned int uiStartAddr;
    
        if (iNumBytesToRead > 64) return (-1);
        uiStartAddr = 64*uiPageToRead;
    
        UCB3CTL1 &= ~UCTR; //make it receiver
    
        __delay_cycles(1000);
    
        UCB3CTL1 |= UCTXSTT; // I2C TX, start condition
    
        for(i=0;i<(iNumBytesToRead-1);i++) {
            while((UCB3IFG&0x0001)==0x00); //check for receive interrupt flag
            *pcBuf = UCB3RXBUF;
            pcBuf++;
        }
    
        UCB3CTL1 |= UCTXSTP;
        while((UCB3IFG&0x0001)==0x00); //check for receive interrupt flag
        *pcBuf = UCB3RXBUF;
        while(UCB3CTL1&UCTXSTP); //Send the start condition
    
        return 0;
    }
    

    So there is a start condition sent at the beginning of the read.

    As for UCSTPIFG getting set, I suggest putting a test for this in the code rather than halting the debugger after setting UCTXSTT. I've seen some strange behaviour when halting the MCU during I2C communication.

  • I certainly did not have the UCTXSTT setting line commented out. You can see it in the #else section below the comment "//NACK polling as per eeprom datasheet" and just before the for loop.

  • Robert: Verified that setting breakpoints is not a good idea. The debugger or something messes up the bits in the I2C control register. Added code to check for STP bit and it does NOT get set. Thanks.

**Attention** This is a public forum