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.

msp430f2618 i2c

Other Parts Discussed in Thread: MSP430F2618

Hi,

I am using USCB1 for I2c of msp430f2618 and slave is LIS331DLH accelerometer.

Below is the code::

I am writing 0x2f data to CNTRL_REG1(0x20) and reading back the same reg to confirm whether data has been written properly.

void main()

{
unsigned char rcv = 0;

WDTCTL = WDTPW + WDTHOLD;
// P2SEL |= 0x00;
P2DIR |= BIT7; //Accelerometer pins
P6DIR |= BIT0;
P2OUT |= BIT7; //CS |= 1; // make CS = HIGH for I2C mode
P6OUT |= BIT0; //SA0 |= 1;

if (CALBC1_16MHZ ==0xFF || CALDCO_16MHZ == 0xFF)
{
while(1); // If calibration constants erased
// do not load, trap CPU!!
}
BCSCTL1 = CALBC1_16MHZ; // Set DCO to 16MHz
DCOCTL = CALDCO_16MHZ;

P5SEL |= 0x06; // Assign I2C pins to USCI_B0
UCB1CTL1 |= UCSWRST; // Enable SW reset
UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB1CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB1BR0 = 42; // fSCL = SMCLK/40 = ~400kHz
UCB1BR1 = 0;
UCB1I2CIE |= UCNACKIE;
// UCB1I2CSA = 0x19;
UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UC1IE |= UCB1TXIE+UCB1RXIE;

UCB1I2CSA = SlaveAddress;
while ((UCB1CTL1 & UCTXSTP));


UCB1CTL1 = UCTR + UCTXSTT;
UCB1TXBUF = 0x20;
while(!(UC1IFG & UCB1TXIFG));     // LINE 1

UCB1TXBUF = 0x2f;
while(!(UC1IFG & UCB1TXIFG));

UCB1CTL1 |= UCTXSTP; // I2C stop condition
UC1IFG &= ~UCB1TXIFG;

UCB1TXBUF = 0x20;
UCB1CTL1 &= ~UCTR;
UCB1CTL1 = UCTXSTT;
while(!(UC1IFG & UCB1TXIFG));
rcv = UCB1RXBUF;

UCB1CTL1 |= UCTXSTP;
UC1IFG &= ~UCB1TXIFG;
}

but the code is hanging at LINE 1 itself..

  • Apparently, the slave doesn’t respond (NACK). So you never get TXIFG set again (instead, NACKIFG is set).
    Besides this, you set UCNACKIE, TXIE and RXIE. Luckily, you never set GIE, or else the MSP would crash on an event. The IE bits enable interrupt handling. The IFG bits are always set and don’t need the IE bits to be set for proper working. Since you don’t have any ISR to handle the interrupts you enabled, the MSP would crash. But by default, interrupts are globally disabled, so your program continues until it waits for a TXIFG that never comes.

    What is the value of SlaveAddress? It must be 0x18 or 0x19, depending on SA0 pin (GND or VCC).

  • Hi Jens,

    I have connected SA0 to VCC so the slave address is 0x19. I do not want ISR to use instead i would like to poll the interrupt flag,

  • Hi Jens,

    I am using msp430f26xx mcu.

    I have modified my code using ISR but only TXIFG is settig and servicing the ISR but i am not receiving RXIFG anf entering the ISR..

    unsigned char TXData[] = {0x20,0x2f};//,0x00,0x02}; // Pointer to TX data
    unsigned char TXData1[] = {0x22,0x02};//{0x20,0x21,0x22};
    unsigned char TXData2[] = {0x20};//{0x28,0x29,0x2a,0x2b,0x2c,0x2d};

    void main(void)
    {

    //int an=0;
    WDTCTL = WDTPW + WDTHOLD;
    // static unsigned char acc_data[7];
    //acc_data[6] = '\0';
    acc_back_data[6] = '\0';


    //P2SEL |= 0x00;
    P2DIR |= BIT7; //Accelerometer pins
    P2DIR |= BIT0;
    P2OUT |= BIT7; //CS |= 1; // make CS = HIGH for I2C mode
    P2OUT |= BIT0; //SA0 |= 1;

    if (CALBC1_16MHZ ==0xFF || CALDCO_16MHZ == 0xFF)
    {
    while(1); // If calibration constants erased
    // do not load, trap CPU!!
    }
    BCSCTL1 = CALBC1_16MHZ; // Set DCO to 16MHz
    DCOCTL = CALDCO_16MHZ;

    // __delay_cycles(16000);

    // while(an < 2)
    //{
    P5SEL |= 0x06; // Assign I2C pins to USCI_B0
    // P5DIR |= 0x02;
    UCB1CTL1 |= UCSWRST; // Enable SW reset
    UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
    UCB1CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
    UCB1BR0 = 150; // fSCL = SMCLK/40 = ~400kHz
    UCB1BR1 = 0;
    UCB1I2CSA = SlaveAddress;

    UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
    UCB1I2CIE |= UCNACKIE;
    UC1IE |= UCB1TXIE+UCB1RXIE;


    while ((UCB1CTL1 & UCTXSTP));

    r_w = 0;
    TXByteCtr = 2;
    PTXData = (unsigned char *)(TXData);
    UCB1CTL1 |= UCTR+ UCTXSTT;
    __bis_SR_register(CPUOFF + GIE);

    // while ((UCB1CTL1 & UCTXSTP));
    TXByteCtr = 2;
    PTXData = (unsigned char *)TXData1;
    UCB1CTL1 |= UCTR +UCTXSTT;
    //__bis_SR_register(CPUOFF + GIE);

    r_w =1;

    TXByteCtr = 1;
    PTXData = (unsigned char *)((TXData2));//(unsigned char *)TXData1;
    UCB1CTL1 |= UCTR + UCTXSTT;;
    rcv=1;
    UCB1CTL1 &= ~UCTR ; // Clear UCTR
    UCB1CTL1 |= UCTXSTT;
    while( !(UCB1CTL1 & UCTXSTT));
    UCB1CTL1 |= UCTR + UCTXSTT;;

    __no_operation();
    __no_operation();
    }

    #pragma vector = USCIAB1TX_VECTOR
    __interrupt void USCIAB1TX_ISR(void)
    {
    if(r_w == 0)
    {
    while(TXByteCtr)// != 0) // Check TX byte counter
    {
    UCB1TXBUF = *PTXData++; // Load TX buffer
    TXByteCtr--;
    }
    UCB1CTL1 |= UCTXSTP; // I2C stop condition
    UCB1CTL1 &= ~UCTXSTT;
    UC1IFG &= ~UCB1TXIFG; // Clear USCI_B0 TX int flag
    __bic_SR_register_on_exit(CPUOFF); // Exit LPM0

    }
    else
    {
    if(rcv == 0)
    {
    while(TXByteCtr)// != 0) // Check TX byte counter
    {
    UCB1TXBUF = *PTXData++; // Load TX buffer
    TXByteCtr--;
    }
    __bic_SR_register_on_exit(CPUOFF);
    }
    else
    {


       acc_data[c] = UCB1RXBUF;


    UCB1CTL1 |= UCTXSTP; // I2C stop condition

    __bic_SR_register_on_exit(CPUOFF);
    }
    }
    }

    I am not able to read back the data return to the register as well in continuous read..

    please looking into this..

  • uma pv said:
    the slave address is 0x19

    Okay, then let’s go for the usual suspects:

    Are you sure that P5.1 and P5.2 are the right pins for UCB1 I2C? Did you twist SDA and SCL? Do you have the required external pull-ups on the two signal lines? Do master and slave have a common GND connection? (don’t laugh – we had several cases in the past)

     

    Yes, I see that you don’t use ISRs. So don’t set any IE bits. The IFG bits are updated independently of the IE bits, they just don’t trigger an interrupt if the corresponding IE bit is not set.

    The readout part is wrong. After you set the TXSTP, you need to wait until it clears. Then you start another transmit, sending just 0x20. (by writing 0x2f to  register 0x20, the internal address counter has moved to register 0x21). Then you don’T set TXSTP. Instead when TXIFG tells you that the 0x20 started sending, you simply clear UCTR and set TXSTT once more, to start a read operation.

    Currently, after you completed the write, you write 0x20 to TXBUF, which is ignored as you already stopped the write transaction).

    Instead of

    UC1IFG&=~UCB1TXIFG; UCB1TXBUF = 0x20;
    you need to do
    while(UCB1CTL1&UCTXSTP);
    UCB1CTL1|=UCTXSTT;
    UCB1TXBUF=0x20;
    while(!(UC1IFG&UCB1TXIFG));

  • hi Jens,

    i have modified my code as u said and is as below

    #include <msp430f2618.h>
    //#include <math.h>
    //#include <stdlib.h>
    //#include <stdio.h>
    //#include <string.h>

    #define ADR_WRT 0x32 // LIS331DLH slave address with WRITE with SA0 = 1
    #define ADR_RD 0x33 // LIS331DLH slave address with READ with SA0 = 1
    #define WHO_AM_I 0x0F
    #define CTRL_REG1 0x20
    #define CTRL_REG2 0x21
    #define CTRL_REG3 0x22
    #define CTRL_REG4 0x23
    #define CTRL_REG5 0x24
    #define STATUS_REG 0x27
    #define OUT_X_L 0xA8
    #define OUT_X_H 0x29
    #define OUT_Y_L 0x2A
    #define OUT_Y_H 0x2B
    #define OUT_Z_L 0x2C
    #define OUT_Z_H 0x2D

    #define ZYXDA 0x08

    #define precision 100000
    #define SlaveAddress 0x19


    void main()

    {
    unsigned char rcv = 0;

    WDTCTL = WDTPW + WDTHOLD;
    // P2SEL |= 0x00;
    P2DIR |= BIT7; //Accelerometer pins
    P6DIR |= BIT0;
    P2OUT |= BIT7; //CS |= 1; // make CS = HIGH for I2C mode
    P6OUT |= BIT0; //SA0 |= 1;

    if (CALBC1_16MHZ ==0xFF || CALDCO_16MHZ == 0xFF)
    {
    while(1); // If calibration constants erased
    // do not load, trap CPU!!
    }
    BCSCTL1 = CALBC1_16MHZ; // Set DCO to 16MHz
    DCOCTL = CALDCO_16MHZ;

    P5SEL |= 0x06; // Assign I2C pins to USCI_B0
    UCB1CTL1 |= UCSWRST; // Enable SW reset
    UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
    UCB1CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
    UCB1BR0 = 42; // fSCL = SMCLK/40 = ~400kHz
    UCB1BR1 = 0;
    UCB1I2CIE |= UCNACKIE;
    // UCB1I2CSA = 0x19;
    UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
    //UC1IE |= UCB1TXIE+UCB1RXIE;

    UCB1I2CSA = SlaveAddress;
    while ((UCB1CTL1 & UCTXSTP));


    UCB1CTL1 = UCTR + UCTXSTT;
    UCB1TXBUF = 0x20;
    while(!(UC1IFG & UCB1TXIFG)); // LINE 1

    UCB1TXBUF = 0x2f;
    while(!(UC1IFG & UCB1TXIFG));

    UCB1CTL1 |= UCTXSTP; // I2C stop condition
    while(UCB1CTL1&UCTXSTP);
    UCB1CTL1|=UCTXSTT;
    UCB1TXBUF=0x20;
    while(!(UC1IFG&UCB1TXIFG));
    rcv = UCB1RXBUF;

    UCB1CTL1 |= UCTXSTP;
    UC1IFG &= ~UCB1TXIFG;
    }

    i am still stucking at LINE1 and i have properly connect SDA of slave to P5.1 and SCLK of slave to P5.2..

    Please look into this 

  • TXIFG (at LINE1) should be get set as soon as the USCI received the ACK form the slave. SO it apparently doesn’t get the ACK. Is UCNACKIFG set instead? It indicates that the slave didn’t respond to the start condition. And in this case, of course the 0x20 is never sent and TXBUF is never ready to receive the next byte to send.

    Instead of waiting for TXIFG, you should wait for UCTXSTT to clear, which means the start byte has been sent. Then check UCNACKIFG whether the USCI got an ACK or not. If not, communication failed (UCNACKIFG) and you should set UCTXSTP. Once UCTXSTT is clear and UCNACKIFG is still clear, communication goes on, and you will see UCTXIFT set again while the first byte is being sent.

**Attention** This is a public forum