Skip to content

Instantly share code, notes, and snippets.

@gquere
Created August 17, 2020 13:44
Show Gist options
  • Save gquere/d532ffaa62e3a23753afd4f0080e4df0 to your computer and use it in GitHub Desktop.
Save gquere/d532ffaa62e3a23753afd4f0080e4df0 to your computer and use it in GitHub Desktop.
dump I2C EEPROM memory from Linux device ioctl
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>
#define READ_SIZE (256)
#define NB_PAGES (256)
/* UTILS **********************************************************************/
void hexprint(const uint8_t *input, const int input_length)
{
int i = 0;
for (i = 0; i < input_length; i++) {
if (i%16 == 0) {
printf("\n");
}
printf("%02x ", input[i]);
}
printf("\n");
}
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);
}
/* MAIN ***********************************************************************/
int main(int argc, char *argv[])
{
/* got these values from i2cdetect */
const char *i2c_device = "/dev/i2c-2";
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;
}
//hexprint(buf, READ_SIZE);
dump_to_file(argv[1], buf, READ_SIZE);
}
close(file);
return 0;
}
@gquere
Copy link
Author

gquere commented Aug 23, 2021

this is almost correct but in my case I get the starting page always different depending on the last read.
how to read from the start and not from a random page?

Sorry not sure where this could be coming from, haven't worked with I2C in years. This was just a hack to dump a simple EEPROM from a beaglebone card. Maybe there's a sequential read page counter for your chip. You should refer to its manual or read the code of a full-blown HAL like the one from STM Cube maybe.

@Zibri
Copy link

Zibri commented Aug 24, 2021

not a problem.. I rewrote the program yesterday to dump and restore a 24c256 very easily and without most of i2c stuff.
I will soon publish it and if you like I will give you the link.
any way to READ a 24c256 you need first to write 2 BYTES, ADDRHI and ADDRLO, then just by using read() you can read it all 256 byte at a time.

to write it is trickier.. you need to write 34 bytes (or less) at a time where the first 2 are the address.
but you have to wait 2-3ms between the writes.

all codes present on github/staroverflow do not work! at least not on an lg tv which has an old linux kernel.
but in this way it works and I correctly dumped and restored the 24c256 eeprom.

@Zibri
Copy link

Zibri commented Aug 27, 2021

Check my fork.. it's even easier.. all that is missing is a simple write:

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

before the read cycle.

25c256 have 16 bit HI then LO, as address.
Smaller eeproms have only 8 so the write must be one byte only.

@Zibri
Copy link

Zibri commented Aug 27, 2021

note: when writing back instead, you must write the address (2 bytes) followed by the data (32bytes maximum), and wait at least 3ms between the writes.

@Zibri
Copy link

Zibri commented Aug 28, 2021

here is the full backup and restore program which now includes also the "aknowledge polling" (before I had just an ugly usleep function).

https://gist.github.com/Zibri/cf8ac0b311301aeeaa8910c7da824bff

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment