Reading and writing EEPROM via I2C with Linux

Reading and writing EEPROM via I2C with Linux

how to read/write eeprom using i2c
linux eeprom sysfs
i2c read/write c code
i2c-tools read eeprom
arduino i2c eeprom programmer
linux i2c eeprom sysfs
linux eeprom module

I trying to read and write an Atmel 24C256 EEPROM with a Raspberry Pi B+ over I2C, but I'm having trouble getting it all to work right.

Here is the code I have so far:

#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <linux/i2c.h>

#define DEVICE_PATH "/dev/i2c-1"

#define PAGE_SIZE 64

#define DEVICE_ADDR 0x50 // 0b1010xxxx

int file_desc;
char buffer[PAGE_SIZE + 2]; // 64 bytes + 2 for the address

void teardownI2C()
    int result = close(file_desc);

void setupI2C()
    file_desc = open(DEVICE_PATH, O_RDWR);
    if(file_desc < 0)
    printf("%s\n", strerror(errno));
    if(ioctl(file_desc, I2C_SLAVE, DEVICE_ADDR) < 0)
    printf("%s\n", strerror(errno));


int write_to_device(char addr_hi, char addr_lo, char * buf, int len)
     struct i2c_rdwr_ioctl_data msg_rdwr;
     struct i2c_msg i2cmsg;
     char my_buf[PAGE_SIZE + 2];
     if(len > PAGE_SIZE + 2)
     printf("Can't write more than %d bytes at a time.\n", PAGE_SIZE);
     return -1;
     int i;
     my_buf[0] = addr_hi;
     my_buf[1] = addr_lo;

     for(i= 0; i < len; i++)
     my_buf[2+i] = buf[i];
     msg_rdwr.msgs = &i2cmsg;
     msg_rdwr.nmsgs = 1;
     i2cmsg.addr  = DEVICE_ADDR;
     i2cmsg.flags = 0;
     i2cmsg.len   = 2+len;
     i2cmsg.buf   = my_buf;

    printf("write_to_device(): %s\n", strerror(errno));
    return -1;

    return 0;


int read_from_device(char addr_hi, char addr_lo, char * buf, int len)
    struct i2c_rdwr_ioctl_data msg_rdwr;
    struct i2c_msg             i2cmsg;

    if(write_to_device(addr_hi, addr_lo ,NULL,0)<0)
    printf("read_from_device(): address reset did not work\n");
    return -1;

    msg_rdwr.msgs = &i2cmsg;
    msg_rdwr.nmsgs = 1;

    i2cmsg.addr  = DEVICE_ADDR;
    i2cmsg.flags = I2C_M_RD;
    i2cmsg.len   = len;
    i2cmsg.buf   = buf;

    printf("read_from_device(): %s\n", strerror(errno));
    return -1;

    return 0;

void fill_buffer(char *buf)
    int i = 0;
    while(i < PAGE_SIZE && *buf)
    buffer[i+2] = *buf++;
    while(i++ < PAGE_SIZE-1)
    buffer[i+2] = '*'; // fill the buffer with something

int main()

    setupI2C(); //setup

    fill_buffer("Here are some words.");
    write_to_device(0x01, 0x00, buffer, PAGE_SIZE);
    char newbuf[PAGE_SIZE];

    if(read_from_device(0x01, 0x00, newbuf, PAGE_SIZE)>0)
    printf("%s\n", newbuf);

    teardownI2C(); //cleanup
    return EXIT_SUCCESS;

Writing to the device like in the line write_to_device(0x01, 0x00, buffer, PAGE_SIZE); doesn't generate any errors but when I try to read from the device, I have to write a "dummy" byte according to the spec sheet and then try to read from the device but for some reason writing the dummy byte results in an error "Input/output error". I can't figure out how this works. I am using two resources to guide me, the Linux I2C-Dev documentation and an example from a similar EEPROM device. I'm sort of stuck here and don't know what to try. Any suggestions or pointers are greatly appreciated!

Alternatively, you could access it via the kernel at24.c driver, if you're able to compile and install a different kernel device tree for your Raspberry Pi.

The kernel device tree needs to specify the EEPROM's type and address, and which I²C bus it's connected to. I'm not sure about Raspberry Pi, but for the BeagleBone Black EEPROM it goes like this:

&i2c0 {
    eeprom: eeprom@50 {
        compatible = "at,24c32";
        reg = <0x50>;

For your device you'd specify compatible = "at,24c256";

Ensure the kernel config specifies CONFIG_EEPROM_AT24=y (or =m).

Then you should be able to access the EEPROM memory from userspace at something like /sys/bus/i2c/devices/0-0050/eeprom or /sys/bus/i2c/drivers/at24/0-0050/eeprom.

eeprog, Linux SMBus (I2C) 24C32 EEPROM reader/writer, I have connected an I2C 24C512 EEPROM to the I2C port of the U3 using the level shifter. The EEPROM is configured on ID=7 (all 3 pins� Reading and writing EEPROM via I2C with Linux. Ask Question Asked 5 years, 2 months ago. Active 3 months ago. Viewed 27k times 4. 2. I trying to

maybe this here might help. since it handles apparently the device you are trying to program and also explains some caveats of addressing 24c256

Read/Write I2C EEPROM?, Atmel, 34C02B 2K, 0x50 - 0x57, SW write protect at 0x30-37. Catalyst This is a simple EEPROM module meant to enable reading the first 256 bytes of an EEPROM (on a SDRAM DIMM for example). However, it will access serial EEPROMs on any I2C adapter. Built with Sphinx using a theme provided by Read the Docs. I2C is a protocol for communication between devices. In this column, the author takes the reader through the process of writing I2C clients in Linux. I2C is a multi-master synchronous serial communication protocol for devices. All devices have addresses through which they communicate with each other.

Small and simple program to understand the easy management of an eeprom

    Simple program to write / read the eeprom AT24C32.
    Developed and tested on the Raspberry pi3B jessie

    To create the executable use the following command:

        gcc -Wall -o thisprogram.exe thisprogram.c

#include <stdio.h>
#include <sys/ioctl.h> // ioctl
#include <fcntl.h>     // open
#include <unistd.h>    // read/write usleep
#include <time.h>
#include <netinet/in.h> // htons
#include <linux/i2c-dev.h>

#pragma pack(1)

#define PAGESIZE 32
#define NPAGES  128

#define ADDRESS 0x57  //  AT24C32's address on I2C bus 

typedef struct {
    ushort AW;
    char  buf[PAGESIZE+2];

static WRITE AT = {0};

int main() {
  int fd;
  char bufIN[180] = {0};
  time_t clock=time(NULL);

  snprintf(AT.buf, PAGESIZE+1, "%s: my first attempt to write", ctime(&clock)); //  the buffer to write, cut to 32 bytes

  if ((fd = open("/dev/i2c-1", O_RDWR)) < 0) {  printf("Couldn't open device! %d\n", fd); return 1; }

  if (ioctl(fd, I2C_SLAVE, ADDRESS) < 0)     { printf("Couldn't find device on address!\n"); return 1; }

  AT.AW = htons(32);    //  I will write to start from byte 0 of page 1 ( 32nd byte of eeprom )

  if (write(fd, &AT, PAGESIZE+2) != (PAGESIZE+2)) { perror("Write error !");    return 1; }
  while (1) { char ap[4];  if (read(fd,&ap,1) != 1) usleep(500); else break; } //   wait on write's end 

  if (write(fd, &AT, 2) != 2) {  perror("Error in sending the reading address");    return 1;  }

  if (read(fd,bufIN,PAGESIZE) != PAGESIZE) { perror("reading error\n"); return 1;}
  printf ("\n%s\n", bufIN);

  return 0;

Kernel driver eeprom — The Linux Kernel documentation, Can you anybody please help to write i2c client in my driver to read the EEPROM content via sysfs.� Re: Using EEPROM via PS-I2C on Zynq in Linux Linux i2c uses 7-bit addresses for both read and write. The driver manages the 8th r/w bit. Try an address of 0x51 instead of 0xA2.

Craig McQueen's answer got me on the right track, but it is not easy to figure the whole thing out on your own. Here is a AT24C256 device tree overlay that works for me on the Raspberry Pi:

/ {
  fragment@0 {
    target = <&i2c1>;
    overlay {
      pinctrl-names = "default";
      pinctrl-0 = <&i2c1_pins>;
      clock-frequency = <100000>;
      status = "okay";
      at24@50 {
        compatible = "atmel,24c256","at24";
        #address-cells = <1>;
        #size-cells = <0>;
        reg = <0x50>;
        pagesize = <64>;
        size = <32768>;
        address-width = <16>;

Save it to "at24c256.dts", compile (might need to install the device tree compiler) it using:

dtc -O dtb -o at24c256.dtbo -b 0 -@ at24c256.dts

and save it in "/boot/overlays". Then activate the overlay by adding:


to "/boot.config.txt" and reboot. You should now have a device file "/sys/class/i2c-dev/i2c-1/device/1-0050/eeprom" (if your I2C bus number is 1) which you can write to like a normal file.

Write to it using e.g.:

echo 'Hello World' | sudo tee /sys/class/i2c-dev/i2c-1/device/1-0050/eeprom

Read from it using e.g.:

sudo more /sys/class/i2c-dev/i2c-1/device/1-0050/eeprom

Not sure how you can get around the su-rights for accessing the device though. Adding the user to the i2c-group does not help...

Reading and Writing Serial EEPROMs, Introduction. Programming and reading I2C memory devices is a common use case for the Aardvark I2C/SPI Host Adapter. There are several ways to do this with� Reading from the EEPROM basically follows the same three step process as writing to the EEPROM: Send the Most Significant Byte of the memory address that you want to write to. Send the Least Significant Byte of the memory address that you want to write to. Ask for the data byte at that location.

My code:

enter code here

__s32 write_eeprom(__s32 fd,__u32 offset,__u32 len,__u8 *buf)
    __s32 ret;
    struct i2c_rdwr_ioctl_data msg_set;
    struct i2c_msg iomsgs;
    __u32 sended, sending;
    __u8 temp[ONE_PAGE + 1];

    if((offset + len) > BYTES_MAX || len == 0)
        printf("write too long than BYTES_MAX\n");
        return -1;
    sended = 0;
    iomsgs.addr = DEVICE_ADDR;
    iomsgs.flags = 0;   //write
    iomsgs.buf = temp;
    msg_set.msgs = &iomsgs;
    msg_set.nmsgs = 1;
    while(len > sended)
        if(len - sended > ONE_PAGE)
            sending = ONE_PAGE;
            sending = len - sended;
        iomsgs.len = sending + 1;
        temp[0] = offset + sended;
        memcpy(&temp[1], buf + sended, sending);
        //printf("sending:%d sended:%d len:%d offset:%d \n", sending, sended, len, offset);
        ret = ioctl(fd, I2C_RDWR, (unsigned long)&msg_set);
        if(ret < 0)
            printf("Error dring I2C_RDWR ioctl with error code: %d\n", ret);
            return ret;
        sended += sending;

    return sended;

how to write i2c client to read eeprom device in raspberry pi , Member "i2c-tools-4.1/eepromer/eeprom.c" (30 Nov 2018, 8544 Bytes) of package tried to format the requested source page into HTML format using ( guessed) C and 14 #include <linux/i2c-dev.h> 15 16 /* 17 this program can read 24C16 (and write len bytes (stored in buf) to eeprom at address addr, page-offset offset� We use linux (CELinux) and an I2C device driver with Linux as well. But our application code also has a non-trivial I2C module that contains all the work-around intelligence for dealing with all the various devices we have experience with. Also, when dealing with I2C issues, I often find that I need to re-acquaint myself with the source spec:

How to Read and Write to an I2C EEPROM Using the Aardvark , Yes, you can use dd or write your own program and use the seek function on the file to move to the offset you want to write to. For example if� Reading & Writing To I2C EEPROM The 64K EEPROM requires an 8-bit device address word following a start condition to enable the chip for a read or write operation. The device address word consists of a mandatory one, zero sequence (1010) for the first four most significant bits as shown. This is common to all 2-wire EEPROM devices.

i2c-tools: eepromer/eeprom.c, The Red Hat Linux distributions contain I2C device drivers for accessing the This program is an example of writing and reading an EEPROM device via� In order to communicate with an I²C peripheral with this simple structure, you must first open the bus for reading and writing like you would any file. A call to open must be used rather than fopen so that writes to the bus are not buffered. Open returns a new file descriptor (a non-negative integer) which can then be used to configure the bus.

How do you read and write from a specific address of an EEPROM , c Reading and writing EEPROM via I2C with Linux - Stack. SPI on a BeagleBone Black for LED domination Strong Random.