Page 1 of 1

How to read i2c eeprom Atmel AT24C128B with RPi

Posted: Sun Mar 10, 2013 12:47 am
by ufo2001
Hello. I am trying to read atmel eeprom AT24C128B chip using RPi and i2c interface (two-wire interface)
I see chip at 0x50 address as /dev/i2c-1 :
root@raspberrypi:/home/pi# i2cdetect -y -a 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
root@raspberrypi:/home/pi#

Then I tried to compile and run code from
http://www.lm-sensors.org/browser/i2c-t ... r/eeprom.c
with various combinations of parameters:

Code: Select all

#define DEFAULT_I2C_BUS      "/dev/i2c-1"
#define DEFAULT_EEPROM_ADDR  0x50         /* the 24C16 sits on i2c address 0x50 */
#define DEFAULT_NUM_PAGES    64            /* we default to a 24C16 eeprom which has 8 pages */
#define BYTES_PER_PAGE       256          /* one eeprom page is 256 byte */
#define MAX_BYTES            16 
But when I run binary file I can read only 256 bytes of eeprom chip

Code: Select all

root@raspberrypi:/home/pi# ./eeprom
base-address of eeproms       : 0x50
number of pages to read       : 64 (0x50 .. 0x8f)
i2c-devicenode is             : /dev/i2c-1
            on filedescriptor : 3

Positioned pointer in eeprom at 0x50 to offset 00000000
Read 16 bytes from eeprom at 0x50, offset 00000000
<omitted here>
Positioned pointer in eeprom at 0x50 to offset 000000f0
Read 16 bytes from eeprom at 0x50, offset 000000f0
ioctl(): Input/output error
ioctl returned -1
root@raspberrypi:/home/pi#
And I can never read more then 256 bytes, although eeprom chip is 128K.
Maybe sources are not for such "big" memory chips and need to be rewritten...
If someone already faced such a quest I will appreciate any help and hints!

Re: How to read i2c eeprom Atmel AT24C128B with RPi

Posted: Mon Mar 11, 2013 3:41 pm
by IanH2
Looking at the datasheet (http://www.atmel.com/Images/doc5296.pdf, page 9, fig 8-1) you need to send two bytes of address, whereas the eeprom_write() function is sending just one.

Very roughly - note I haven't tested this - you'll need to do something like this:

Code: Select all

int eeprom_write(int fd,
	                 unsigned int addr,
	                 unsigned int offset,
	                 unsigned char *buf,
	                 unsigned char len
	)

...
	        char _buf[MAX_BYTES + 2];
...

	        if(len+offset >65536){
	            fprintf(stderr,"Sorry, len(%d)+offset(%d) > 64K\n",
	                        len,offset);
...
	        _buf[0]=(offset >> 8) & 0xFF;
	        _buf[1]=(offset & 0xFF);

	        for(i=0;i<len;i++) /* copy buf[0..n] -> _buf[2..n+2] */
	            _buf[2+i]=buf[i];
...
	        i2cmsg.len   = 2+len;
...
}

Re: How to read i2c eeprom Atmel AT24C128B with RPi

Posted: Tue Mar 19, 2013 7:11 am
by ufo2001
Hello. Thank you for your hint. I tried to continue...

/* The definition I found for structure I2C_MSG */

Code: Select all

struct i2c_msg {
	        __u16 addr;                   //unsigned short
	        unsigned short flags;           
	#define I2C_M_TEN               0x10
	#define I2C_M_RD                0x01
	#define I2C_M_NOSTART           0x4000
	#define I2C_M_REV_DIR_ADDR      0x2000
	#define I2C_M_IGNORE_NAK        0x1000
	#define I2C_M_NO_RD_ACK         0x0800
	        short len;                        
	        char *buf;                        
	};




int eeprom_write(int fd,
		 unsigned int addr,
		 unsigned int offset,
		 unsigned char *buf,
		 unsigned char len
)
{

..................Some code here....................

	struct i2c_rdwr_ioctl_data msg_rdwr;
	struct i2c_msg             i2cmsg;
	int i;
	char _buf[MAX_BYTES + 1];

..................Some code here....................


	_buf[0]=offset;    /* _buf[0] is the offset into the eeprom page! */
	for(i=0;i<len;i++) /* copy buf[0..n] -> _buf[1..n+1] */
    	_buf[1+i]=buf[i];

..................Some code here....................

	i2cmsg.addr  = addr;
	i2cmsg.flags = 0;
	i2cmsg.len   = 1+len;
	i2cmsg.buf   = _buf;                     

..................Some code here....................

}
I'm not experienced in a linux-kernel programming, so I may had some errors. But I don't understand why should I copy an OFFSET in a _buf[0]? I red your previous comments about
problems with a memory addressing. And I also don't understand why I should do things like that:

char _buf[MAX_BYTES + 2]; /* +2 ????? */

_buf[0]=offset; /* _buf[0] is the offset into the eeprom page! */
_buf[1]=addr;
for(i=0;i<len;i++) /* copy buf[0..n] -> _buf[2..n+2] */
_buf[2+i]=buf;


Because in above definition it's clear that structure I2C_MSG uses __u16 addr. And char * buf is just a char buffer, does not require any adding of an address and an offset at the beginning of it.
Maybe we should put the ADDR in the first octet of the i2c_msg.addr and the OFFSET in the last octet of i2c_msg.addr?
Thanks again.

Re: How to read i2c eeprom Atmel AT24C128B with RPi

Posted: Thu May 30, 2013 3:41 pm
by PanzerSajt
So what was the actual solution?
I'm having the same problem but with a 24c016 chip.
If someone could help me I would appreciate it.
However i2cdump is able to read out the chip but I would like to write to the eeprom as well.
http://pastebin.com/cxRbWd3P

Re: How to read i2c eeprom Atmel AT24C128B with RPi

Posted: Wed Oct 02, 2013 4:53 pm
by dlethe
Anybody still watching this thread? I've got a RTC / AT24C32 based board and have similar problem.

Re: How to read i2c eeprom Atmel AT24C128B with RPi

Posted: Mon Feb 09, 2015 9:53 am
by Jack75
You need to put some delay between the writes. At least 4ms.

Here is the additional code to use a simple 4ms timer. Declaration as below.

Code: Select all

int main(int argc, char **argv){
    int i,j;
	
    /* filedescriptor and name of device */
    int d; 
    char *dn=DEFAULT_I2C_BUS;
	
    /* filedescriptor and name of data file */
    int f=-1;
    char *fn=NULL;
	
    unsigned int addr=DEFAULT_EEPROM_ADDR;
    int rwmode=0;
    int pages=DEFAULT_NUM_PAGES;
	
    int force=0; /* suppress warning on write! */

    struct timeval t;   /* This is the addition at the declaration section */


And this is the code at the writing to eeprom section .. you just need to find this section in the file you already had.

Code: Select all

for(j=0;j<(BYTES_PER_PAGE/MAX_BYTES);j++)
	    {
		/*Additional code for simple 4ms timer */
                /*Set 4000us=4ms timer*/ 
	        t.tv_sec = 0;
                t.tv_usec = 4000;
                select(0,NULL,NULL,NULL,&t);

                if(eeprom_write(d,addr+i,j*MAX_BYTES,buf+(j*MAX_BYTES),MAX_BYTES)<0)
                    exit(1);
            }