用户态读取32k I2C EEPROM如何设置起始地址并实现i2cset等效功能
问题根因
I2C EEPROM内部维护了一个地址指针,每次读写操作后指针会自动向后偏移对应操作的字节数。你之前的代码没有主动设置该指针的初始值,所以每次程序运行时都会继承上一次操作结束后指针的位置,才会出现读取起始地址不固定的问题。
你用到的i2cset -y 4 0x50 0x00 0x00命令,本质就是向地址为0x50的EEPROM写入2字节的起始地址0x00 0x00,将设备内部的地址指针复位到存储空间的起始位置。
代码实现方案
只需要在设置好I2C从设备地址之后、进入读循环之前,主动写入2字节的起始地址即可,等效于你手动执行的i2cset命令。同时你原来的代码还存在两个可优化的问题:
dump_to_file函数中使用O_CREAT标志打开文件时,没有指定文件权限,会导致生成的文件权限异常dump_to_file函数写完数据后没有关闭文件描述符,多次调用会出现文件描述符泄漏,还可能导致数据没有刷入磁盘
修改后的完整代码如下:
#include <stdlib.h> #include <stdio.h> #include <stdint.h> #include <fcntl.h> #include <unistd.h> #include <linux/i2c-dev.h> #include <sys/ioctl.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) { // O_CREAT标志必须指定第三个参数为文件权限,这里设置为用户读写、其他用户只读 int output_file = open(output_file_path, O_RDWR|O_APPEND|O_CREAT, 0644); if (output_file < 0) { printf("Failed opening output file %s\n", output_file_path); return; } write(output_file, buffer, buffer_length); // 写完主动关闭文件,避免文件描述符泄漏和数据缓存问题 close(output_file); } int main(int argc, char *argv[]) { if (argc < 2) { printf("Usage: %s <output_file_path>\n", argv[0]); return 1; } /* 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; } // 等效于i2cset -y 4 0x50 0x00 0x00,写入16位起始地址0x0000 uint8_t start_addr[] = {0x00, 0x00}; if (write(file, start_addr, sizeof(start_addr)) != sizeof(start_addr)) { printf("Failed to set EEPROM start address\n"); close(file); return 1; } int i = 0; for (i = 0; i < NB_PAGES; i++) { uint8_t buf[READ_SIZE] = {0}; if (read(file, buf, READ_SIZE) != READ_SIZE) { printf("Failed reading at page %d\n", i); close(file); return 1; } dump_to_file(argv[1], buf, READ_SIZE); } close(file); printf("EEPROM dump completed, total size: %d bytes\n", READ_SIZE * NB_PAGES); return 0; }
内容的提问来源于stack exchange,提问作者Zibri
相关产品推荐
相关产品推荐

