2

I need to read an eeprom in an embedded device.

So far this "almost" worked:

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>

#include <linux/i2c-dev.h>


#define READ_SIZE   (256)
#define NB_PAGES    (128)



void dump_to_file(const char *output_file_path,
          const uint8_t *buffer, const int buffer_length)
{
    int output_file = open(output_file_path, O_RDWR|O_APPEND|O_CREAT);
    if (output_file < 0) {
        printf("Failed opening output file %s\n", output_file_path);
        return;
    }

    write(output_file, buffer, buffer_length);
}


int main(int argc, char *argv[])
{
    /* got these values from i2cdetect */
    const char *i2c_device = "/dev/i2c-4";
    const int device_address = 0x50;

    /* open the i2c device file */
    int file = open(i2c_device, O_RDWR);
    if (file < 0) {
        printf("Failed opening %s\n", i2c_device);
        return 1;
    }

    if (ioctl(file, I2C_SLAVE, device_address) < 0) {
        printf("Failed addressing device at %02X\n", device_address);
        close(file);
        return 1;
    }

    int i = 0;
    for (i = 0; i < NB_PAGES; i++) {
        char buf[READ_SIZE] = {0};

        if (read(file, buf, READ_SIZE) != READ_SIZE) {
            printf("Failed reading\n");
            close(file);
            return 1;
        }

        dump_to_file(argv[1], buf, READ_SIZE);
    }

    close(file);

    return 0;
}

By "almost" I mean that it dumps the full eeprom but the START depends on the last block read..
It's not always the same.
If I read 10 blocks. then run the program again I read the next ones and not the first 10.

How to set the starting address?

Update: if I do:

i2cset -y 4 0x50 0x00 0x00

and the run the above code, it works. so how can I put the equivalent of the i2cset command in the code?

Zibri
  • 9,096
  • 3
  • 52
  • 44

1 Answers1

2

Done! It wasn't easy because I could not find documentations anywhere.. but I thought that since the eeprom is 32K, maybe it was "like" a 24c256. But even in that case I found nothing in userspace until I decided to go by instinct. I studied i2cset source, understood what it did and put it in the code.

Here is the result, which dumps a full i2c 32k eprom from userspace.

Note a full backup and restore utility can be found here: https://gist.github.com/Zibri/cf8ac0b311301aeeaa8910c7da824bff

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>


#define READ_SIZE       (256)
#define NB_PAGES        (128)

void dump_to_file(const char *output_file_path,
                  const uint8_t *buffer, const int buffer_length)
{
        int output_file = open(output_file_path, O_RDWR|O_APPEND|O_CREAT);
        if (output_file < 0) {
                printf("Failed opening output file %s\n", output_file_path);
                return;
        }

        write(output_file, buffer, buffer_length);
}


int main(int argc, char *argv[])
{

        const char *i2c_device = "/dev/i2c-4";
        const int device_address = 0x50;

        int file = open(i2c_device, O_RDWR);
        if (file < 0) {
                printf("Failed opening %s\n", i2c_device);
                return 1;
        }

        if (ioctl(file, I2C_SLAVE, device_address) < 0) {
                printf("Failed addressing device at %02X\n", device_address);
                close(file);
                return 1;
        }

        int i = 0;

        write(file,'\x00\x00',2); // ADDRESS

        for (i = 0; i < NB_PAGES; i++) {
                char buf[READ_SIZE] = {0};

                if (read(file, buf, READ_SIZE) != READ_SIZE) {
                        printf("Failed reading\n");
                        close(file);
                        return 1;
                }

                dump_to_file(argv[1], buf, READ_SIZE);
        }

        close(file);

        return 0;
}
Zibri
  • 9,096
  • 3
  • 52
  • 44
  • And why not to use in-kernel driver for that? – 0andriy Aug 23 '21 at 07:56
  • because I don't see it in my TV :D – Zibri Aug 23 '21 at 09:30
  • @0andriy how would you use it anyway to read and write a 24c256 eeprom? I am curious. – Zibri Aug 23 '21 at 09:31
  • As a file: https://unix.stackexchange.com/questions/399916/how-do-you-read-and-write-from-a-specific-address-of-an-eeprom-from-sysfs. Another relevant link: https://stackoverflow.com/questions/52493181/linux-i2c-eeprom-sys-bus-i2c-eeprom-file-is-read-only. And one more: https://stackoverflow.com/questions/52499762/linux-instantiate-from-user-space-eeprom-new-device – 0andriy Aug 23 '21 at 20:42
  • oh yeah.. sure.. @0andriy, but the tv does not have a fully working sysfs...had to do it by hand. – Zibri Aug 27 '21 at 16:18