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 in MSP430F169 having USART module

Other Parts Discussed in Thread: MSP430F169

Hello,

I am extremely new at programming a microcontroller and would like you to help me out in the following program I have written.

I need to read and write using the I2C from MSP430F169 which has USART module to AD7150, a capacitance to digital converter.

The following program always gets stuck in the line highlighted below, during the first write session itself. I could have made a very silly mistake while programming, I am really sorry, but I really need help.

Also, while communication do I need to send the slave address myself along with the read/write bit? Or I don't have to, as I I have already mentioned the slave address in the register and R/W bit goes on its own during the start bit.

The pull up resistors are there at 100kOhm and the clock frequency when measured is 57.7kHz.

Any help or suggestion would be great!!

Thank you so much! I really appreciate it.

I2C_Init(); //I2C Initialisation

     

//CH1 setup Register

I2C_write(0x0B,0xCB);

//CH1 CAPDAC Register

I2C_write(0x11,0x8C);

     

//CH2 setup Register

I2C_write(0x0E,0xCB);

//CH2 CAPDAC Register

I2C_write(0x12,0x8C);

//I2C Initialisation

void I2C_Init(void)

{

      P3SEL |= 0x0A;    //Assign I2C pins to module

      U0CTL |= SYNC + I2C +MST; // Synchronous, Switch USART0 to I2C mode, Set MSP430 as Master

      U0CTL &= ~I2CEN;

      I2CTCTL |= I2CSSEL_2 + I2CRM; // Set clock source as SMCLK, Repeat Mode

      I2CSA = 0x48;     //Slave Address

      U0CTL |= I2CEN;   // Enable I2C

}

 

//I2C Write Mode

void I2C_write(unsigned char address,unsigned char config)

{

      I2CIE |= TXRDYIE; //Enable Transmit interrupt

      I2CTCTL |= I2CTRX + I2CSTT + I2CSTP;      //Initiate Transfer

      while((I2CIFG & TXRDYIFG)==0);      //Wait for transmitter to be ready

      I2CDRB = address; //Send register address

      while((I2CIFG & TXRDYIFG)==0);      //Wait for transmitter to be ready

      I2CDRB = config; // Send configuration data

      while((I2CTCTL & I2CSTP)==0x02); // Wait for stop condition

      I2CIE &= ~TXRDYIE; // Disable Transmit interrupt

}

 

//I2C Read Mode

void I2C_read(unsigned char address, unsigned char i)

{

      I2CIE |= TXRDYIE; //Enable Transmit interrupt

      I2CTCTL |= I2CTRX + I2CSTT + I2CSTP;

      while((I2CIFG & TXRDYIFG)==0);      //Initiate Transfer

      I2CDRB = address; //Send register address from which data needs to be read

      I2CIE &= ~TXRDYIE;      // Disable Transmit interrupt

      I2CIE |= RXRDYIE; //Enable Receive interrupt

      I2CTCTL |= I2CSTT;      // Restart condition

      I2CTCTL &= ~I2CTRX;     //MSP430 in Read mode

      while((I2CIFG & RXRDYIFG)==0);      //Wait for receiver to be ready

      i = I2CDRB; // Receive MSByte from AD7150

      i = i<<8;

      while((I2CIFG & RXRDYIFG)==0);      //Wait for receiver to be ready

      i = i + I2CDRB;   // Receive LSByte from AD7150

      while((I2CTCTL & I2CSTP)==0x02);    // Wait for stop condition

      I2CIE &= ~RXRDYIE;      // Disable receive interrupt

 

}

 

 

  • shake4990 said:
          I2CIE |= TXRDYIE; //Enable Transmit interrupt

    THis line enables interrupts for the TX event.

    So the moment TXRDYIFG is set, the processor calls teh assigned ISR. I bet you don't have one, so the processor jumps into the void.
    Sicn eyou want to handlew the TX event in your normal code flow (busy-waiting), you must not set any IE bit.

    shake4990 said:
          I2CTCTL |= I2CTRX + I2CSTT + I2CSTP;      //Initiate Transfer

    Setting I2CSTT adn I2CSTP at the same time, uses I2CNDAT register to determine the number of bytes to transmit. I don't see you setting it anywhere.
    So you mus tnot set I2CSTP at this point. Rather set it when TXRDYIFG is set and you don't want to send more bytes. Then wait for it to clear again.

    In I2CRead, you set I2CTRX, which actually causes transmit mode while you want to be in read mode. You must clear I2CTRX instead.
    Here again, don't set I2CSTP. Set it when you got all the bytes you want. Do so before reading the last byte, so the USART won't start reading anothe rbyte before senting the stop.

    In both functions, read and write, I2CRM needs to be set, because the number of bytes to transmit/receive is determined by software.

    Also, the I2CSTP needs to be set before the last data byte is written to I2CDR, but not before the address has been acknowledged (unless you don't want to send anything but just to check for the slaves existence). Once TXRDYIFG is set, teh I2C expects you to write something to I2CDR, The flowchart doesn't show a way to end transmission here properly.
    Similarly, when reading, you'll need to set I2CSTP before the last byte you want to read has arrived in I2CDR, else you will receive another byte.
    According to the flowchart, the I2C doesn't wait until you actually read the byte before it acknowledges it and continues reading the next one.

    I really don't like the USARTs I2C module. Much too high-level for easy use. :)

  • wow, thank you so much for all your time and effort! I really really appreciate it!

    I actually did realize that after posting this code here, so I reformed it quite a bit and now my write function works perfectly, the problem is in the read function, where it is getting stuck at the receive interrupt place. And when I checked the register value of RXRDYIFG it was 0 only. So I dont know why is it showing that the code is stuck there. Can this be because of the character 'i' that I am using? Or it is the same reason of ISR that you mentioned above?

    Also, while reading I will have to send the register address from where I want to read the data, so I will have to use the write function in read too!

    Thank you once again! I don't know how to thank you more! :)

    //I2C Initialisation

    void I2C_Init(void)

    {

          P3SEL |= 0x0A;    //Assign I2C pins to module

          P3DIR &= ~0x0A;

          U0CTL |= SYNC + I2C; // Synchronous, Switch USART0 to I2C mode, Set MSP430 as Master

          U0CTL &= ~I2CEN;

          I2CTCTL |= I2CTRX + I2CSSEL_2; // Set clock source as SMCLK, Transmit mode

          I2CSA = 0x48;     //Slave Address

          U0CTL |= I2CEN;   // Enable I2C

    }

     

     //I2C Write Mode

    void I2C_write(unsigned int address,unsigned char config)

    {

        while (I2CDCTL & I2CBUSY); // waits for I2C to complete its working

        U0CTL |= MST;              // define Master Mode

        I2CTCTL |= I2CTRX;           // Transmit Mode

        I2CIFG &= ~TXRDYIFG;      // Clear Transmit Interrupt Flag

        I2CIE = TXRDYIE;          // enable Transmit ready interrupt

     

        I2CNDAT = 2;        // 2 bytes of data, counter

        I2CTCTL |= I2CSTT;  //Initiate Transfer

        I2CTCTL |= I2CSTP;   // I2C stop condition

     

        while((I2CIFG & TXRDYIFG)==0); //Wait for transmitter to be ready

        I2CDRB = address;                //Send register address

        while((I2CIFG & TXRDYIFG)==0); //Wait for transmitter to be ready

        I2CDRB = config;               // Send configuration data

        }

     

    //I2C Read Mode

    void I2C_read(unsigned int address, unsigned char i)

    {

        while (I2CDCTL & I2CBUSY); // waits for I2C to complete its working

        U0CTL |= MST;              // define Master Mode

        I2CTCTL |= I2CTRX;         // Transmit Mode

        I2CIFG &= ~TXRDYIFG;      // Clear Transmit Interrupt Flag

        I2CIE = TXRDYIE;           // enable Transmit ready interrupt

     

        I2CNDAT = 1;

        I2CTCTL |= I2CSTT;              // Initiate transfer

        while((I2CIFG & TXRDYIFG)==0); 

        I2CDRB = address;   //Send data register address

       

        I2CTCTL &= ~I2CTRX;     // Receive Mode

        U0CTL |= MST;             // Master Mode

        I2CIFG &= ~RXRDYIFG;      // Clear Receive Interrupt Flag

        I2CIE &= ~TXRDYIE;        // Disable Transmit ready interrupt

        I2CIE = RXRDYIE;          // Enable Receive ready interrupt

     

        I2CNDAT = 1;

        I2CTCTL |= I2CSTT;        // Restart condition

        I2CTCTL |= I2CSTP;        // I2C stop condition

        while((I2CIFG & RXRDYIFG)==0);   //Wait for receiver to be ready

        i = I2CDRB;   // Receive Byte from AD7150

         

    }

     

     

  • shake4990 said:
        I2CTCTL |= I2CSTT;        // Restart condition
        I2CTCTL |= I2CSTP;        // I2C stop condition
        while((I2CIFG & RXRDYIFG)==0);   //Wait for receiver to be ready
     

    That's expected behavior with this code. :)

    When you set I2CSTT, the USART sends start condition, slave address and direction, no matter whether it is a start or a restart. So when you set I2CSTP in the next line, the slave address hasn't been sent, the slave ahs not acked and no byte is in the process of receiving. So once the start is finished, no matter whether the slave has sent ACK or not, the stop will immediately follow and no byte is being requested and received ever.

    You'll need to wait until I2CSTT is cleared, then set I2CSTP, then check for a NACK (no slave there) and when there was no NACK, then you may wait for a byte to come in.
    (Maybe you'll need to check for a NACK before you set I2CSTP, I'm not sure of this detail)

**Attention** This is a public forum