I2C - how to read/write EEPROM 27xx256

How is the correct way to describe and read the EEPROM 27xx256? We have 3 blocks on the I2C bus. Two of them (LM75 and RTC8564) I can read / write without problems. With the 27xx256, on the other hand, written and read data are always different. Have you any idea what I could change?

	// Initialize I2Cx, without affecting hardware registers
	i2c = Imx7I2c_Init(L"I2C1");
	if (i2c == NULL)
		printf("Error in I2c_Init()\r\n");
	// ====== BusScan ======
	i2cScan(i2c);
	// Open the i2c port
	Imx7I2c_Open(i2c);
	// Change configuration as required
	Imx7I2c_SetConfigInt(i2c, L"BitRateHz", 400000, StoreVolatile);		// Set I2C speed to 400KHz
	Imx7I2c_SetConfigInt(i2c, L"SlaveAddrSize", 7, StoreVolatile);		// Set 7 bit Slave address
	//#rl 0x48:LM75-3	Digital Temperature Sensor
	//#rl 0x50:LC256	SEEPROM 256kb(x8)
	//#rl 0x51:RTC8564	Real Time Clock 	
	Imx7I2c_SetConfigInt(i2c, L"SlaveAddr", 0x50, StoreVolatile);
	//I2C Write
	i = 0;	
	writebuf[i++] = 'T';
	writebuf[i++] = 'E';
	writebuf[i++] = 'S';
	writebuf[i++] = 'T';
	writebuf[i++] = '1';
	writebuf[i++] = '2';
	writebuf[i++] = '3';
	writebuf[i] = '4';
	// I2C Write EEPROM
	if (Imx7I2c_SetConfigInt(i2c, L"RegisterAddrSize", 16, StoreVolatile) == TRUE)		// 16bit Register address to send
	{
		Imx7I2c_SetConfigInt(i2c, L"RegisterAddr", 0, StoreVolatile);					// write to adress 0
		returnValue = Imx7I2c_Write(i2c, (DWORD*)writebuf, 8);							// write 8bytes
		if (returnValue != I2C_RW_FAILURE)
			printf("\nwrite to EEPROM: %d, %d, %d, %d, %d, %d, %d, %d  \r\n", writebuf[0], writebuf[1], writebuf[2], writebuf[3], writebuf[4], writebuf[5], writebuf[6], writebuf[7]);
	}
	// I2C Read EEPROM
	for (i = 0; i < 8; i++)
		readbuf[i] = 0;

	if (Imx7I2c_SetConfigInt(i2c, L"RegisterAddrSize", 0, StoreVolatile) == TRUE)		// No Register address to send
	//if (Imx7I2c_SetConfigInt(i2c, L"RegisterAddrSize", 16, StoreVolatile) == TRUE)		//  16bit Register address to send
	{
		Imx7I2c_SetConfigInt(i2c, L"RegisterAddr", 0, StoreVolatile);					// read from adress 0
		returnValue = Imx7I2c_Read(i2c, (DWORD*)readbuf, 8);							// read 8bytes
		if (returnValue != I2C_RW_FAILURE)
		{
			printf("\nread from EEPROM: %d, %d, %d, %d, %d, %d, %d, %d  \r\n", readbuf[0], readbuf[1], readbuf[2], readbuf[3], readbuf[4], readbuf[5], readbuf[6], readbuf[7]);
		}
	}
	// Close and deinit I2C port
	Imx7I2c_Close(i2c);
	Imx7I2c_Deinit(i2c);
  • How do you define writebuf and readbuf? They should be BYTE type.
  • You need to use L"RegisterAddrSize", 16 at line 38. Otherwise reading starts from current address (8 in your case)

From your code, it seems that the EEPROM accepts a 16-bit address when writing but no address when reading, is that correct?
If you do a read without specifying an address then you may read from the current address. If the EEPROM keeps only one address for both reads and writes, then you will read from the end of the data you just wrote.

P.S. since you are using 16 bit addresses you may also need to be careful about byte ordering of those. This is not, of course, an issue as long as you use address 0, but it can become a problem if you use different addresses. We are going to fix the issue in the libraries, allowing you to set the desired byte ordering, but at the moment you will have to swap high and low bytes yourself.

readbuf, writebuf are defined as BYTE[128]. Line 38 set to L “RegisterAddrSize”, 16. Read and write now with cast to (BYTE *). Unfortunately without success.565-i2c-27xx256-1.png

I changed my source to make further tests.

I rather believe that reading works, but writing does not. The written value 170(dez) I never see, but it seems that in previous attempts 54(dez) and 55(dez) was written in the EEPROM.
566-i2c-27xx256-2.png

The problem is writing. I recorded with the oscilloscope. For L “RegisterAddrSize”, 16 and L “RegisterAddrSize”, 8 there is no difference. The driver always has one address byte. When reading, it works. There are 1 or 2 address bytes.

if (Imx7I2c_SetConfigInt(i2c, L"RegisterAddrSize", 16, StoreVolatile) == TRUE)		// 16bit Register address to send
{
    unsigned long writeAdr = 0;
    returnValue = Imx7I2c_Write(i2c, (BYTE*)writebuf, 1);	// write 1byte
    if (returnValue != I2C_RW_FAILURE)
        printf("\nwrite to EEPROM  Adr.0x%04x: %d \r", writeAdr, writebuf[0]);	
}

Thank you for pointing out this issue, we are going to look at it and hopefully fix it in the future releases of the library.

You can try to embed address to write operation. Could you try something like this

     Imx7I2c_SetConfigInt(i2c, L"SlaveAddr", 0x50, StoreVolatile);
     Imx7I2c_SetConfigInt(i2c, L"RegisterAddrSize", 0, StoreVolatile)
     i = 0;    
     writebuf[i++] = 0;   //Address High Byte
     writebuf[i++] = 0;   //Address Low Byte
     writebuf[i++] = 'T';
    ...
     writebuf[i] = '4';

    //writing
     Imx7I2c_Write(i2c, (BYTE*)writebuf, 10);    
     ...
     //reading
     writebuf[0] = 0;   //Address High Byte
     writebuf[1] = 0;   //Address Low Byte
     Imx7I2c_Write(i2c, (BYTE*)writebuf, 2);  //Set read address
     Imx7I2c_Read(i2c, (BYTE*)readbuf, 8);   //read data

I have the same problem with iMX6DL, on WEC7. I am trying to read AT24C16 memory with 16 bit address size. Read appears to work (but I haven’t used a high address), write works only in 8 bit address.
I tried the “embedded address” recommandded, that requires extra delays, between write and read commands, but still not working.
I am using ToradexCeLibraries_2.1b4266-20171228.zip
Is there other lib package that has the fix for 16 bit addressing?

For reading, I found a workaround, but it does not work for writing.
Basically, I use 8bit addressing, and when reading address goes after 0xFF, I make a dummy read from address 0xFF, to my real address, then set address size to zero, and read the content I am interested in. If I try the same, with write, I mean reading dummy from 0xFF, untill the address I am interested in, the write still uses the first byte from data, as 8 bit address, even if I made sure I setup address size to zero…

Dear @core,

Could you please test with our latest library release(2.3 or 2.3b4536) and let us know is that issue still present.

You can do a test with I2c tool, it is built using the library.

If still issue presents then could you try below answer workaround as of now?

Hi @raja.tx ,
I tried both libraries sets and 16 bit I2C operations do not work. The behavior is the same as the older libraries, for 16 bit address size. I try to write at 0x137, “demo” letters, and the library write it at offset 0x000, 0x37 as data, then “Demo” letters. I tried also I2CTool, which works for 8 bit, do not works for 16 bit either. It does not report any error, but it does not change memory content either. Read leaves data field unchanged. I am not sure if or OS system created with BSP1.1 is having something to do with it.
[LE] The answer below do not helps in my case. Writing is always using 8 bit register value regardless of register size being set to zero.

Hi @raja.tx ,
I tried to change de OS image, but I get an error “Invalid file signature.” when trying to flash the nk7.nbx image, from v1.4. Do I need to change bootloader too? Can I still use my OS image, based on BSP v1.1, if I update bootloader?

Dear @core,

We always recommend you to use corresponding version bootloader along with NK.bin. First, update the OS image then update boot loader and then reboot the device. Also, please use the UpdateTool which is included with release package and we don’t recommend image inbuilt updatetool. Sometimes, latest version updatetool might have a fix for an issue with latest image update.

Please have a look below documentation related to this topic

https://developer.toradex.com/knowledge-base/apalis-imx6-wince-bring-up

https://developer.toradex.com/knowledge-base/production-programming-for-imx6-modules

@raja.tx ,
I tried to write boot loader from 1.4 with command from first link. First, I got the image is not in the root folder, to the “flashloader 0” command. Then I notice the help usage says that default name is eboot.imx, which was not available in the 1.4 archive, so I used what I had “flashloader 0 eboot-colibri.img”, the write was sucessfully, however the lootloader is not loading anymore, nothing on serial output…
[LE] I had to do recovery mode and update to 1.4 bootloader, the the OS image. I tried I2CTool and 16 bit operation is not working again. What kind of device are you using?

Dear @core,

I am just tested with external RTC chip with I2c tool. 8 bit addressing, 16 bit addressing, little endian and big endian settings are working.

Could you please share below items in order to verify the issue and reproduce it on our side.

  1. Please log debug message

  2. Try various options available in I2c tool and verify which all are working by capturing the waveform

  3. Please share reproducible application source code with captured output waveform and let me run the application and verify it. Could you consider to use Colibri Eval board on-board RTC to test this?

  4. Share your hardware setup details.

I will try to collect more information on my end. Basically, I use a I2C memory based smartcard, that has AT24C16 memory type. It supports bulk read, entire memory from one shot, that is the reason I am able to read full memory ok. On write, it has a page write mode, that allow me to write up to 16 bytes at once, then I need to change the address. That is the reason write operation is problematic, above 0xFF address. 8 bit address operation works without problems, 16 bit does not. I hope I will have some data for you, in a few days, since now I am working in a different project, as well, and I cannot allocate all my time.

Dear @core,

Thank you for your reply and we are waiting for your test results.

Hi @raja.tx ,
I verified the I2C bus data and it was looking good. Then I read specs again, for I2C memory, and notice that 16 bit addressing is not the way to work with this memory type. Actually it is only working with 8 bit address, and upper MSB bits are send thru device id LSB bits, meaning, If I want to send address 0x234, I need to set device address to 0x52 (0x50 is the real device address and 2 is the upper 16 bit part of address), and the register address set to 0x34. This way worked. Sorry for the confusion. The original BSP v1.1 library was enough to work with this memory based smartcard.