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 Interfacing

Other Parts Discussed in Thread: MSP430G2231, MSP430G2221

Hey,

I am new to MSP430. I have to write data to an external memory( Non- volatile) chip (DS1682). It supports 2 wire serial interface( I2C). I am using MSP430G2231. And also i have to read the bytes written onto this chip. Does msp430g2231 have any inbuilt library to read and write data onto external memory..i have to write 16 bit data. 

  • Hi Pavan,

    the MSP430G2231 has built in an USI module which will support you in hardware. Here is one of the code examples:

    //******************************************************************************
    //  MSP430G2x21/G2x31 Demo - I2C Master Receiver, single byte
    //
    //  Description: I2C Master communicates with I2C Slave using
    //  the USI. Slave data should increment from 0x00 with each transmitted byte
    //  which is verified by the Master.
    //  LED off for address or data Ack; LED on for address or data NAck.
    //  ACLK = n/a, MCLK = SMCLK = Calibrated 1MHz
    //
    //  ***THIS IS THE MASTER CODE***
    //
    //                  Slave                      Master
    //          (msp430g2x21_usi_09.c)
    //            MSP430G2x21/G2x31           MSP430G2x21/G2x31
    //             -----------------          -----------------
    //         /|\|              XIN|-    /|\|              XIN|-
    //          | |                 |      | |                 |
    //          --|RST          XOUT|-     --|RST          XOUT|-
    //            |                 |        |                 |
    //      LED <-|P1.0             |        |                 |
    //            |                 |        |             P1.0|-> LED
    //            |         SDA/P1.7|------->|P1.7/SDA         |
    //            |         SCL/P1.6|<-------|P1.6/SCL         |
    //
    //  Note: internal pull-ups are used in this example for SDA & SCL
    //
    //  D. Dang
    //  Texas Instruments Inc.
    //  October 2010
    //  Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10
    //******************************************************************************

    #include <msp430g2221.h>


    char SLV_data = 0x00;                  // Variable for received data
    char SLV_Addr = 0x91;                  // Address is 0x48 << 1 bit + 1 for Read
    int I2C_State = 0;                     // State variable

    void main(void)
    {
      volatile unsigned int i;             // Use volatile to prevent removal

      WDTCTL = WDTPW + WDTHOLD;            // Stop watchdog
      if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)                                     
      {  
        while(1);                          // If calibration constants are erased
                                           // do not load, trap CPU!!
      }
      BCSCTL1 = CALBC1_1MHZ;               // Set DCO
      DCOCTL = CALDCO_1MHZ;

      P1OUT = 0xC0;                        // P1.6 & P1.7 Pullups
      P1REN |= 0xC0;                       // P1.6 & P1.7 Pullups
      P1DIR = 0xFF;                        // Unused pins as outputs
      P2OUT = 0;
      P2DIR = 0xFF;

      USICTL0 = USIPE6+USIPE7+USIMST+USISWRST;// Port & USI mode setup
      USICTL1 = USII2C+USIIE;              // Enable I2C mode & USI interrupt
      USICKCTL = USIDIV_3+USISSEL_2+USICKPL;// Setup USI clocks: SCL = SMCLK/8 (~120kHz)
      USICNT |= USIIFGCC;                  // Disable automatic clear control
      USICTL0 &= ~USISWRST;                // Enable USI
      USICTL1 &= ~USIIFG;                  // Clear pending flag
      _EINT();

      while(1)
      {
        USICTL1 |= USIIFG;                 // Set flag and start communication
        LPM0;                              // CPU off, await USI interrupt
        _NOP();                            // Used for IAR
        for (i = 0; i < 5000; i++);        // Dummy delay between communication cycles
      }
    }

    /******************************************************
    // USI interrupt service routine
    ******************************************************/
    #pragma vector = USI_VECTOR
    __interrupt void USI_TXRX (void)
    {
      switch(I2C_State)
        {
          case 0: // Generate Start Condition & send address to slave
                  P1OUT |= 0x01;           // LED on: sequence start
                  USISRL = 0x00;           // Generate Start Condition...
                  USICTL0 |= USIGE+USIOE;
                  USICTL0 &= ~USIGE;
                  USISRL = SLV_Addr;       // ... and transmit address, R/W = 1
                  USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, TX Address
                  I2C_State = 2;           // Go to next state: receive address (N)Ack
                  break;

          case 2: // Receive Address Ack/Nack bit
                  USICTL0 &= ~USIOE;       // SDA = input
                  USICNT |= 0x01;          // Bit counter = 1, receive (N)Ack bit
                  I2C_State = 4;           // Go to next state: check (N)Ack
                  break;

          case 4: // Process Address Ack/Nack & handle data RX
                  if (USISRL & 0x01)       // If Nack received...
                  { // Prep Stop Condition
                    USICTL0 |= USIOE;
                    USISRL = 0x00;
                    USICNT |=  0x01;       // Bit counter = 1, SCL high, SDA low
                    I2C_State = 10;        // Go to next state: generate Stop
                    P1OUT |= 0x01;         // Turn on LED: error
                  }
                  else                     // Ack received
                  { // Receive Data from slave
                    USICNT |=  0x08;       // Bit counter = 8, RX data
                    I2C_State = 6;         // Go to next state: Test data and (N)Ack
                    P1OUT &= ~0x01;        // LED off
                  }
                  break;

          case 6: // Send Data Ack/Nack bit
                  USICTL0 |= USIOE;        // SDA = output
                  if (USISRL == SLV_data)  // If data valid...
                  {
                    USISRL = 0x00;         // Send Ack
                    SLV_data++;            // Increment Slave data
                    P1OUT &= ~0x01;        // LED off
                  }
                  else
                  {
                    USISRL = 0xFF;         // Send NAck
                    P1OUT |= 0x01;         // LED on: error
                  }
                  USICNT |= 0x01;          // Bit counter = 1, send (N)Ack bit
                  I2C_State = 8;           // Go to next state: prep stop
                  break;

          case 8: // Prep Stop Condition
                  USICTL0 |= USIOE;        // SDA = output
                  USISRL = 0x00;
                  USICNT |=  0x01;         // Bit counter = 1, SCL high, SDA low
                  I2C_State = 10;          // Go to next state: generate Stop
                  break;

          case 10: // Generate Stop Condition
                  USISRL = 0x0FF;          // USISRL = 1 to release SDA
                  USICTL0 |= USIGE;        // Transparent latch enabled
                  USICTL0 &= ~(USIGE+USIOE);// Latch/SDA output disabled
                  I2C_State = 0;           // Reset state machine for next transmission
                  LPM0_EXIT;               // Exit active for next transfer
                  break;
        }

      USICTL1 &= ~USIIFG;                  // Clear pending flag
    }

    from: http://www.ti.com/lit/zip/slac463

  • Thanks for the early reply Jan!

    But shouldnt I use MSP430G2231 as a master ? I have seen the example code which sends/transmits multiple bytes (usi_12 in the example codes). But I was not able to figure out where to put the data which i want to write!

    any help would be greatly appreciated  !

  • PAVAN ANAND said:
    But shouldnt I use MSP430G2231 as a master ?

    This is code for the master. Howeve,r it is code for a master receiver. You require code for master transmitter.

    The differences aren't that big. A different slave address to be sent (LSB clear instead of set), no ACK bit generated but received instead, and write outgoing byte to USISRL before writing the count instead of writing the count, waiting until it reaches zero and reading the incoming byte from USISRL.

  • Hey,

    Can i use the  program shown below to send multiple bytes to my eeprom chip( example code) ? but i am not able to figure out where to enter the data which i need to send..also my eeprom has 32 bits..and i have to write the first 16 bits with data..how to access the first 16 bits..plz help

  • //******************************************************************************
    // MSP430G2x21/G2x31 Demo - I2C Master Transmitter / Reciever, multiple bytes
    //
    // Description: I2C Master communicates with I2C Slave using
    // the USI. Master data should increment from 0x55 with each transmitted byte
    // and Master determines the number of bytes recieved, set by
    // the Number_of_Bytes value. LED off for address or data Ack;
    // LED on for address or data NAck.
    // ACLK = n/a, MCLK = SMCLK = Calibrated 1MHz
    //
    //
    // ***THIS IS THE MASTER CODE***
    //
    // Slave Master
    // (msp430g2x21_usi_15.c)
    // MSP430G2x21/G2x31 MSP430G2x21/G2x31
    // ----------------- -----------------
    // /|\| XIN|- /|\| XIN|-
    // | | | | | |
    // --|RST XOUT|- --|RST XOUT|-
    // | | | |
    // LED <-|P1.0 | | |
    // | | | P1.0|-> LED
    // | SDA/P1.7|------->|P1.6/SDA |
    // | SCL/P1.6|<-------|P1.7/SCL |
    //
    // Note: internal pull-ups are used in this example for SDA & SCL
    //
    // D. Dang
    // Texas Instruments Inc.
    // October 2010
    // Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10
    //******************************************************************************

    #include <msp430g2221.h>


    #define number_of_bytes 5 // How many bytes?

    void Master_Transmit(void);
    void Master_Recieve(void);

    void Setup_USI_Master_TX(void);
    void Setup_USI_Master_RX(void);

    char MST_Data = 0x55; // Variable for transmitted data
    char SLV_Addr = 0x90;
    int I2C_State, Bytecount, Transmit = 0; // State variable
    void Data_TX (void);
    void Data_RX (void);
    void main(void)
    {
    volatile unsigned int i; // Use volatile to prevent removal

    WDTCTL = WDTPW + WDTHOLD; // Stop watchdog
    if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
    {
    while(1); // If calibration constants erased
    // do not load, trap CPU!!
    }

    BCSCTL1 = CALBC1_1MHZ; // Set DCO
    DCOCTL = CALDCO_1MHZ;

    P1OUT = 0xC0; // P1.6 & P1.7 Pullups, others to 0
    P1REN |= 0xC0; // P1.6 & P1.7 Pullups
    P1DIR = 0xFF; // Unused pins as outputs
    P2OUT = 0;
    P2DIR = 0xFF;



    while(1)
    {
    Master_Transmit();
    _NOP(); // Used for IAR

    Master_Recieve();
    _NOP();
    }
    }

    /******************************************************
    // USI interrupt service routine
    // Data Transmit : state 0 -> 2 -> 4 -> 10 -> 12 -> 14
    // Data Recieve : state 0 -> 2 -> 4 -> 6 -> 8 -> 14
    ******************************************************/
    #pragma vector = USI_VECTOR
    __interrupt void USI_TXRX (void)
    {
    switch(__even_in_range(I2C_State,14))
    {
    case 0: // Generate Start Condition & send address to slave
    P1OUT |= 0x01; // LED on: sequence start
    Bytecount = 0;
    USISRL = 0x00; // Generate Start Condition...
    USICTL0 |= USIGE+USIOE;
    USICTL0 &= ~USIGE;
    if (Transmit == 1){
    USISRL = 0x90; // Address is 0x48 << 1 bit + 0 (rw)
    }
    if (Transmit == 0){
    USISRL = 0x91; // 0x91 Address is 0x48 << 1 bit
    // + 1 for Read
    }
    USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, TX Address
    I2C_State = 2; // next state: rcv address (N)Ack
    break;

    case 2: // Receive Address Ack/Nack bit
    USICTL0 &= ~USIOE; // SDA = input
    USICNT |= 0x01; // Bit counter=1, receive (N)Ack bit
    I2C_State = 4; // Go to next state: check (N)Ack
    break;

    case 4: // Process Address Ack/Nack & handle data TX

    if(Transmit == 1){
    USICTL0 |= USIOE; // SDA = output
    if (USISRL & 0x01) // If Nack received...
    { // Send stop...
    USISRL = 0x00;
    USICNT |= 0x01; // Bit counter=1, SCL high, SDA low
    I2C_State = 14; // Go to next state: generate Stop
    P1OUT |= 0x01; // Turn on LED: error
    }
    else
    { // Ack received, TX data to slave...
    USISRL = MST_Data++; // Load data byte
    USICNT |= 0x08; // Bit counter = 8, start TX
    I2C_State = 10; // next state: receive data (N)Ack
    Bytecount++;
    P1OUT &= ~0x01; // Turn off LED
    break;
    }
    } if(Transmit == 0){

    if (USISRL & 0x01) // If Nack received
    { // Prep Stop Condition
    USICTL0 |= USIOE;
    USISRL = 0x00;
    USICNT |= 0x01; // Bit counter= 1, SCL high, SDA low
    I2C_State = 8; // Go to next state: generate Stop
    P1OUT |= 0x01; // Turn on LED: error
    }
    else{ Data_RX();} // Ack received


    }
    break;

    case 6: // Send Data Ack/Nack bit
    USICTL0 |= USIOE; // SDA = output
    if (Bytecount <= number_of_bytes-2)
    { // If this is not the last byte
    USISRL = 0x00; // Send Ack
    P1OUT &= ~0x01; // LED off
    I2C_State = 4; // Go to next state: data/rcv again
    Bytecount++;
    }

    else //last byte: send NACK
    {
    USISRL = 0xFF; // Send NAck
    P1OUT |= 0x01; // LED on: end of comm
    I2C_State = 8; // stop condition
    }
    USICNT |= 0x01; // Bit counter = 1, send (N)Ack bit
    break;

    case 8: // Prep Stop Condition
    USICTL0 |= USIOE; // SDA = output
    USISRL = 0x00;
    USICNT |= 0x01; // Bit counter= 1, SCL high, SDA low
    I2C_State = 14; // Go to next state: generate Stop
    break;

    case 10: // Receive Data Ack/Nack bit
    USICTL0 &= ~USIOE; // SDA = input
    USICNT |= 0x01; // Bit counter = 1, receive (N)Ack bit
    I2C_State = 12; // Go to next state: check (N)Ack
    break;

    case 12: // Process Data Ack/Nack & send Stop
    USICTL0 |= USIOE;
    if (Bytecount == number_of_bytes){// If last byte
    USISRL = 0x00;

    I2C_State = 14; // Go to next state: generate Stop
    P1OUT |= 0x01;
    USICNT |= 0x01; } // set count=1 to trigger next state
    else{
    P1OUT &= ~0x01; // Turn off LED
    Data_TX(); // TX byte
    }
    break;

    case 14:// Generate Stop Condition
    USISRL = 0x0FF; // USISRL = 1 to release SDA
    USICTL0 |= USIGE; // Transparent latch enabled
    USICTL0 &= ~(USIGE+USIOE); // Latch/SDA output disabled
    I2C_State = 0; // Reset state machine for next xmt
    LPM0_EXIT; // Exit active for next transfer
    break;
    }

    USICTL1 &= ~USIIFG; // Clear pending flag
    }


    void Data_TX (void){

    USISRL = MST_Data++; // Load data byte
    USICNT |= 0x08; // Bit counter = 8, start TX
    I2C_State = 10; // next state: receive data (N)Ack
    Bytecount++;
    }

    void Data_RX (void){
    USICTL0 &= ~USIOE; // SDA = input --> redundant
    USICNT |= 0x08; // Bit counter = 8, RX data
    I2C_State = 6; // Next state: Test data and (N)Ack
    P1OUT &= ~0x01; // LED off
    }


    void Setup_USI_Master_TX (void)
    {
    _DINT();
    Bytecount = 0;
    Transmit = 1;
    USICTL0 = USIPE6+USIPE7+USIMST+USISWRST; // Port & USI mode setup
    USICTL1 = USII2C+USIIE; // Enable I2C mode & USI interrupt
    USICKCTL = USIDIV_7+USISSEL_2+USICKPL; // USI clk: SCL = SMCLK/128
    USICNT |= USIIFGCC; // Disable automatic clear control
    USICTL0 &= ~USISWRST; // Enable USI
    USICTL1 &= ~USIIFG; // Clear pending flag
    _EINT();
    }


    void Setup_USI_Master_RX (void)
    {
    _DINT();
    Bytecount = 0;
    Transmit = 0;
    USICTL0 = USIPE6+USIPE7+USIMST+USISWRST; // Port & USI mode setup
    USICTL1 = USII2C+USIIE; // Enable I2C mode & USI interrupt
    USICKCTL = USIDIV_7+USISSEL_2+USICKPL; // USI clks: SCL = SMCLK/128
    USICNT |= USIIFGCC; // Disable automatic clear control
    USICTL0 &= ~USISWRST; // Enable USI
    USICTL1 &= ~USIIFG; // Clear pending flag
    _EINT();

    }

    void Master_Transmit(void){
    Setup_USI_Master_TX();
    USICTL1 |= USIIFG; // Set flag and start communication
    LPM0; // CPU off, await USI interrupt
    __delay_cycles(10000); // Delay between comm cycles
    }
    void Master_Recieve(void){
    Setup_USI_Master_RX();
    USICTL1 |= USIIFG; // Set flag and start communication
    LPM0; // CPU off, await USI interrupt
    __delay_cycles(10000); // Delay between comm cycles
    }
  • //******************************************************************************
    // MSP430G2x21/G2x31 Demo - I2C Master Transmitter / Reciever, multiple bytes
    //
    // Description: I2C Master communicates with I2C Slave using
    // the USI. Master data should increment from 0x55 with each transmitted byte
    // and Master determines the number of bytes recieved, set by
    // the Number_of_Bytes value. LED off for address or data Ack;
    // LED on for address or data NAck.
    // ACLK = n/a, MCLK = SMCLK = Calibrated 1MHz
    //
    //
    // ***THIS IS THE MASTER CODE***
    //
    // Slave Master
    // (msp430g2x21_usi_15.c)
    // MSP430G2x21/G2x31 MSP430G2x21/G2x31
    // ----------------- -----------------
    // /|\| XIN|- /|\| XIN|-
    // | | | | | |
    // --|RST XOUT|- --|RST XOUT|-
    // | | | |
    // LED <-|P1.0 | | |
    // | | | P1.0|-> LED
    // | SDA/P1.7|------->|P1.6/SDA |
    // | SCL/P1.6|<-------|P1.7/SCL |
    //
    // Note: internal pull-ups are used in this example for SDA & SCL
    //
    // D. Dang
    // Texas Instruments Inc.
    // October 2010
    // Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10
    //******************************************************************************

    #include <msp430g2221.h>


    #define number_of_bytes 5 // How many bytes?

    void Master_Transmit(void);
    void Master_Recieve(void);

    void Setup_USI_Master_TX(void);
    void Setup_USI_Master_RX(void);

    char MST_Data = 0x55; // Variable for transmitted data
    char SLV_Addr = 0x90;
    int I2C_State, Bytecount, Transmit = 0; // State variable
    void Data_TX (void);
    void Data_RX (void);
    void main(void)
    {
    volatile unsigned int i; // Use volatile to prevent removal

    WDTCTL = WDTPW + WDTHOLD; // Stop watchdog
    if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
    {
    while(1); // If calibration constants erased
    // do not load, trap CPU!!
    }

    BCSCTL1 = CALBC1_1MHZ; // Set DCO
    DCOCTL = CALDCO_1MHZ;

    P1OUT = 0xC0; // P1.6 & P1.7 Pullups, others to 0
    P1REN |= 0xC0; // P1.6 & P1.7 Pullups
    P1DIR = 0xFF; // Unused pins as outputs
    P2OUT = 0;
    P2DIR = 0xFF;



    while(1)
    {
    Master_Transmit();
    _NOP(); // Used for IAR

    Master_Recieve();
    _NOP();
    }
    }

    /******************************************************
    // USI interrupt service routine
    // Data Transmit : state 0 -> 2 -> 4 -> 10 -> 12 -> 14
    // Data Recieve : state 0 -> 2 -> 4 -> 6 -> 8 -> 14
    ******************************************************/
    #pragma vector = USI_VECTOR
    __interrupt void USI_TXRX (void)
    {
    switch(__even_in_range(I2C_State,14))
    {
    case 0: // Generate Start Condition & send address to slave
    P1OUT |= 0x01; // LED on: sequence start
    Bytecount = 0;
    USISRL = 0x00; // Generate Start Condition...
    USICTL0 |= USIGE+USIOE;
    USICTL0 &= ~USIGE;
    if (Transmit == 1){
    USISRL = 0x90; // Address is 0x48 << 1 bit + 0 (rw)
    }
    if (Transmit == 0){
    USISRL = 0x91; // 0x91 Address is 0x48 << 1 bit
    // + 1 for Read
    }
    USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, TX Address
    I2C_State = 2; // next state: rcv address (N)Ack
    break;

    case 2: // Receive Address Ack/Nack bit
    USICTL0 &= ~USIOE; // SDA = input
    USICNT |= 0x01; // Bit counter=1, receive (N)Ack bit
    I2C_State = 4; // Go to next state: check (N)Ack
    break;

    case 4: // Process Address Ack/Nack & handle data TX

    if(Transmit == 1){
    USICTL0 |= USIOE; // SDA = output
    if (USISRL & 0x01) // If Nack received...
    { // Send stop...
    USISRL = 0x00;
    USICNT |= 0x01; // Bit counter=1, SCL high, SDA low
    I2C_State = 14; // Go to next state: generate Stop
    P1OUT |= 0x01; // Turn on LED: error
    }
    else
    { // Ack received, TX data to slave...
    USISRL = MST_Data++; // Load data byte
    USICNT |= 0x08; // Bit counter = 8, start TX
    I2C_State = 10; // next state: receive data (N)Ack
    Bytecount++;
    P1OUT &= ~0x01; // Turn off LED
    break;
    }
    } if(Transmit == 0){

    if (USISRL & 0x01) // If Nack received
    { // Prep Stop Condition
    USICTL0 |= USIOE;
    USISRL = 0x00;
    USICNT |= 0x01; // Bit counter= 1, SCL high, SDA low
    I2C_State = 8; // Go to next state: generate Stop
    P1OUT |= 0x01; // Turn on LED: error
    }
    else{ Data_RX();} // Ack received


    }
    break;

    case 6: // Send Data Ack/Nack bit
    USICTL0 |= USIOE; // SDA = output
    if (Bytecount <= number_of_bytes-2)
    { // If this is not the last byte
    USISRL = 0x00; // Send Ack
    P1OUT &= ~0x01; // LED off
    I2C_State = 4; // Go to next state: data/rcv again
    Bytecount++;
    }

    else //last byte: send NACK
    {
    USISRL = 0xFF; // Send NAck
    P1OUT |= 0x01; // LED on: end of comm
    I2C_State = 8; // stop condition
    }
    USICNT |= 0x01; // Bit counter = 1, send (N)Ack bit
    break;

    case 8: // Prep Stop Condition
    USICTL0 |= USIOE; // SDA = output
    USISRL = 0x00;
    USICNT |= 0x01; // Bit counter= 1, SCL high, SDA low
    I2C_State = 14; // Go to next state: generate Stop
    break;

    case 10: // Receive Data Ack/Nack bit
    USICTL0 &= ~USIOE; // SDA = input
    USICNT |= 0x01; // Bit counter = 1, receive (N)Ack bit
    I2C_State = 12; // Go to next state: check (N)Ack
    break;

    case 12: // Process Data Ack/Nack & send Stop
    USICTL0 |= USIOE;
    if (Bytecount == number_of_bytes){// If last byte
    USISRL = 0x00;

    I2C_State = 14; // Go to next state: generate Stop
    P1OUT |= 0x01;
    USICNT |= 0x01; } // set count=1 to trigger next state
    else{
    P1OUT &= ~0x01; // Turn off LED
    Data_TX(); // TX byte
    }
    break;

    case 14:// Generate Stop Condition
    USISRL = 0x0FF; // USISRL = 1 to release SDA
    USICTL0 |= USIGE; // Transparent latch enabled
    USICTL0 &= ~(USIGE+USIOE); // Latch/SDA output disabled
    I2C_State = 0; // Reset state machine for next xmt
    LPM0_EXIT; // Exit active for next transfer
    break;
    }

    USICTL1 &= ~USIIFG; // Clear pending flag
    }


    void Data_TX (void){

    USISRL = MST_Data++; // Load data byte
    USICNT |= 0x08; // Bit counter = 8, start TX
    I2C_State = 10; // next state: receive data (N)Ack
    Bytecount++;
    }

    void Data_RX (void){
    USICTL0 &= ~USIOE; // SDA = input --> redundant
    USICNT |= 0x08; // Bit counter = 8, RX data
    I2C_State = 6; // Next state: Test data and (N)Ack
    P1OUT &= ~0x01; // LED off
    }


    void Setup_USI_Master_TX (void)
    {
    _DINT();
    Bytecount = 0;
    Transmit = 1;
    USICTL0 = USIPE6+USIPE7+USIMST+USISWRST; // Port & USI mode setup
    USICTL1 = USII2C+USIIE; // Enable I2C mode & USI interrupt
    USICKCTL = USIDIV_7+USISSEL_2+USICKPL; // USI clk: SCL = SMCLK/128
    USICNT |= USIIFGCC; // Disable automatic clear control
    USICTL0 &= ~USISWRST; // Enable USI
    USICTL1 &= ~USIIFG; // Clear pending flag
    _EINT();
    }


    void Setup_USI_Master_RX (void)
    {
    _DINT();
    Bytecount = 0;
    Transmit = 0;
    USICTL0 = USIPE6+USIPE7+USIMST+USISWRST; // Port & USI mode setup
    USICTL1 = USII2C+USIIE; // Enable I2C mode & USI interrupt
    USICKCTL = USIDIV_7+USISSEL_2+USICKPL; // USI clks: SCL = SMCLK/128
    USICNT |= USIIFGCC; // Disable automatic clear control
    USICTL0 &= ~USISWRST; // Enable USI
    USICTL1 &= ~USIIFG; // Clear pending flag
    _EINT();

    }

    void Master_Transmit(void){
    Setup_USI_Master_TX();
    USICTL1 |= USIIFG; // Set flag and start communication
    LPM0; // CPU off, await USI interrupt
    __delay_cycles(10000); // Delay between comm cycles
    }
    void Master_Recieve(void){
    Setup_USI_Master_RX();
    USICTL1 |= USIIFG; // Set flag and start communication
    LPM0; // CPU off, await USI interrupt
    __delay_cycles(10000); // Delay between comm cycles
    }
  • PAVAN ANAND said:
    i am not able to figure out where to enter the data which i need to send


    In the code you posted, the transmitter sends the value in MST_Data, then increases it. So starting with 0x55 ("U"), it will send "UVWXY" (5 bytes).

    To send an independent string, you must change the following:

    change
    char MST_Data = 0x55;
    to
    unsigned char * MST_Data = myData;

    add your data array
    unsigned char myData[number_of_bytes]="data"; // or "= {0x12, 0x34, 64, 'a', 0};"

    and change the lines containing
    USISRL=MST_Data++;
    to
    USISRL=*(MST_Data++);

    Then it will number_of_bytes bytes from myData to the slave.

  • Thanks.That helped me a lot.

    How do I access these registers? I  have the data sheet I have to write bytes to addresses 09 and 0A

  • I tried the suggestions..plz tell me how to access particular registers on my chip? and to read the data is it enough if i just change the slave address and transmit variable =0?

  • Hi,

    i just finished creating another example with USI in I2C mode, it is available under the following wiki page:

    http://processors.wiki.ti.com/index.php/I2C_Communication_with_USI_Module

    the library provided in the example code should be more straight forward and easier to be understood.

    Comments are highly welcomed.

    -Leo-

  • PAVAN ANAND said:
    plz tell me how to access particular registers on my chip

    There are two types of registers. Processor registers and hardware registers. Processor registers are outside the scope of the C language. Since it is necessary to access the status register, the compiler provides intrinsics (pseudo-functions) like bic_SR_register(x).
    Hardware registers are mapped in teh normal processor memory space. They are accessed liek ram or flash by the processor. And for the compiler, the header files (mspxxxx.h) define them as volatile variables. So you can use them by their defined name as if they were normal variables.

    PAVAN ANAND said:
    and to read the data is it enough if i just change the slave address and transmit variable=0?

    ??? Sorry, I don't understand what you mean.

  • In the program I mentioned to write data onto my eeprom chip is it enough if i change the slave address and transmit=1 to send data?

    According to the eeprom datasheet (DS1682 ETC) I have to send 1) Slave address first 2) Then the register address 3) Then the actual data

    In the program I posted above, I dont see where the registers are addressed. Where do I send register addresses?

  • I have to send slave address first, then the register byte then the actual data..plz reply!

  • PAVAN ANAND said:
    In the program I mentioned to write data onto my eeprom chip is it enough if i change the slave address and transmit=1 to send data?

    well, yes, sort of. Actually, you don't change the address, you change the direction control bit that is part of the slave addressing byte, but not part of the slave address. However, most datasheets jsut include this bit and give two addresses for read and write.
    If you ever use an MSP with USCI module, then this bit is NOT part of the slave address (you have to specify in a separate register) and will be added by USCI hardware depending on transfer direction.

    PAVAN ANAND said:
    According to the eeprom datasheet (DS1682 ETC) I have to send 1) Slave address first 2) Then the register address 3) Then the actual data


    THat's the usualy way. After the start condition, you send the sklave address (7 bits), the direction bit (one bit, of course) and check for the slave ACK. THis is done for read or write identically.
    Now in write mode, you send one byte with the address, then the data. Mos tslaves simply increase teh address after each data byte. However, slaves wiht more than 8 bit (256 byte) address range may require a two-byte address.

    PAVAN ANAND said:
    In the program I posted above, I dont see where the registers are addressed. Where do I send register addresses?

    The program just sends a fixed sequence of bytes, beginning with 0x55 and then incrementing. It does not send independent values. Hence the correcitons/changes I suggested.

  • Jens-michael Gross ,

    The data sheet of DS1682 specifically says that I have to send register address after sending the slave address while writing. N either my program nor your's has this facility. In my program there is facility to send slave address first then the data bytes, but where do I send the register? (I have to send register address right after I send the slave address ).

  • Say if I want to send data to address 0x02 memory on the DS1682 , how do I do it?. Sorry if i was not clear before 

  • PAVAN ANAND said:
    The data sheet of DS1682 specifically says that I have to send register address after sending the slave address while writing

    The address is just another data byte. The first data byte you send is interpreted as address, not as data that is to be written. There is no special 'I'm now sending the address' command.
    If you start a write treansfer, the first byte (or the first two bytes, if the address is 16 bit) sets the address counter. Every further byte sent is written to this address and the address is incremented. If you end the write transfer and start a read transfer, readign starts from the last address. So writing just the address and then turn to reading will set the address for reading.

    The sequence is

    send start condition
    send slave address + '0' bit for write
    read and check ACK bit from slave
    send address byte
    read and check ACK bit from slave
    send first data byte
    read and check ACK bit
    send next data byte
    [...]
    send stop condition

  • That answers all my questions..thanks Jens for your support! 

  • Hey,

    I am not able to write the write single byte using the example code

    //******************************************************************************
    // MSP430G2x21/G2x31 Demo - I2C Master Transmitter, single byte
    //
    // Description: I2C Master communicates with I2C Slave using
    // the USI. Master data is sent and increments from 0x00 with each transmitted
    // byte which is verified by the slave.
    // LED off for address or data Ack; LED on for address or data NAck.
    // ACLK = n/a, MCLK = SMCLK = Calibrated 1MHz
    //
    // ***THIS IS THE MASTER CODE***
    //
    // Slave Master
    // (msp430g2x21_usi_08.c)
    // MSP430G2x21/G2x31 MSP430G2x21/G2x31
    // ----------------- -----------------
    // /|\| XIN|- /|\| XIN|-
    // | | | | | |
    // --|RST XOUT|- --|RST XOUT|-
    // | | | |
    // LED <-|P1.0 | | |
    // | | | P1.0|-> LED
    // | SDA/P1.7|<-------|P1.7/SDA |
    // | SCL/P1.6|<-------|P1.6/SCL |
    //
    // Note: internal pull-ups are used in this example for SDA & SCL
    //
    // D. Dang
    // Texas Instruments Inc.
    // October 2010
    // Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10
    //******************************************************************************

    #include <msp430g2231.h>

    char MST_Data = 0; // Variable for transmitted data
    char SLV_Addr = 0xd6; // Address is 0x48 << 1 bit + 0 for Write
    int I2C_State = 0; // State variable

    void main(void)
    {
    volatile unsigned int i; // Use volatile to prevent removal

    WDTCTL = WDTPW + WDTHOLD; // Stop watchdog
    if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
    {
    while(1); // If calibration constants erased
    // do not load, trap CPU!!
    }
    BCSCTL1 = CALBC1_1MHZ; // Set DCO
    DCOCTL = CALDCO_1MHZ;

    P1OUT = 0xC0; // P1.6 & P1.7 Pullups, others to 0
    P1REN |= 0xC0; // P1.6 & P1.7 Pullups
    P1DIR = 0xFF; // Unused pins as outputs
    P2OUT = 0;
    P2DIR = 0xFF;

    USICTL0 = USIPE6+USIPE7+USIMST+USISWRST; // Port & USI mode setup
    USICTL1 = USII2C+USIIE; // Enable I2C mode & USI interrupt
    USICKCTL = USIDIV_3+USISSEL_2+USICKPL; // Setup USI clocks: SCL = SMCLK/8 (~125kHz)
    USICNT |= USIIFGCC; // Disable automatic clear control
    USICTL0 &= ~USISWRST; // Enable USI
    USICTL1 &= ~USIIFG; // Clear pending flag
    _EINT();

    while(1)
    {
    USICTL1 |= USIIFG; // Set flag and start communication
    LPM0; // CPU off, await USI interrupt
    _NOP(); // Used for IAR
    for (i = 0; i < 5000; i++); // Dummy delay between communication cycles
    }
    }

    /******************************************************
    // USI interrupt service routine
    ******************************************************/
    #pragma vector = USI_VECTOR
    __interrupt void USI_TXRX (void)
    {
    switch(I2C_State)
    {
    case 0: // Generate Start Condition & send address to slave
    P1OUT |= 0x01; // LED on: sequence start
    USISRL = 0x00; // Generate Start Condition...
    USICTL0 |= USIGE+USIOE;
    USICTL0 &= ~USIGE;
    USISRL = SLV_Addr; // ... and transmit address, R/W = 0
    USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, TX Address
    I2C_State = 2; // Go to next state: receive address (N)Ack
    break;

    case 2: // Receive Address Ack/Nack bit
    USICTL0 &= ~USIOE; // SDA = input
    USICNT |= 0x01; // Bit counter = 1, receive (N)Ack bit
    I2C_State = 4; // Go to next state: check (N)Ack
    break;

    case 4: // Process Address Ack/Nack & handle data TX
    USICTL0 |= USIOE; // SDA = output
    if (USISRL & 0x01) // If Nack received...
    { // Send stop...
    USISRL = 0x00;
    USICNT |= 0x01; // Bit counter = 1, SCL high, SDA low
    I2C_State = 10; // Go to next state: generate Stop
    P1OUT |= 0x01; // Turn on LED: error
    }
    else
    { // Ack received, TX data to slave...
    USISRL = MST_Data; // Load data byte
    USICNT |= 0x08; // Bit counter = 8, start TX
    I2C_State = 6; // Go to next state: receive data (N)Ack
    P1OUT &= ~0x01; // Turn off LED
    }
    break;

    case 6: // Receive Data Ack/Nack bit
    USICTL0 &= ~USIOE; // SDA = input
    USICNT |= 0x01; // Bit counter = 1, receive (N)Ack bit
    I2C_State = 8; // Go to next state: check (N)Ack
    break;

    case 8: // Process Data Ack/Nack & send Stop
    USICTL0 |= USIOE;
    if (USISRL & 0x01) // If Nack received...
    P1OUT |= 0x01; // Turn on LED: error
    else // Ack received
    {
    MST_Data++; // Increment Master data
    P1OUT &= ~0x01; // Turn off LED
    }
    // Send stop...
    USISRL = 0x00;
    USICNT |= 0x01; // Bit counter = 1, SCL high, SDA low
    I2C_State = 10; // Go to next state: generate Stop
    break;

    case 10:// Generate Stop Condition
    USISRL = 0x0FF; // USISRL = 1 to release SDA
    USICTL0 |= USIGE; // Transparent latch enabled
    USICTL0 &= ~(USIGE+USIOE);// Latch/SDA output disabled
    I2C_State = 0; // Reset state machine for next transmission
    LPM0_EXIT; // Exit active for next transfer
    break;
    }

    USICTL1 &= ~USIIFG; // Clear pending flag
    }
    
    
    
    
    I have changed the slave address to 0xD6 and nothing else. What should I do?
  • Hey,

    I am not able to write the write single byte using the example code

    //******************************************************************************
    // MSP430G2x21/G2x31 Demo - I2C Master Transmitter, single byte
    //
    // Description: I2C Master communicates with I2C Slave using
    // the USI. Master data is sent and increments from 0x00 with each transmitted
    // byte which is verified by the slave.
    // LED off for address or data Ack; LED on for address or data NAck.
    // ACLK = n/a, MCLK = SMCLK = Calibrated 1MHz
    //
    // ***THIS IS THE MASTER CODE***
    //
    // Slave Master
    // (msp430g2x21_usi_08.c)
    // MSP430G2x21/G2x31 MSP430G2x21/G2x31
    // ----------------- -----------------
    // /|\| XIN|- /|\| XIN|-
    // | | | | | |
    // --|RST XOUT|- --|RST XOUT|-
    // | | | |
    // LED <-|P1.0 | | |
    // | | | P1.0|-> LED
    // | SDA/P1.7|<-------|P1.7/SDA |
    // | SCL/P1.6|<-------|P1.6/SCL |
    //
    // Note: internal pull-ups are used in this example for SDA & SCL
    //
    // D. Dang
    // Texas Instruments Inc.
    // October 2010
    // Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10
    //******************************************************************************

    #include <msp430g2231.h>

    char MST_Data = 0; // Variable for transmitted data
    char SLV_Addr = 0xd6; // Address is 0x48 << 1 bit + 0 for Write
    int I2C_State = 0; // State variable

    void main(void)
    {
    volatile unsigned int i; // Use volatile to prevent removal

    WDTCTL = WDTPW + WDTHOLD; // Stop watchdog
    if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
    {
    while(1); // If calibration constants erased
    // do not load, trap CPU!!
    }
    BCSCTL1 = CALBC1_1MHZ; // Set DCO
    DCOCTL = CALDCO_1MHZ;

    P1OUT = 0xC0; // P1.6 & P1.7 Pullups, others to 0
    P1REN |= 0xC0; // P1.6 & P1.7 Pullups
    P1DIR = 0xFF; // Unused pins as outputs
    P2OUT = 0;
    P2DIR = 0xFF;

    USICTL0 = USIPE6+USIPE7+USIMST+USISWRST; // Port & USI mode setup
    USICTL1 = USII2C+USIIE; // Enable I2C mode & USI interrupt
    USICKCTL = USIDIV_3+USISSEL_2+USICKPL; // Setup USI clocks: SCL = SMCLK/8 (~125kHz)
    USICNT |= USIIFGCC; // Disable automatic clear control
    USICTL0 &= ~USISWRST; // Enable USI
    USICTL1 &= ~USIIFG; // Clear pending flag
    _EINT();

    while(1)
    {
    USICTL1 |= USIIFG; // Set flag and start communication
    LPM0; // CPU off, await USI interrupt
    _NOP(); // Used for IAR
    for (i = 0; i < 5000; i++); // Dummy delay between communication cycles
    }
    }

    /******************************************************
    // USI interrupt service routine
    ******************************************************/
    #pragma vector = USI_VECTOR
    __interrupt void USI_TXRX (void)
    {
    switch(I2C_State)
    {
    case 0: // Generate Start Condition & send address to slave
    P1OUT |= 0x01; // LED on: sequence start
    USISRL = 0x00; // Generate Start Condition...
    USICTL0 |= USIGE+USIOE;
    USICTL0 &= ~USIGE;
    USISRL = SLV_Addr; // ... and transmit address, R/W = 0
    USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, TX Address
    I2C_State = 2; // Go to next state: receive address (N)Ack
    break;

    case 2: // Receive Address Ack/Nack bit
    USICTL0 &= ~USIOE; // SDA = input
    USICNT |= 0x01; // Bit counter = 1, receive (N)Ack bit
    I2C_State = 4; // Go to next state: check (N)Ack
    break;

    case 4: // Process Address Ack/Nack & handle data TX
    USICTL0 |= USIOE; // SDA = output
    if (USISRL & 0x01) // If Nack received...
    { // Send stop...
    USISRL = 0x00;
    USICNT |= 0x01; // Bit counter = 1, SCL high, SDA low
    I2C_State = 10; // Go to next state: generate Stop
    P1OUT |= 0x01; // Turn on LED: error
    }
    else
    { // Ack received, TX data to slave...
    USISRL = MST_Data; // Load data byte
    USICNT |= 0x08; // Bit counter = 8, start TX
    I2C_State = 6; // Go to next state: receive data (N)Ack
    P1OUT &= ~0x01; // Turn off LED
    }
    break;

    case 6: // Receive Data Ack/Nack bit
    USICTL0 &= ~USIOE; // SDA = input
    USICNT |= 0x01; // Bit counter = 1, receive (N)Ack bit
    I2C_State = 8; // Go to next state: check (N)Ack
    break;

    case 8: // Process Data Ack/Nack & send Stop
    USICTL0 |= USIOE;
    if (USISRL & 0x01) // If Nack received...
    P1OUT |= 0x01; // Turn on LED: error
    else // Ack received
    {
    MST_Data++; // Increment Master data
    P1OUT &= ~0x01; // Turn off LED
    }
    // Send stop...
    USISRL = 0x00;
    USICNT |= 0x01; // Bit counter = 1, SCL high, SDA low
    I2C_State = 10; // Go to next state: generate Stop
    break;

    case 10:// Generate Stop Condition
    USISRL = 0x0FF; // USISRL = 1 to release SDA
    USICTL0 |= USIGE; // Transparent latch enabled
    USICTL0 &= ~(USIGE+USIOE);// Latch/SDA output disabled
    I2C_State = 0; // Reset state machine for next transmission
    LPM0_EXIT; // Exit active for next transfer
    break;
    }

    USICTL1 &= ~USIIFG; // Clear pending flag
    }
    
    
    
    
    I have changed the slave address to 0xD6 and nothing else. What should I do?
    If i debug, the code enters a loop and it doesnt go over lpm0
    And in the oscilloscope SDA is in high impedence 
  • PAVAN ANAND said:
    char SLV_Addr = 0xd6; // Address is 0x48 << 1 bit + 0 for Write

    Last time I checked, 0x48<<1 resolved to 0x90, not 0xd6.
    So where comes 0xd6 from?
    PAVAN ANAND said:
    for (i = 0; i < 5000; i++); // Dummy delay between communication cycles
    Depending on compiler and optimization level, this is no delay at all. It is simply an i=5000 instruction.
    If you intend to waste CPU time, use the __delay_cycles intrinsic.

    PAVAN ANAND said:
    I have changed the slave address to 0xD6 and nothing else.

    And with a different slave address it works? then there is a problem with the code for the case that a slave doesn't answer. I just don't see a problem there.
    Well, I'm no USI expert. I never used the USI personally.

**Attention** This is a public forum