Linux下的eeprom读写操作

转载地址:http://blog.csdn.net/yuzeze/article/details/51890555

利用Linux内核自带的IIC总线驱动,按系统提供的框架,用ioctl方法对eeprom设备进行读写操作,并分别按单字节及多字节读写方式,对外提供函数接口,以供外部程序方便调用。

  程序由3个文件组成,分别为头文件<eeprom_io.h>,函数实现文件<eeprom_io.c>,及测试程序<test.c>。
<eeprom_io.h>

/* ************************************************************************** * File name: eeprom_io.h * Function: eeprom读写操作 * Description: 利用系统提供的I2C总线驱动实现eeprom设备的读写方法, * 对外开放4个函数接口, 分别为: * 单字节写入函数: int eeprom_byte_write(u8 pos, u8 data) * 单字节读取函数: u8 eeprom_byte_read(u8 pos) * 多字节写入函数: int eeprom_page_write(u8 pos, u8 *data, int size) * 多字节读取函数: int eeprom_page_read(u8 pos, u8 *data, int size) * Author & Date: Joshua Chan, 2011/12/18 * **************************************************************************/ #ifndef _EEPROM_IO_H #define _EEPROM_IO_H #include <linux/i2c.h> #include <linux/i2c-dev.h> /* I2C总线ioctl方法所使用的结构体 */ typedef struct i2c_rdwr_ioctl_data ioctl_st; typedef unsigned char u8; typedef unsigned int u32; /* eeprom的slave_address, 对于AT24C08, 容量为1024 bytes, 由于byte_address 仅有8位, 只能表示0 ~ 255 bytes, 故此需在slave_address中分出2位来配合 byte_address一起寻址, 而slave_address可以取值0x50, 0x51, 0x52, 0x53, 配合byte_address刚好可以实现0 ~ 1023 bytes的寻址, 另外byte_address 取值范围从0 ~ 255, 若大于255则按其值对256取余计算 */ enum eeprom_address { eeprom_addr0 = 0x50, eeprom_addr1 = 0x51, eeprom_addr2 = 0x52, eeprom_addr3 = 0x53, }; #define DEV_PATH "/dev/i2c/0" //设备文件路径 #define I2C_M_WR 0 //定义写标志 #define MAX_MSG_NR 2 //根据AT24C08手册, 最大消息数为2 #define EEPROM_BLOCK_SIZE 256 //每个block容量256 bytes #define EEPROM_PAGE_SIZE 16 //AT24C08页大小为16字节 #define I2C_MSG_SIZE (sizeof(struct i2c_msg)) /* 自定义eeprom参数结构体 */ typedef struct eeprom_data { u8 slave_addr; u8 byte_addr; u8 len; u8 *buf; } eeprom_st; /* 从eeprom的pos位置处读取1个字节 @pos: eeprom的byte_address, 取值范围为0 ~ 255 返回值为读取的字节数据 */ extern u8 eeprom_byte_read(u8 pos); /* 将1个字节数据写入eeprom的pos位置 @pos: eeprom的byte_address, 取值范围为0 ~ 255 @data: 待写入的字节数据 */ extern int eeprom_byte_write(u8 pos, u8 data); /* 从eeprom的pos位置开始读取size长度数据 @pos: eeprom的byte_address, 取值范围为0 ~ 255 @data: 接收数据的缓冲区 @size: 待读取的数据长度, 取值范围为1 ~ 16 */ extern int eeprom_page_read(u8 pos, u8 *data, int size); /* 自eeprom的pos位置开始写入数据 @pos: eeprom的byte_address, 取值范围为0 ~ 255 @data: 待写入的数据 @size: 待写入数据的长度, 取值范围为1 ~ 16 */ extern int eeprom_page_write(u8 pos, u8 *data, int size); #endif


<eeprom_io.c>

/* *************************************************************************** * File name: eeprom_io.c * Function: eeprom读写操作 * Description: 利用系统提供的I2C总线驱动实现eeprom设备的读写方法, * 对外开放4个函数接口, 分别为: * 单字节写入函数: int eeprom_byte_write(u8 pos, u8 data) * 单字节读取函数: u8 eeprom_byte_read(u8 pos) * 多字节写入函数: int eeprom_page_write(u8 pos, u8 *data, int size) * 多字节读取函数: int eeprom_page_read(u8 pos, u8 *data, int size) * Author & Date: Joshua Chan, 2011/12/18 * **************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <sys/ioctl.h> #include "eeprom_io.h" /* 对设备进行初始化设置, 设置超时时间及重发次数, 参数为设备文件描述符 */ static int eeprom_init(int fd) { ioctl(fd, I2C_TIMEOUT, 4); ioctl(fd, I2C_RETRIES, 2); return 0; } /* 初始化一个ioctl_st结构, 并预分配空间 */ static ioctl_st *ioctl_st_init(void) { ioctl_st *iocs; iocs = malloc(sizeof(ioctl_st)); if (!(iocs)) { perror("malloc iocs:"); return NULL; } iocs->msgs = malloc(I2C_MSG_SIZE * MAX_MSG_NR); if (!(iocs->msgs)) { perror("malloc iocs->msgs"); return NULL; } iocs->msgs[0].buf = malloc(EEPROM_PAGE_SIZE + 1); if (!(iocs->msgs[0].buf)) { perror("malloc iocs->msgs[0].buf"); return NULL; } iocs->msgs[1].buf = malloc(EEPROM_PAGE_SIZE + 1); if (!(iocs->msgs[1].buf)) { perror("malloc iocs->msgs[1].buf"); return NULL; } return iocs; } /* 销毁ioctl_st结构, 释放空间 */ static void ioctl_st_release(ioctl_st *iocs) { free(iocs->msgs[0].buf); free(iocs->msgs[1].buf); free(iocs->msgs); free(iocs); } /* 根据eeprom_st结构生成page_read时序所需的ioctl_st结构 */ static void page_read_st_gen(ioctl_st *iocs, eeprom_st *eeps) { int size = eeps->len; iocs->nmsgs = 2; //page_read需2次start信号 /* 第1次信号 */ iocs->msgs[0].addr = eeps->slave_addr; //填入slave_addr iocs->msgs[0].flags = I2C_M_WR; //write标志 iocs->msgs[0].len = 1; //信号长度1字节 iocs->msgs[0].buf[0] = eeps->byte_addr; //填入byte_addr /* 第2次信号 */ iocs->msgs[1].addr = eeps->slave_addr; //填入slave_addr iocs->msgs[1].flags = I2C_M_RD; //read标志 iocs->msgs[1].len = size; //信号长度: 待读数据长度 memset(iocs->msgs[1].buf, 0, size); //先清零, 待读数据将自动存放于此 } /* 用ioctl方法从eeprom中读取数据 */ static int page_read(int fd, ioctl_st *iocs, eeprom_st *eeps) { int ret; int size = eeps->len; page_read_st_gen(iocs, eeps); ret = ioctl(fd, I2C_RDWR, (u32)iocs); if (ret == -1) { perror("ioctl"); return ret; } /* 将读取的数据从ioctl结构中复制到用户buf */ memcpy(eeps->buf, iocs->msgs[1].buf, size); // printf("read byte ioctl ret = %d\n", ret); return ret; } /* 从eeprom的pos位置开始读取size长度数据 @pos: eeprom的byte_address, 取值范围为0 ~ 255 @data: 接收数据的缓冲区 @size: 待读取的数据长度, 取值范围为1 ~ 16 */ int eeprom_page_read(u8 pos, u8 *data, int size) { int fd; u8 *buf = data; eeprom_st eeps; ioctl_st *iocs = ioctl_st_init(); fd = open(DEV_PATH, O_RDONLY); if (fd < 0) { perror("open eeprom"); return 0; } /* 判断要读取数据的长度size有效性 */ if (size > 16) size = 16; else if (size < 1) return 0; if (size > (EEPROM_BLOCK_SIZE - pos)) size = EEPROM_BLOCK_SIZE - pos; eeprom_init(fd); eeps.slave_addr = eeprom_addr0; eeps.byte_addr = pos; eeps.len = size; eeps.buf = buf; page_read(fd, iocs, &eeps); ioctl_st_release(iocs); close(fd); return size; } /* 根据eeprom_st结构生成page_write时序所需的ioctl_st结构 */ static void page_write_st_gen(ioctl_st *iocs, eeprom_st *eeps) { int size = eeps->len; iocs->nmsgs = 1; //page_write只需1次start信号 iocs->msgs[0].addr = eeps->slave_addr; //填入slave_addr iocs->msgs[0].flags = I2C_M_WR; //write标志 iocs->msgs[0].len = size + 1; //信号长度: 待写入数据长度 + byte_addr长度 iocs->msgs[0].buf[0] = eeps->byte_addr; //第1字节为byte_addr memcpy((iocs->msgs[0].buf + 1), eeps->buf, size); //copy待写数据 } /* 用ioctl方法向eeprom中写入数据 */ static int page_write(int fd, ioctl_st *iocs, eeprom_st *eeps) { int ret; page_write_st_gen(iocs, eeps); ret = ioctl(fd, I2C_RDWR, (u32)iocs); if (ret == -1) { perror("ioctl"); return ret; } printf("write byte ioctl ret = %d\n", ret); return ret; } /* 自eeprom的pos位置开始写入数据 @pos: eeprom的byte_address, 取值范围为0 ~ 255 @data: 待写入的数据 @size: 待写入数据的长度, 取值范围为1 ~ 16 */ int eeprom_page_write(u8 pos, u8 *data, int size) { int fd; u8 *buf = data; eeprom_st eeps; ioctl_st *iocs = ioctl_st_init(); fd = open(DEV_PATH, O_WRONLY); if (fd < 0) { perror("open eeprom"); return 0; } /* 判断要读取数据的长度size有效性 */ if (size > 16) size = 16; else if (size < 1) return 0; if (size > (EEPROM_BLOCK_SIZE - pos)) size = EEPROM_BLOCK_SIZE - pos; eeprom_init(fd); eeps.slave_addr = eeprom_addr0; eeps.byte_addr = pos; eeps.len = size; eeps.buf = buf; page_write(fd, iocs, &eeps); ioctl_st_release(iocs); close(fd); return size; } /* 从eeprom的pos位置处读取1个字节 @pos: eeprom的byte_address, 取值范围为0 ~ 255 返回值为读取的字节数据 */ u8 eeprom_byte_read(u8 pos) { u8 buf; eeprom_page_read(pos, &buf, 1); return buf; } /* 将1个字节数据写入eeprom的pos位置 @pos: eeprom的byte_address, 取值范围为0 ~ 255 @data: 待写入的字节数据 */ int eeprom_byte_write(u8 pos, u8 data) { int ret; u8 buf = data; ret = eeprom_page_write(pos, &buf, 1); return ret; }


<test.c>
/* *************************************************************
 * File name:   eeprom_test.c
 * Function:    eeprom读写操作
 * Description: eeprom读写操作测试程序
 * Author & Date: Joshua Chan, 2011/12/18 
 * *************************************************************/
#include "eeprom_io.h"

int main(int argc, char *argv[])
{
    u8 pos = 3;
    u8 data[5] = {32, 15, 99, 250, 6};

    eeprom_byte_write(pos, data[0]);  //单字节写操作

    data[0] = eeprom_byte_read(pos);  //单字节读操作

    eeprom_page_write(pos, data, 5);  //多字节写操作

    eeprom_page_read(pos, data, 5);   //多字节读操作

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值