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.

CCS/MSP430F5529: I2C help on MSP430F5529

Part Number: MSP430F5529
Other Parts Discussed in Thread: INA260, MSP430F2619, ENERGIA

Tool/software: Code Composer Studio

Team,

I  am a filed appications rotator working on getting a new sensor demo up and running for a customer. The sensor requires i2c and we are demoing on the MSP430F5529. Currently I am struggling just to get the i2c working so that I can write to and read from registers. I am not sure the sensor I am supposed to be demoing works correctly so currently I am just trying to read and write to/from a INA260 EVM over i2c. I have tried multiple approaches so far. I tried basing code off the USCIB0 read and write multiple bytes "examples". I also tried porting other peoples I2c code from other microcontrollers to the 5529 but have had little success. I believe my main issue is writing the ISR, I have found no good examples for this. 

Question #1:

Does TI have any good I2C examples for reading/writing to a device?

Question#2:

I included my 3 approaches below. If any of them seem close I would greatly appreciate your input on how I can get up and running with I2C. I have used I2C before on microchip controllers and have read all the TI literature I can find (User guide, datasheet, how to use I2C, basics of I2C, and mspware). I am also now familiar with the USCI library. 

Approach 1: wrote i2c based on the example code for the MSP430F2619.

main.c
#include <stdio.h>
#include <msp430f5529.h>
#include <lib5529i2c.h>

unsigned char array[5] = { 0x00, 0x07, 0x27};
unsigned char array2[5];
signed char byteCtr;
unsigned char *TI_receive_field;
unsigned char *TI_transmit_field;


void main(void)
{

    WDTCTL = WDTPW + WDTHOLD; // Disable Watchdog
    P1DIR |= 0x01;
    P1OUT= 0x00;// configure P1.0 as output
    _EINT(); // enable interrupts
    __enable_interrupt();
    TI_USCI_I2C_transmitinit(0x40, 0x12); // initialize USCI
    while ( TI_USCI_I2C_notready() );
    TI_USCI_I2C_transmit(3,array); // transmit the first 3 bytes of array
    //LPM0; // put CPU to sleep during communication
    TI_USCI_I2C_receiveinit(0x40,0x12);
    while ( TI_USCI_I2C_notready() );
    TI_USCI_I2C_receive(3,array2);
}

lib5529i2c.h

/*
 * lib5529i2c.h
 *
 *  Created on: Feb 9, 2018
 *      Author: a0226654
 */

#ifndef LIB5529I2C_H_
#define LIB5529I2C_H_

#define SDA_PIN BIT0                                  // msp430x261x UCB0SDA pin
#define SCL_PIN BIT1                                  // msp430x261x UCB0SCL pin



void TI_USCI_I2C_receiveinit(unsigned char slave_address, unsigned char prescale);
void TI_USCI_I2C_transmitinit(unsigned char slave_address, unsigned char prescale);


void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field);
void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field);


unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address);
unsigned char TI_USCI_I2C_notready();


#endif /* LIB5529I2C_H_ */





lib5529i2c.c

//******************************************************************************
//   MSP430 USCI I2C Transmitter and Receiver
//
//  Description: This code configures the MSP430's USCI module as
//  I2C master capable of transmitting and receiving bytes.
//
//  ***THIS IS THE MASTER CODE***
//
//                    Master
//                 MSP430F2619
//             -----------------
//         /|\|              XIN|-
//          | |                 |
//          --|RST          XOUT|-
//            |                 |
//            |                 |
//            |                 |
//            |         SDA/P3.1|------->
//            |         SCL/P3.2|------->
//
// Note: External pull-ups are needed for SDA & SCL
//
// Uli Kretzschmar
// Texas Instruments Deutschland GmbH
// November 2007
// Built with IAR Embedded Workbench Version: 3.42A
//******************************************************************************

#include "msp430f5529.h"                        // device specific header
//#include "msp430x22x4.h"
//#include "msp430x23x0.h"
//#include "msp430xG46x.h"
// ...                                         // more devices are possible

#include "lib5529i2c.h"

signed char byteCtr;
unsigned char *TI_receive_field;
unsigned char *TI_transmit_field;
int q=0;
//------------------------------------------------------------------------------
// void TI_USCI_I2C_receiveinit(unsigned char slave_address,
//                              unsigned char prescale)
//
// This function initializes the USCI module for master-receive operation.
//
// IN:   unsigned char slave_address   =>  Slave Address
//       unsigned char prescale        =>  SCL clock adjustment
//-----------------------------------------------------------------------------
void TI_USCI_I2C_receiveinit(unsigned char slave_address,
                             unsigned char prescale){
  P3SEL |= SDA_PIN + SCL_PIN;                 // Assign I2C pins to USCI_B0
  UCB0CTL1 = UCSWRST;                        // Enable SW reset
  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;       // I2C Master, synchronous mode
  UCB0CTL1 = UCSSEL_2 + UCSWRST;              // Use SMCLK, keep SW reset
  UCB0BR0 = prescale;                         // set prescaler
  UCB0BR1 = 0;
  UCB0I2CSA = slave_address;                  // set slave address
  UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation
  UCB0IE = UCNACKIE;
  UCB0IE = UCRXIE;                            // Enable RX interrupt
}

//------------------------------------------------------------------------------
// void TI_USCI_I2C_transmitinit(unsigned char slave_address,
//                               unsigned char prescale)
//
// This function initializes the USCI module for master-transmit operation.
//
// IN:   unsigned char slave_address   =>  Slave Address
//       unsigned char prescale        =>  SCL clock adjustment
//------------------------------------------------------------------------------
void TI_USCI_I2C_transmitinit(unsigned char slave_address,
                          unsigned char prescale){
  P3SEL |= SDA_PIN + SCL_PIN;                 // Assign I2C pins to USCI_B0
  UCB0CTL1 |= UCSWRST;                        // Enable SW reset
  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;       // I2C Master, synchronous mode
  UCB0CTL1 = UCSSEL_2 + UCSWRST;              // Use SMCLK, keep SW reset
  UCB0BR0 = prescale;                         // set prescaler
  UCB0BR1 = 0;
  UCB0I2CSA = slave_address;                  // Set slave address
  UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation
  UCB0IE = UCNACKIE;
  UCB0IE |= UCTXIE;                            // Enable TX ready interrupt
}

//------------------------------------------------------------------------------
// void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field)
//
// This function is used to start an I2C commuincation in master-receiver mode.
//
// IN:   unsigned char byteCount  =>  number of bytes that should be read
//       unsigned char *field     =>  array variable used to store received data
//------------------------------------------------------------------------------
void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field){
  TI_receive_field = field;
  if ( byteCount == 1 ){
    byteCtr = 0 ;
    __disable_interrupt();
    UCB0CTL1 |= UCTXSTT;                      // I2C start condition
    while (UCB0CTL1 & UCTXSTT);               // Start condition sent?
    UCB0CTL1 |= UCTXSTP;                      // I2C stop condition
    __enable_interrupt();
  } else if ( byteCount > 1 ) {
    byteCtr = byteCount - 2 ;
    UCB0CTL1 |= UCTXSTT;                      // I2C start condition
  } else
    while (1);                                // illegal parameter
}

//------------------------------------------------------------------------------
// void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field)
//
// This function is used to start an I2C commuincation in master-transmit mode.
//
// IN:   unsigned char byteCount  =>  number of bytes that should be transmitted
//       unsigned char *field     =>  array variable. Its content will be sent.
//------------------------------------------------------------------------------
void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field){
  TI_transmit_field = field;
  byteCtr = byteCount;
  UCB0CTL1 |= UCTR + UCTXSTT;                 // I2C TX, start condition
}

//------------------------------------------------------------------------------
// unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address)
//
// This function is used to look for a slave address on the I2C bus.
//
// IN:   unsigned char slave_address  =>  Slave Address
// OUT:  unsigned char                =>  0: address was not found,
//                                        1: address found
//------------------------------------------------------------------------------
unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address){
  unsigned char ie2_bak, slaveadr_bak, ucb0i2cie, returnValue;
  ucb0i2cie = UCB0IE;                      // restore old UCB0I2CIE
  ie2_bak = UCB0IE;                              // store IE2 register
  slaveadr_bak = UCB0I2CSA;                   // store old slave address
  UCB0IE &= ~ UCNACKIE;                    // no NACK interrupt
  UCB0I2CSA = slave_address;                  // set slave address
  UCB0IE &= ~(UCTXIE + UCRXIE);              // no RX or TX interrupts
  __disable_interrupt();
  UCB0CTL1 |= UCTR + UCTXSTT + UCTXSTP;       // I2C TX, start condition
  while (UCB0CTL1 & UCTXSTP);                 // wait for STOP condition

  returnValue = !(UCB0STAT & UCNACKIFG);
  __enable_interrupt();
  UCB0IE = ie2_bak;                              // restore IE2
  UCB0I2CSA = slaveadr_bak;                   // restore old slave address
  UCB0IE = ucb0i2cie;                      // restore old UCB0CTL1
  return returnValue;                         // return whether or not
                                              // a NACK occured
}

//------------------------------------------------------------------------------
// unsigned char TI_USCI_I2C_notready()
//
// This function is used to check if there is commuincation in progress.
//
// OUT:  unsigned char  =>  0: I2C bus is idle,
//                          1: communication is in progress
//------------------------------------------------------------------------------
unsigned char TI_USCI_I2C_notready(){
  return (UCB0STAT & UCBBUSY);
}


#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
{
    switch (__even_in_range(UCB0IV, 12))
        {

        case 10:
            q=10;// Vector 10: RXIFG -- I am not using it yet (but I'll need it)
            if (UCB0STAT & UCNACKIFG){            // send STOP if slave sends NACK
              UCB0CTL1 |= UCTXSTP;
              UCB0STAT &= ~UCNACKIFG;
            }
            break;
        case 12:
            q=12;// Vector 12: TXIFG
            if (P2IFG & UCRXIFG){
                    if ( byteCtr == 0 ){
                      UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
                      *TI_receive_field = UCB0RXBUF;
                      TI_receive_field++;
                    }
                    else {
                      *TI_receive_field = UCB0RXBUF;
                      TI_receive_field++;
                      byteCtr--;
                    }
                  }
                  else {
                    if (byteCtr == 0){
                      UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
                      P2IFG &= ~UCTXIFG;                     // Clear USCI_B0 TX int flag
                    }
                    else {
                      UCB0TXBUF = *TI_transmit_field;
                      TI_transmit_field++;
                      byteCtr--;
                    }
                  }
            break;
        default:
            break;

        }

    }

Approach 2: Wrote library based off 5529 read/write example code 

#include "msp430f5529.h"                        // device specific header
//#include "msp430x22x4.h"
//#include "msp430x23x0.h"
//#include "msp430xG46x.h"
// ...                                         // more devices are possible

#include "lib5529i2c.h"

signed char byteCtr;
unsigned char *TI_receive_field;
unsigned char *TI_transmit_field;
unsigned char TXByteCtr=0;
unsigned char RXByteCtr=0;

void TI_USCI_I2C_receiveinit(unsigned char slave_address,
                             unsigned char prescale){
  P3SEL |= SDA_PIN + SCL_PIN;                 // Assign I2C pins to USCI_B0
  UCB0CTL1 = UCSWRST;                        // Enable SW reset
  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;       // I2C Master, synchronous mode
  UCB0CTL1 = UCSSEL_2 + UCSWRST;              // Use SMCLK, keep SW reset
  UCB0BR0 = prescale;                         // set prescaler
  UCB0BR1 = 0;
  UCB0I2CSA = slave_address;                  // set slave address
  UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation
  UCB0IE = UCNACKIE;
  UCB0IE = UCRXIE;                            // Enable RX interrupt
}


void TI_USCI_I2C_transmitinit(unsigned char slave_address,
                          unsigned char prescale){
  P3SEL |= SDA_PIN + SCL_PIN;                 // Assign I2C pins to USCI_B0
  UCB0CTL1 |= UCSWRST;                        // Enable SW reset
  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;       // I2C Master, synchronous mode
  UCB0CTL1 = UCSSEL_2 + UCSWRST;              // Use SMCLK, keep SW reset
  UCB0BR0 = prescale;                         // set prescaler
  UCB0BR1 = 0;
  UCB0I2CSA = slave_address;                  // Set slave address
  UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation
  UCB0IE = UCNACKIE;
  UCB0IE |= UCTXIE;                            // Enable TX ready interrupt
}


void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field){
  TI_receive_field = field;
  if ( byteCount == 1 ){
    RXByteCtr = 0 ;
    __disable_interrupt();
    UCB0CTL1 |= UCTXSTT;                      // I2C start condition
    while (UCB0CTL1 & UCTXSTT);               // Start condition sent?
    UCB0CTL1 |= UCTXSTP;                      // I2C stop condition
    __enable_interrupt();
  } else if ( byteCount > 1 ) {
      RXByteCtr = byteCount - 2 ;
    UCB0CTL1 |= UCTXSTT;                      // I2C start condition
  } else
    while (1);                                // illegal parameter
}


void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field){
  TI_transmit_field = field;
  TXByteCtr = byteCount;
  UCB0CTL1 |= UCTR + UCTXSTT;                 // I2C TX, start condition
}


unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address){
  unsigned char ie2_bak, slaveadr_bak, ucb0i2cie, returnValue;
  ucb0i2cie = UCB0IE;                      // restore old UCB0I2CIE
  ie2_bak = UCB0IE;                              // store IE2 register
  slaveadr_bak = UCB0I2CSA;                   // store old slave address
  UCB0IE &= ~ UCNACKIE;                    // no NACK interrupt
  UCB0I2CSA = slave_address;                  // set slave address
  UCB0IE &= ~(UCTXIE + UCRXIE);              // no RX or TX interrupts
  __disable_interrupt();
  UCB0CTL1 |= UCTR + UCTXSTT + UCTXSTP;       // I2C TX, start condition
  while (UCB0CTL1 & UCTXSTP);                 // wait for STOP condition

  returnValue = !(UCB0STAT & UCNACKIFG);
  __enable_interrupt();
  UCB0IE = ie2_bak;                              // restore IE2
  UCB0I2CSA = slaveadr_bak;                   // restore old slave address
  UCB0IE = ucb0i2cie;                      // restore old UCB0CTL1
  return returnValue;                         // return whether or not
                                              // a NACK occured
}


unsigned char TI_USCI_I2C_notready(){
  return (UCB0STAT & UCBBUSY);
}


#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
{
    switch (__even_in_range(UCB0IV, 12))
        {

        case 10:
            
            RXByteCtr--;                            // Decrement RX byte counter
                if (RXByteCtr)
                {
                    *TI_receive_field = UCB0RXBUF;               // Move RX data to address PRxData
                  if (RXByteCtr == 1)                   // Only one byte left?
                    UCB0CTL1 |= UCTXSTP;                // Generate I2C stop condition
                }
                else
                {
                    *TI_receive_field = UCB0RXBUF;                 // Move final RX data to PRxData
                  __bic_SR_register_on_exit(LPM0_bits); // Exit active CPU
                }
            
        case 12:
            
            if (TXByteCtr)                          // Check TX byte counter
               {
                 UCB0TXBUF = *TI_transmit_field;               // Load TX buffer
                 TXByteCtr--;                          // Decrement TX byte counter
               }
               else
               {
                 UCB0CTL1 |= UCTXSTP;                  // I2C stop condition
                 UCB0IFG &= ~UCTXIFG;                  // Clear USCI_B0 TX int flag
                 __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
               }
            
        default:
            break;

        }

    }

/*
* Here's an example using an MSP430G2553 to read/write using I2C to an 24LC512 and DS3231 RTC.
* Two functions are provided for read and write.
*
* The code avoids any while loops, and relies completely on interrupts and low power modes of the MSP430 to reduce the power consumption to the
* minimum.
*
* Author: Ahmed Talaat (aa_talaat@yahoo.com)
* Date: 19 October 2012
*/

    #include  "msp430f5529.h"

    #define ONEBYTEADDR 1
    #define TWOBYTEADDR 2
    #define WRITE       0                       // ISR mode WRITE or READ
    #define READ        1
    #define NOACK       2
    #define EEPROM_ADDR 0x40
    #define DS3231_ADDR 0x00

    unsigned char txdataEEPROM[2];
    unsigned char txdataDS3231[7] = {0x20, 0x30, 0x20, 0x04, 0x17, 0x10, 0x12};
    unsigned char rxdata[150];

    typedef struct {
        volatile unsigned char *data_buf;       // address of tx or rx data buffer
        volatile unsigned char buf_size;        // size of the buffer
        volatile unsigned char buf_index;       // index in the buffer
        volatile unsigned char addr_index;      // index of the byte address (0,1)
        volatile unsigned char isr_mode;        // Tx or Rx affects the interrupt logic
        volatile unsigned char addr_high_byte;  // High byte of the address to read/write to
        volatile unsigned char addr_low_byte;   // Low byte of the address to read/write to
        volatile unsigned char addr_type;       // two bytes like eeprom or 1 byte like RTC for example
    } i2c_t;

    i2c_t   i2c_packet;

    void i2c_init(void);
    void i2c_tx(unsigned char, unsigned char *, unsigned char, unsigned char, unsigned char, unsigned char);
    void i2c_rx(unsigned char, unsigned char *, unsigned char, unsigned char, unsigned char, unsigned char);
    void usdelay(int);

    void main(void)
    {
       WDTCTL = WDTPW + WDTHOLD;                // Stop WDT
       i2c_init();                              // Initialize I2C
       txdataEEPROM[0]=0x61;
       txdataEEPROM[1]=0x3F;

       i2c_tx(EEPROM_ADDR, txdataEEPROM, sizeof(txdataEEPROM)-1,ONEBYTEADDR,0x00,0x00);//i2c TX 115 bytes starting @ address 01:00

       i2c_rx(EEPROM_ADDR, rxdata, 2,ONEBYTEADDR,0x00,0x00);//i2c RX 115 bytes from EEPROM starting @ address 01:00
  

       LPM0;                                    // Enter LPM0 w/ interrupts
    }

    void i2c_init(void){
        P3SEL |= BIT0 + BIT1;                   //Set I2C pins
        //P1SEL2|= BIT6 + BIT7;
        UCB0CTL1 |= UCSWRST;                    //Enable SW reset
        UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;   //I2C Master, synchronous mode
        UCB0CTL1 = UCSSEL_2 + UCSWRST;          //Use SMCLK, keep SW reset
        UCB0BR0 = 10;                           //fSCL = SMCLK/11 = ~100kHz
        UCB0BR1 = 0;
        UCB0CTL1 &= ~UCSWRST;                   //Clear SW reset, resume operation
        UCB0IE |= UCTXIE;                        //Enable TX interrupt
        UCB0IE |= UCRXIE;                        //Enable RX interrupt
        UCB0IE |= UCNACKIE;                  //Need to enable the status change interrupt
        __enable_interrupt();                   //Enable global interrupt
    }


    void i2c_tx(unsigned char slave_addr, unsigned char *txdata, unsigned char bufSize, unsigned char addr_size,
                        unsigned char high_byte_addr, unsigned char low_byte_addr) {
        i2c_packet.isr_mode=WRITE;
        i2c_packet.data_buf=txdata;
        i2c_packet.buf_size=bufSize;
        i2c_packet.buf_index=0;
        i2c_packet.addr_type=addr_size;
        i2c_packet.addr_high_byte=high_byte_addr;
        i2c_packet.addr_low_byte=low_byte_addr;
        i2c_packet.addr_index=0;
        UCB0I2CSA = slave_addr;                 //Slave Address

        while (1) {
            UCB0CTL1 |= UCTR + UCTXSTT;         // I2C TX, start condition
            LPM0;                               // Enter LPM0
                                                // and remain until all data is TX'd
            if (i2c_packet.isr_mode == NOACK){  // If no ack received, then sleep for 0.5ms and try again
                i2c_packet.isr_mode = WRITE;
                i2c_packet.addr_index=0;        // Reset the address index for the next write operation
                usdelay(500);

            } else {
                break;                          // Successful write, then quit
            }
        }
    }

    /*
     * This functions reads from any I2C device. It takes as parameters:
     *  - The slave address (7 bits)
     *  - Pointer to the data buffer to fill with data read.
     *  - Size of the buffer
     *  - Size of the address location to start writing at. Being 2 bytes for some of the EEPROMs and single byte
     *    for other devices. Please note that the ISR of this function assumes that the address bytes are written high
     *    byte first, then low byte second.
     *    In case of single byte address device, only the high byte will be used to set the address.
     *  - The high byte and low byte address for the location to start reading at.
     *
     *  The function starts with a write operation to specify the address at which the read operation with start
     *  In case the start condition of the write operation is not ack (for example EEPROM busy with a a previous write cycle),
     *  the corresponding interrupts detects this condition, generates a stop signal, and a Timer A1 (not Timer A0)
     *  is activated for 0.5 ms, then the trial for writing is repeated.
     *
     *  Once the write address is successful, the functions switch to read mode, and fills the buffer provided
     *
     */


    void i2c_rx(unsigned char slave_addr, unsigned char *rxdata, unsigned char bufSize, unsigned char addr_size,
            unsigned char high_byte_addr, unsigned char low_byte_addr) {
        i2c_packet.isr_mode=READ;               // The ISR will send the address bytes, then wake CPU.
        i2c_packet.addr_type=addr_size;
        i2c_packet.addr_high_byte=high_byte_addr;
        i2c_packet.addr_low_byte=low_byte_addr;
        i2c_packet.addr_index=0;
        UCB0I2CSA = slave_addr;                 // Slave Address

        while (1) {
            UCB0CTL1 |= UCTR + UCTXSTT;         // I2C TX, start condition
            LPM0;                               // Enter LPM0
                                                // and remain until all data is TX'd
            if (i2c_packet.isr_mode == NOACK){  // If no ack received, then sleep for 0.5ms and try again
                i2c_packet.isr_mode = READ;
                i2c_packet.addr_index=0;        // Reset the address index for the next write operation
                usdelay(500);
            } else {
                break;                          // Successful write, then quit
            }
        }
                                                // We wrote already the address, so now read only data.
        i2c_packet.addr_index=i2c_packet.addr_type;
        i2c_packet.data_buf=rxdata;
        i2c_packet.buf_size=bufSize;
        i2c_packet.buf_index=0;
        UCB0CTL1 &= ~UCTR;                      // I2C RX
        UCB0CTL1 |= UCTXSTT;                    // I2C re-start condition
        LPM0;                                   // Enter LPM0
                                                // and remain until all data is received
    }


    //interrupt(USCIAB0RX_VECTOR) state change to trap the no_Ack from slave case

/*
 * This interrupt is called each time the UCSI_B module is either ready to get a new byte in UCB0TXBUF to send to the I2C device, or
 * a new byte is read into UCB0RXBUF and we should pick it up.
 * The interrupt is called as both UCB0TXIE and UCB0RXIE are enabled. To stop this interrupt being called indefinitely, the corresponding
 * interrupt flag should be cleared.
 * These flags are automatically clearly by the USCI_B module if the UCB0XXBUF is access. However, if we are to do something different than reading
 * or writing a byte to/from the UCB0XXBUF, we need to clear the corresponding flag by ourselves or the ISR will be called for ever,
 * and the whole program will hang.
 */


#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
{
    switch (__even_in_range(UCB0IV, 12))
        {
        case 10:
            RXByteCtr--;                            // Decrement RX byte counter
                if (RXByteCtr)
                {
                  *PRxData++ = UCB0RXBUF;               // Move RX data to address PRxData
                  if (RXByteCtr == 1)                   // Only one byte left?
                    UCB0CTL1 |= UCTXSTP;                // Generate I2C stop condition
                }
                else
                {
                  *PRxData = UCB0RXBUF;                 // Move final RX data to PRxData
                  __bic_SR_register_on_exit(LPM0_bits); // Exit active CPU
                }
        case 12:
            // Transmit address bytes irrespective of send or receive mode.*/
                    if (i2c_packet.addr_index==0){
                       UCB0TXBUF = i2c_packet.addr_high_byte;
                       i2c_packet.addr_index++;
                    }
                    else if (i2c_packet.addr_index==1 && i2c_packet.addr_type==TWOBYTEADDR){
                        UCB0TXBUF = i2c_packet.addr_low_byte;
                        i2c_packet.addr_index++;
                    }
                    else if(UCTXIFG & P2IFG && i2c_packet.isr_mode==READ) {
                                                            // USCI_B is ready to get a new data byte to transmit it, and we are in READ mode.
                                                            // So, we should not continue writing, but should exit to the calling function to
                                                            // switch the USCI_B into read mode
                        P2IFG &= ~UCTXIFG;                 // Clear USCI_B0 TX int flag manually as we did not write to the UCB0TXBUF
                        LPM0_EXIT;                          // Exit LPM0
                    }

                    else if(UCTXIFG & P2IFG && i2c_packet.isr_mode==WRITE){// USCI_B is ready to get a new data byte to transmit it, and we are in write mode.

                        if(i2c_packet.buf_index == i2c_packet.buf_size){    // If no more data to transmit, then issue stop condition and wake CPU.
                            P2IFG &= ~UCTXIFG;                             // Clear USCI_B0 TX int flag manually as we did not write to the UCB0TXBUF
                            UCB0CTL1 |= UCTXSTP;                            // I2C stop condition
                            LPM0_EXIT;                                      // Exit LPM0
                        } else {
                            UCB0TXBUF = i2c_packet.data_buf[i2c_packet.buf_index];
                            i2c_packet.buf_index++;                         // Increment TX byte counter
                        }
                   }
                    else if (UCRXIFG & P2IFG && i2c_packet.addr_index==i2c_packet.addr_type) {
                                                                            // Read mode, and we already completed writing the address
                    i2c_packet.data_buf[i2c_packet.buf_index]= UCB0RXBUF;
                    i2c_packet.buf_index++;                             // Increment RX byte counter
                    if(i2c_packet.buf_index == i2c_packet.buf_size){    // If last byte to receive, then issue stop condition and wake CPU.
                        P2IFG &= ~UCRXIFG;                             // Clear USCI_B0 RX int flag
                        UCB0CTL1 |= UCTXSTP;                            // I2C stop condition here to avoid reading any extra bytes
                        LPM0_EXIT;                                      // Exit LPM0
                    }
                }
/*
            break;
        default:
            break;
*/
        }

    }




    //------------------------------------------------------------------------------
    // micro seconds delays
    //
    void usdelay(int interval){
                                    // Setup TimerA
        TA1CCTL0 = CCIE;            // interrupt enabled
        TA1CCR0 = TA1R + interval;  // micro secs @ 1Mhz Clock
        TA1CTL = TASSEL_2 + MC_2;   // SMCLK, continuous mode.
        LPM0;                       // suspend CPU
    }

    // Timer A1 interrupt service routine. TIMERx_Ay_VECTOR.(x being the index of the timer, y of the vector for this timer)
    #pragma vector=TIMER1_A0_VECTOR
    __interrupt void Timer1_A0 (void)
    {
        TA1CTL = 0;                     // Stop Timer_A1
        LPM0_EXIT;                      // Return active
    }

//******************************************************************************//   MSP430 USCI I2C Transmitter and Receiver////  Description: This code configures the MSP430's USCI module as//  I2C master capable of transmitting and receiving bytes.////  ***THIS IS THE MASTER CODE***////                    Master//                 MSP430F2619//             -----------------//         /|\|              XIN|-//          | |                 |//          --|RST          XOUT|-//            |                 |//            |                 |//            |                 |//            |         SDA/P3.1|------->//            |         SCL/P3.2|------->//// Note: External pull-ups are needed for SDA & SCL//// Uli Kretzschmar// Texas Instruments Deutschland GmbH// November 2007// Built with IAR Embedded Workbench Version: 3.42A//******************************************************************************/*#include "msp430f5529.h"                        // device specific header//#include "msp430x22x4.h"//#include "msp430x23x0.h"//#include "msp430xG46x.h"// ...                                         // more devices are possible
#include "lib5529i2c.h"
signed char byteCtr;unsigned char *TI_receive_field;unsigned char *TI_transmit_field;int q=0;//------------------------------------------------------------------------------// void TI_USCI_I2C_receiveinit(unsigned char slave_address,//                              unsigned char prescale)//// This function initializes the USCI module for master-receive operation.//// IN:   unsigned char slave_address   =>  Slave Address//       unsigned char prescale        =>  SCL clock adjustment//-----------------------------------------------------------------------------void TI_USCI_I2C_receiveinit(unsigned char slave_address,                             unsigned char prescale){  P3SEL |= SDA_PIN + SCL_PIN;                 // Assign I2C pins to USCI_B0  UCB0CTL1 = UCSWRST;                        // Enable SW reset  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;       // I2C Master, synchronous mode  UCB0CTL1 = UCSSEL_2 + UCSWRST;              // Use SMCLK, keep SW reset  UCB0BR0 = prescale;                         // set prescaler  UCB0BR1 = 0;  UCB0I2CSA = slave_address;                  // set slave address  UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation  UCB0IE = UCNACKIE;  UCB0IE = UCRXIE;                            // Enable RX interrupt}
//------------------------------------------------------------------------------// void TI_USCI_I2C_transmitinit(unsigned char slave_address,//                               unsigned char prescale)//// This function initializes the USCI module for master-transmit operation.//// IN:   unsigned char slave_address   =>  Slave Address//       unsigned char prescale        =>  SCL clock adjustment//------------------------------------------------------------------------------void TI_USCI_I2C_transmitinit(unsigned char slave_address,                          unsigned char prescale){  P3SEL |= SDA_PIN + SCL_PIN;                 // Assign I2C pins to USCI_B0  UCB0CTL1 |= UCSWRST;                        // Enable SW reset  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;       // I2C Master, synchronous mode  UCB0CTL1 = UCSSEL_2 + UCSWRST;              // Use SMCLK, keep SW reset  UCB0BR0 = prescale;                         // set prescaler  UCB0BR1 = 0;  UCB0I2CSA = slave_address;                  // Set slave address  UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation  UCB0IE = UCNACKIE;  UCB0IE |= UCTXIE;                            // Enable TX ready interrupt}
//------------------------------------------------------------------------------// void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field)//// This function is used to start an I2C commuincation in master-receiver mode.//// IN:   unsigned char byteCount  =>  number of bytes that should be read//       unsigned char *field     =>  array variable used to store received data//------------------------------------------------------------------------------void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field){  TI_receive_field = field;  if ( byteCount == 1 ){    byteCtr = 0 ;    __disable_interrupt();    UCB0CTL1 |= UCTXSTT;                      // I2C start condition    while (UCB0CTL1 & UCTXSTT);               // Start condition sent?    UCB0CTL1 |= UCTXSTP;                      // I2C stop condition    __enable_interrupt();  } else if ( byteCount > 1 ) {    byteCtr = byteCount - 2 ;    UCB0CTL1 |= UCTXSTT;                      // I2C start condition  } else    while (1);                                // illegal parameter}
//------------------------------------------------------------------------------// void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field)//// This function is used to start an I2C commuincation in master-transmit mode.//// IN:   unsigned char byteCount  =>  number of bytes that should be transmitted//       unsigned char *field     =>  array variable. Its content will be sent.//------------------------------------------------------------------------------void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field){  TI_transmit_field = field;  byteCtr = byteCount;  UCB0CTL1 |= UCTR + UCTXSTT;                 // I2C TX, start condition}
//------------------------------------------------------------------------------// unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address)//// This function is used to look for a slave address on the I2C bus.//// IN:   unsigned char slave_address  =>  Slave Address// OUT:  unsigned char                =>  0: address was not found,//                                        1: address found//------------------------------------------------------------------------------unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address){  unsigned char ie2_bak, slaveadr_bak, ucb0i2cie, returnValue;  ucb0i2cie = UCB0IE;                      // restore old UCB0I2CIE  ie2_bak = UCB0IE;                              // store IE2 register  slaveadr_bak = UCB0I2CSA;                   // store old slave address  UCB0IE &= ~ UCNACKIE;                    // no NACK interrupt  UCB0I2CSA = slave_address;                  // set slave address  UCB0IE &= ~(UCTXIE + UCRXIE);              // no RX or TX interrupts  __disable_interrupt();  UCB0CTL1 |= UCTR + UCTXSTT + UCTXSTP;       // I2C TX, start condition  while (UCB0CTL1 & UCTXSTP);                 // wait for STOP condition
  returnValue = !(UCB0STAT & UCNACKIFG);  __enable_interrupt();  UCB0IE = ie2_bak;                              // restore IE2  UCB0I2CSA = slaveadr_bak;                   // restore old slave address  UCB0IE = ucb0i2cie;                      // restore old UCB0CTL1  return returnValue;                         // return whether or not                                              // a NACK occured}
//------------------------------------------------------------------------------// unsigned char TI_USCI_I2C_notready()//// This function is used to check if there is commuincation in progress.//// OUT:  unsigned char  =>  0: I2C bus is idle,//                          1: communication is in progress//------------------------------------------------------------------------------unsigned char TI_USCI_I2C_notready(){  return (UCB0STAT & UCBBUSY);}

#pragma vector = USCI_B0_VECTOR__interrupt void USCI_B0_ISR(void){    switch (__even_in_range(UCB0IV, 12))        {
        case 10:            q=10;// Vector 10: RXIFG -- I am not using it yet (but I'll need it)            if (UCB0STAT & UCNACKIFG){            // send STOP if slave sends NACK              UCB0CTL1 |= UCTXSTP;              UCB0STAT &= ~UCNACKIFG;            }            break;        case 12:            q=12;// Vector 12: TXIFG            if (P2IFG & UCRXIFG){                    if ( byteCtr == 0 ){                      UCB0CTL1 |= UCTXSTP;                    // I2C stop condition                      *TI_receive_field = UCB0RXBUF;                      TI_receive_field++;                    }                    else {                      *TI_receive_field = UCB0RXBUF;                      TI_receive_field++;                      byteCtr--;                    }                  }                  else {                    if (byteCtr == 0){                      UCB0CTL1 |= UCTXSTP;                    // I2C stop condition                      P2IFG &= ~UCTXIFG;                     // Clear USCI_B0 TX int flag                    }                    else {                      UCB0TXBUF = *TI_transmit_field;                      TI_transmit_field++;                      byteCtr--;                    }                  }            break;        default:            break;
        }
    }

*/

  • Team, 

    Sorry it doesnt look like I attached my last approach correctly. Here it is:

    /*
    * Here's an example using an MSP430G2553 to read/write using I2C to an 24LC512 and DS3231 RTC.
    * Two functions are provided for read and write.
    *
    * The code avoids any while loops, and relies completely on interrupts and low power modes of the MSP430 to reduce the power consumption to the
    * minimum.
    *
    * Author: Ahmed Talaat (aa_talaat@yahoo.com)
    * Date: 19 October 2012
    */
    
        #include  "msp430f5529.h"
    
        #define ONEBYTEADDR 1
        #define TWOBYTEADDR 2
        #define WRITE       0                       // ISR mode WRITE or READ
        #define READ        1
        #define NOACK       2
        #define EEPROM_ADDR 0x40
        #define DS3231_ADDR 0x00
    
        unsigned char txdataEEPROM[2];
        unsigned char txdataDS3231[7] = {0x20, 0x30, 0x20, 0x04, 0x17, 0x10, 0x12};
        unsigned char rxdata[150];
    
        typedef struct {
            volatile unsigned char *data_buf;       // address of tx or rx data buffer
            volatile unsigned char buf_size;        // size of the buffer
            volatile unsigned char buf_index;       // index in the buffer
            volatile unsigned char addr_index;      // index of the byte address (0,1)
            volatile unsigned char isr_mode;        // Tx or Rx affects the interrupt logic
            volatile unsigned char addr_high_byte;  // High byte of the address to read/write to
            volatile unsigned char addr_low_byte;   // Low byte of the address to read/write to
            volatile unsigned char addr_type;       // two bytes like eeprom or 1 byte like RTC for example
        } i2c_t;
    
        i2c_t   i2c_packet;
    
        void i2c_init(void);
        void i2c_tx(unsigned char, unsigned char *, unsigned char, unsigned char, unsigned char, unsigned char);
        void i2c_rx(unsigned char, unsigned char *, unsigned char, unsigned char, unsigned char, unsigned char);
        void usdelay(int);
    
        void main(void)
        {
           WDTCTL = WDTPW + WDTHOLD;                // Stop WDT
           i2c_init();                              // Initialize I2C
           txdataEEPROM[0]=0x61;
           txdataEEPROM[1]=0x3F;
    
           i2c_tx(EEPROM_ADDR, txdataEEPROM, sizeof(txdataEEPROM)-1,ONEBYTEADDR,0x00,0x00);//i2c TX 115 bytes starting @ address 01:00
    
           i2c_rx(EEPROM_ADDR, rxdata, 2,ONEBYTEADDR,0x00,0x00);//i2c RX 115 bytes from EEPROM starting @ address 01:00
      
    
           LPM0;                                    // Enter LPM0 w/ interrupts
        }
    
        void i2c_init(void){
            P3SEL |= BIT0 + BIT1;                   //Set I2C pins
            //P1SEL2|= BIT6 + BIT7;
            UCB0CTL1 |= UCSWRST;                    //Enable SW reset
            UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;   //I2C Master, synchronous mode
            UCB0CTL1 = UCSSEL_2 + UCSWRST;          //Use SMCLK, keep SW reset
            UCB0BR0 = 10;                           //fSCL = SMCLK/11 = ~100kHz
            UCB0BR1 = 0;
            UCB0CTL1 &= ~UCSWRST;                   //Clear SW reset, resume operation
            UCB0IE |= UCTXIE;                        //Enable TX interrupt
            UCB0IE |= UCRXIE;                        //Enable RX interrupt
            UCB0IE |= UCNACKIE;                  //Need to enable the status change interrupt
            __enable_interrupt();                   //Enable global interrupt
        }
    
    
        void i2c_tx(unsigned char slave_addr, unsigned char *txdata, unsigned char bufSize, unsigned char addr_size,
                            unsigned char high_byte_addr, unsigned char low_byte_addr) {
            i2c_packet.isr_mode=WRITE;
            i2c_packet.data_buf=txdata;
            i2c_packet.buf_size=bufSize;
            i2c_packet.buf_index=0;
            i2c_packet.addr_type=addr_size;
            i2c_packet.addr_high_byte=high_byte_addr;
            i2c_packet.addr_low_byte=low_byte_addr;
            i2c_packet.addr_index=0;
            UCB0I2CSA = slave_addr;                 //Slave Address
    
            while (1) {
                UCB0CTL1 |= UCTR + UCTXSTT;         // I2C TX, start condition
                LPM0;                               // Enter LPM0
                                                    // and remain until all data is TX'd
                if (i2c_packet.isr_mode == NOACK){  // If no ack received, then sleep for 0.5ms and try again
                    i2c_packet.isr_mode = WRITE;
                    i2c_packet.addr_index=0;        // Reset the address index for the next write operation
                    usdelay(500);
    
                } else {
                    break;                          // Successful write, then quit
                }
            }
        }
    
        /*
         * This functions reads from any I2C device. It takes as parameters:
         *  - The slave address (7 bits)
         *  - Pointer to the data buffer to fill with data read.
         *  - Size of the buffer
         *  - Size of the address location to start writing at. Being 2 bytes for some of the EEPROMs and single byte
         *    for other devices. Please note that the ISR of this function assumes that the address bytes are written high
         *    byte first, then low byte second.
         *    In case of single byte address device, only the high byte will be used to set the address.
         *  - The high byte and low byte address for the location to start reading at.
         *
         *  The function starts with a write operation to specify the address at which the read operation with start
         *  In case the start condition of the write operation is not ack (for example EEPROM busy with a a previous write cycle),
         *  the corresponding interrupts detects this condition, generates a stop signal, and a Timer A1 (not Timer A0)
         *  is activated for 0.5 ms, then the trial for writing is repeated.
         *
         *  Once the write address is successful, the functions switch to read mode, and fills the buffer provided
         *
         */
    
    
        void i2c_rx(unsigned char slave_addr, unsigned char *rxdata, unsigned char bufSize, unsigned char addr_size,
                unsigned char high_byte_addr, unsigned char low_byte_addr) {
            i2c_packet.isr_mode=READ;               // The ISR will send the address bytes, then wake CPU.
            i2c_packet.addr_type=addr_size;
            i2c_packet.addr_high_byte=high_byte_addr;
            i2c_packet.addr_low_byte=low_byte_addr;
            i2c_packet.addr_index=0;
            UCB0I2CSA = slave_addr;                 // Slave Address
    
            while (1) {
                UCB0CTL1 |= UCTR + UCTXSTT;         // I2C TX, start condition
                LPM0;                               // Enter LPM0
                                                    // and remain until all data is TX'd
                if (i2c_packet.isr_mode == NOACK){  // If no ack received, then sleep for 0.5ms and try again
                    i2c_packet.isr_mode = READ;
                    i2c_packet.addr_index=0;        // Reset the address index for the next write operation
                    usdelay(500);
                } else {
                    break;                          // Successful write, then quit
                }
            }
                                                    // We wrote already the address, so now read only data.
            i2c_packet.addr_index=i2c_packet.addr_type;
            i2c_packet.data_buf=rxdata;
            i2c_packet.buf_size=bufSize;
            i2c_packet.buf_index=0;
            UCB0CTL1 &= ~UCTR;                      // I2C RX
            UCB0CTL1 |= UCTXSTT;                    // I2C re-start condition
            LPM0;                                   // Enter LPM0
                                                    // and remain until all data is received
        }
    
    
        //interrupt(USCIAB0RX_VECTOR) state change to trap the no_Ack from slave case
    
    /*
     * This interrupt is called each time the UCSI_B module is either ready to get a new byte in UCB0TXBUF to send to the I2C device, or
     * a new byte is read into UCB0RXBUF and we should pick it up.
     * The interrupt is called as both UCB0TXIE and UCB0RXIE are enabled. To stop this interrupt being called indefinitely, the corresponding
     * interrupt flag should be cleared.
     * These flags are automatically clearly by the USCI_B module if the UCB0XXBUF is access. However, if we are to do something different than reading
     * or writing a byte to/from the UCB0XXBUF, we need to clear the corresponding flag by ourselves or the ISR will be called for ever,
     * and the whole program will hang.
     */
    
    
    #pragma vector = USCI_B0_VECTOR
    __interrupt void USCI_B0_ISR(void)
    {
        switch (__even_in_range(UCB0IV, 12))
            {
            case 10:
                RXByteCtr--;                            // Decrement RX byte counter
                    if (RXByteCtr)
                    {
                      *PRxData++ = UCB0RXBUF;               // Move RX data to address PRxData
                      if (RXByteCtr == 1)                   // Only one byte left?
                        UCB0CTL1 |= UCTXSTP;                // Generate I2C stop condition
                    }
                    else
                    {
                      *PRxData = UCB0RXBUF;                 // Move final RX data to PRxData
                      __bic_SR_register_on_exit(LPM0_bits); // Exit active CPU
                    }
            case 12:
                // Transmit address bytes irrespective of send or receive mode.*/
                        if (i2c_packet.addr_index==0){
                           UCB0TXBUF = i2c_packet.addr_high_byte;
                           i2c_packet.addr_index++;
                        }
                        else if (i2c_packet.addr_index==1 && i2c_packet.addr_type==TWOBYTEADDR){
                            UCB0TXBUF = i2c_packet.addr_low_byte;
                            i2c_packet.addr_index++;
                        }
                        else if(UCTXIFG & P2IFG && i2c_packet.isr_mode==READ) {
                                                                // USCI_B is ready to get a new data byte to transmit it, and we are in READ mode.
                                                                // So, we should not continue writing, but should exit to the calling function to
                                                                // switch the USCI_B into read mode
                            P2IFG &= ~UCTXIFG;                 // Clear USCI_B0 TX int flag manually as we did not write to the UCB0TXBUF
                            LPM0_EXIT;                          // Exit LPM0
                        }
    
                        else if(UCTXIFG & P2IFG && i2c_packet.isr_mode==WRITE){// USCI_B is ready to get a new data byte to transmit it, and we are in write mode.
    
                            if(i2c_packet.buf_index == i2c_packet.buf_size){    // If no more data to transmit, then issue stop condition and wake CPU.
                                P2IFG &= ~UCTXIFG;                             // Clear USCI_B0 TX int flag manually as we did not write to the UCB0TXBUF
                                UCB0CTL1 |= UCTXSTP;                            // I2C stop condition
                                LPM0_EXIT;                                      // Exit LPM0
                            } else {
                                UCB0TXBUF = i2c_packet.data_buf[i2c_packet.buf_index];
                                i2c_packet.buf_index++;                         // Increment TX byte counter
                            }
                       }
                        else if (UCRXIFG & P2IFG && i2c_packet.addr_index==i2c_packet.addr_type) {
                                                                                // Read mode, and we already completed writing the address
                        i2c_packet.data_buf[i2c_packet.buf_index]= UCB0RXBUF;
                        i2c_packet.buf_index++;                             // Increment RX byte counter
                        if(i2c_packet.buf_index == i2c_packet.buf_size){    // If last byte to receive, then issue stop condition and wake CPU.
                            P2IFG &= ~UCRXIFG;                             // Clear USCI_B0 RX int flag
                            UCB0CTL1 |= UCTXSTP;                            // I2C stop condition here to avoid reading any extra bytes
                            LPM0_EXIT;                                      // Exit LPM0
                        }
                    }
    /*
                break;
            default:
                break;
    */
            }
    
        }
    
    
    
    
        //------------------------------------------------------------------------------
        // micro seconds delays
        //
        void usdelay(int interval){
                                        // Setup TimerA
            TA1CCTL0 = CCIE;            // interrupt enabled
            TA1CCR0 = TA1R + interval;  // micro secs @ 1Mhz Clock
            TA1CTL = TASSEL_2 + MC_2;   // SMCLK, continuous mode.
            LPM0;                       // suspend CPU
        }
    
        // Timer A1 interrupt service routine. TIMERx_Ay_VECTOR.(x being the index of the timer, y of the vector for this timer)
        #pragma vector=TIMER1_A0_VECTOR
        __interrupt void Timer1_A0 (void)
        {
            TA1CTL = 0;                     // Stop Timer_A1
            LPM0_EXIT;                      // Return active
        }
    

  • Hi,

    sorry but this is too much code for me to look at :)

    Why do not you take the examples in "Resource Explorer"? They seem easier to me.

    Or you can just try to do it with ENERGIA.

    What I usually do is to merge the Writing example with the Reading example.

    This is the code for MSP430F55xx_uscib0_i2c_08.c:

    /* --COPYRIGHT--,BSD_EX
     * Copyright (c) 2012, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     *******************************************************************************
     * 
     *                       MSP430 CODE EXAMPLE DISCLAIMER
     *
     * MSP430 code examples are self-contained low-level programs that typically
     * demonstrate a single peripheral function or device feature in a highly
     * concise manner. For this the code may rely on the device's power-on default
     * register values and settings such as the clock configuration and care must
     * be taken when combining code from several examples to avoid potential side
     * effects. Also see www.ti.com/grace for a GUI- and www.ti.com/msp430ware
     * for an API functional library-approach to peripheral configuration.
     *
     * --/COPYRIGHT--*/
    //******************************************************************************
    //  MSP430F552x Demo - USCI_B0 I2C Master TX multiple bytes to MSP430 Slave
    //
    //  Description: This demo connects two MSP430's via the I2C bus. The master
    //  transmits to the slave. This is the MASTER CODE. It cntinuously
    //  transmits an array of data and demonstrates how to implement an I2C
    //  master transmitter sending multiple bytes using the USCI_B0 TX interrupt.
    //  ACLK = n/a, MCLK = SMCLK = BRCLK = default DCO = ~1.045MHz
    //
    // ***to be used with "MSP430F55xx_uscib0_i2c_09.c" ***
    //
    //                                /|\  /|\
    //                MSP430F5529     10k  10k      MSP430F5529
    //                   slave         |    |         master
    //             -----------------   |    |   -----------------
    //           -|XIN  P3.0/UCB0SDA|<-|----+->|P3.0/UCB0SDA  XIN|-
    //            |                 |  |       |                 |
    //           -|XOUT             |  |       |             XOUT|-
    //            |     P3.1/UCB0SCL|<-+------>|P3.1/UCB0SCL     |
    //            |                 |          |                 |
    //
    //   Bhargavi Nisarga
    //   Texas Instruments Inc.
    //   April 2009
    //   Built with CCSv4 and IAR Embedded Workbench Version: 4.21
    //******************************************************************************
    
    #include <msp430.h>
    
    unsigned char *PTxData;                     // Pointer to TX data
    unsigned char TXByteCtr;
    
    const unsigned char TxData[] =              // Table of data to transmit
    {
      0x11,
      0x22,
      0x33,
      0x44,
      0x55
    };
    
    int main(void)
    {
      unsigned int i;
    
      WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
      P3SEL |= 0x03;                            // Assign I2C pins to USCI_B0
      UCB0CTL1 |= UCSWRST;                      // Enable SW reset
      UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;     // I2C Master, synchronous mode
      UCB0CTL1 = UCSSEL_2 + UCSWRST;            // Use SMCLK, keep SW reset
      UCB0BR0 = 12;                             // fSCL = SMCLK/12 = ~100kHz
      UCB0BR1 = 0;
      UCB0I2CSA = 0x48;                         // Slave Address is 048h
      UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
      UCB0IE |= UCTXIE;                         // Enable TX interrupt
    
      while (1)
      {
        for(i=0;i<10;i++);                      // Delay required between transaction
        PTxData = (unsigned char *)TxData;      // TX array start address
                                                // Place breakpoint here to see each
                                                // transmit operation.
        TXByteCtr = sizeof TxData;              // Load TX byte counter
    
        UCB0CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
        
        __bis_SR_register(LPM0_bits + GIE);     // Enter LPM0, enable interrupts
        __no_operation();                       // Remain in LPM0 until all data
                                                // is TX'd
        while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
      }
    }
    
    //------------------------------------------------------------------------------
    // The USCIAB0TX_ISR is structured such that it can be used to transmit any
    // number of bytes by pre-loading TXByteCtr with the byte count. Also, TXData
    // points to the next byte to transmit.
    //------------------------------------------------------------------------------
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector = USCI_B0_VECTOR
    __interrupt void USCI_B0_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCI_B0_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
      switch(__even_in_range(UCB0IV,12))
      {
      case  0: break;                           // Vector  0: No interrupts
      case  2: break;                           // Vector  2: ALIFG
      case  4: break;                           // Vector  4: NACKIFG
      case  6: break;                           // Vector  6: STTIFG
      case  8: break;                           // Vector  8: STPIFG
      case 10: break;                           // Vector 10: RXIFG
      case 12:                                  // Vector 12: TXIFG  
        if (TXByteCtr)                          // Check TX byte counter
        {
          UCB0TXBUF = *PTxData++;               // Load TX buffer
          TXByteCtr--;                          // Decrement TX byte counter
        }
        else
        {
          UCB0CTL1 |= UCTXSTP;                  // I2C stop condition
          UCB0IFG &= ~UCTXIFG;                  // Clear USCI_B0 TX int flag
          __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
        }  
      default: break;
      }
    }
    

  • Hello Luke,

    It's generally not a good practice to post large portions of code expecting the community to review it all. Instead, I would recommend breaking up your larger issue into smaller, more manageable questions, which are easier to provide targeted feedback and elicit feedback from our community.

    As kazola correctly pointed out, our code examples in Resource Explorer are the best starting point on the coding side. Another starting point we recommend is the Solutions to Common eUSCI and USCI Serial Communication Issues on MSP430™ MCUs app note (see Section 5). Also, when working with I2C, a logic analyzer should be required, since it will show you exactly what is and isn't getting transmitted.

    Hopefully this helps your development!

    Regards,

    James

    MSP Customer Applications

**Attention** This is a public forum