您的位置:首页 > 运维架构 > Linux

linux下通过i2c总线读写EEPROM

2012-07-23 16:45 316 查看
by 韩大卫@吉林师范大学

handawei@jusontech.com

转载请务必表明出处。

我的上篇文章《Linux下使用I2C总线读写 EEPROM(读写i2c从设备通用程序)》给出了通过IIC总线,如何读写EEPROM相应位置的内容。

但是有一些功能没有实现:

比如:  只能单独操作一个寄存器地址,不能一次性写入大量内容;

    只能读一个寄存器的数值,不能可选择性地一次读出大量内容;

这是由于为了做到通用化,我们的i2c没有一次性大量读写的功能。 在本程序中针对EEPROM做了一些改进,详细说明可以在help_info() 中找到。

FOR EXAMPLE:

    eep -r  0x08                        Display the contents of EEPROM from 0x00 to 0x08

    eep -ro 0x08                        Display the contents of EEPROM from 0x08

    eep -r  0x02 0x80                    Display the contents of EEPROM from address 0x20 to x080

    eep -s  0x04 "hello world!"                Write "hello world!" to EEPROM from 0x04

    eep -d /dev/i2c-1 -s  0x04 "hello world!"        Write "hello world!" to EEPROM from 0x04 with path"/dev/i2c-1"

*************************************************************

以下是具体代码:
main.c

********************** *******************************

#include "i2c.h"

#define TIMEOUT        4

#define RETRY        2

#define READ_ONLY    1

static int fd ;

static int addr = 0x57;  // EEPROM addr

static int offset;

static int offset_end;

inline int read_data(u16 addr, u8 offset, u8 *val){

    int ret;

   

    ret = i2c_read_data(addr,offset,val);

    if(ret < 0){

        printf("%s error!\n",__FUNCTION__);

        exit(-1);

    }

    return 0;

}

inline int write_data(u16 addr, u8 offset, u8 val){

    int ret;

   

    ret = i2c_write_data(addr,offset,val);

    if(ret < 0){

        printf("%s:error = %s\n",__FUNCTION__,strerror(errno));

        exit(-1);

    }

    usleep(10000);    // 重要!

    return 0;

}

int eep_write(u16 addr,u8 offset,char* argv){

    //u8 data = (u8)strtoul(argv,0,16);

    int i,j,len    = 0;

    char* data    = argv;

   

    while( *data++ ){

        len++;

    }

    data = argv;

    printf("len = %d\n",len);

    for( i = offset ,j = 0;i < offset + len ;i++,j++ ){

        write_data(addr,i,data[j]);

    }

    printf("write success,data = %s\n",argv);

    return 0;

}

int eep_read(u16 addr,u8 offset_start,u8 offset_end,int flags){

   

    int i;

    u8 buf[256] = {0};

    if( flags ){

        read_data(addr,offset_end,&buf[0]);

        printf("read success,data[%d] = %c\n",offset,buf[0]);

    }else{

        printf("read success,data = ");

        for(i = offset_start ; i <= offset_end ; i++){       

            read_data(addr,i,&buf[i]);       

            printf("%c",buf[i]);   

        }

        printf("\n");

    }   

   

    return 0;

}

void error_info(void){

    printf("cmd error! ");

    printf("Please input --help or -h  for help information\n");

    exit(-1);

}   

void help_info(void){

        printf("\nUsage: eep OPTIONS OFFSET [OFFSET_END] [DATA]\n");

        printf("\nDisplay the contents of EEPROM ,or write DATA to EEPROM\n");

        printf("\nOptions:\n");

        printf("\n\t-r OFFST \t\t\t\tDisplay the contents of EEPROM from 0x00 to OFFSET\n");

        printf("\n\t-r OFFSET OFFSET_END\t\t\tDisplay the contents of EEPROM from OFFSET to OFFSET_END\n");

        printf("\n\t-s OFFSET DATA\t\t\t\twrite DATA to EEPROM form OFFSET\n");

    printf("\n\t-h or --help\t\t\t\tshow help information\n");

    printf("\nOFFSET\tFORMAT: 0xXX  0xXX can change from 00 to ff\n");

    printf("\nFOR EXAMPLE:\n");

    printf("\n\teep -r  0x08\t\t\t\tDisplay the contents of EEPROM from 0x00 to 0x08\n");

    printf("\n\teep -ro 0x08\t\t\t\tDisplay the contents of EEPROM from 0x08\n");

    printf("\n\teep -r  0x02 0x80\t\t\tDisplay the contents of EEPROM from address 0x20 to x080\n");

    printf("\n\teep -s  0x04 \"hello world!\"\t\tWrite \"hello world!\" to EEPROM from 0x04\n\n");

}

int i2c_path(char * argv){

    fd = i2c_open(argv,TIMEOUT,RETRY);

    if( fd < 0 ){   

        printf("i2c_open error!\n");

        exit(-1);

    }   

    return 0;

}

int i2c_offs(char *argv){

    return (u8)strtoul(argv,0,16);

}

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

    int flags;

   

    switch(argc){

    case 2 :{

                if(!strcmp(argv[1],"-h") || !strcmp(argv[1],"--help")){

                        help_info();

                }else

            error_info();

        }break;

        case 3 :{

        if(!strcmp(argv[1],"-r" )|| !strcmp(argv[1],"-ro" )){

            flags    = (!strcmp(argv[1],"-ro")) ? READ_ONLY : 0 ;

                    i2c_path("/dev/i2c-0");

            offset    = i2c_offs(argv[2]);   

            eep_read(addr,0,offset,flags);

        }else

            error_info();   

        }break;

        case 4 :{

        if(!strcmp(argv[1],"-r")){

                    i2c_path("/dev/i2c-0");

            offset        = i2c_offs(argv[2]);   

            offset_end    = i2c_offs(argv[3]);   

            eep_read(addr,offset,offset_end,0);

        }else if(!strcmp(argv[1],"-s")){

            i2c_path("/dev/i2c-0");

            offset        = i2c_offs(argv[2]);

            eep_write(addr,offset,argv[3]);   

        }else

            error_info();   

        }break;

        case 5 :{

                if(!strcmp(argv[1],"-d")){

                        i2c_path(argv[2]);

                    if(!strcmp(argv[3],"-r") || !strcmp(argv[3],"-ro")){

                            i2c_offs(argv[4]);

                flags   = (!strcmp(argv[3],"-ro")) ? READ_ONLY : 0 ;

                            offset  = i2c_offs(argv[4]);   

                            eep_read(addr,0,offset,flags);

            }else

                error_info();

                }else

            error_info();

        }break;

        case 6 :{

              if(!strcmp(argv[1],"-d")){

                        i2c_path(argv[2]);

                        if(!strcmp(argv[3],"-r")){

                                offset        = i2c_offs(argv[4]);

                offset_end    = i2c_offs(argv[5]);

                eep_read(addr,offset,offset_end,0);

                        }else if(!strcmp(argv[3],"-s")){

                offset        = i2c_offs(argv[4]);

                eep_write(addr,offset,argv[5]);

            }else

                error_info();

                }else

            error_info();   

        }break;

        default:

            error_info();   

        }

    return 0;

}

*************************** ********************************

i2c.c

*********************************************************

#include "i2c.h"

static int fd;

int

i2c_read_data(u16 addr, u8 offset, u8 *val)

{

    int i,ret = 0;

    struct i2c_rdwr_ioctl_data *data;

    if ((data = (struct i2c_rdwr_ioctl_data *)malloc(sizeof(struct i2c_rdwr_ioctl_data))) == NULL)

    return -1;

    data->nmsgs = 2;

    if ((data->msgs = (struct i2c_msg *)malloc(data->nmsgs * sizeof(struct i2c_msg))) == NULL) {

        ret = -1;

        goto errexit3;

    }

    if ((data->msgs[0].buf = (unsigned char *)malloc( EEPROM_PAGE_SIZE + 1 )) == NULL) {

        ret = -1;

        goto errexit2;

    }

    if ((data->msgs[1].buf = (unsigned char *)malloc( EEPROM_PAGE_SIZE + 1 )) == NULL) {

        ret = -1;

        goto errexit1;

    }

    data->msgs[0].addr    = addr;

    data->msgs[0].flags    = I2C_M_WR;

    data->msgs[0].len    = 1;

    data->msgs[0].buf[0]    = offset;

    data->msgs[1].addr    = addr;

    data->msgs[1].flags    = I2C_M_RD;

    data->msgs[1].len    = 1;   

    data->msgs[1].buf[0]    = 0;

    if ((ret = __i2c_send(fd, data)) < 0)   

        goto errexit0;

    for(i = 0 ;i < data->msgs[1].len; i++)

        val[i] = data->msgs[1].buf[i];

errexit0:

    free(data->msgs[1].buf);

errexit1:

    free(data->msgs[0].buf);

errexit2:

    free(data->msgs);

errexit3:

    free(data);

    return ret;

}

int

i2c_write_data(u16 addr, u8 offset, u8 val)

{

    int ret = 0;

    struct i2c_rdwr_ioctl_data *data;

    if ((data = (struct i2c_rdwr_ioctl_data *)malloc(sizeof(struct i2c_rdwr_ioctl_data))) == NULL)

        return -1;

    data->nmsgs = 1;

    if ((data->msgs = (struct i2c_msg *)malloc(data->nmsgs * sizeof(struct i2c_msg))) == NULL) {

        ret = -1;

        goto errexit2;

    }

    if ((data->msgs[0].buf = (unsigned char *)malloc( 2 * (EEPROM_PAGE_SIZE + 1))) == NULL) {

        ret = -1;

        goto errexit1;

    }

    data->msgs[0].addr    = addr;

    data->msgs[0].flags    = 0;

    data->msgs[0].len    = 2;

    data->msgs[0].buf[0]    = offset;

    data->msgs[0].buf[1]    = val;

    if ((ret = __i2c_send(fd, data)) < 0){

        ret = -1;

        goto errexit0;

    }

errexit0:

    free(data->msgs[0].buf);

errexit1:

    free(data->msgs);

errexit2:

    free(data);

    return ret;

}

int

i2c_open(unsigned char* dev, unsigned int timeout, unsigned int retry)

{

    if ((fd = open(dev, O_RDWR)) < 0)

        return fd;

    __i2c_set(fd, timeout, retry);

    return fd;

}

static int

__i2c_send(int fd, struct i2c_rdwr_ioctl_data *data)

{

    if (fd < 0)

        return -1;

    if (data == NULL)

        return -1;

    if (data->msgs == NULL || data->nmsgs == 0)

        return -1;

   

    return ioctl(fd, I2C_RDWR, (unsigned long)data) ;

}

static int

__i2c_set(int fd, unsigned int timeout, unsigned int retry)

{

    if (fd == 0 )

        return -1;

    ioctl(fd, I2C_TIMEOUT, timeout ? timeout : I2C_DEFAULT_TIMEOUT);

    ioctl(fd, I2C_RETRIES, retry ? retry : I2C_DEFAULT_RETRY);

   

    return 0;

}

void

i2c_close(int fd)

{

    if (fd < 0)

        return;

    close(fd);

}

unsigned bcd2bin(unsigned char val)

{      

        return (val & 0x0f) + (val >> 4) * 10; 

}

unsigned char bin2bcd(unsigned val)

{      

        return ((val / 10) << 4) + val % 10;

}   

******************************************************

i2c.h:

*********************************************************

 #ifndef _EEPROM_IO_H

#define _EEPROM_TO_H

#include <linux/i2c.h>

#include <linux/i2c-dev.h>

#include <linux/rtc.h>

#include <stdio.h>

#include <linux/types.h>

#include <stdlib.h>

#include <fcntl.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/ioctl.h>

#include <errno.h>

#include <string.h>

#define I2C_DEFAULT_TIMEOUT        1

#define I2C_DEFAULT_RETRY        2

#define I2C_M_WR        0                //定义写标志

#define MAX_MSG_NR        2                //根据AT24C02手册, 最大消息数为2

#define EEPROM_BLOCK_SIZE    256                //每个block容量256 bytes

#define EEPROM_PAGE_SIZE    8                  //用页写,AT24C02页大小为8字节

#define I2C_MSG_SIZE         (sizeof(struct i2c_msg))

typedef unsigned char           u8;

typedef unsigned short          u16;

typedef unsigned int            u32;

typedef unsigned long long      u64;

typedef signed char             s8;

typedef short                   s16;            

typedef int                     s32;

typedef long long               s64;

unsigned bcd2bin(unsigned char val);

unsigned bcd2bin(unsigned char val);

static int

__i2c_send(int fd, struct i2c_rdwr_ioctl_data *data);

static int

__i2c_set(int fd, unsigned int timeout, unsigned int retry);

int

i2c_read_data(u16 addr, u8 offset, u8 *val);

int

i2c_write_data(u16 addr, u8 offset, u8 val);

int

i2c_open(unsigned char* dev, unsigned int timeout, unsigned int retry);

#endif

****************************************************************
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c linux struct null path function