I am running a modified version of the example code Example_2833xI2C_eeprom to write then read 500 values to/from the eeprom via I2C module.
I am only able to write 125 values before the ReadData function gets stuck in a loop because the send no-stop code equals 0x0020 (command to send master trans
msg without stop bit).
The code doesn't stop on an error, it actually remains within the ReadData function in an endless loop.
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;
//
// /* increment low address byte */
// I2cMsgOut1.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;
}
} // 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;
}
// 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;
// I2cMsgIn1.MemoryHighAddr = 0x00E0;
// I2cMsgIn1.MemoryLowAddr = 0x0030;
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; // 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.
//===========================================================================