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.

MSP430 I2C Implementation

Other Parts Discussed in Thread: MSP430BT5190

I'm trying to use the example code (modified to work with my MSP430BT5190) for a read from an I2C slave with the MSP430 as the Master, but I'm having trouble understanding how the code works. Specifically What I'm wondering about most is in order to do an I2C read, the sequence for reading from my slave device (which seems fairly standard for I2C) is to send [START] > [SLAVE ADDRESS] > [R/W]  receive an [ACK] from the slave, and then to send [DESIRED ADDRESS TO READ FROM] and then the slave will send back the data in that register/address followed by an [ACK] (and here you would decide to do a repeated start or send a STOP), but in the example code I don't see the desired address implemented anywhere so I'm not sure how I can do a read with it. I've included my modified code below and for understanding my I2C slave is connected to P9.2/UCB2SOMI/UCB2SCL and P9.1/UCB2SIMO/UCB2SDA for the SCL and SDA lines respectively.

#include <msp430.h>

int TXByteCtr;
unsigned char PRxData;
int Rx = 0;
char WHO_AM_I = 0x00;

char itgAddress = 0x1C;
void init_I2C(void);
void Transmit(void);
void Receive(void);


int main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
  P9SEL |= 0x06;                            // I2C pins
  init_I2C();




  while(1){
      //Transmit process
      Rx = 0;
      TXByteCtr = 1;
      Transmit();
      //Receive process
      Rx = 1;
      Receive();
  }
}

//-------------------------------------------------------------------------------
// The USCI_B0 data ISR is used to move received data from the I2C slave
// to the MSP430 memory. It is structured such that it can be used to receive
//-------------------------------------------------------------------------------
#pragma vector = USCI_B2_VECTOR
__interrupt void USCI_B2_ISR(void)
{
  if(Rx == 1){                              // Master Recieve?
      PRxData = UCB2RXBUF;                       // Get RX data
      __bic_SR_register_on_exit(CPUOFF);        // Exit LPM0
  }

  else{                                     // Master Transmit
      if (TXByteCtr)                            // Check TX byte counter
        {
          UCB2TXBUF = WHO_AM_I;                     // Load TX buffer
          TXByteCtr--;                            // Decrement TX byte counter
        }
        else
        {
          UCB2CTL1 |= UCTXSTP;                    // I2C stop condition
          UCB2IFG &= ~UCTXIFG;                     // Clear USCI_B0 TX int flag
          __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
        }
 }

}
void init_I2C(void) {
      UCB2CTL1 |= UCSWRST;                      // Enable SW reset
      UCB2CTL0 = UCMST + UCMODE_3 + UCSYNC;     // I2C Master, synchronous mode
      UCB2CTL1 = UCSSEL_2 + UCSWRST;            // Use SMCLK, keep SW reset
      UCB2BR0 = 12;                             // fSCL = SMCLK/12 = ~100kHz
      UCB2BR1 = 0;
      UCB2I2CSA = itgAddress;                         // Slave Address is 069h
      UCB2CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
      UCB2IE |= UCRXIE + UCTXIE;               //Enable RX and TX interrupt
}

void Transmit(void){
    while (UCB2CTL1 & UCTXSTP);             // Ensure stop condition got sent
    UCB2CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
    __bis_SR_register(CPUOFF + GIE);        // Enter LPM0 w/ interrupts
}
void Receive(void){
        while (UCB2CTL1 & UCTXSTP);             // Ensure stop condition got sent
        UCB2CTL1 &= ~UCTR ;                     // Clear UCTR
        UCB2CTL1 |= UCTXSTT;                    // I2C start condition
        while (UCB2CTL1 & UCTXSTT);             // Start condition sent?
        UCB2CTL1 |= UCTXSTP;                    // I2C stop condition
        __bis_SR_register(CPUOFF + GIE);        // Enter LPM0 w/ interrupts
}

  • Michael,

    With many I2C devices you need to Start a write operation, send the register address from which you want to read, then send a restart for a read operation and read as many bytes as you want. The TI examples I have seen are for devices which have only one register, therefore, no register address is sent.

    I hope this helps you out. The data sheet for the I2C device you are trying to talk to should spell it all out.

    Good Luck,

    Corky

  • Hi Corky,

    Thanks for that explanation about the example being to a device with only one address to read and thus it isn't specified, as my biggest confusion was why I didn't see a read address being sent.


    Do you know if any examples exist that do implement reads to a device that has multiple addresses? Otherwise I can try combining the read and write examples for my purposes in order to read from my device after writing the address I want to read from.

    As for my device data sheet it does work as you described, my confusion just laid with the example code and why it didn't work that way which you cleared up so thanks again.

    Cheers,

    Michael

  • A read operation is exactly that: a read. Nothing is sent (except the initial slave address in the start byte).
    So the operation is either start a write operation, send the register address to read from, start a read operation, receive the content, send a stop
    or (in case there is only one register to read from, like on the 8-bit digital I/O chip), simply start read operation, read, read, read, stop. Nothing (except the slave address for selecting the slave on the bus and the R/W bit) is ever sent by the master in this case. This is likely what your example code does.

**Attention** This is a public forum