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.

Reading consecutive values from EEPROM via I2C



I am trying to read 500 values stored on an EEPROM via I2C. The values were written to the EEPROM via I2C using the Example_2833xI2C_eeprom.c code using the F28335 Experimenter's Kit.

I have tried to reset the I2C module and setting different bits but this register continues to show to be equal to 1:

I2caRegs.I2CSTR.bit.BB 

The code will only read 1 value stored on the eeprom and continues in an endless loop. I cannot generate a stop condition so it can get out of the loop. Any suggestions? Attached is the code with my modifications.

//###########################################################################
//
// FILE:    modified_Example_2833xI2c_eeprom.c - modified by Chuck Jackel - June 6, 2013
//
// TITLE:   DSP2833x I2C EEPROM Example
//
// ASSUMPTIONS:
//
//    This program requires the DSP2833x header files.
//
//    This program requires an external I2C EEPROM connected to
//    the I2C bus at address 0x50.
//
//    As supplied, this project is configured for "boot to SARAM"
//    operation.  The 2833x Boot Mode table is shown below.
//    For information on configuring the boot mode of an eZdsp,
//    please refer to the documentation included with the eZdsp,
//
//       $Boot_Table:
//
//         GPIO87   GPIO86     GPIO85   GPIO84
//          XA15     XA14       XA13     XA12
//           PU       PU         PU       PU
//        ==========================================
//            1        1          1        1    Jump to Flash
//            1        1          1        0    SCI-A boot
//            1        1          0        1    SPI-A boot
//            1        1          0        0    I2C-A boot
//            1        0          1        1    eCAN-A boot
//            1        0          1        0    McBSP-A boot
//            1        0          0        1    Jump to XINTF x16
//            1        0          0        0    Jump to XINTF x32
//            0        1          1        1    Jump to OTP
//            0        1          1        0    Parallel GPIO I/O boot
//            0        1          0        1    Parallel XINTF boot
//            0        1          0        0    Jump to SARAM	    <- "boot to SARAM"
//            0        0          1        1    Branch to check boot mode
//            0        0          1        0    Boot to flash, bypass ADC cal
//            0        0          0        1    Boot to SARAM, bypass ADC cal
//            0        0          0        0    Boot to SCI-A, bypass ADC cal
//                                              Boot_Table_End$
//
// DESCRIPTION:
//
//    This program will write 1-14 words to EEPROM and read them back.
//    The data written and the EEPROM address written to are contained
//    in the message structure, I2cMsgOut1. The data read back will be
//    contained in the message structure I2cMsgIn1.
//
//    This program will work with the on-board I2C EEPROM supplied on
//    the F2833x eZdsp.
//
//
//###########################################################################
// Original Author: D.F.
//
// $TI Release: 2833x/2823x Header Files and Peripheral Examples V133 $
// $Release Date: June 8, 2012 $
//###########################################################################


#include "DSP28x_Project.h"     // Device Headerfile and Examples Include File

// Note: I2C Macros used in this example can be found in the
// DSP2833x_I2C_defines.h file

// Prototype statements for functions found within this file.
void   I2CA_Init(void);
Uint16 I2CA_WriteData(struct I2CMSG *msg);
Uint16 I2CA_ReadData(struct I2CMSG *msg);
interrupt void i2c_int1a_isr(void);
void pass(void);
void fail(void);

#define I2C_SLAVE_ADDR        0x50
#define I2C_NUMBYTES          14
#define I2C_EEPROM_HIGH_ADDR  0x00
#define I2C_EEPROM_LOW_ADDR   0x30

// Global variables
// Two bytes will be used for the outgoing address,
// thus only setup 14 bytes maximum
struct I2CMSG I2cMsgOut1={I2C_MSGSTAT_SEND_WITHSTOP,
                          I2C_SLAVE_ADDR,
                          I2C_NUMBYTES,
                          I2C_EEPROM_HIGH_ADDR,
                          I2C_EEPROM_LOW_ADDR,
                          0x12,                   // Msg Byte 1
                          0x34,                   // Msg Byte 2
                          0x56,                   // Msg Byte 3
                          0x78,                   // Msg Byte 4
                          0x9A,                   // Msg Byte 5
                          0xBC,                   // Msg Byte 6
                          0xDE,                   // Msg Byte 7
                          0xF0,                   // Msg Byte 8
                          0x11,                   // Msg Byte 9
                          0x10,                   // Msg Byte 10
                          0x11,                   // Msg Byte 11
                          0x12,                   // Msg Byte 12
                          0x13,                   // Msg Byte 13
                          0x12};                   // Msg Byte 14



struct I2CMSG I2cMsgIn1={ I2C_MSGSTAT_SEND_NOSTOP,
                          I2C_SLAVE_ADDR,
                          I2C_NUMBYTES,
                          I2C_EEPROM_HIGH_ADDR,
                          I2C_EEPROM_LOW_ADDR};

struct I2CMSG *CurrentMsgPtr;				// Used in interrupts
Uint16 PassCount;
Uint16 FailCount;
Uint16 WriteFaultIndex = 0;



void main(void)
 {
   Uint16 Error;
   Uint16 i;

   CurrentMsgPtr = &I2cMsgOut1;

// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the DSP2833x_SysCtrl.c file.
   InitSysCtrl();


// Step 2. Initalize GPIO:
// This example function is found in the DSP2833x_Gpio.c file and
// illustrates how to set the GPIO to it's default state.
// InitGpio();
// Setup only the GP I/O only for I2C functionality
   InitI2CGpio();

// Step 3. Clear all interrupts and initialize PIE vector table:
// Disable CPU interrupts
   DINT;

// Initialize PIE control registers to their default state.
// The default state is all PIE interrupts disabled and flags
// are cleared.
// This function is found in the DSP2833x_PieCtrl.c file.
   InitPieCtrl();

// Disable CPU interrupts and clear all CPU interrupt flags:
   IER = 0x0000;
   IFR = 0x0000;

// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
// This will populate the entire table, even if the interrupt
// is not used in this example.  This is useful for debug purposes.
// The shell ISR routines are found in DSP2833x_DefaultIsr.c.
// This function is found in DSP2833x_PieVect.c.
   InitPieVectTable();

// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
   EALLOW;	// This is needed to write to EALLOW protected registers
   PieVectTable.I2CINT1A = &i2c_int1a_isr;
   EDIS;   // This is needed to disable write to EALLOW protected registers

// Step 4. Initialize all the Device Peripherals:
// This function is found in DSP2833x_InitPeripherals.c
// InitPeripherals(); // Not required for this example
   I2CA_Init();

// Step 5. User specific code

   // Clear Counters
   PassCount = 0;
   FailCount = 0;

   // Clear incoming message buffer
   for (i = 0; i < I2C_MAX_BUFFER_SIZE; i++)
   {
       I2cMsgIn1.MsgBuffer[i] = 0x0000;
      //I2cMsgOut1.MsgBuffer[i] =0x0000;
   }

// Enable interrupts required for this example

// Enable I2C interrupt 1 in the PIE: Group 8 interrupt 1
   PieCtrlRegs.PIEIER8.bit.INTx1 = 1;

// Enable CPU INT8 which is connected to PIE group 8
   IER |= M_INT8;
   EINT;

   // Application loop
   for(;;)
   {

	   /* increment high address byte by page # */
	   //I2cMsgOut1.MemoryHighAddr = (WriteFaultIndex * 128) >> 8;
	   I2cMsgIn1.MemoryHighAddr = (WriteFaultIndex * 128) >> 8;

	   /* increment low address byte */
	   //I2cMsgOut1.MemoryLowAddr = (0x0030 + (WriteFaultIndex * 128)) & 0x00FF;
	   I2cMsgIn1.MemoryLowAddr = (0x0030 + (WriteFaultIndex * 128)) & 0x00FF;

//	   for(i=0; i < I2C_NUMBYTES; i++)
//	   {
//		   I2cMsgOut1.MsgBuffer[i] = WriteFaultIndex;
//	   }

//	   WriteFaultIndex++;
//	   if(WriteFaultIndex >= 500)
//	               {
//		   	   	   asm("   ESTOP0");
//	               	// WriteFaultIndex = 500;
//	               }




	  //////////////////////////////////
      // Write data to EEPROM section //
      //////////////////////////////////

      // Check the outgoing message to see if it should be sent.
      // In this example it is initialized to send with a stop bit.
//      if(I2cMsgOut1.MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP)
//      {
//         Error = I2CA_WriteData(&I2cMsgOut1);
//         // If communication is correctly initiated, set msg status to busy
//         // and update CurrentMsgPtr for the interrupt service routine.
//         // Otherwise, do nothing and try again next loop. Once message is
//         // initiated, the I2C interrupts will handle the rest. Search for
//         // ICINTR1A_ISR in the i2c_eeprom_isr.c file.
//         if (Error == I2C_SUCCESS)
//         {
//            CurrentMsgPtr = &I2cMsgOut1;
//            //I2cMsgOut1.MsgStatus = I2C_MSGSTAT_WRITE_BUSY;
//            WriteFaultIndex++;
//            	   if(WriteFaultIndex >= 500)
//            	               {
//            		   	   	   asm("   ESTOP0");
//            	               	// WriteFaultIndex = 500;
//            	               }
//
//
//
//
//
//         }
//      }  // end of write section


	   I2cMsgOut1.MsgStatus = I2C_MSGSTAT_INACTIVE;
	   I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP;


	   ///////////////////////////////////
      // Read data from EEPROM section //
      ///////////////////////////////////

      // Check outgoing message status. Bypass read section if status is
      // not inactive.
      if (I2cMsgOut1.MsgStatus == I2C_MSGSTAT_INACTIVE)
      {
         // Check incoming message status.
         if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)
         {
            // EEPROM address setup portion
            while(I2CA_ReadData(&I2cMsgIn1) != I2C_SUCCESS)
            {
               // Maybe setup an attempt counter to break an infinite while
               // loop. The EEPROM will send back a NACK while it is performing
               // a write operation. Even though the write communique is
               // complete at this point, the EEPROM could still be busy
               // programming the data. Therefore, multiple attempts are
               // necessary.
            }
            // Update current message pointer and message status
            CurrentMsgPtr = &I2cMsgIn1;
            I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY;
                        WriteFaultIndex++;
                        I2CA_Init();

                     	   if(WriteFaultIndex >= 500)
                       	      {
                       		   	asm("   ESTOP0");
                        	    // WriteFaultIndex = 500;
                        	  }

         }

         // Once message has progressed past setting up the internal address
         // of the EEPROM, send a restart to read the data bytes from the
         // EEPROM. Complete the communique with a stop bit. MsgStatus is
         // updated in the interrupt service routine.
         else if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_RESTART)
         {
            // Read data portion
            while(I2CA_ReadData(&I2cMsgIn1) != I2C_SUCCESS)
            {
               // Maybe setup an attempt counter to break an infinite while
               // loop.
            }
            // Update current message pointer and message status
            CurrentMsgPtr = &I2cMsgIn1;
            I2cMsgIn1.MsgStatus = I2C_MSGSTAT_READ_BUSY;
            I2CA_Init();
         }

      }  // end of read section

   }   // end of for(;;)
}   // end of main


void I2CA_Init(void)
{
   // Initialize I2C
   I2caRegs.I2CSAR = 0x0050;		// Slave address - EEPROM control code

   #if (CPU_FRQ_150MHZ)             // Default - For 150MHz SYSCLKOUT
        I2caRegs.I2CPSC.all = 14;   // Prescaler - need 7-12 Mhz on module clk (150/15 = 10MHz)
   #endif
   #if (CPU_FRQ_100MHZ)             // For 100 MHz SYSCLKOUT
     I2caRegs.I2CPSC.all = 9;	    // Prescaler - need 7-12 Mhz on module clk (100/10 = 10MHz)
   #endif

   I2caRegs.I2CCLKL = 10;			// NOTE: must be non zero
   I2caRegs.I2CCLKH = 5;			// NOTE: must be non zero
   I2caRegs.I2CIER.all = 0x24;		// Enable SCD & ARDY interrupts

   I2caRegs.I2CMDR.all = 0x0020;	// Take I2C out of reset
   									// Stop I2C when suspended

   I2caRegs.I2CFFTX.all = 0x6000;	// Enable FIFO mode and TXFIFO
   I2caRegs.I2CFFRX.all = 0x2040;	// Enable RXFIFO, clear RXFFINT,

   return;
}


Uint16 I2CA_WriteData(struct I2CMSG *msg)
{
   Uint16 i;

   // Wait until the STP bit is cleared from any previous master communication.
   // Clearing of this bit by the module is delayed until after the SCD bit is
   // set. If this bit is not checked prior to initiating a new message, the
   // I2C could get confused.
   if (I2caRegs.I2CMDR.bit.STP == 1)
   {
      return I2C_STP_NOT_READY_ERROR;
   }

   // Setup slave address
   I2caRegs.I2CSAR = msg->SlaveAddress;

   // Check if bus busy
   if (I2caRegs.I2CSTR.bit.BB == 1)
   {
      return I2C_BUS_BUSY_ERROR;
   }

   // Setup number of bytes to send
   // MsgBuffer + Address
   I2caRegs.I2CCNT = msg->NumOfBytes+2;


         // I2cMsgOut1.MemoryHighAddr = 0x00E0;
         // I2cMsgOut1.MemoryLowAddr =  0x0030;


   // Setup data to send
   I2caRegs.I2CDXR = msg->MemoryHighAddr;
   I2caRegs.I2CDXR = msg->MemoryLowAddr;
// for (i=0; i<msg->NumOfBytes-2; i++)
   for (i=0; i<msg->NumOfBytes; i++)

   {
      I2caRegs.I2CDXR = *(msg->MsgBuffer+i);
   }

   // Send start as master transmitter
   I2caRegs.I2CMDR.all = 0x6E20;

   return I2C_SUCCESS;
}


Uint16 I2CA_ReadData(struct I2CMSG *msg)
{
   // Wait until the STP bit is cleared from any previous master communication.
   // Clearing of this bit by the module is delayed until after the SCD bit is
   // set. If this bit is not checked prior to initiating a new message, the
   // I2C could get confused.
   if (I2caRegs.I2CMDR.bit.STP == 1)
   {
      return I2C_STP_NOT_READY_ERROR;
   }

   I2caRegs.I2CSAR = msg->SlaveAddress;

   if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)
   {
      // Check if bus busy
      if (I2caRegs.I2CSTR.bit.BB == 1)
      {
         return I2C_BUS_BUSY_ERROR;
      }
      I2caRegs.I2CCNT = 2;



      I2caRegs.I2CDXR = msg->MemoryHighAddr;
      I2caRegs.I2CDXR = msg->MemoryLowAddr;
      I2caRegs.I2CMDR.all = 0x2620;			// Send data to setup EEPROM address
   }
   else if(msg->MsgStatus == I2C_MSGSTAT_RESTART)
   {
      I2caRegs.I2CCNT = msg->NumOfBytes;	// Setup how many bytes to expect
      I2caRegs.I2CMDR.all = 0x2C20;			// originally 0x2C20. Send restart as master receiver
   }


   return I2C_SUCCESS;
}

interrupt void i2c_int1a_isr(void)     // I2C-A
{
   Uint16 IntSource, i;

   // Read interrupt source
   IntSource = I2caRegs.I2CISRC.all;

   // Interrupt source = stop condition detected
   if(IntSource == I2C_SCD_ISRC)
   {
      // If completed message was writing data, reset msg to inactive state
      if (CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_WRITE_BUSY)
      {
         CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;
      }
      else
      {
         // If a message receives a NACK during the address setup portion of the
         // EEPROM read, the code further below included in the register access ready
         // interrupt source code will generate a stop condition. After the stop
         // condition is received (here), set the message status to try again.
         // User may want to limit the number of retries before generating an error.
         if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
         {
            CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP;
         }
         // If completed message was reading EEPROM data, reset msg to inactive state
         // and read data from FIFO.
         else if (CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_READ_BUSY)
         {
            CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;
            for(i=0; i < I2C_NUMBYTES; i++)
            {
              CurrentMsgPtr->MsgBuffer[i] = I2caRegs.I2CDRR;
            }
         {
         // Check recieved data
         for(i=0; i < I2C_NUMBYTES; i++)
         {
            if(I2cMsgIn1.MsgBuffer[i] == I2cMsgOut1.MsgBuffer[i])
            {
                PassCount++;
            }
            else
            {
                FailCount++;
            }
         }
         if(PassCount == I2C_NUMBYTES)
         {
            pass();
         }
         else
         {
            fail();
         }


      }

    }
      }
   }  // end of stop condition detected

   // Interrupt source = Register Access Ready
   // This interrupt is used to determine when the EEPROM address setup portion of the
   // read data communication is complete. Since no stop bit is commanded, this flag
   // tells us when the message has been sent instead of the SCD flag. If a NACK is
   // received, clear the NACK bit and command a stop. Otherwise, move on to the read
   // data portion of the communication.
   else if(IntSource == I2C_ARDY_ISRC)
   {
      if(I2caRegs.I2CSTR.bit.NACK == 1)
      {
         I2caRegs.I2CMDR.bit.STP = 1;
         I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT;
      }
      else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
      {
         CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_RESTART;
      }
   }  // end of register access ready

   else
   {
      // Generate some error due to invalid interrupt source
      asm("   ESTOP0");
   }

   // Enable future I2C (PIE Group 8) interrupts
   PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;
}

void pass()
{
//    asm("   ESTOP0");
//    for(;;);
}

void fail()
{
//    asm("   ESTOP0");
//    for(;;);
}


//===========================================================================
// No more.
//===========================================================================

  • Hello Charles,

    What's the purpose of having I2CA_Init(); in several several places?  I would think it would only be called once at the beginning of the program.

    Stephen

  • You commented out the eeprom write section of the code, i.e. Error = I2CA_WriteData(&I2cMsgOut1). 

  • Hello Charles,

    There are two parts to reading from the EEPROM: Address setup and the actual read. 

    You will want to remove the I2CA_Init(); from both parts and then move the following code from the first to the second part:

    WriteFaultIndex++;   

    if(WriteFaultIndex >= 500)

    {                            

               asm("   ESTOP0");                              // WriteFaultIndex = 500;       

    }

    I think that will fix it.

    Stephen

  • Also, The way you are computing the low and high byte of the address seems strange.

    Stephen

  • The low and high address byte computation is based on the memory

    requirements of the Microchip LC512 eeprom, 64K x 8 with page

    writes of 128 bytes of data.

    I commented out the Write section in order to confirm my code was actually reading from the eeprom and not simply

    filling up an array with values generated from the Write code.

    I was using Init() twice in the code in order to send a stop condition. This obviously did not work.

  • Hello Charles,

    Did you try my suggestions?

    The address calculation still doesn't look correct.  The low memory bytes is jumping back and forth between 0x30 and 0xB0 (see below). Is that what you want?

    Stephen

    WriteFaultIndex memory high memory low
    0 0 30
    1 0 B0
    2 0 130
    3 0 1B0
    4 0 230
    5 0 2B0
    6 0 330
    7 0 3B0
    8 0 430
    9 0 4B0
    10 0 530
    11 0 5B0
    12 0 630
    13 0 6B0
    14 0 730
    15 0 7B0
    16 0 830
    17 0 8B0
    18 0 930
    19 0 9B0
    20 0 A30
    21 0 AB0
    22 0 B30
    23 0 BB0
    24 0 C30
    25 0 CB0
    26 0 D30
    27 0 DB0
    28 0 E30
    29 0 EB0
    30 0 F30
    31 0 FB0
    32 1 1030
    33 1 10B0
  • I am able to get the WriteFaultIndex to cycle to 122 with 122 values written to the eeprom but the Read code is resulting in reading incorrect values.

    Why is the code getting stuck in a loop when the WriteFaultIndex = 122 ?

    I changed the addressing method for the high and low byte address but this did not seem to change anything. Attached is the code.

    //###########################################################################
    //
    // FILE:    modified_Example_2833xI2c_eeprom.c - modified by Chuck Jackel - June 6, 2013
    //
    // TITLE:   DSP2833x I2C EEPROM Example
    //
    // ASSUMPTIONS:
    //
    //    This program requires the DSP2833x header files.
    //
    //    This program requires an external I2C EEPROM connected to
    //    the I2C bus at address 0x50.
    //
    //    As supplied, this project is configured for "boot to SARAM"
    //    operation.  The 2833x Boot Mode table is shown below.
    //    For information on configuring the boot mode of an eZdsp,
    //    please refer to the documentation included with the eZdsp,
    //
    //       $Boot_Table:
    //
    //         GPIO87   GPIO86     GPIO85   GPIO84
    //          XA15     XA14       XA13     XA12
    //           PU       PU         PU       PU
    //        ==========================================
    //            1        1          1        1    Jump to Flash
    //            1        1          1        0    SCI-A boot
    //            1        1          0        1    SPI-A boot
    //            1        1          0        0    I2C-A boot
    //            1        0          1        1    eCAN-A boot
    //            1        0          1        0    McBSP-A boot
    //            1        0          0        1    Jump to XINTF x16
    //            1        0          0        0    Jump to XINTF x32
    //            0        1          1        1    Jump to OTP
    //            0        1          1        0    Parallel GPIO I/O boot
    //            0        1          0        1    Parallel XINTF boot
    //            0        1          0        0    Jump to SARAM	    <- "boot to SARAM"
    //            0        0          1        1    Branch to check boot mode
    //            0        0          1        0    Boot to flash, bypass ADC cal
    //            0        0          0        1    Boot to SARAM, bypass ADC cal
    //            0        0          0        0    Boot to SCI-A, bypass ADC cal
    //                                              Boot_Table_End$
    //
    // DESCRIPTION:
    //
    //    This program will write 1-14 words to EEPROM and read them back.
    //    The data written and the EEPROM address written to are contained
    //    in the message structure, I2cMsgOut1. The data read back will be
    //    contained in the message structure I2cMsgIn1.
    //
    //    This program will work with the on-board I2C EEPROM supplied on
    //    the F2833x eZdsp.
    //
    //
    //###########################################################################
    // Original Author: D.F.
    //
    // $TI Release: 2833x/2823x Header Files and Peripheral Examples V133 $
    // $Release Date: June 8, 2012 $
    //###########################################################################
    
    
    #include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
    
    // Note: I2C Macros used in this example can be found in the
    // DSP2833x_I2C_defines.h file
    
    // Prototype statements for functions found within this file.
    void   I2CA_Init(void);
    Uint16 I2CA_WriteData(struct I2CMSG *msg);
    Uint16 I2CA_ReadData(struct I2CMSG *msg);
    interrupt void i2c_int1a_isr(void);
    void pass(void);
    void fail(void);
    
    #define I2C_SLAVE_ADDR        0x50
    #define I2C_NUMBYTES          14
    #define I2C_EEPROM_HIGH_ADDR  0x00
    #define I2C_EEPROM_LOW_ADDR   0x30
    
    // Global variables
    // Two bytes will be used for the outgoing address,
    // thus only setup 14 bytes maximum
    struct I2CMSG I2cMsgOut1={I2C_MSGSTAT_SEND_WITHSTOP,
                              I2C_SLAVE_ADDR,
                              I2C_NUMBYTES,
                              I2C_EEPROM_HIGH_ADDR,
                              I2C_EEPROM_LOW_ADDR,
                              0x12,                   // Msg Byte 1
                              0x34,                   // Msg Byte 2
                              0x56,                   // Msg Byte 3
                              0x78,                   // Msg Byte 4
                              0x9A,                   // Msg Byte 5
                              0xBC,                   // Msg Byte 6
                              0xDE,                   // Msg Byte 7
                              0xF0,                   // Msg Byte 8
                              0x11,                   // Msg Byte 9
                              0x10,                   // Msg Byte 10
                              0x11,                   // Msg Byte 11
                              0x12,                   // Msg Byte 12
                              0x13,                   // Msg Byte 13
                              0x12};                   // Msg Byte 14
    
    
    
    struct I2CMSG I2cMsgIn1={ I2C_MSGSTAT_SEND_NOSTOP,
                              I2C_SLAVE_ADDR,
                              I2C_NUMBYTES,
                              I2C_EEPROM_HIGH_ADDR,
                              I2C_EEPROM_LOW_ADDR};
    
    struct I2CMSG *CurrentMsgPtr;				// Used in interrupts
    Uint16 PassCount;
    Uint16 FailCount;
    Uint16 WriteFaultIndex = 0;
    
    
    
    void main(void)
     {
       Uint16 Error;
       Uint16 i;
    
       CurrentMsgPtr = &I2cMsgOut1;
    
    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the DSP2833x_SysCtrl.c file.
       InitSysCtrl();
    
    
    // Step 2. Initalize GPIO:
    // This example function is found in the DSP2833x_Gpio.c file and
    // illustrates how to set the GPIO to it's default state.
    // InitGpio();
    // Setup only the GP I/O only for I2C functionality
       InitI2CGpio();
    
    // Step 3. Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
       DINT;
    
    // Initialize PIE control registers to their default state.
    // The default state is all PIE interrupts disabled and flags
    // are cleared.
    // This function is found in the DSP2833x_PieCtrl.c file.
       InitPieCtrl();
    
    // Disable CPU interrupts and clear all CPU interrupt flags:
       IER = 0x0000;
       IFR = 0x0000;
    
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This will populate the entire table, even if the interrupt
    // is not used in this example.  This is useful for debug purposes.
    // The shell ISR routines are found in DSP2833x_DefaultIsr.c.
    // This function is found in DSP2833x_PieVect.c.
       InitPieVectTable();
    
    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
       EALLOW;	// This is needed to write to EALLOW protected registers
       PieVectTable.I2CINT1A = &i2c_int1a_isr;
       EDIS;   // This is needed to disable write to EALLOW protected registers
    
    // Step 4. Initialize all the Device Peripherals:
    // This function is found in DSP2833x_InitPeripherals.c
    // InitPeripherals(); // Not required for this example
       I2CA_Init();
    
    // Step 5. User specific code
    
       // Clear Counters
       PassCount = 0;
       FailCount = 0;
    
       // Clear incoming message buffer
       for (i = 0; i < I2C_MAX_BUFFER_SIZE; i++)
       {
           I2cMsgIn1.MsgBuffer[i] = 0x0000;
           I2cMsgOut1.MsgBuffer[i] =0x0000;
       }
    
    // Enable interrupts required for this example
    
    // Enable I2C interrupt 1 in the PIE: Group 8 interrupt 1
       PieCtrlRegs.PIEIER8.bit.INTx1 = 1;
    
    // Enable CPU INT8 which is connected to PIE group 8
       IER |= M_INT8;
       EINT;
    
       // Application loop
       for(;;)
       {
    
    	   /* increment high address byte by page # */
    	   I2cMsgOut1.MemoryHighAddr = (WriteFaultIndex * 128) >> 8;
    	   I2cMsgIn1.MemoryHighAddr = (WriteFaultIndex * 128) >> 8;
    
    	   /* increment low address byte */
    	   I2cMsgOut1.MemoryLowAddr = (WriteFaultIndex * 128) & 0x00FF;
    	   I2cMsgIn1.MemoryLowAddr =  (WriteFaultIndex * 128) & 0x00FF;
    
    	   for(i=0; i < I2C_NUMBYTES; i++)
    	   {
    		   I2cMsgOut1.MsgBuffer[i] = 99;
    	   }
    
    
    
    
    
    
    
    	  //////////////////////////////////
          // Write data to EEPROM section //
          //////////////////////////////////
    
          // Check the outgoing message to see if it should be sent.
          // In this example it is initialized to send with a stop bit.
          if(I2cMsgOut1.MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP)
          {
             Error = I2CA_WriteData(&I2cMsgOut1);
             // If communication is correctly initiated, set msg status to busy
             // and update CurrentMsgPtr for the interrupt service routine.
             // Otherwise, do nothing and try again next loop. Once message is
             // initiated, the I2C interrupts will handle the rest. Search for
             // ICINTR1A_ISR in the i2c_eeprom_isr.c file.
             if (Error == I2C_SUCCESS)
             {
                CurrentMsgPtr = &I2cMsgOut1;
                I2cMsgOut1.MsgStatus = I2C_MSGSTAT_WRITE_BUSY;
    
    
    
    
    
    
             }
          }  // end of write section
    
    
    //	   I2cMsgOut1.MsgStatus = I2C_MSGSTAT_INACTIVE;
    //	   I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP;
    
    
    	   ///////////////////////////////////
          // Read data from EEPROM section //
          ///////////////////////////////////
    
          // Check outgoing message status. Bypass read section if status is
          // not inactive.
          if (I2cMsgOut1.MsgStatus == I2C_MSGSTAT_INACTIVE)
          {
             // Check incoming message status.
             if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)
             {
                // EEPROM address setup portion
                while(I2CA_ReadData(&I2cMsgIn1) != I2C_SUCCESS)
                {
                   // Maybe setup an attempt counter to break an infinite while
                   // loop. The EEPROM will send back a NACK while it is performing
                   // a write operation. Even though the write communique is
                   // complete at this point, the EEPROM could still be busy
                   // programming the data. Therefore, multiple attempts are
                   // necessary.
                }
                // Update current message pointer and message status
                CurrentMsgPtr = &I2cMsgIn1;
                I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY;
                WriteFaultIndex++;
                            	   if(WriteFaultIndex >= 500)
                            	               {
                            		   	   	   asm("   ESTOP0");
                            	               	// WriteFaultIndex = 500;
                            	               }
    
             }
    
             // Once message has progressed past setting up the internal address
             // of the EEPROM, send a restart to read the data bytes from the
             // EEPROM. Complete the communique with a stop bit. MsgStatus is
             // updated in the interrupt service routine.
             else if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_RESTART)
             {
                // Read data portion
                while(I2CA_ReadData(&I2cMsgIn1) != I2C_SUCCESS)
                {
                   // Maybe setup an attempt counter to break an infinite while
                   // loop.
                }
                // Update current message pointer and message status
                CurrentMsgPtr = &I2cMsgIn1;
                I2cMsgIn1.MsgStatus = I2C_MSGSTAT_READ_BUSY;
    
    
             }
    
          }  // end of read section
    
       }   // end of for(;;)
    }   // end of main
    
    
    void I2CA_Init(void)
    {
       // Initialize I2C
       I2caRegs.I2CSAR = 0x0050;		// Slave address - EEPROM control code
    
       #if (CPU_FRQ_150MHZ)             // Default - For 150MHz SYSCLKOUT
            I2caRegs.I2CPSC.all = 14;   // Prescaler - need 7-12 Mhz on module clk (150/15 = 10MHz)
       #endif
       #if (CPU_FRQ_100MHZ)             // For 100 MHz SYSCLKOUT
         I2caRegs.I2CPSC.all = 9;	    // Prescaler - need 7-12 Mhz on module clk (100/10 = 10MHz)
       #endif
    
       I2caRegs.I2CCLKL = 10;			// NOTE: must be non zero
       I2caRegs.I2CCLKH = 5;			// NOTE: must be non zero
       I2caRegs.I2CIER.all = 0x24;		// Enable SCD & ARDY interrupts
    
       I2caRegs.I2CMDR.all = 0x0020;	// Take I2C out of reset
       									// Stop I2C when suspended
    
       I2caRegs.I2CFFTX.all = 0x6000;	// Enable FIFO mode and TXFIFO
       I2caRegs.I2CFFRX.all = 0x2040;	// Enable RXFIFO, clear RXFFINT,
    
       return;
    }
    
    
    Uint16 I2CA_WriteData(struct I2CMSG *msg)
    {
       Uint16 i;
    
       // Wait until the STP bit is cleared from any previous master communication.
       // Clearing of this bit by the module is delayed until after the SCD bit is
       // set. If this bit is not checked prior to initiating a new message, the
       // I2C could get confused.
       if (I2caRegs.I2CMDR.bit.STP == 1)
       {
          return I2C_STP_NOT_READY_ERROR;
       }
    
       // Setup slave address
       I2caRegs.I2CSAR = msg->SlaveAddress;
    
       // Check if bus busy
       if (I2caRegs.I2CSTR.bit.BB == 1)
       {
          return I2C_BUS_BUSY_ERROR;
       }
    
       // Setup number of bytes to send
       // MsgBuffer + Address
       I2caRegs.I2CCNT = msg->NumOfBytes+2;
    
    
             // I2cMsgOut1.MemoryHighAddr = 0x00E0;
             // I2cMsgOut1.MemoryLowAddr =  0x0030;
    
    
       // Setup data to send
       I2caRegs.I2CDXR = msg->MemoryHighAddr;
       I2caRegs.I2CDXR = msg->MemoryLowAddr;
    // for (i=0; i<msg->NumOfBytes-2; i++)
       for (i=0; i<msg->NumOfBytes; i++)
    
       {
          I2caRegs.I2CDXR = *(msg->MsgBuffer+i);
       }
    
       // Send start as master transmitter
       I2caRegs.I2CMDR.all = 0x6E20;
    
       return I2C_SUCCESS;
    }
    
    
    Uint16 I2CA_ReadData(struct I2CMSG *msg)
    {
       // Wait until the STP bit is cleared from any previous master communication.
       // Clearing of this bit by the module is delayed until after the SCD bit is
       // set. If this bit is not checked prior to initiating a new message, the
       // I2C could get confused.
       if (I2caRegs.I2CMDR.bit.STP == 1)
       {
          return I2C_STP_NOT_READY_ERROR;
       }
    
       I2caRegs.I2CSAR = msg->SlaveAddress;
    
       if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)
       {
          // Check if bus busy
          if (I2caRegs.I2CSTR.bit.BB == 1)
          {
             return I2C_BUS_BUSY_ERROR;
          }
          I2caRegs.I2CCNT = 2;
    
    
    
          I2caRegs.I2CDXR = msg->MemoryHighAddr;
          I2caRegs.I2CDXR = msg->MemoryLowAddr;
          I2caRegs.I2CMDR.all = 0x2620;			// Send data to setup EEPROM address
       }
       else if(msg->MsgStatus == I2C_MSGSTAT_RESTART)
       {
          I2caRegs.I2CCNT = msg->NumOfBytes;	// Setup how many bytes to expect
          I2caRegs.I2CMDR.all = 0x2C20;			// originally 0x2C20. Send restart as master receiver
       }
    
    
       return I2C_SUCCESS;
    }
    
    interrupt void i2c_int1a_isr(void)     // I2C-A
    {
       Uint16 IntSource, i;
    
       // Read interrupt source
       IntSource = I2caRegs.I2CISRC.all;
    
       // Interrupt source = stop condition detected
       if(IntSource == I2C_SCD_ISRC)
       {
          // If completed message was writing data, reset msg to inactive state
          if (CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_WRITE_BUSY)
          {
             CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;
          }
          else
          {
             // If a message receives a NACK during the address setup portion of the
             // EEPROM read, the code further below included in the register access ready
             // interrupt source code will generate a stop condition. After the stop
             // condition is received (here), set the message status to try again.
             // User may want to limit the number of retries before generating an error.
             if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
             {
                CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP;
             }
             // If completed message was reading EEPROM data, reset msg to inactive state
             // and read data from FIFO.
             else if (CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_READ_BUSY)
             {
                CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;
                for(i=0; i < I2C_NUMBYTES; i++)
                {
                  CurrentMsgPtr->MsgBuffer[i] = I2caRegs.I2CDRR;
                }
             {
             // Check recieved data
             for(i=0; i < I2C_NUMBYTES; i++)
             {
                if(I2cMsgIn1.MsgBuffer[i] == I2cMsgOut1.MsgBuffer[i])
                {
                    PassCount++;
                }
                else
                {
                    FailCount++;
                }
             }
             if(PassCount == I2C_NUMBYTES)
             {
                pass();
             }
             else
             {
                fail();
             }
    
    
          }
    
        }
          }
       }  // end of stop condition detected
    
       // Interrupt source = Register Access Ready
       // This interrupt is used to determine when the EEPROM address setup portion of the
       // read data communication is complete. Since no stop bit is commanded, this flag
       // tells us when the message has been sent instead of the SCD flag. If a NACK is
       // received, clear the NACK bit and command a stop. Otherwise, move on to the read
       // data portion of the communication.
       else if(IntSource == I2C_ARDY_ISRC)
       {
          if(I2caRegs.I2CSTR.bit.NACK == 1)
          {
             I2caRegs.I2CMDR.bit.STP = 1;
             I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT;
          }
          else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
          {
             CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_RESTART;
          }
       }  // end of register access ready
    
       else
       {
          // Generate some error due to invalid interrupt source
          asm("   ESTOP0");
       }
    
       // Enable future I2C (PIE Group 8) interrupts
       PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;
    }
    
    void pass()
    {
    //    asm("   ESTOP0");
    //    for(;;);
    }
    
    void fail()
    {
    //    asm("   ESTOP0");
    //    for(;;);
    }
    
    
    //===========================================================================
    // No more.
    //===========================================================================
    

  • The I2cMsgOut1 is set up to write 14 bytes for every write.  Also, I2cMsgIn1 is set up to read 14 bytes every read. 

    If you want to write continuously, your address calculation will have to take care of page boundaries, i.e. if the address computed is greater than 32 (=page size), your program will have to adjust the low and high memory byte accordingly, i.e.

     I2cMsgIn1.MemoryLowAddr+= 14;

    if I2cMsgIn1.MemoryLowAddr>= 32)
    {
       I2cMsgOut1.MemoryHighAddr++;
       I2cMsgIn1.MemoryLowAddr %= 32;
    }

    Place the above code after the second read and remove your existing address computation code.

    also, I don't think you want to remove the NAK code, i.e.
       else if (IntSource == I2C_NACK_ISRC)
       {
          I2caRegs.I2CMDR.bit.STP = 1;
          I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT;      
       } 

    if you don't have this code, the i2c module won't generate a stop when it recieves a NAK causing the bus to stay busy and your code won't be able to progress futher.

    Also, I think you should move the following right after the second read, i.e.
          if (I2cMsgOut1.MsgStatus == I2C_MSGSTAT_INACTIVE)
          {
             // Check incoming message status.
             if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)
             {
                // EEPROM address setup portion
                while(I2CA_ReadData(&I2cMsgIn1) != I2C_SUCCESS)
                {
                   // Maybe setup an attempt counter to break an infinite while
                   // loop. The EEPROM will send back a NACK while it is performing
                   // a write operation. Even though the write communique is
                   // complete at this point, the EEPROM could still be busy
                   // programming the data. Therefore, multiple attempts are
                   // necessary.
                }
                // Update current message pointer and message status
                CurrentMsgPtr = &I2cMsgIn1;
                I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY;
             }

             // Once message has progressed past setting up the internal address
             // of the EEPROM, send a restart to read the data bytes from the
             // EEPROM. Complete the communique with a stop bit. MsgStatus is
             // updated in the interrupt service routine.
             else if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_RESTART)
             {
                // Read data portion
                while(I2CA_ReadData(&I2cMsgIn1) != I2C_SUCCESS)
                {
                   // Maybe setup an attempt counter to break an infinite while
                   // loop.
                }
                // Update current message pointer and message status
                CurrentMsgPtr = &I2cMsgIn1;
                I2cMsgIn1.MsgStatus = I2C_MSGSTAT_READ_BUSY;

                WriteFaultIndex++;
                                if(WriteFaultIndex >= 500)
                                            {
                                         asm("   ESTOP0");
                                             // WriteFaultIndex = 500;
                                            }

                I2cMsgIn1.MemoryLowAddr+= 14;

                if I2cMsgIn1.MemoryLowAddr>= 32)
                {
                       I2cMsgOut1.MemoryHighAddr++;
                      I2cMsgIn1.MemoryLowAddr %= 32;
                  }


             }

          }  // end of read sectio

    Stephen

  • I just noticed you said the eeprom is 128 bytes/page.

    Therefore, you'll need to change the 32 to 128 in the address calculation code I gave you.

    Stephen

  • Stephen,

    Thank you for these suggestions and code revisions. I'll try it and post my results.

    -Chuck

  •   Stephen,

    I added the high/low address computation code, but I am confused by your comments. You say to add the address computation code,

    then you say DO NOT remove code that is already in the ISR, then you say add code a huge section of code that is already there. 

    Also, how is the high address for MsgIn calculated? There is only an MsgOut high byte computation.

    Attached is my revised code. As is, it gets stuck in a loop with WriteFaultIndex = 1.

    - Chuck

    //###########################################################################
    //
    // FILE:    modified_Example_2833xI2c_eeprom.c - modified by Chuck Jackel - June 6, 2013
    //
    // TITLE:   DSP2833x I2C EEPROM Example
    //
    // ASSUMPTIONS:
    //
    //    This program requires the DSP2833x header files.
    //
    //    This program requires an external I2C EEPROM connected to
    //    the I2C bus at address 0x50.
    //
    //    As supplied, this project is configured for "boot to SARAM"
    //    operation.  The 2833x Boot Mode table is shown below.
    //    For information on configuring the boot mode of an eZdsp,
    //    please refer to the documentation included with the eZdsp,
    //
    //       $Boot_Table:
    //
    //         GPIO87   GPIO86     GPIO85   GPIO84
    //          XA15     XA14       XA13     XA12
    //           PU       PU         PU       PU
    //        ==========================================
    //            1        1          1        1    Jump to Flash
    //            1        1          1        0    SCI-A boot
    //            1        1          0        1    SPI-A boot
    //            1        1          0        0    I2C-A boot
    //            1        0          1        1    eCAN-A boot
    //            1        0          1        0    McBSP-A boot
    //            1        0          0        1    Jump to XINTF x16
    //            1        0          0        0    Jump to XINTF x32
    //            0        1          1        1    Jump to OTP
    //            0        1          1        0    Parallel GPIO I/O boot
    //            0        1          0        1    Parallel XINTF boot
    //            0        1          0        0    Jump to SARAM	    <- "boot to SARAM"
    //            0        0          1        1    Branch to check boot mode
    //            0        0          1        0    Boot to flash, bypass ADC cal
    //            0        0          0        1    Boot to SARAM, bypass ADC cal
    //            0        0          0        0    Boot to SCI-A, bypass ADC cal
    //                                              Boot_Table_End$
    //
    // DESCRIPTION:
    //
    //    This program will write 1-14 words to EEPROM and read them back.
    //    The data written and the EEPROM address written to are contained
    //    in the message structure, I2cMsgOut1. The data read back will be
    //    contained in the message structure I2cMsgIn1.
    //
    //    This program will work with the on-board I2C EEPROM supplied on
    //    the F2833x eZdsp.
    //
    //
    //###########################################################################
    // Original Author: D.F.
    //
    // $TI Release: 2833x/2823x Header Files and Peripheral Examples V133 $
    // $Release Date: June 8, 2012 $
    //###########################################################################
    
    
    #include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
    
    // Note: I2C Macros used in this example can be found in the
    // DSP2833x_I2C_defines.h file
    
    // Prototype statements for functions found within this file.
    void   I2CA_Init(void);
    Uint16 I2CA_WriteData(struct I2CMSG *msg);
    Uint16 I2CA_ReadData(struct I2CMSG *msg);
    interrupt void i2c_int1a_isr(void);
    void pass(void);
    void fail(void);
    
    #define I2C_SLAVE_ADDR        0x50
    #define I2C_NUMBYTES          14
    #define I2C_EEPROM_HIGH_ADDR  0x00
    #define I2C_EEPROM_LOW_ADDR   0x30
    
    // Global variables
    // Two bytes will be used for the outgoing address,
    // thus only setup 14 bytes maximum
    struct I2CMSG I2cMsgOut1={I2C_MSGSTAT_SEND_WITHSTOP,
                              I2C_SLAVE_ADDR,
                              I2C_NUMBYTES,
                              I2C_EEPROM_HIGH_ADDR,
                              I2C_EEPROM_LOW_ADDR,
                              0x12,                   // Msg Byte 1
                              0x34,                   // Msg Byte 2
                              0x56,                   // Msg Byte 3
                              0x78,                   // Msg Byte 4
                              0x9A,                   // Msg Byte 5
                              0xBC,                   // Msg Byte 6
                              0xDE,                   // Msg Byte 7
                              0xF0,                   // Msg Byte 8
                              0x11,                   // Msg Byte 9
                              0x10,                   // Msg Byte 10
                              0x11,                   // Msg Byte 11
                              0x12,                   // Msg Byte 12
                              0x13,                   // Msg Byte 13
                              0x12};                   // Msg Byte 14
    
    
    
    struct I2CMSG I2cMsgIn1={ I2C_MSGSTAT_SEND_NOSTOP,
                              I2C_SLAVE_ADDR,
                              I2C_NUMBYTES,
                              I2C_EEPROM_HIGH_ADDR,
                              I2C_EEPROM_LOW_ADDR};
    
    struct I2CMSG *CurrentMsgPtr;				// Used in interrupts
    Uint16 PassCount;
    Uint16 FailCount;
    Uint16 WriteFaultIndex = 0;
    
    
    
    void main(void)
     {
       Uint16 Error;
       Uint16 i;
    
       CurrentMsgPtr = &I2cMsgOut1;
    
    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the DSP2833x_SysCtrl.c file.
       InitSysCtrl();
    
    
    // Step 2. Initalize GPIO:
    // This example function is found in the DSP2833x_Gpio.c file and
    // illustrates how to set the GPIO to it's default state.
    // InitGpio();
    // Setup only the GP I/O only for I2C functionality
       InitI2CGpio();
    
    // Step 3. Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
       DINT;
    
    // Initialize PIE control registers to their default state.
    // The default state is all PIE interrupts disabled and flags
    // are cleared.
    // This function is found in the DSP2833x_PieCtrl.c file.
       InitPieCtrl();
    
    // Disable CPU interrupts and clear all CPU interrupt flags:
       IER = 0x0000;
       IFR = 0x0000;
    
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This will populate the entire table, even if the interrupt
    // is not used in this example.  This is useful for debug purposes.
    // The shell ISR routines are found in DSP2833x_DefaultIsr.c.
    // This function is found in DSP2833x_PieVect.c.
       InitPieVectTable();
    
    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
       EALLOW;	// This is needed to write to EALLOW protected registers
       PieVectTable.I2CINT1A = &i2c_int1a_isr;
       EDIS;   // This is needed to disable write to EALLOW protected registers
    
    // Step 4. Initialize all the Device Peripherals:
    // This function is found in DSP2833x_InitPeripherals.c
    // InitPeripherals(); // Not required for this example
       I2CA_Init();
    
    // Step 5. User specific code
    
       // Clear Counters
       PassCount = 0;
       FailCount = 0;
    
       // Clear incoming message buffer
       for (i = 0; i < I2C_MAX_BUFFER_SIZE; i++)
       {
           I2cMsgIn1.MsgBuffer[i] = 0x0000;
           //I2cMsgOut1.MsgBuffer[i] =0x0000;
       }
    
    // Enable interrupts required for this example
    
    // Enable I2C interrupt 1 in the PIE: Group 8 interrupt 1
       PieCtrlRegs.PIEIER8.bit.INTx1 = 1;
    
    // Enable CPU INT8 which is connected to PIE group 8
       IER |= M_INT8;
       EINT;
    
       // Application loop
       for(;;)
       {
    
    	  //////////////////////////////////
          // Write data to EEPROM section //
          //////////////////////////////////
    
          // Check the outgoing message to see if it should be sent.
          // In this example it is initialized to send with a stop bit.
          if(I2cMsgOut1.MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP)
          {
             Error = I2CA_WriteData(&I2cMsgOut1);
             // If communication is correctly initiated, set msg status to busy
             // and update CurrentMsgPtr for the interrupt service routine.
             // Otherwise, do nothing and try again next loop. Once message is
             // initiated, the I2C interrupts will handle the rest. Search for
             // ICINTR1A_ISR in the i2c_eeprom_isr.c file.
             if (Error == I2C_SUCCESS)
             {
                CurrentMsgPtr = &I2cMsgOut1;
                I2cMsgOut1.MsgStatus = I2C_MSGSTAT_WRITE_BUSY;
             }
          }  // end of write section
    
          ///////////////////////////////////
          // Read data from EEPROM section //
          ///////////////////////////////////
    
          // Check outgoing message status. Bypass read section if status is
          // not inactive.
          if (I2cMsgOut1.MsgStatus == I2C_MSGSTAT_INACTIVE)
          {
             // Check incoming message status.
             if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)
             {
                // EEPROM address setup portion
                while(I2CA_ReadData(&I2cMsgIn1) != I2C_SUCCESS)
                {
                   // Maybe setup an attempt counter to break an infinite while
                   // loop. The EEPROM will send back a NACK while it is performing
                   // a write operation. Even though the write communique is
                   // complete at this point, the EEPROM could still be busy
                   // programming the data. Therefore, multiple attempts are
                   // necessary.
                }
                // Update current message pointer and message status
                CurrentMsgPtr = &I2cMsgIn1;
                I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY;
    
    
             }
    
             // Once message has progressed past setting up the internal address
             // of the EEPROM, send a restart to read the data bytes from the
             // EEPROM. Complete the communique with a stop bit. MsgStatus is
             // updated in the interrupt service routine.
             else if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_RESTART)
             {
                // Read data portion
                while(I2CA_ReadData(&I2cMsgIn1) != I2C_SUCCESS)
                {
                   // Maybe setup an attempt counter to break an infinite while
                   // loop.
                }
                // Update current message pointer and message status
                CurrentMsgPtr = &I2cMsgIn1;
                I2cMsgIn1.MsgStatus = I2C_MSGSTAT_READ_BUSY;
                WriteFaultIndex++;
                               if(WriteFaultIndex >= 500)
                                   {
                              	   	   asm("   ESTOP0");
                              	   	   // WriteFaultIndex = 500;
                                   }
    
                I2cMsgIn1.MemoryLowAddr+= 14;
                   		   	   if (I2cMsgIn1.MemoryLowAddr>= 128)
                       		   	   {
                       		   	      I2cMsgOut1.MemoryHighAddr++;
                       		   	      I2cMsgIn1.MemoryLowAddr %= 128;
                      		   	   }
    
             }
    
          }  // end of read section
    
    
    
       }   // end of for(;;)
    }   // end of main
    
    
    void I2CA_Init(void)
    {
       // Initialize I2C
       I2caRegs.I2CSAR = 0x0050;		// Slave address - EEPROM control code
    
       #if (CPU_FRQ_150MHZ)             // Default - For 150MHz SYSCLKOUT
            I2caRegs.I2CPSC.all = 14;   // Prescaler - need 7-12 Mhz on module clk (150/15 = 10MHz)
       #endif
       #if (CPU_FRQ_100MHZ)             // For 100 MHz SYSCLKOUT
         I2caRegs.I2CPSC.all = 9;	    // Prescaler - need 7-12 Mhz on module clk (100/10 = 10MHz)
       #endif
    
       I2caRegs.I2CCLKL = 10;			// NOTE: must be non zero
       I2caRegs.I2CCLKH = 5;			// NOTE: must be non zero
       I2caRegs.I2CIER.all = 0x24;		// Enable SCD & ARDY interrupts
    
       I2caRegs.I2CMDR.all = 0x0020;	// Take I2C out of reset
       									// Stop I2C when suspended
    
       I2caRegs.I2CFFTX.all = 0x6000;	// Enable FIFO mode and TXFIFO
       I2caRegs.I2CFFRX.all = 0x2040;	// Enable RXFIFO, clear RXFFINT,
    
       return;
    }
    
    
    Uint16 I2CA_WriteData(struct I2CMSG *msg)
    {
       Uint16 i;
    
       // Wait until the STP bit is cleared from any previous master communication.
       // Clearing of this bit by the module is delayed until after the SCD bit is
       // set. If this bit is not checked prior to initiating a new message, the
       // I2C could get confused.
       if (I2caRegs.I2CMDR.bit.STP == 1)
       {
          return I2C_STP_NOT_READY_ERROR;
       }
    
       // Setup slave address
       I2caRegs.I2CSAR = msg->SlaveAddress;
    
       // Check if bus busy
       if (I2caRegs.I2CSTR.bit.BB == 1)
       {
          return I2C_BUS_BUSY_ERROR;
       }
    
       // Setup number of bytes to send
       // MsgBuffer + Address
       I2caRegs.I2CCNT = msg->NumOfBytes+2;
    
    
             // I2cMsgOut1.MemoryHighAddr = 0x00E0;
             // I2cMsgOut1.MemoryLowAddr =  0x0030;
    
    
       // Setup data to send
       I2caRegs.I2CDXR = msg->MemoryHighAddr;
       I2caRegs.I2CDXR = msg->MemoryLowAddr;
    // for (i=0; i<msg->NumOfBytes-2; i++)
       for (i=0; i<msg->NumOfBytes; i++)
    
       {
          I2caRegs.I2CDXR = *(msg->MsgBuffer+i);
       }
    
       // Send start as master transmitter
       I2caRegs.I2CMDR.all = 0x6E20;
    
       return I2C_SUCCESS;
    }
    
    
    Uint16 I2CA_ReadData(struct I2CMSG *msg)
    {
       // Wait until the STP bit is cleared from any previous master communication.
       // Clearing of this bit by the module is delayed until after the SCD bit is
       // set. If this bit is not checked prior to initiating a new message, the
       // I2C could get confused.
       if (I2caRegs.I2CMDR.bit.STP == 1)
       {
          return I2C_STP_NOT_READY_ERROR;
       }
    
       I2caRegs.I2CSAR = msg->SlaveAddress;
    
       if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)
       {
          // Check if bus busy
          if (I2caRegs.I2CSTR.bit.BB == 1)
          {
             return I2C_BUS_BUSY_ERROR;
          }
          I2caRegs.I2CCNT = 2;
    
    
    
          I2caRegs.I2CDXR = msg->MemoryHighAddr;
          I2caRegs.I2CDXR = msg->MemoryLowAddr;
          I2caRegs.I2CMDR.all = 0x2620;			// Send data to setup EEPROM address
       }
       else if(msg->MsgStatus == I2C_MSGSTAT_RESTART)
       {
          I2caRegs.I2CCNT = msg->NumOfBytes;	// Setup how many bytes to expect
          I2caRegs.I2CMDR.all = 0x2C20;			// originally 0x2C20. Send restart as master receiver
       }
    
    
       return I2C_SUCCESS;
    }
    
    interrupt void i2c_int1a_isr(void)     // I2C-A
    {
       Uint16 IntSource, i;
    
       // Read interrupt source
       IntSource = I2caRegs.I2CISRC.all;
    
       // Interrupt source = stop condition detected
       if(IntSource == I2C_SCD_ISRC)
       {
          // If completed message was writing data, reset msg to inactive state
          if (CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_WRITE_BUSY)
          {
             CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;
          }
          else
          {
             // If a message receives a NACK during the address setup portion of the
             // EEPROM read, the code further below included in the register access ready
             // interrupt source code will generate a stop condition. After the stop
             // condition is received (here), set the message status to try again.
             // User may want to limit the number of retries before generating an error.
             if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
             {
                CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP;
             }
             // If completed message was reading EEPROM data, reset msg to inactive state
             // and read data from FIFO.
             else if (CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_READ_BUSY)
             {
                CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;
                for(i=0; i < I2C_NUMBYTES; i++)
                {
                  CurrentMsgPtr->MsgBuffer[i] = I2caRegs.I2CDRR;
                }
             {
             // Check recieved data
             for(i=0; i < I2C_NUMBYTES; i++)
             {
                if(I2cMsgIn1.MsgBuffer[i] == I2cMsgOut1.MsgBuffer[i])
                {
                    PassCount++;
                }
                else
                {
                    FailCount++;
                }
             }
             if(PassCount == I2C_NUMBYTES)
             {
                pass();
             }
             else
             {
                fail();
             }
    
    
          }
    
        }
          }
       }  // end of stop condition detected
    
       // Interrupt source = Register Access Ready
       // This interrupt is used to determine when the EEPROM address setup portion of the
       // read data communication is complete. Since no stop bit is commanded, this flag
       // tells us when the message has been sent instead of the SCD flag. If a NACK is
       // received, clear the NACK bit and command a stop. Otherwise, move on to the read
       // data portion of the communication.
       else if(IntSource == I2C_ARDY_ISRC)
       {
          if(I2caRegs.I2CSTR.bit.NACK == 1)
          {
             I2caRegs.I2CMDR.bit.STP = 1;
             I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT;
          }
          else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
          {
             CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_RESTART;
          }
       }  // end of register access ready
    
       else
       {
          // Generate some error due to invalid interrupt source
          asm("   ESTOP0");
       }
    
       // Enable future I2C (PIE Group 8) interrupts
       PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;
    }
    
    void pass()
    {
    //    asm("   ESTOP0");
    //    for(;;);
    }
    
    void fail()
    {
    //    asm("   ESTOP0");
    //    for(;;);
    }
    
    
    //===========================================================================
    // No more.
    //===========================================================================
    

  • You need to add the following to i2c_int1a_isr() right after   IntSource = I2caRegs.I2CISRC.all; and right before   else if(IntSource == I2C_SCD_ISRC).  This code was in the original example.

       if (IntSource ==  I2C_NO_ISRC)
       {
           IntSource = I2C_NO_ISRC;
       }
       else if (IntSource == I2C_NACK_ISRC)
       {
          I2caRegs.I2CMDR.bit.STP = 1;
          I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT;      
       }

    Also, put a break point at if(PassCount == I2C_NUMBYTES) and check to see if you received the data.

  • Oh.  I forgot to say that both the Out and In addresses need the same value. so:

     I2cMsgIn1.MemoryLowAddr+= 14;

    if I2cMsgIn1.MemoryLowAddr>= 128)
    {
       I2cMsgIn1.MemoryHighAddr++;
       I2cMsgIn1.MemoryLowAddr %= 128;

    }

    I2cMsgOut1.MemoryLowAddr = I2cMsgIn1.MemoryLowAddr;

    I2cMsgOut1.MemoryHighAddr = I2cMsgIn1.MemoryHighAddr;

    I might have made so mistakes, so look over them carefully.  I am just trying to give some direction.

     

  • Stephen,
    I am confused. Where does this code actually need to go? The right after and right before locations do not make sense. The original example

    code does not have "else if(IntSource == I2C_SCD_ISRC)" in the i2c_int1a_isr().

    Please clarify.
    Thank you,

    Chuck 

  • As shown below (Add the code that highlighted green. NOTE: I didn't show all the code.):

    interrupt void i2c_int1a_isr(void)     // I2C-A
    {
       Uint16 IntSource, i;

       // Read interrupt source
       IntSource = I2caRegs.I2CISRC.all;
       
       if (IntSource ==  I2C_NO_ISRC)
       {
           IntSource = I2C_NO_ISRC;
       }
       else if (IntSource == I2C_NACK_ISRC)
       {
          I2caRegs.I2CMDR.bit.STP = 1;
          I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT;      
       }  
       // Interrupt source = stop condition detected
       else if(IntSource == I2C_SCD_ISRC)
       {

  • Stephen,

    I added those revisions and the code compiles okay but stays in an endless loop of going back and forth from

    the Write and Read functions with WriteFaultIndex staying at 1.

    Attached is the revised code with your additions. Thank you for your help.

    -Chuck

    //###########################################################################
    //
    // FILE:    modified_Example_2833xI2c_eeprom.c - modified by Chuck Jackel - June 6, 2013
    //
    // TITLE:   DSP2833x I2C EEPROM Example
    //
    // ASSUMPTIONS:
    //
    //    This program requires the DSP2833x header files.
    //
    //    This program requires an external I2C EEPROM connected to
    //    the I2C bus at address 0x50.
    //
    //    As supplied, this project is configured for "boot to SARAM"
    //    operation.  The 2833x Boot Mode table is shown below.
    //    For information on configuring the boot mode of an eZdsp,
    //    please refer to the documentation included with the eZdsp,
    //
    //       $Boot_Table:
    //
    //         GPIO87   GPIO86     GPIO85   GPIO84
    //          XA15     XA14       XA13     XA12
    //           PU       PU         PU       PU
    //        ==========================================
    //            1        1          1        1    Jump to Flash
    //            1        1          1        0    SCI-A boot
    //            1        1          0        1    SPI-A boot
    //            1        1          0        0    I2C-A boot
    //            1        0          1        1    eCAN-A boot
    //            1        0          1        0    McBSP-A boot
    //            1        0          0        1    Jump to XINTF x16
    //            1        0          0        0    Jump to XINTF x32
    //            0        1          1        1    Jump to OTP
    //            0        1          1        0    Parallel GPIO I/O boot
    //            0        1          0        1    Parallel XINTF boot
    //            0        1          0        0    Jump to SARAM	    <- "boot to SARAM"
    //            0        0          1        1    Branch to check boot mode
    //            0        0          1        0    Boot to flash, bypass ADC cal
    //            0        0          0        1    Boot to SARAM, bypass ADC cal
    //            0        0          0        0    Boot to SCI-A, bypass ADC cal
    //                                              Boot_Table_End$
    //
    // DESCRIPTION:
    //
    //    This program will write 1-14 words to EEPROM and read them back.
    //    The data written and the EEPROM address written to are contained
    //    in the message structure, I2cMsgOut1. The data read back will be
    //    contained in the message structure I2cMsgIn1.
    //
    //    This program will work with the on-board I2C EEPROM supplied on
    //    the F2833x eZdsp.
    //
    //
    //###########################################################################
    // Original Author: D.F.
    //
    // $TI Release: 2833x/2823x Header Files and Peripheral Examples V133 $
    // $Release Date: June 8, 2012 $
    //###########################################################################
    
    
    #include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
    
    // Note: I2C Macros used in this example can be found in the
    // DSP2833x_I2C_defines.h file
    
    // Prototype statements for functions found within this file.
    void   I2CA_Init(void);
    Uint16 I2CA_WriteData(struct I2CMSG *msg);
    Uint16 I2CA_ReadData(struct I2CMSG *msg);
    interrupt void i2c_int1a_isr(void);
    void pass(void);
    void fail(void);
    
    #define I2C_SLAVE_ADDR        0x50
    #define I2C_NUMBYTES          14
    #define I2C_EEPROM_HIGH_ADDR  0x00
    #define I2C_EEPROM_LOW_ADDR   0x30
    
    // Global variables
    // Two bytes will be used for the outgoing address,
    // thus only setup 14 bytes maximum
    struct I2CMSG I2cMsgOut1={I2C_MSGSTAT_SEND_WITHSTOP,
                              I2C_SLAVE_ADDR,
                              I2C_NUMBYTES,
                              I2C_EEPROM_HIGH_ADDR,
                              I2C_EEPROM_LOW_ADDR,
                              0x12,                   // Msg Byte 1
                              0x34,                   // Msg Byte 2
                              0x56,                   // Msg Byte 3
                              0x78,                   // Msg Byte 4
                              0x9A,                   // Msg Byte 5
                              0xBC,                   // Msg Byte 6
                              0xDE,                   // Msg Byte 7
                              0xF0,                   // Msg Byte 8
                              0x11,                   // Msg Byte 9
                              0x10,                   // Msg Byte 10
                              0x11,                   // Msg Byte 11
                              0x12,                   // Msg Byte 12
                              0x13,                   // Msg Byte 13
                              0x12};                   // Msg Byte 14
    
    
    
    struct I2CMSG I2cMsgIn1={ I2C_MSGSTAT_SEND_NOSTOP,
                              I2C_SLAVE_ADDR,
                              I2C_NUMBYTES,
                              I2C_EEPROM_HIGH_ADDR,
                              I2C_EEPROM_LOW_ADDR};
    
    struct I2CMSG *CurrentMsgPtr;				// Used in interrupts
    Uint16 PassCount;
    Uint16 FailCount;
    Uint16 WriteFaultIndex = 0;
    
    
    
    void main(void)
     {
       Uint16 Error;
       Uint16 i;
    
       CurrentMsgPtr = &I2cMsgOut1;
    
    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the DSP2833x_SysCtrl.c file.
       InitSysCtrl();
    
    
    // Step 2. Initalize GPIO:
    // This example function is found in the DSP2833x_Gpio.c file and
    // illustrates how to set the GPIO to it's default state.
    // InitGpio();
    // Setup only the GP I/O only for I2C functionality
       InitI2CGpio();
    
    // Step 3. Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
       DINT;
    
    // Initialize PIE control registers to their default state.
    // The default state is all PIE interrupts disabled and flags
    // are cleared.
    // This function is found in the DSP2833x_PieCtrl.c file.
       InitPieCtrl();
    
    // Disable CPU interrupts and clear all CPU interrupt flags:
       IER = 0x0000;
       IFR = 0x0000;
    
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This will populate the entire table, even if the interrupt
    // is not used in this example.  This is useful for debug purposes.
    // The shell ISR routines are found in DSP2833x_DefaultIsr.c.
    // This function is found in DSP2833x_PieVect.c.
       InitPieVectTable();
    
    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
       EALLOW;	// This is needed to write to EALLOW protected registers
       PieVectTable.I2CINT1A = &i2c_int1a_isr;
       EDIS;   // This is needed to disable write to EALLOW protected registers
    
    // Step 4. Initialize all the Device Peripherals:
    // This function is found in DSP2833x_InitPeripherals.c
    // InitPeripherals(); // Not required for this example
       I2CA_Init();
    
    // Step 5. User specific code
    
       // Clear Counters
       PassCount = 0;
       FailCount = 0;
    
       // Clear incoming message buffer
       for (i = 0; i < I2C_MAX_BUFFER_SIZE; i++)
       {
           I2cMsgIn1.MsgBuffer[i] = 0x0000;
           //I2cMsgOut1.MsgBuffer[i] =0x0000;
       }
    
    // Enable interrupts required for this example
    
    // Enable I2C interrupt 1 in the PIE: Group 8 interrupt 1
       PieCtrlRegs.PIEIER8.bit.INTx1 = 1;
    
    // Enable CPU INT8 which is connected to PIE group 8
       IER |= M_INT8;
       EINT;
    
       // Application loop
       for(;;)
       {
    
    	  //////////////////////////////////
          // Write data to EEPROM section //
          //////////////////////////////////
    
          // Check the outgoing message to see if it should be sent.
          // In this example it is initialized to send with a stop bit.
          if(I2cMsgOut1.MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP)
          {
             Error = I2CA_WriteData(&I2cMsgOut1);
             // If communication is correctly initiated, set msg status to busy
             // and update CurrentMsgPtr for the interrupt service routine.
             // Otherwise, do nothing and try again next loop. Once message is
             // initiated, the I2C interrupts will handle the rest. Search for
             // ICINTR1A_ISR in the i2c_eeprom_isr.c file.
             if (Error == I2C_SUCCESS)
             {
                CurrentMsgPtr = &I2cMsgOut1;
                I2cMsgOut1.MsgStatus = I2C_MSGSTAT_WRITE_BUSY;
             }
          }  // end of write section
    
          ///////////////////////////////////
          // Read data from EEPROM section //
          ///////////////////////////////////
    
          // Check outgoing message status. Bypass read section if status is
          // not inactive.
          if (I2cMsgOut1.MsgStatus == I2C_MSGSTAT_INACTIVE)
          {
             // Check incoming message status.
             if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)
             {
                // EEPROM address setup portion
                while(I2CA_ReadData(&I2cMsgIn1) != I2C_SUCCESS)
                {
                   // Maybe setup an attempt counter to break an infinite while
                   // loop. The EEPROM will send back a NACK while it is performing
                   // a write operation. Even though the write communique is
                   // complete at this point, the EEPROM could still be busy
                   // programming the data. Therefore, multiple attempts are
                   // necessary.
                }
                // Update current message pointer and message status
                CurrentMsgPtr = &I2cMsgIn1;
                I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY;
    
    
             }
    
             // Once message has progressed past setting up the internal address
             // of the EEPROM, send a restart to read the data bytes from the
             // EEPROM. Complete the communique with a stop bit. MsgStatus is
             // updated in the interrupt service routine.
             else if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_RESTART)
             {
                // Read data portion
                while(I2CA_ReadData(&I2cMsgIn1) != I2C_SUCCESS)
                {
                   // Maybe setup an attempt counter to break an infinite while
                   // loop.
                }
                // Update current message pointer and message status
                CurrentMsgPtr = &I2cMsgIn1;
                I2cMsgIn1.MsgStatus = I2C_MSGSTAT_READ_BUSY;
                WriteFaultIndex++;
                               if(WriteFaultIndex >= 500)
                                   {
                              	   	   asm("   ESTOP0");
                              	   	   // WriteFaultIndex = 500;
                                   }
    
                I2cMsgIn1.MemoryLowAddr+= 14;
    
                   		   	   if (I2cMsgIn1.MemoryLowAddr>= 128)
                       		   	   {
                       		   	      I2cMsgIn1.MemoryHighAddr++;
                       		   	      I2cMsgIn1.MemoryLowAddr %= 128;
                      		   	   }
                   		   	   I2cMsgOut1.MemoryHighAddr = I2cMsgIn1.MemoryHighAddr;
                   		   	   I2cMsgOut1.MemoryLowAddr = I2cMsgIn1.MemoryLowAddr;
             }
    
          }  // end of read section
    
    
    
       }   // end of for(;;)
    }   // end of main
    
    
    void I2CA_Init(void)
    {
       // Initialize I2C
       I2caRegs.I2CSAR = 0x0050;		// Slave address - EEPROM control code
    
       #if (CPU_FRQ_150MHZ)             // Default - For 150MHz SYSCLKOUT
            I2caRegs.I2CPSC.all = 14;   // Prescaler - need 7-12 Mhz on module clk (150/15 = 10MHz)
       #endif
       #if (CPU_FRQ_100MHZ)             // For 100 MHz SYSCLKOUT
         I2caRegs.I2CPSC.all = 9;	    // Prescaler - need 7-12 Mhz on module clk (100/10 = 10MHz)
       #endif
    
       I2caRegs.I2CCLKL = 10;			// NOTE: must be non zero
       I2caRegs.I2CCLKH = 5;			// NOTE: must be non zero
       I2caRegs.I2CIER.all = 0x24;		// Enable SCD & ARDY interrupts
    
       I2caRegs.I2CMDR.all = 0x0020;	// Take I2C out of reset
       									// Stop I2C when suspended
    
       I2caRegs.I2CFFTX.all = 0x6000;	// Enable FIFO mode and TXFIFO
       I2caRegs.I2CFFRX.all = 0x2040;	// Enable RXFIFO, clear RXFFINT,
    
       return;
    }
    
    
    Uint16 I2CA_WriteData(struct I2CMSG *msg)
    {
       Uint16 i;
    
       // Wait until the STP bit is cleared from any previous master communication.
       // Clearing of this bit by the module is delayed until after the SCD bit is
       // set. If this bit is not checked prior to initiating a new message, the
       // I2C could get confused.
       if (I2caRegs.I2CMDR.bit.STP == 1)
       {
          return I2C_STP_NOT_READY_ERROR;
       }
    
       // Setup slave address
       I2caRegs.I2CSAR = msg->SlaveAddress;
    
       // Check if bus busy
       if (I2caRegs.I2CSTR.bit.BB == 1)
       {
          return I2C_BUS_BUSY_ERROR;
       }
    
       // Setup number of bytes to send
       // MsgBuffer + Address
       I2caRegs.I2CCNT = msg->NumOfBytes+2;
    
    
             // I2cMsgOut1.MemoryHighAddr = 0x00E0;
             // I2cMsgOut1.MemoryLowAddr =  0x0030;
    
    
       // Setup data to send
       I2caRegs.I2CDXR = msg->MemoryHighAddr;
       I2caRegs.I2CDXR = msg->MemoryLowAddr;
    // for (i=0; i<msg->NumOfBytes-2; i++)
       for (i=0; i<msg->NumOfBytes; i++)
    
       {
          I2caRegs.I2CDXR = *(msg->MsgBuffer+i);
       }
    
       // Send start as master transmitter
       I2caRegs.I2CMDR.all = 0x6E20;
    
       return I2C_SUCCESS;
    }
    
    
    Uint16 I2CA_ReadData(struct I2CMSG *msg)
    {
       // Wait until the STP bit is cleared from any previous master communication.
       // Clearing of this bit by the module is delayed until after the SCD bit is
       // set. If this bit is not checked prior to initiating a new message, the
       // I2C could get confused.
       if (I2caRegs.I2CMDR.bit.STP == 1)
       {
          return I2C_STP_NOT_READY_ERROR;
       }
    
       I2caRegs.I2CSAR = msg->SlaveAddress;
    
       if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)
       {
          // Check if bus busy
          if (I2caRegs.I2CSTR.bit.BB == 1)
          {
             return I2C_BUS_BUSY_ERROR;
          }
          I2caRegs.I2CCNT = 2;
    
    
    
          I2caRegs.I2CDXR = msg->MemoryHighAddr;
          I2caRegs.I2CDXR = msg->MemoryLowAddr;
          I2caRegs.I2CMDR.all = 0x2620;			// Send data to setup EEPROM address
       }
       else if(msg->MsgStatus == I2C_MSGSTAT_RESTART)
       {
          I2caRegs.I2CCNT = msg->NumOfBytes;	// Setup how many bytes to expect
          I2caRegs.I2CMDR.all = 0x2C20;			// originally 0x2C20. Send restart as master receiver
       }
    
    
       return I2C_SUCCESS;
    }
    
    interrupt void i2c_int1a_isr(void)     // I2C-A
    {
       Uint16 IntSource, i;
    
       // Read interrupt source
       IntSource = I2caRegs.I2CISRC.all;
    
       if (IntSource ==  I2C_NO_ISRC)
       {
           IntSource = I2C_NO_ISRC;
       }
       else if (IntSource == I2C_NACK_ISRC)
       {
          I2caRegs.I2CMDR.bit.STP = 1;
          I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT;
       }
    
       // Interrupt source = stop condition detected
       else if(IntSource == I2C_SCD_ISRC)
       {
          // If completed message was writing data, reset msg to inactive state
          if (CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_WRITE_BUSY)
          {
             CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;
          }
          else
          {
             // If a message receives a NACK during the address setup portion of the
             // EEPROM read, the code further below included in the register access ready
             // interrupt source code will generate a stop condition. After the stop
             // condition is received (here), set the message status to try again.
             // User may want to limit the number of retries before generating an error.
             if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
             {
                CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP;
             }
             // If completed message was reading EEPROM data, reset msg to inactive state
             // and read data from FIFO.
             else if (CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_READ_BUSY)
             {
                CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;
                for(i=0; i < I2C_NUMBYTES; i++)
                {
                  CurrentMsgPtr->MsgBuffer[i] = I2caRegs.I2CDRR;
                }
             {
             // Check recieved data
             for(i=0; i < I2C_NUMBYTES; i++)
             {
                if(I2cMsgIn1.MsgBuffer[i] == I2cMsgOut1.MsgBuffer[i])
                {
                    PassCount++;
                }
                else
                {
                    FailCount++;
                }
             }
             if(PassCount == I2C_NUMBYTES)
             {
                pass();
             }
             else
             {
                fail();
             }
    
    
          }
    
        }
          }
       }  // end of stop condition detected
    
       // Interrupt source = Register Access Ready
       // This interrupt is used to determine when the EEPROM address setup portion of the
       // read data communication is complete. Since no stop bit is commanded, this flag
       // tells us when the message has been sent instead of the SCD flag. If a NACK is
       // received, clear the NACK bit and command a stop. Otherwise, move on to the read
       // data portion of the communication.
       else if(IntSource == I2C_ARDY_ISRC) //originally I2C_ARDY_ISRC
       {
          if(I2caRegs.I2CSTR.bit.NACK == 1)
          {
             I2caRegs.I2CMDR.bit.STP = 1;
             I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT;
          }
          else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
          {
             CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_RESTART;
          }
       }  // end of register access ready
    
       else
       {
          // Generate some error due to invalid interrupt source
          asm("   ESTOP0");
       }
    
       // Enable future I2C (PIE Group 8) interrupts
       PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;
    }
    
    void pass()
    {
    //    asm("   ESTOP0");
    //    for(;;);
    }
    
    void fail()
    {
    //    asm("   ESTOP0");
    //    for(;;);
    }
    
    
    //===========================================================================
    // No more.
    //===========================================================================
    

  • Right after updating the address, You need to change I2cMsgOut1.MsgStatus and I2cMsgIn1.MsgStatus to there initial values, i.e. I2cMsgOut1.MsgStatus = I2C_MSGSTAT_SEND_WITHSTOP and I2cMsgIn1.MsgStatus I2C_MSGSTAT_SEND_NOSTOP..

  • Steven,

    I added the status update code. Now the code stays in an endless loop with WriteFaultIndex = 2. The error code returned from the Write()  is 0x5555 which is I2C_STP_NOT_READY_ERROR.

    I am going to put in a for-loop after the address update to see if a delay between reading and writing will allow the i2c module to clear the stp bit.

    Any other ideas?

    -Chuck

  • Did it write and read correctly for WriteFaultIndex = 1?  Before testing again, change the Ouput Values, so you are not just reading the previously written ones.

    Take a look at the following: http://e2e.ti.com/support/microcontrollers/c2000/f/171/p/267248/939049.aspx#939049

    Also, puts some break points to see if you are getting a NAK.

    Stephen

     

  • Stephen,

    Here is what I have so far:

    1. The code gets stuck in an endless loop with WriteFaultIndex = 2.

    2. I2CSTR register = 0x3C08 which indicates bit 13 of I2CSTR is set, i.e. NACK sent.

    3. I2cMsgIn1.MsgBuffer[x] all equal 0x0000, so it appears no data is being read from the eeprom into the buffer.

    4. I2CFFTX = 0x6E80. This shows enabled TX FIFO operation, an TX FIFO interrupt condition has occurred and there is 1110 bytes in FIFO.

    5. I2CFFRX = 0x3080. Rx FIFO enabled with 16 bytes in Rx FIFO and interrupt condition has occurred.

    Attached is the current version of my code:

    //###########################################################################
    //
    // FILE:    modified_Example_2833xI2c_eeprom.c - modified by Chuck Jackel - June 6, 2013
    //
    // TITLE:   DSP2833x I2C EEPROM Example
    //
    // ASSUMPTIONS:
    //
    //    This program requires the DSP2833x header files.
    //
    //    This program requires an external I2C EEPROM connected to
    //    the I2C bus at address 0x50.
    //
    //    As supplied, this project is configured for "boot to SARAM"
    //    operation.  The 2833x Boot Mode table is shown below.
    //    For information on configuring the boot mode of an eZdsp,
    //    please refer to the documentation included with the eZdsp,
    //
    //       $Boot_Table:
    //
    //         GPIO87   GPIO86     GPIO85   GPIO84
    //          XA15     XA14       XA13     XA12
    //           PU       PU         PU       PU
    //        ==========================================
    //            1        1          1        1    Jump to Flash
    //            1        1          1        0    SCI-A boot
    //            1        1          0        1    SPI-A boot
    //            1        1          0        0    I2C-A boot
    //            1        0          1        1    eCAN-A boot
    //            1        0          1        0    McBSP-A boot
    //            1        0          0        1    Jump to XINTF x16
    //            1        0          0        0    Jump to XINTF x32
    //            0        1          1        1    Jump to OTP
    //            0        1          1        0    Parallel GPIO I/O boot
    //            0        1          0        1    Parallel XINTF boot
    //            0        1          0        0    Jump to SARAM	    <- "boot to SARAM"
    //            0        0          1        1    Branch to check boot mode
    //            0        0          1        0    Boot to flash, bypass ADC cal
    //            0        0          0        1    Boot to SARAM, bypass ADC cal
    //            0        0          0        0    Boot to SCI-A, bypass ADC cal
    //                                              Boot_Table_End$
    //
    // DESCRIPTION:
    //
    //    This program will write 1-14 words to EEPROM and read them back.
    //    The data written and the EEPROM address written to are contained
    //    in the message structure, I2cMsgOut1. The data read back will be
    //    contained in the message structure I2cMsgIn1.
    //
    //    This program will work with the on-board I2C EEPROM supplied on
    //    the F2833x eZdsp.
    //
    //
    //###########################################################################
    // Original Author: D.F.
    //
    // $TI Release: 2833x/2823x Header Files and Peripheral Examples V133 $
    // $Release Date: June 8, 2012 $
    //###########################################################################
    
    
    #include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
    
    // Note: I2C Macros used in this example can be found in the
    // DSP2833x_I2C_defines.h file
    
    // Prototype statements for functions found within this file.
    void   I2CA_Init(void);
    Uint16 I2CA_WriteData(struct I2CMSG *msg);
    Uint16 I2CA_ReadData(struct I2CMSG *msg);
    interrupt void i2c_int1a_isr(void);
    void pass(void);
    void fail(void);
    
    #define I2C_SLAVE_ADDR        0x50
    #define I2C_NUMBYTES          14
    #define I2C_EEPROM_HIGH_ADDR  0x00
    #define I2C_EEPROM_LOW_ADDR   0x30
    
    // Global variables
    // Two bytes will be used for the outgoing address,
    // thus only setup 14 bytes maximum
    struct I2CMSG I2cMsgOut1={I2C_MSGSTAT_SEND_WITHSTOP,
                              I2C_SLAVE_ADDR,
                              I2C_NUMBYTES,
                              I2C_EEPROM_HIGH_ADDR,
                              I2C_EEPROM_LOW_ADDR,
                              0x12,                   // Msg Byte 1
                              0x34,                   // Msg Byte 2
                              0x56,                   // Msg Byte 3
                              0x78,                   // Msg Byte 4
                              0x9A,                   // Msg Byte 5
                              0xBC,                   // Msg Byte 6
                              0xDE,                   // Msg Byte 7
                              0xF0,                   // Msg Byte 8
                              0x11,                   // Msg Byte 9
                              0x10,                   // Msg Byte 10
                              0x11,                   // Msg Byte 11
                              0x12,                   // Msg Byte 12
                              0x13,                   // Msg Byte 13
                              0x12};                   // Msg Byte 14
    
    //                          0x11,                   // Msg Byte 1
    //                          0x22,                   // Msg Byte 2
    //                          0x33,                   // Msg Byte 3
    //                          0x44,                   // Msg Byte 4
    //                          0x55,                   // Msg Byte 5
    //                          0x66,                   // Msg Byte 6
    //                          0x77,                   // Msg Byte 7
    //                          0x88,                   // Msg Byte 8
    //                          0x99,                   // Msg Byte 9
    //                          0x56,                   // Msg Byte 10
    //                          0x67,                   // Msg Byte 11
    //                          0x78,                   // Msg Byte 12
    //                          0x89,                   // Msg Byte 13
    //                          0x90};                  // Msg Byte 14
    
    
    
    
    
    struct I2CMSG I2cMsgIn1={ I2C_MSGSTAT_SEND_NOSTOP,
                              I2C_SLAVE_ADDR,
                              I2C_NUMBYTES,
                              I2C_EEPROM_HIGH_ADDR,
                              I2C_EEPROM_LOW_ADDR};
    
    struct I2CMSG *CurrentMsgPtr;				// Used in interrupts
    Uint16 PassCount;
    Uint16 FailCount;
    Uint16 WriteFaultIndex = 0;
    
    
    
    void main(void)
     {
       Uint16 Error;
       Uint16 i;
    
       CurrentMsgPtr = &I2cMsgOut1;
    
    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the DSP2833x_SysCtrl.c file.
       InitSysCtrl();
    
    
    // Step 2. Initalize GPIO:
    // This example function is found in the DSP2833x_Gpio.c file and
    // illustrates how to set the GPIO to it's default state.
    // InitGpio();
    // Setup only the GP I/O only for I2C functionality
       InitI2CGpio();
    
    // Step 3. Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
       DINT;
    
    // Initialize PIE control registers to their default state.
    // The default state is all PIE interrupts disabled and flags
    // are cleared.
    // This function is found in the DSP2833x_PieCtrl.c file.
       InitPieCtrl();
    
    // Disable CPU interrupts and clear all CPU interrupt flags:
       IER = 0x0000;
       IFR = 0x0000;
    
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This will populate the entire table, even if the interrupt
    // is not used in this example.  This is useful for debug purposes.
    // The shell ISR routines are found in DSP2833x_DefaultIsr.c.
    // This function is found in DSP2833x_PieVect.c.
       InitPieVectTable();
    
    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
       EALLOW;	// This is needed to write to EALLOW protected registers
       PieVectTable.I2CINT1A = &i2c_int1a_isr;
       EDIS;   // This is needed to disable write to EALLOW protected registers
    
    // Step 4. Initialize all the Device Peripherals:
    // This function is found in DSP2833x_InitPeripherals.c
    // InitPeripherals(); // Not required for this example
       I2CA_Init();
    
    // Step 5. User specific code
    
       // Clear Counters
       PassCount = 0;
       FailCount = 0;
    
       // Clear incoming message buffer
       for (i = 0; i < I2C_MAX_BUFFER_SIZE; i++)
       {
           I2cMsgIn1.MsgBuffer[i] = 0x0000;
           //I2cMsgOut1.MsgBuffer[i] =0x0000;
       }
    
    // Enable interrupts required for this example
    
    // Enable I2C interrupt 1 in the PIE: Group 8 interrupt 1
       PieCtrlRegs.PIEIER8.bit.INTx1 = 1;
    
    // Enable CPU INT8 which is connected to PIE group 8
       IER |= M_INT8;
       EINT;
    
       // Application loop
       for(;;)
       {
    
    	  //////////////////////////////////
          // Write data to EEPROM section //
          //////////////////////////////////
    
          // Check the outgoing message to see if it should be sent.
          // In this example it is initialized to send with a stop bit.
          if(I2cMsgOut1.MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP)
          {
             Error = I2CA_WriteData(&I2cMsgOut1);
             // If communication is correctly initiated, set msg status to busy
             // and update CurrentMsgPtr for the interrupt service routine.
             // Otherwise, do nothing and try again next loop. Once message is
             // initiated, the I2C interrupts will handle the rest. Search for
             // ICINTR1A_ISR in the i2c_eeprom_isr.c file.
             if (Error == I2C_SUCCESS)
             {
                CurrentMsgPtr = &I2cMsgOut1;
                I2cMsgOut1.MsgStatus = I2C_MSGSTAT_WRITE_BUSY;
             }
          }  // end of write section
    
          ///////////////////////////////////
          // Read data from EEPROM section //
          ///////////////////////////////////
    
          // Check outgoing message status. Bypass read section if status is
          // not inactive.
          if (I2cMsgOut1.MsgStatus == I2C_MSGSTAT_INACTIVE)
          {
             // Check incoming message status.
             if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)
             {
                // EEPROM address setup portion
                while(I2CA_ReadData(&I2cMsgIn1) != I2C_SUCCESS)
                {
                   // Maybe setup an attempt counter to break an infinite while
                   // loop. The EEPROM will send back a NACK while it is performing
                   // a write operation. Even though the write communique is
                   // complete at this point, the EEPROM could still be busy
                   // programming the data. Therefore, multiple attempts are
                   // necessary.
                }
                // Update current message pointer and message status
                CurrentMsgPtr = &I2cMsgIn1;
                I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY;
    
    
             }
    
             // Once message has progressed past setting up the internal address
             // of the EEPROM, send a restart to read the data bytes from the
             // EEPROM. Complete the communique with a stop bit. MsgStatus is
             // updated in the interrupt service routine.
             else if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_RESTART)
             {
                // Read data portion
                while(I2CA_ReadData(&I2cMsgIn1) != I2C_SUCCESS)
                {
                   // Maybe setup an attempt counter to break an infinite while
                   // loop.
                }
                // Update current message pointer and message status
                CurrentMsgPtr = &I2cMsgIn1;
                I2cMsgIn1.MsgStatus = I2C_MSGSTAT_READ_BUSY;
                WriteFaultIndex++;
                               if(WriteFaultIndex >= 500)
                                   {
                              	   	   asm("   ESTOP0");
                              	   	   // WriteFaultIndex = 500;
                                   }
    
                I2cMsgIn1.MemoryLowAddr+= 14;
    
                   		   	   if (I2cMsgIn1.MemoryLowAddr>= 128)
                       		   	   {
                       		   	      I2cMsgIn1.MemoryHighAddr++;
                       		   	      I2cMsgIn1.MemoryLowAddr %= 128;
                      		   	   }
                   		   	   I2cMsgOut1.MemoryHighAddr = I2cMsgIn1.MemoryHighAddr;
                   		   	   I2cMsgOut1.MemoryLowAddr = I2cMsgIn1.MemoryLowAddr;
    
                   		   	   I2cMsgOut1.MsgStatus = I2C_MSGSTAT_SEND_WITHSTOP;
                   		   	   I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP;
    
             }
    
          }  // end of read section
    
    
    
       }   // end of for(;;)
    }   // end of main
    
    
    void I2CA_Init(void)
    {
       // Initialize I2C
       I2caRegs.I2CSAR = 0x0050;		// Slave address - EEPROM control code
    
       #if (CPU_FRQ_150MHZ)             // Default - For 150MHz SYSCLKOUT
            I2caRegs.I2CPSC.all = 14;   // Prescaler - need 7-12 Mhz on module clk (150/15 = 10MHz)
       #endif
       #if (CPU_FRQ_100MHZ)             // For 100 MHz SYSCLKOUT
         I2caRegs.I2CPSC.all = 9;	    // Prescaler - need 7-12 Mhz on module clk (100/10 = 10MHz)
       #endif
    
       I2caRegs.I2CCLKL = 10;			// NOTE: must be non zero
       I2caRegs.I2CCLKH = 5;			// NOTE: must be non zero
       I2caRegs.I2CIER.all = 0x24;		// Enable SCD & ARDY interrupts
    
       I2caRegs.I2CMDR.all = 0x0020;	// Take I2C out of reset
       									// Stop I2C when suspended
    
       I2caRegs.I2CFFTX.all = 0x6000;	// Enable FIFO mode and TXFIFO
       I2caRegs.I2CFFRX.all = 0x2040;	// Enable RXFIFO, clear RXFFINT,
    
       return;
    }
    
    
    Uint16 I2CA_WriteData(struct I2CMSG *msg)
    {
       Uint16 i;
    
       // Wait until the STP bit is cleared from any previous master communication.
       // Clearing of this bit by the module is delayed until after the SCD bit is
       // set. If this bit is not checked prior to initiating a new message, the
       // I2C could get confused.
       if (I2caRegs.I2CMDR.bit.STP == 1)
       {
          return I2C_STP_NOT_READY_ERROR;
       }
    
       // Setup slave address
       I2caRegs.I2CSAR = msg->SlaveAddress;
    
       // Check if bus busy
       if (I2caRegs.I2CSTR.bit.BB == 1)
       {
          return I2C_BUS_BUSY_ERROR;
       }
    
       // Setup number of bytes to send
       // MsgBuffer + Address
       I2caRegs.I2CCNT = msg->NumOfBytes+2;
    
    
       // Setup data to send
       I2caRegs.I2CDXR = msg->MemoryHighAddr;
       I2caRegs.I2CDXR = msg->MemoryLowAddr;
    // for (i=0; i<msg->NumOfBytes-2; i++)
       for (i=0; i<msg->NumOfBytes; i++)
    
       {
          I2caRegs.I2CDXR = *(msg->MsgBuffer+i);
       }
    
       // Send start as master transmitter
       I2caRegs.I2CMDR.all = 0x6E20;
    
       return I2C_SUCCESS;
    }
    
    
    Uint16 I2CA_ReadData(struct I2CMSG *msg)
    {
       // Wait until the STP bit is cleared from any previous master communication.
       // Clearing of this bit by the module is delayed until after the SCD bit is
       // set. If this bit is not checked prior to initiating a new message, the
       // I2C could get confused.
       if (I2caRegs.I2CMDR.bit.STP == 1)
       {
          return I2C_STP_NOT_READY_ERROR;
       }
    
       I2caRegs.I2CSAR = msg->SlaveAddress;
    
       if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)
       {
          // Check if bus busy
          if (I2caRegs.I2CSTR.bit.BB == 1)
          {
             return I2C_BUS_BUSY_ERROR;
          }
          I2caRegs.I2CCNT = 2;
    
    
    
          I2caRegs.I2CDXR = msg->MemoryHighAddr;
          I2caRegs.I2CDXR = msg->MemoryLowAddr;
          I2caRegs.I2CMDR.all = 0x2620;			// orig 0x2620. Send data to setup EEPROM address
       }
       else if(msg->MsgStatus == I2C_MSGSTAT_RESTART)
       {
          I2caRegs.I2CCNT = msg->NumOfBytes;	// Setup how many bytes to expect
          I2caRegs.I2CMDR.all = 0x2C20;			// originally 0x2C20. Send restart as master receiver
       }
    
    
       return I2C_SUCCESS;
    }
    
    interrupt void i2c_int1a_isr(void)     // I2C-A
    {
       Uint16 IntSource, i;
    
       // Read interrupt source
       IntSource = I2caRegs.I2CISRC.all;
    
       if (IntSource ==  I2C_NO_ISRC)
       {
           IntSource = I2C_NO_ISRC;
       }
       else if (IntSource == I2C_NACK_ISRC)
       {
          I2caRegs.I2CMDR.bit.STP = 1;
          I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT;
       }
    
       // Interrupt source = stop condition detected
       else if(IntSource == I2C_SCD_ISRC)
       {
          // If completed message was writing data, reset msg to inactive state
          if (CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_WRITE_BUSY)
          {
             CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;
          }
          else
          {
             // If a message receives a NACK during the address setup portion of the
             // EEPROM read, the code further below included in the register access ready
             // interrupt source code will generate a stop condition. After the stop
             // condition is received (here), set the message status to try again.
             // User may want to limit the number of retries before generating an error.
             if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
             {
                CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP;
             }
             // If completed message was reading EEPROM data, reset msg to inactive state
             // and read data from FIFO.
             else if (CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_READ_BUSY)
             {
                CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;
                for(i=0; i < I2C_NUMBYTES; i++)
                {
                  CurrentMsgPtr->MsgBuffer[i] = I2caRegs.I2CDRR;
                }
             {
             // Check recieved data
             for(i=0; i < I2C_NUMBYTES; i++)
             {
                if(I2cMsgIn1.MsgBuffer[i] == I2cMsgOut1.MsgBuffer[i])
                {
                    PassCount++;
                }
                else
                {
                    FailCount++;
                }
             }
             if(PassCount == I2C_NUMBYTES)
             {
                pass();
             }
             else
             {
                fail();
             }
    
    
          }
    
        }
          }
       }  // end of stop condition detected
    
       // Interrupt source = Register Access Ready
       // This interrupt is used to determine when the EEPROM address setup portion of the
       // read data communication is complete. Since no stop bit is commanded, this flag
       // tells us when the message has been sent instead of the SCD flag. If a NACK is
       // received, clear the NACK bit and command a stop. Otherwise, move on to the read
       // data portion of the communication.
       else if(IntSource == I2C_ARDY_ISRC) //originally I2C_ARDY_ISRC
       {
          if(I2caRegs.I2CSTR.bit.NACK == 1)
          {
             I2caRegs.I2CMDR.bit.STP = 1;
             I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT;
          }
          else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
          {
             CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_RESTART;
          }
       }  // end of register access ready
    
       else
       {
          // Generate some error due to invalid interrupt source
          asm("   ESTOP0");
       }
    
       // Enable future I2C (PIE Group 8) interrupts
       PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;
    }
    
    void pass()
    {
    //    asm("   ESTOP0");
    //    for(;;);
    }
    
    void fail()
    {
    //    asm("   ESTOP0");
    //    for(;;);
    }
    
    
    //===========================================================================
    // No more.
    //===========================================================================
    

  • Woops. The Addresses and WriteFaultIndex counter are being update before the read is complete. 

    Move the code the updates the addresses and writeFault Counter to the location right after

             if(PassCount == I2C_NUMBYTES)

             {

                  pass();

              }

              else

             {

                 fail();

              }

     

    In other words, move this code:

                WriteFaultIndex++;

                               if(WriteFaultIndex >= 500)

                                   {

                                    asm("   ESTOP0");

                                    // WriteFaultIndex = 500;

                                   }

                I2cMsgIn1.MemoryLowAddr+= 14;

                         if (I2cMsgIn1.MemoryLowAddr>= 128)

                             {

                                I2cMsgIn1.MemoryHighAddr++;

                                I2cMsgIn1.MemoryLowAddr %= 128;

                            }

                         I2cMsgOut1.MemoryHighAddr = I2cMsgIn1.MemoryHighAddr;

                         I2cMsgOut1.MemoryLowAddr = I2cMsgIn1.MemoryLowAddr;

                         I2cMsgOut1.MsgStatus = I2C_MSGSTAT_SEND_WITHSTOP;

                         I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP;

     

  • Stephen,

    The code stayed in an endless loop with the above modification at WriteFaultIndex = 3.

    When I added this code at the beginning of the Write(), the code functioned as desired and wrote and read 500 values:

    for (i = 0; i < I2C_MAX_BUFFER_SIZE; i++)

    {

    I2cMsgOut1.

    MsgBuffer[i] = WriteFaultIndex;

    }

    Thank you for your help!

    -Chuck

  •  I am not sure why that's working -  I really haven't analyzed the code that much.

    It might be a good idea to set a breakpoint at several locations with a breakpoint property condition equal to WriteFaultIndex == 3 (or may WriteFaultIndex == 2 to see what happens beforeWriteFaultIndex  equals 3) to see what's happening.

    You could also increment the data each time through the loop to see if its actually writing data each time and not just reading previously stored data.   

    Stephen