I2C EEPROM Interface

Discussion to talk about software related topics only.
Post Reply
khoney
Posts: 125
Joined: Fri Sep 11, 2009 12:43 pm

I2C EEPROM Interface

Post by khoney »

I've been trying to interface to a Microchip I2C Serial EEPROM. Surprisingly, I was unable to find any examples, forum posts, etc. related to accessing one.

I've been able to successfully write and read back to the EEPROM (according to my logic analyzer), but the data I get back on a read is incorrect - for the first byte of the EEPROM I'm getting the address/control byte, and fo rthe second byte read I get the first data byte.

The following code is used for the read

Code: Select all

#define EEPROM_ADDR 0x50
typedef struct _EEPROM_CFG {
   BYTE unit_id;
   BYTE volume;
} EEPROM_CFG;

static EEPROM_CFG eeprom_cfg;


void ReadEEPROM(void)
{
PBYTE eeprom_ptr;
int i;

eeprom_ptr = (PBYTE) &eeprom_cfg;

I2CInit();
I2CStart(EEPROM_ADDR, I2C_START_WRITE, I2C_RX_TX_TIMEOUT);
I2CSend (0x00); // Send EEPROM address MSB
I2CSend (0x00); // Send EEPROM address LSB
I2CRestart (EEPROM_ADDR, I2C_START_READ, I2C_RX_TX_TIMEOUT); // Send restart to prevent stop bit

for (i=0; i < sizeof (eeprom_cfg); i++) {
   I2CRead (eeprom_ptr++);
}
I2CStop();
}  
The logic analyzer shows a write of EEPROM address 0, followed by a read of the two values I had previously written to EEPROM (0x05 and 0x07). However, in my code, the values stored in my eeprom_cfg structure are 0xA1 for eeprom_cfg.unit_id and 0x05 for eeprom_cfg.volume.

Does anyone see anything wrong with this read sequence? Again, according to my protocol analyzer, the proper data is being returned.
khoney
Posts: 125
Joined: Fri Sep 11, 2009 12:43 pm

Re: I2C EEPROM Interface

Post by khoney »

The attached image shows the EEPROM sequential read sequence. Shows the setting of the EEPROM start address to 0, followed by a sequential read of two data bytes.
Attachments
scope_1.png
scope_1.png (32.38 KiB) Viewed 8852 times
User avatar
lgitlitz
Posts: 331
Joined: Wed Apr 23, 2008 11:43 am
Location: San Diego, CA
Contact:

Re: I2C EEPROM Interface

Post by lgitlitz »

Is it possible you are somehow reading to the wrong addresses. The first byte you read is garbage but the second one you read is what you expect the first one to be. I would check the byte immediately after the second byte to see if that is the 0x07. If so you have a pointer problem. Also I do not believe that the compiler will guarantee data in a struct to be packed. It is possible that the compiler might put some dummy bytes in between the values so that your data is aligned and faster to access. If you are going to use a struct then you are much better off directly accessing the data rather then incrementing a pointer. If you want your struct to be guaranteed to be packed then you must use the following attribute in the struct definition "__attribute__( ( packed) )". Look at the configrecord struct definition in system.h for an example. I still suggest accessing each variable in the struct individually as with will make your code much easier to read.

Also you may want to try using the higher level I2C functions. These functions should make your code simpler. It will also more closely follow some details in the I2C specification such as NAKing the last byte to be read. Here is what is should look like for your code:

BYTE I2Cdata[10];
memset( I2Cdata, 0, 10 );

I2CInit();

// send two bytes and do not stop
if( I2CSendBuf( EEPROM_ADDR, I2Cdata, 2, false ) != I2C_MASTER_OK ) error

// Send restart to begin reading
if( I2CRestart (EEPROM_ADDR, I2C_START_READ ) != I2C_NEXT_READ_OK ) error

// read two bytes, this will end with a stop
if( I2CReadBuf( EEPROM_ADDR, I2Cdata, 2 ) != I2C_OK ) error

EEPROM_CFG.unit_id = I2Cdata[0]; EEPROM_CFG.volume = I2Cdata[1];
khoney
Posts: 125
Joined: Fri Sep 11, 2009 12:43 pm

Re: I2C EEPROM Interface

Post by khoney »

Larry,

The first byte is actually not garbage - it is the Address byte (50H<<1 + read bit). That was the last thing put in the i2c data register by the driver before the first read. So it's as if this value is being returned on the first read.
khoney
Posts: 125
Joined: Fri Sep 11, 2009 12:43 pm

Re: I2C EEPROM Interface

Post by khoney »

Larry,
I just tried your code example and it works. I then tried passing my original structure pointer as the destination for the last I2CReadBuf call instead of using the array. That also works. My command sequence must not be the equivalent of yours, but I don't know why. I suspect that for some reason my first I2CRead must be returning the last written value to the data register instead of actually reading a new value from the bus, and therefore everything gets off by one byte.

The protocol analyzer got yanked from me, so I can't see what the difference is in the signalling, if any.
jsampson
Posts: 3
Joined: Sat May 09, 2009 3:44 pm

Re: I2C EEPROM Interface

Post by jsampson »

khoney wrote:Larry,
I just tried your code example and it works. I then tried passing my original structure pointer as the destination for the last I2CReadBuf call instead of using the array. That also works. My command sequence must not be the equivalent of yours, but I don't know why. I suspect that for some reason my first I2CRead must be returning the last written value to the data register instead of actually reading a new value from the bus, and therefore everything gets off by one byte.

The protocol analyzer got yanked from me, so I can't see what the difference is in the signalling, if any.
Actually, now that someone mentions it, I had the same problem. I was using basic reads and writes. Rather than tracking it down I just did an extra read since the first byte was always "extra". Here is my (trimmed down) code if it helps to track down a problem. I was apparently trying to read back one byte but my comment says was I reading an extra byte to skip the first one.

This was with release Rel22_rc2.

Code: Select all

	switch(i2c_state) {
		case 0:
			s1 = I2CStart( SLAVE_OTHER, I2C_START_WRITE, 20 );
			s2 = I2CSend( 'B', 20 );
			I2CStop(10);
			i2c_state++;
			break;
		case 1:
         s3 = I2CStart( SLAVE_OTHER, I2C_START_READ, 20 );
		//	s3 = I2CRestart( SLAVE_OTHER, I2C_START_READ, 20 );
			s4 = I2CRead(&s6, 20); // Read an extra one since first byte is hosed
			I2C_SET_NO_ACK;
			s5 = I2CRead(&s8, 20);
			I2CStop(20);
			i2c_state = 0;
			break;
	}
khoney
Posts: 125
Joined: Fri Sep 11, 2009 12:43 pm

Re: I2C EEPROM Interface

Post by khoney »

That's exactly what I did as a workaround before Larry posted his version. I think our way of doing it should have worked, given the description of what each of the functions do.
User avatar
lgitlitz
Posts: 331
Joined: Wed Apr 23, 2008 11:43 am
Location: San Diego, CA
Contact:

Re: I2C EEPROM Interface

Post by lgitlitz »

There was a pretty major fix to this driver back in September 08 that may correct this issue. It looks like the first release with these changes was 23rc1.
khoney
Posts: 125
Joined: Fri Sep 11, 2009 12:43 pm

Re: I2C EEPROM Interface

Post by khoney »

I'm running 24RC2.
User avatar
lgitlitz
Posts: 331
Joined: Wed Apr 23, 2008 11:43 am
Location: San Diego, CA
Contact:

Re: I2C EEPROM Interface

Post by lgitlitz »

Actually, I see this problem. It should be fixed y the next release. Use the code I posted with the higher level functions, this will remain functionally the same. The i2cread functionality will change to what it should be.
Post Reply