C语言 从Linux用户空间读取/写入EEPROM

kpbpu008  于 2023-04-11  发布在  Linux
关注(0)|答案(1)|浏览(423)

我正在开发一个基于iMX8MP MPU的定制嵌入式设备。我需要从用户空间读取连接到Linux中i2c-0总线上地址0x 50的EEPROM的前16位。
首先,我写在我的eeprom感谢u-boot如下:

u-boot=> i2c mw 0x50 0x00.2 57
u-boot=> i2c mw 0x50 0x01.2 69
u-boot=> i2c mw 0x50 0x02.2 74
u-boot=> i2c mw 0x50 0x03.2 65
u-boot=> i2c mw 0x50 0x04.2 6B
u-boot=> i2c mw 0x50 0x05.2 69
u-boot=> i2c mw 0x50 0x06.2 6F

然后,我检查了重启后的值是否正确写入eeprom,如下所示:

u-boot=> i2c md 0x50 0x0.2 B
0000: 57 69 74 65 6b 69 6f 20 53 41 53

我写了一个代码,使用ioctlsI2C_SLAVE_FORCEI2C_SMBUS请求与EEPROM通信。但是,显示的值不正确,我不知道为什么。

#include <stdio.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <errno.h>
#include <stdlib.h>
#include <strings.h>

#define I2C_ADDRESS 0x50
#define I2C_BUS "/dev/i2c-0"

int main(void)
{
    int file;
    char filename[20];
    int res;
    unsigned char data[16];

    snprintf(filename, 19, "%s", I2C_BUS);
    file = open(filename, O_RDWR);
    if (file < 0) {
        perror("open");
        exit(1);
    }

    res = ioctl(file, I2C_SLAVE_FORCE, I2C_ADDRESS);
    if (res < 0) {
        perror("ioctl");
        exit(1);
    }

    struct i2c_smbus_ioctl_data ioctl_data = {
        .read_write = I2C_SMBUS_READ,
        .command = 0x00, /* read start address */
        .size = I2C_SMBUS_WORD_DATA,
        .data = data,
    };

    res = ioctl(file, I2C_SMBUS, &ioctl_data);
    if (res < 0) {
        perror("ioctl");
        exit(1);
    }
    printf("Data read: ");
    for (int i = 0; i < 16; i++) {
        printf("%02x ", data[i]);
    }
    printf("\n");
    close(file);
    return 0;
}

输出为:

data read : ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00

在这一点上,我不知道为什么它不工作。任何提示将不胜感激

jm81lzqq

jm81lzqq1#

在eeprom上读/写有一种更容易的方法。事实上,如果有一个名为“eeprom”的文件,例如在/sys/devices/platform/soc@0/30800000.bus/30a20000.i2c/i2c-0/0-0050下,这意味着有一个用于此eeprom的内核驱动程序。
一个简单的cat到/sys/devices/platform/soc@0/30800000.bus/30a20000.i2c/i2c-0/0-0050/uevent表示相应的驱动程序:

DRIVER=at24
OF_NAME=eeprom
OF_FULLNAME=/soc@0/bus@30800000/i2c@30a20000/eeprom@50
OF_COMPATIBLE_0=atmel,24c32
OF_COMPATIBLE_N=1
MODALIAS=of:NeepromT(null)Catmel,24c32

at24.c是我的eeprom的内核驱动程序,我可以通过访问eeprom文件/sys/devices/platform/soc@0/30800000.bus/30a20000.i2c/i2c-0/0-0050/eeprom来进行读写操作。
你可以在下面找到一个虚拟的C程序,它允许我在eeprom上读写。

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

#define EEPROM_ARGUMENT 2
#define RDWR_ARGUMENT 3
#define MINIMAL_ARGUMENT 4
#define OFFSET_ARGUMENT 4

#define EEPROM_SOM "/sys/devices/platform/soc@0/30800000.bus/30a20000.i2c/i2c-0/0-0050/eeprom"

void read_eeprom(int fd, uint16_t offset, unsigned long read_count) {
    char *buff = (char*) malloc(read_count * sizeof(char));
    if (pread(fd, buff, read_count, offset) != read_count) {
        printf("Error: could not read data from device\n");
        close(fd);
        exit(-1);
    }
    printf("Data read: ");
    for (int i = 0; i < read_count; i++) {
        printf("%02x ", buff[i]);
    }
    printf("\n");
    close(fd);
    free(buff);
    exit(0);
}

void write_eeprom(int fd, uint16_t offset, const char* write_word) {
    if (pwrite(fd, write_word, strlen(write_word),offset) != strlen(write_word)) {
        printf("Error: could not write data to device\n");
        exit(-1);
    }
    close(fd);
    exit(0);
}

int main(int argc, char* argv[]) {
    unsigned long read_count;
    const char *mode = argv[1];
    const char *write_word = argv[RDWR_ARGUMENT];
    const char *eeprom;
    uint16_t offset = 0x00;
    int fd;

    if (argc < MINIMAL_ARGUMENT) goto usage;
    if (argv[OFFSET_ARGUMENT]) 
        offset = strtoul(argv[OFFSET_ARGUMENT], NULL, 0);

    if (!strcmp(argv[EEPROM_ARGUMENT], "EEPROM_SOM"))
        eeprom = EEPROM_SOM;
    else goto usage;

    if (!strcmp(mode, "read")) {
        read_count = strtoul(argv[RDWR_ARGUMENT], NULL, 0);
        fd = open(eeprom, O_RDONLY);
        if (fd < 0) 
            goto open_error;
        read_eeprom(fd, offset, read_count);
    }

    else if (!strcmp(mode, "write")) {
        fd = open(eeprom, O_WRONLY);
        if (fd < 0) goto open_error;
        write_eeprom(fd, offset, write_word);
    }
    else goto usage;

    return 0;

usage:
    errx(-1, "[read/write] [eeprom] [bytes to read/word to write] optional:[offset]\nSupported eeprom: EEPROM_SOM");

open_error:
    printf("Error: could not open device file %s\n", eeprom);
    return -1;
}

相关问题