PIC: PIC32MX564F128L
EEPROM: 24AA16
I've put together some code for the PIC, in C, to read & write to an external EEPROM, via I2C. When I use these methods to write a single byte, then read it back again for verification, it works. If I change the write location, it works, so I presume the addressing is working, and the byte I read back matches the write, so that appears to work too. All good so far!
I then extended the code to use the same routine 100 times, writing different bytes in adjacent locations. I.E. Write values 0 to 99 in Locations x to x + 99. I then proceeded to read back the 100 locations to verify the writes, and this is where it goes wrong.
It would appear, from various tests, that the write method performs all the writes in the same location, as the read method gets the last value (99) from the first location, and nothing (0xFF) from the other locations!
The scope shows that the clock is good, and the data line toggling, which I expected as the single write works.
Debug on the PIC shows that the addresses being used by the methods are sequential, so I'm a little stumped as to why all the writes are being performed in the same location! I can change this location, but it always just uses the first byte for all values.
Anyone know what could be wrong?
My code is here, and the entry point is testEeprom():
// ----------------------------------------------------------------------------
#include "eeprom.h"
//#define _PLIB_DISABLE_LEGACY
#include <plib.h>
//// ----------------------------------------------------------------------------
#define SYS_CLOCK (80000000L)
#define GetSystemClock() (SYS_CLOCK)
#define GetPeripheralClock() (SYS_CLOCK / 2)
#define GetInstructionClock() (SYS_CLOCK)
#define I2C_CLOCK_FREQ 100000
#define EEPROM_I2C_BUS I2C1
#define EEPROM_ADDRESS 0x50 // 0b1010000 Serial EEPROM address
#define EEPROM_STORAGE_LOCATION 0x0100
#define DATA_ARRAY_SIZE 100
// ----------------------------------------------------------------------------
UINT8 EEPROM_Data_Array[DATA_ARRAY_SIZE];
UINT8 EEPROM_Data_Array_RX[DATA_ARRAY_SIZE];
BOOL EEPROM_Success;
I2C_7_BIT_ADDRESS SlaveAddress;
// ----------------------------------------------------------------------------
void i2c_wait(unsigned int cnt)
{
while (--cnt)
{
Nop();
Nop();
} // while
}
// ----------------------------------------------------------------------------
BOOL StartTransfer(BOOL restart)
{
I2C_STATUS status;
// Send the Start (or Restart) signal
if (restart)
{
I2CRepeatStart(EEPROM_I2C_BUS);
}
else
{
// Wait for the bus to be idle, then start the transfer
while (!I2CBusIsIdle(EEPROM_I2C_BUS));
if (I2CStart(EEPROM_I2C_BUS) != I2C_SUCCESS)
{
debugTrace("I2C Error: Bus collision during transfer Start\r\n");
return FALSE;
}
}
// Wait for the signal to complete
do
{
status = I2CGetStatus(EEPROM_I2C_BUS);
}
while (!(status & I2C_START));
return TRUE;
}
// ----------------------------------------------------------------------------
BOOL TransmitOneByte(UINT8 data)
{
// Wait for the transmitter to be ready
while (!I2CTransmitterIsReady(EEPROM_I2C_BUS));
// Transmit the byte
if (I2CSendByte(EEPROM_I2C_BUS, data) == I2C_MASTER_BUS_COLLISION)
{
debugTrace("I2C Error: I2C Master Bus Collision\r\n");
return FALSE;
}
// Wait for the transmission to finish
while (!I2CTransmissionHasCompleted(EEPROM_I2C_BUS));
return TRUE;
}
// ----------------------------------------------------------------------------
void StopTransfer(void)
{
I2C_STATUS status;
// Send the Stop signal
I2CStop(EEPROM_I2C_BUS);
// Wait for the signal to complete
do
{
status = I2CGetStatus(EEPROM_I2C_BUS);
}
while (!(status & I2C_STOP));
}
// ----------------------------------------------------------------------------
void initIcd()
{
UINT32 actualClock;
EEPROM_Success = TRUE;
// Set the I2C baudrate
actualClock = I2CSetFrequency(EEPROM_I2C_BUS, GetPeripheralClock(), I2C_CLOCK_FREQ);
if (abs(actualClock - I2C_CLOCK_FREQ) > I2C_CLOCK_FREQ / 10)
{
debugTrace("Error: I2C1 clock frequency (%u) error exceeds 10%%.\r\n", (unsigned) actualClock);
}
// Enable the I2C bus
I2CEnable(EEPROM_I2C_BUS, TRUE);
}
// ----------------------------------------------------------------------------
// Send the data to EEPROM to program one location
// ----------------------------------------------------------------------------
void txIcd(unsigned int address, unsigned char value)
{
BOOL Acknowledged;
int Index;
UINT8 i2cData[4];
int DataSz;
EEPROM_Success = TRUE;
// Initialize the data buffer
I2C_FORMAT_7_BIT_ADDRESS(SlaveAddress, EEPROM_ADDRESS, I2C_WRITE);
i2cData[0] = SlaveAddress.byte;
i2cData[1] = address >> 8; // EEPROM location to program (high address byte)
i2cData[2] = address & 0xFF; // EEPROM location to program (low address byte)
i2cData[3] = value; // EEPROM location to program (low address byte)
DataSz = 4;
// Start the transfer to write data to the EEPROM
if (!StartTransfer(FALSE))
{
debugTrace("I2C Error: Can't Start Transfer TX (1)\r\n");
return;
}
// Transmit all header
Index = 0;
while (EEPROM_Success && (Index < DataSz))
{
// Transmit a byte
if (TransmitOneByte(i2cData[Index]))
{
// Advance to the next byte
Index++;
// Verify that the byte was acknowledged
if (!I2CByteWasAcknowledged(EEPROM_I2C_BUS))
{
debugTrace("I2C Error: Sent byte was not acknowledged (1)\r\n");
EEPROM_Success = FALSE;
}
}
else
{
EEPROM_Success = FALSE;
}
}
// End the transfer (hang here if an error occured)
StopTransfer();
if (!EEPROM_Success)
{
debugTrace("I2C Error: No Success on TX (1)\r\n");
return;
}
// Wait for EEPROM to complete write process, by polling the ack status.
Acknowledged = FALSE;
do
{
// Start the transfer to address the EEPROM
if (!StartTransfer(FALSE))
{
debugTrace("I2C Error: Can't Start Transfer TX (2)\r\n");
return;
}
// Transmit just the EEPROM's address
if (TransmitOneByte(SlaveAddress.byte))
{
// Check to see if the byte was acknowledged
Acknowledged = I2CByteWasAcknowledged(EEPROM_I2C_BUS);
}
else
{
EEPROM_Success = FALSE;
}
// End the transfer (stop here if an error occured)
StopTransfer();
if (!EEPROM_Success)
{
debugTrace("I2C Error: No Success on TX (2)\r\n");
return;
}
}
while (Acknowledged != TRUE);
}
// ----------------------------------------------------------------------------
// Read the data back from the EEPROM.
// ----------------------------------------------------------------------------
unsigned char rxIcd(unsigned int address)
{
UINT8 i2cbyte;
UINT8 i2cData[3];
int DataSz;
int Index;
EEPROM_Success = TRUE;
// Initialize the data buffer
I2C_FORMAT_7_BIT_ADDRESS(SlaveAddress, EEPROM_ADDRESS, I2C_WRITE);
i2cData[0] = SlaveAddress.byte;
i2cData[1] = address >> 8; // EEPROM location to program (high address byte)
i2cData[2] = address & 0xFF; // EEPROM location to program (low address byte)
DataSz = 3;
// Start the transfer to write data to the EEPROM
if (!StartTransfer(FALSE))
{
debugTrace("I2C Error: Can't Start Transfer TX (1)\r\n");
return;
}
// Transmit all header
Index = 0;
while (EEPROM_Success && (Index < DataSz))
{
// Transmit a byte
if (TransmitOneByte(i2cData[Index]))
{
// Advance to the next byte
Index++;
}
else
{
EEPROM_Success = FALSE;
}
// Verify that the byte was acknowledged
if (!I2CByteWasAcknowledged(EEPROM_I2C_BUS))
{
debugTrace("I2C Error: Sent byte was not acknowledged (1)\r\n");
EEPROM_Success = FALSE;
}
}
// Restart and send the EEPROM's internal address to switch to a read transfer
if (EEPROM_Success)
{
// Send a Repeated Started condition
if (!StartTransfer(TRUE))
{
debugTrace("I2C Error: Can't Start Transfer TX (4)\r\n");
return;
}
// Transmit the address with the READ bit set
I2C_FORMAT_7_BIT_ADDRESS(SlaveAddress, EEPROM_ADDRESS, I2C_READ);
if (TransmitOneByte(SlaveAddress.byte))
{
// Verify that the byte was acknowledged
if (!I2CByteWasAcknowledged(EEPROM_I2C_BUS))
{
debugTrace("I2C Error: Sent byte was not acknowledged (3)\r\n");
EEPROM_Success = FALSE;
}
}
else
{
EEPROM_Success = FALSE;
}
}
// Read the data from the desired address
if (EEPROM_Success)
{
if (I2CReceiverEnable(EEPROM_I2C_BUS, TRUE) == I2C_RECEIVE_OVERFLOW)
{
debugTrace("I2C Error: I2C Receive Overflow\r\n");
EEPROM_Success = FALSE;
}
else
{
while (!I2CReceivedDataIsAvailable(EEPROM_I2C_BUS));
i2cbyte = I2CGetByte(EEPROM_I2C_BUS);
}
}
// End the transfer (stop here if an error occured)
StopTransfer();
if (!EEPROM_Success)
{
debugTrace("I2C Error: No Success on TX (3)\r\n");
return;
}
return i2cbyte;
}
// ----------------------------------------------------------------------------
void testEeprom(void)
{
unsigned int i;
BOOL failed = FALSE;
unsigned char value;
// Create & Write 100 byte array
for (i = 0; i < DATA_ARRAY_SIZE; i++)
{
EEPROM_Data_Array[i] = i;
initIcd();
txIcd(EEPROM_STORAGE_LOCATION + i, EEPROM_Data_Array[i]);
StopTransfer();
I2CEnable(EEPROM_I2C_BUS, FALSE);
} // for i
// Read back & varify data against array
for (i = 0; i < DATA_ARRAY_SIZE; i++)
{
initIcd();
value = rxIcd(EEPROM_STORAGE_LOCATION + i);
if (EEPROM_Data_Array[i] != value)
{
failed = TRUE;
break;
}
StopTransfer();
I2CEnable(EEPROM_I2C_BUS, FALSE);
} // for i
if (failed == FALSE)
{
debugTrace("I2C SUCCESS\r\n");
}
else
{
debugTrace("I2C FAILED %d: %d != %d\r\n", i, value, EEPROM_Data_Array[i]);
}
while(1);
}
// ----------------------------------------------------------------------------