Because of the holidays, TI E2E™ design support forum responses will be delayed from Dec. 25 through Jan. 2. Thank you for your patience.

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: Reading/Writing to 24AA32AF EEPROM

Part Number: MSP430F5529

Tool/software: Code Composer Studio

Hello,

I am simply trying to write a single byte to the 24AA32AF EEPROM and then read the byte back but when I attempt this simple operation I am unable to read and write correctly. I have downloaded the I2Croutines.c and I2Croutines.h files from TI which includes EEPROM read, write, and acknowledge functions. I changed the SDA to P3.0 and SCL to P3.1. I also set the slave address to 0xA0 to agree with the control byte of b10100000. Now I am attempting to run a simple main program which should write and read a byte but I am not getting the correct result. 

#include <msp430f5529.h>
#include "I2Croutines.h"
int main(void)
{
    unsigned int i;
    WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
    InitI2C(0xA0);

    EEPROM_ByteWrite(0x0000,0x12);
    EEPROM_AckPolling();

    unsigned char read_val = EEPROM_RandomRead(0x0000);

    while(1);

    return 0;
}

I am confused why this does not correctly write to and read from the EEPROM. The code that I got from TI for I2Croutines can be seen below.

I2CRoutines.c:

#include "msp430f5418a.h"
#include "I2Croutines.h"

#define     MAXPAGEWRITE   64

int PtrTransmit;
unsigned char I2CBufferArray[66];
unsigned char I2CBuffer;

/*----------------------------------------------------------------------------*/
// Description:
//   Initialization of the I2C Module
/*----------------------------------------------------------------------------*/
void InitI2C(unsigned char eeprom_i2c_address)

 // I2C address = 0xA0 for 10100000?

{
	I2C_PORT_DIR |= SDA_PIN + SCL_PIN;
  I2C_PORT_SEL |= SDA_PIN + SCL_PIN;        // Assign I2C pins to USCI_B0

  // Recommended initialisation steps of I2C module as shown in User Guide:
  UCB0CTL1 |= UCSWRST;                      // Enable SW reset
  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;     // I2C Master, synchronous mode
  UCB0CTL1 = UCSSEL_2 + UCTR + UCSWRST;     // Use SMCLK, TX mode, keep SW reset
  UCB0BR0 = SCL_CLOCK_DIV;                  // fSCL = SMCLK/12 = ~100kHz
  UCB0BR1 = 0;
  UCB0I2CSA  = eeprom_i2c_address;          // define Slave Address
                                            // In this case the Slave Address
                                            // defines the control byte that is
                                            // sent to the EEPROM.
  //UCB0I2COA = 0x01A5;                       // own address.
 // UCB0IE|=UCTXIE+UCRXIE;
  UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation

  if (UCB0STAT & UCBBUSY)                   // test if bus to be free
  {                                         // otherwise a manual Clock on is
                                            // generated
    I2C_PORT_SEL &= ~SCL_PIN;               // Select Port function for SCL
    I2C_PORT_OUT &= ~SCL_PIN;               //
    I2C_PORT_DIR |= SCL_PIN;                // drive SCL low
    I2C_PORT_SEL |= SDA_PIN + SCL_PIN;      // select module function for the
                                            // used I2C pins
  };
  __enable_interrupt();
}

/*---------------------------------------------------------------------------*/
// Description:
//   Initialization of the I2C Module for Write operation.
/*---------------------------------------------------------------------------*/
void I2CWriteInit(void)
{
  UCB0CTL1 |= UCTR;                         // UCTR=1 => Transmit Mode (R/W bit = 0)
  UCB0IFG &= ~UCTXIFG;
  UCB0IE &= ~UCRXIE;                         // disable Receive ready interrupt
  UCB0IE|= UCTXIE;                          // enable Transmit ready interrupt
}

/*----------------------------------------------------------------------------*/
// Description:
//   Initialization of the I2C Module for Read operation.
/*----------------------------------------------------------------------------*/
void I2CReadInit(void)
{
  UCB0CTL1 &= ~UCTR;                        // UCTR=0 => Receive Mode (R/W bit = 1)
  UCB0IFG &= ~UCRXIFG;
  UCB0IE &= ~UCTXIE;                         // disable Transmit ready interrupt
  UCB0IE |= UCRXIE;                          // enable Receive ready interrupt
}

/*----------------------------------------------------------------------------*/
// Description:
//   Byte Write Operation. The communication via the I2C bus with an EEPROM
//   (2465) is realized. A data byte is written into a user defined address.
/*----------------------------------------------------------------------------*/
void EEPROM_ByteWrite(unsigned int Address, unsigned char Data)
{
  unsigned char adr_hi;
  unsigned char adr_lo;

  while (UCB0STAT & UCBUSY);                // wait until I2C module has
                                            // finished all operations.

  adr_hi = Address >> 8;                    // calculate high byte
  adr_lo = Address & 0xFF;                  // and low byte of address

  I2CBufferArray[2] = adr_hi;               // Low byte address.
  I2CBufferArray[1] = adr_lo;               // High byte address.
  I2CBufferArray[0] = Data;
  PtrTransmit = 2;                          // set I2CBufferArray Pointer

  I2CWriteInit();
  UCB0CTL1 |= UCTXSTT;                      // start condition generation
                                            // => I2C communication is started
//  __bis_SR_register(LPM0_bits + GIE);       // Enter LPM0 w/ interrupts
  while(UCB0CTL1 & UCTXSTP);                // Ensure stop condition got sent
}

/*----------------------------------------------------------------------------*/
// Description:
//   Page Write Operation. The communication via the I2C bus with an EEPROM
//   (24xx65) is realized. A data byte is written into a user defined address.
/*----------------------------------------------------------------------------*/
void EEPROM_PageWrite(unsigned int StartAddress, unsigned char * Data, unsigned char Size)
{
  volatile unsigned int i = 0;
  volatile unsigned char counterI2cBuffer;
  unsigned char adr_hi;
  unsigned char adr_lo;
  unsigned int currentAddress = StartAddress;
  unsigned char currentSize = Size;
  unsigned char bufferPtr = 0;
  unsigned char moreDataToRead = 1;

  while (UCB0STAT & UCBUSY);                // wait until I2C module has
                                            // finished all operations.

  // Execute until no more data in Data buffer
  while(moreDataToRead)
  {
    adr_hi = currentAddress >> 8;           // calculate high byte
    adr_lo = currentAddress & 0xFF;         // and low byte of address

    // Chop data down to 64-byte packets to be transmitted at a time
    // Maintain pointer of current startaddress
    if(currentSize > MAXPAGEWRITE)
    {
      bufferPtr = bufferPtr + MAXPAGEWRITE;
      counterI2cBuffer = MAXPAGEWRITE - 1;
      PtrTransmit = MAXPAGEWRITE + 1;       // set I2CBufferArray Pointer
      currentSize = currentSize - MAXPAGEWRITE;
      currentAddress = currentAddress + MAXPAGEWRITE;

      // Get start address
      I2CBufferArray[MAXPAGEWRITE + 1] = adr_hi; // High byte address.
      I2CBufferArray[MAXPAGEWRITE] = adr_lo; // Low byte address.
    }
    else
    {
      bufferPtr = bufferPtr + currentSize;
      counterI2cBuffer = currentSize - 1;
      PtrTransmit = currentSize + 1;        // set I2CBufferArray Pointer.
      moreDataToRead = 0;
      currentAddress = currentAddress + currentSize;

      // Get start address
      I2CBufferArray[currentSize + 1] = adr_hi; // High byte address.
      I2CBufferArray[currentSize] = adr_lo; // Low byte address.
    }

    // Copy data to I2CBufferArray
    unsigned char temp;
    for(i ; i < bufferPtr ; i++)
    {
      temp = Data[i];                       // Required or else IAR throws a
                                            // warning [Pa082]
      I2CBufferArray[counterI2cBuffer] = temp;
      counterI2cBuffer--;
    }

    I2CWriteInit();
    UCB0CTL1 |= UCTXSTT;                    // start condition generation
                                            // => I2C communication is started
  //  __bis_SR_register(LPM0_bits + GIE);     // Enter LPM0 w/ interrupts
    while(UCB0CTL1 & UCTXSTP);              // Ensure stop condition got sent

    EEPROM_AckPolling();                    // Ensure data is written in EEPROM
  }
}

/*----------------------------------------------------------------------------*/
// Description:
//   Current Address Read Operation. Data is read from the EEPROM. The current
//   address from the EEPROM is used.
/*----------------------------------------------------------------------------*/
unsigned char EEPROM_CurrentAddressRead(void)
{
  while(UCB0STAT & UCBUSY);                 // wait until I2C module has
                                            // finished all operations
  I2CReadInit();

  UCB0CTL1 |= UCTXSTT;                      // I2C start condition
  while(UCB0CTL1 & UCTXSTT);                // Start condition sent?
  UCB0CTL1 |= UCTXSTP;                      // I2C stop condition
  //__bis_SR_register(LPM0_bits + GIE);       // Enter LPM0 w/ interrupts
  while(UCB0CTL1 & UCTXSTP);                // Ensure stop condition got sent
  return I2CBuffer;
}

/*----------------------------------------------------------------------------*/
// Description:
//   Random Read Operation. Data is read from the EEPROM. The EEPROM
//   address is defined with the parameter Address.
/*----------------------------------------------------------------------------*/
unsigned char EEPROM_RandomRead(unsigned int Address)
{
  unsigned char adr_hi;
  unsigned char adr_lo;

  while (UCB0STAT & UCBUSY);                // wait until I2C module has
                                            // finished all operations

  adr_hi = Address >> 8;                    // calculate high byte
  adr_lo = Address & 0xFF;                  // and low byte of address

  I2CBufferArray[1] = adr_hi;               // store single bytes that have to
  I2CBufferArray[0] = adr_lo;               // be sent in the I2CBuffer.
  PtrTransmit = 1;                          // set I2CBufferArray Pointer

  // Write Address first
  I2CWriteInit();
  UCB0CTL1 |= UCTXSTT;                      // start condition generation
                                            // => I2C communication is started
  //__bis_SR_register(LPM0_bits + GIE);       // Enter LPM0 w/ interrupts
  while(UCB0CTL1 & UCTXSTP);                // Ensure stop condition got sent

  // Read Data byte
  I2CReadInit();

  UCB0CTL1 |= UCTXSTT;                      // I2C start condition
  while(UCB0CTL1 & UCTXSTT);                // Start condition sent?
  UCB0CTL1 |= UCTXSTP;                      // I2C stop condition
  //__bis_SR_register(LPM0_bits + GIE);       // Enter LPM0 w/ interrupts
  while(UCB0CTL1 & UCTXSTP);                // Ensure stop condition got sent
  return I2CBuffer;
}

/*----------------------------------------------------------------------------*/
// Description:
//   Sequential Read Operation. Data is read from the EEPROM in a sequential
//   form from the parameter address as a starting point. Specify the size to
//   be read and populate to a Data buffer.
/*----------------------------------------------------------------------------*/
void EEPROM_SequentialRead(unsigned int Address , unsigned char * Data , unsigned int Size)
{
  unsigned char adr_hi;
  unsigned char adr_lo;
  unsigned int counterSize;

  while (UCB0STAT & UCBUSY);                // wait until I2C module has
                                            // finished all operations

  adr_hi = Address >> 8;                    // calculate high byte
  adr_lo = Address & 0xFF;                  // and low byte of address

  I2CBufferArray[1] = adr_hi;               // store single bytes that have to
  I2CBufferArray[0] = adr_lo;               // be sent in the I2CBuffer.
  PtrTransmit = 1;                          // set I2CBufferArray Pointer

  // Write Address first
  I2CWriteInit();
  UCB0CTL1 |= UCTXSTT;                      // start condition generation
                                            // => I2C communication is started
  //__bis_SR_register(LPM0_bits + GIE);       // Enter LPM0 w/ interrupts
  while(UCB0CTL1 & UCTXSTP);                // Ensure stop condition got sent

  // Read Data byte
  UCB0CTL1 &= ~UCTR;                        // UCTR=0 => Receive Mode (R/W bit = 1)
  UCB0IFG &= ~UCRXIFG;
  UCB0IE &= ~UCTXIE;                         // disable Transmit ready interrupt
  UCB0IE |= UCRXIE;                          // enable Receive ready interrupt

  UCB0CTL1 |= UCTXSTT;                      // I2C start condition
  while(UCB0CTL1 & UCTXSTT);                // Start condition sent?

  for(counterSize = 0 ; counterSize < Size ; counterSize++)
  {
    //__bis_SR_register(LPM0_bits + GIE);     // Enter LPM0 w/ interrupts
    Data[counterSize] = I2CBuffer;
  }
  UCB0CTL1 |= UCTXSTP;                      // I2C stop condition
  //__bis_SR_register(LPM0_bits + GIE);       // Enter LPM0 w/ interrupts
  while(UCB0CTL1 & UCTXSTP);                // Ensure stop condition got sent
}

/*----------------------------------------------------------------------------*/
// Description:
//   Acknowledge Polling. The EEPROM will not acknowledge if a write cycle is
//   in progress. It can be used to determine when a write cycle is completed.
/*----------------------------------------------------------------------------*/
void EEPROM_AckPolling(void)
{
  while (UCB0STAT & UCBUSY);                // wait until I2C module has
                                            // finished all operations
  do
  {
    UCB0STAT = 0x00;                        // clear I2C interrupt flags
    UCB0CTL1 |= UCTR;                       // I2CTRX=1 => Transmit Mode (R/W bit = 0)
    UCB0CTL1 &= ~UCTXSTT;
    UCB0CTL1 |= UCTXSTT;                    // start condition is generated
    while(UCB0CTL1 & UCTXSTT)               // wait till I2CSTT bit was cleared
    {
      if(!(UCNACKIFG & UCB0STAT))           // Break out if ACK received
        break;
    }
    UCB0CTL1 |= UCTXSTP;                    // stop condition is generated after
                                            // slave address was sent => I2C communication is started
    while (UCB0CTL1 & UCTXSTP);             // wait till stop bit is reset
    __delay_cycles(500);                    // Software delay
  }while(UCNACKIFG & UCB0STAT);
}

/*---------------------------------------------------------------------------*/
/*  Interrupt Service Routines                                               */
/*     Note that the Compiler version is checked in the following code and   */
/*     depending of the Compiler Version the correct Interrupt Service       */
/*     Routine definition is used.                                           */
//#if __VER__ < 200
   // interrupt [USCIAB0TX_VECTOR] void TX_ISR_I2C(void)
//#else
#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
//#endif
{
  if(UCTXIFG & UCB0IFG)
  {
    UCB0TXBUF = I2CBufferArray[PtrTransmit];// Load TX buffer
    PtrTransmit--;                          // Decrement TX byte counter
    if(PtrTransmit < 0)
    {
      while(!(UCB0IFG & UCTXIFG));
      UCB0CTL1 |= UCTXSTP;                  // I2C stop condition
      UCB0IE &= ~UCTXIE;                     // disable interrupts.
      UCB0IFG &= ~UCTXIFG;                   // Clear USCI_B0 TX int flag
    //  __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
    }
  }
  else if(UCRXIFG & UCB0IFG)
  {
    I2CBuffer = UCB0RXBUF;                  // store received data in buffer
    //__bic_SR_register_on_exit(LPM0_bits);   // Exit LPM0
  }
}

I2CRoutines.h:

#define I2C_PORT_SEL  P3SEL
#define I2C_PORT_OUT  P3OUT
#define I2C_PORT_REN  P3REN
#define I2C_PORT_DIR  P3DIR
#define SDA_PIN       BIT0                  // UCB0SDA pin
#define SCL_PIN       BIT1                  // UCB0SCL pin
#define SCL_CLOCK_DIV 0x12                  // SCL clock devider

void InitI2C(unsigned char eeprom_i2c_address);
void EEPROM_ByteWrite(unsigned int Address , unsigned char Data);
void EEPROM_PageWrite(unsigned int StartAddress , unsigned char * Data , unsigned char Size);
unsigned char EEPROM_RandomRead(unsigned int Address);
unsigned char EEPROM_CurrentAddressRead(void);
void EEPROM_SequentialRead(unsigned int Address , unsigned char * Data , unsigned int Size);
void EEPROM_AckPolling(void);

  • Hi Gavin,

    I noticed you put the function InitI2C(); with parameter 0xA0, to try to make the I2C address match 1010000. But actually you need to pass 0x50 here, as I2C address is 7-bit and the last bit of 0xA0 is for read/write access. So actually you need to pass the 7 MSB bit into here.

    Some detail in our User's Guide:

  • In addition to what Harry (correctly) recommended:

      //__bis_SR_register(LPM0_bits + GIE);       // Enter LPM0 w/ interrupts

    This doesn't match the code for SLAA208A. Commenting out all of these "wait for completion" sequences changes the flow, and more or less guarantees failure.

    I suggest you refresh to the original code (there's a link in the .pdf).

    Unsolicited: There are also some questionable uses of "UCBUSY" (vs "UCBBUSY"), though those are in the original. UCBUSY always reads as 0 in I2C mode [Ref User guide SLAU208Q) Tables 37-20 and 38-7].

  • Hello Harry and Bruce,

    Thank you for your replies your suggestions made a lot of sense so I have updated my slave address to 0x50 and uncommented all 

    __bis_SR_register(LPM0_bits + GIE);

    and 

    __bic_SR_register_on_exit(LPM0_bits);

    lines. I am still having issues though. When I attempt my first byte write the code only enters the ISR once and exits before the PtrTransmit if statement below executes. 

    if(PtrTransmit < 0)
        {
          while(!(UCB0IFG & UCTXIFG));
          //UCB0CTL1 |= UCTXSTP;                  // I2C stop condition
          UCB0IE &= ~UCTXIE;                     // disable interrupts.
          UCB0IFG &= ~UCTXIFG;                   // Clear USCI_B0 TX int flag
          __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
        }

    After looking at the registers in the debugger it seems the TX interrupt flag is cleared whenever I fill the TX buffer and doesnt get set again before the stop bit is set. Should I manually set the TX interrupt flag in the interrupt if I know I still have more bytes to send the EEPROM or is there a way to continue to send bytes before the stop bit is set?

    Thank you again for your help.

  • The sequence you describe sounds suspiciously like you're getting a NACK on the address. 

    What sort of board are you using for the EEPROM? I'm particularly interested in how the A0-A2 pins are configured.

  • I was indeed getting a NACK. I checked my wiring and the wire to vcc wasnt connected on the breadboard. The write and read operations are now working correctly. Thank you for all your help!

**Attention** This is a public forum