天嵌 ARM开发社区

 找回密码
 注册
查看: 3549|回复: 13

i2c 读eep的问题

[复制链接]
chris_xi 发表于 2013-9-22 00:05:56 | 显示全部楼层 |阅读模式
今天看到原理图上的i2c只挂了个eeprom,写了个测试程序,通过ioctl去读写eep,可后来发现其中只有部分字节可写,大部分写不进去。每次上电后读到的eep中相同位置的值是不变的,应该可以说明可以正常读到。
读写都用的ioctl下的I2C_RDWR接口,读的时候会先写读的偏移下去,完全按照手册上指定地址度时序去读。可是写不知道为什么,很多地址写的值是不会变的。不知道是否是因为频率高了?频率建议在代码哪里修改?
i2c-dev.c和i2c-2410.c(板子是s210,但代码已验证移植自2410,估计tq移植没改名字)这两个文件中没找到配置的位置,又不想暴力修改时钟?
Calvin 发表于 2013-9-22 11:20:21 | 显示全部楼层
这里不关时钟的问题;EEPROM只支持Byte write和page write;而按照你所描述的,出错的原因是你没有按照datasheet说的page write来操作EEPROM。以下是datasheet的摘录
PAGE WRITE: The 2K EEPROM is capable of an 8-bytepage write, and the 4K and 8K devices are capable of 16-
byte page writes.
A page write is initiated the same as a byte write, but the
microcontroller does not send a stop condition after the first
data word is clocked in. Instead, after the EEPROM
acknowledges receipt of the first data word, the microcontroller
can transmit up to seven (2K) or fifteen (4K, 8K)
more data words. The EEPROM will respond with a zero
after each data word received. The microcontroller must
terminate the page write sequence with a stop condition

2K EEPROM 一个I2C时序只可以最多写8个字节,之后就必须要给出停止位,终止本次传输。而且读者进行下一次写操作之前必须延时10Ms,因为EEPROM的写时序为10ms。
回复

使用道具 举报

Calvin 发表于 2013-9-22 11:26:35 | 显示全部楼层
这里不关时钟的问题;EEPROM只支持Byte write和page write;而按照你所描述的,出错的原因是你没有按照datasheet说的page write来操作EEPROM。以下是datasheet的摘录
PAGE WRITE: The 2K EEPROM is capable of an 8-bytepage write, and the 4K and 8K devices are capable of 16-
byte page writes.
A page write is initiated the same as a byte write, but the
microcontroller does not send a stop condition after the first
data word is clocked in. Instead, after the EEPROM
acknowledges receipt of the first data word, the microcontroller
can transmit up to seven (2K) or fifteen (4K, 8K)
more data words. The EEPROM will respond with a zero
after each data word received. The microcontroller must
terminate the page write sequence with a stop condition
2K EEPROM 一个I2C时序只可以最多写8个字节,之后就必须要给出停止位,终止本次传输。而且读者进行下一次写操作之前必须延时10Ms,因为EEPROM的写时序为10ms。
回复

使用道具 举报

 楼主| chris_xi 发表于 2013-9-22 20:29:15 | 显示全部楼层
我是按照字节写的Byte Write:写时序按照附件中的模式,3个字节:地址,偏移,一个字节
关键代码:
        int wrlen = 2;   //(包含eep中偏移)
        char aaaa[32] = {0};
        i2c_data.msgs->addr = atoi(argv[2]);  //(从地址)
        i2c_data.msgs->len = wrlen;  
        i2c_data.msgs->flags = 0;   //写
      
        i2c_data.nmsgs = 1;         //一条消息
        i2c_data.msgs->buf = aaaa;

        i2c_data.msgs->buf[0] = atoi(argv[3]);     //EEP中偏移地址
        i2c_data.msgs->buf[1] = atoi(argv[4]);     //要写入的data

        ret = ioctl(fd,I2C_RDWR,&i2c_data);

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
回复

使用道具 举报

Calvin 发表于 2013-9-23 16:52:50 | 显示全部楼层
chris_xi 发表于 2013-9-22 20:29
我是按照字节写的Byte Write:写时序按照附件中的模式,3个字节:地址,偏移,一个字节
关键代码:
      ...

那你按照byte write时序写完一个字节后,有没有等待10ms再去写下一个字节? 这里无论是byte write还是page write模式都需要等待10ms,这个10ms是eeprom内部的写时序,如果你编程的时候没有加入延时,那么就会出现有部分字节可以写到,有部份字节写不进去eeprom的;所以在一个完整的写时序之后,务必要加延时,这里延时10ms就可以,至于其他类型的eeprom就看具体的datasheet说明了。
回复

使用道具 举报

 楼主| chris_xi 发表于 2013-9-23 22:49:43 | 显示全部楼层
本帖最后由 chris_xi 于 2013-9-23 22:51 编辑

我的测试代码只一次写一个字节
回复

使用道具 举报

 楼主| chris_xi 发表于 2013-9-23 23:19:10 | 显示全部楼层
/*参数1: 读写。参数2:SLAVE地址.参数3以后为buf中偏移*/
int main(int argc,char **argv)
{
    unsigned char a[128] = {0};
    struct i2c_rdwr_ioctl_data i2c_data;

    i2c_data.nmsgs = 0;
    i2c_data.msgs = (struct i2c_msg __user *)a;

    i2c_data.msgs->buf = NULL;

    int ret = -1;
        int n = 0;

        fd = open("/dev/i2c-0",O_RDONLY );

        if(fd < 0)
        {
                perror("/dev/i2c-0");
                return -1;
        }

    printf("line = %d\n",__LINE__);
    /*i2c-dev.c中ioctl读命令字*/
    if(0 == strncmp(argv[1],"iocread"))
    {
        unsigned char bbbb[16];
        int wrlen = 1;
        i2c_data.msgs->addr = atoi(argv[2]);

        i2c_data.msgs->len = wrlen;
        i2c_data.msgs->flags = 0;
        i2c_data.nmsgs = 1;

        i2c_data.msgs->buf = bbbb;

        printf("line = %d\n",__LINE__);
        i2c_data.msgs->buf[0] = atoi(argv[3]);
        printf("read addr = 0x%x, offset = 0x%x\n",i2c_data.msgs->addr, i2c_data.msgs->buf[0]);
        ret = ioctl(fd,I2C_RDWR,&i2c_data);
        if(ret < 0)
        {
            printf("ioctl fail\n");
        }

        wrlen = atoi(argv[4]);
        printf("wrlen = 0x%x\n",wrlen);
        i2c_data.msgs->addr = atoi(argv[2]);
        i2c_data.msgs->len = wrlen;
        i2c_data.msgs->flags = 1;
        i2c_data.nmsgs = 1;
        i2c_data.msgs->buf = (unsigned char*)malloc(wrlen);
        if(NULL == i2c_data.msgs->buf)
        {
            printf("malloc buf fail\n");
            return -1;
        }
        memset(i2c_data.msgs->buf,0,wrlen);

        printf("read addr = 0x%x\n",i2c_data.msgs->addr);
        ret = ioctl(fd,I2C_RDWR,&i2c_data);
        if(ret < 0)
        {
            printf("ioctl fail\n");
            return -1;
        }
        int i = 0;
        for(i = 0; i < i2c_data.msgs->len; i++)
        {
            printf("buf[%d] = 0x%x\n",i,i2c_data.msgs->buf[i]);
        }
        free(i2c_data.msgs->buf);

    }
    else if(0 == strncmp(argv[1],"iocwrite"))//i2c-dev.c中ioctl写命令字
    {
        /*设置超时时间和重试次数*/
        ioctl(fd,I2C_TIMEOUT,50);//timeout 500ms
        ioctl(fd,I2C_RETRIES,2);
        /*填写msgs结构体*/
        int wrlen = 2;
        char aaaa[32] = {0};
        i2c_data.msgs->addr = atoi(argv[2]);
        i2c_data.msgs->len = wrlen;
        i2c_data.msgs->flags = 0;
        i2c_data.nmsgs = 1;
        i2c_data.msgs->buf = aaaa;

        i2c_data.msgs->buf[0] = atoi(argv[3]);//片内偏移地址
        i2c_data.msgs->buf[1] = atoi(argv[4]);//要写入的值
        printf("atoi(argv[4]) = 0x%x,i2c_data.msgs->len = 0x%x\n",atoi(argv[4]),i2c_data.msgs->len);
        printf("write addr = 0x%x, offset = 0x%x, val = 0x%x\n",i2c_data.msgs->addr, i2c_data.msgs->buf[0], i2c_data.msgs->buf[1]);
        ret = ioctl(fd,I2C_RDWR,&i2c_data);
        if(ret < 0)
        {
            printf("ioctl fail\n");
        }

    }
    else if(0 == strncmp(argv[1],"write"))
    {
        unsigned char cccc[32] = {0};
        cccc[0] = atoi(argv[2]);
        cccc[1] = atoi(argv[3]);
        cccc[2] = atoi(argv[4]);
        write(fd,cccc,3);
    }
    else
    {
        printf("i2c_test op addr offset val/len\n");
    }


        close(fd);
        return 0;
}
回复

使用道具 举报

 楼主| chris_xi 发表于 2013-9-23 23:20:08 | 显示全部楼层
刚才又试了下,把timeout调大了点,还是不行
回复

使用道具 举报

Calvin 发表于 2013-9-24 10:17:06 | 显示全部楼层
本帖最后由 Calvin 于 2013-9-24 11:11 编辑
chris_xi 发表于 2013-9-23 23:20
刚才又试了下,把timeout调大了点,还是不行


这里的timeout主要是用于对同一I2C总线的竞争的时候,如果在timeout时间得不到I2C的总线权那么就返回,跟我之前说的10ms的写时序没有任何关系,而且这里的timeout是用于SMBUS协议的,而你的代码不是用SMBUS的方法;不如你把整个相关的代码以及如何测试的、怎么判断的,都发上来吧
回复

使用道具 举报

 楼主| chris_xi 发表于 2013-9-25 00:30:06 | 显示全部楼层
压缩包里是压缩代码很简单,make下就可以用,只包ioctl含读写命令:
读:./i2c_test iocread 45 0 10
写:./i2c_test iocwrite 45 80 9
命令格式:i2c_test <读或者写> <器件地址> <片内偏移> <写时写入值>/<读时读出长度>

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
回复

使用道具 举报

Calvin 发表于 2013-9-26 18:16:44 | 显示全部楼层
chris_xi 发表于 2013-9-25 00:30
压缩包里是压缩代码很简单,make下就可以用,只包ioctl含读写命令:
读:./i2c_test iocread 45 0 10
写: ...

我们用的代码是用smbus协议接口的,这个smbus协议接口可以,建议你用smbus协议接口来操作
回复

使用道具 举报

 楼主| chris_xi 发表于 2013-9-26 23:30:48 | 显示全部楼层
但是我看了驱动代码,i2c应该也是支持的,smbus有没有测试代码,分享下,多谢
回复

使用道具 举报

 楼主| chris_xi 发表于 2013-9-26 23:46:26 | 显示全部楼层
又看了下smbus驱动,貌似smbus不支持啊
static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
        .master_xfer                = s3c24xx_i2c_xfer,
        .functionality                = s3c24xx_i2c_func,
};
如果不支持还是会调master_xfer
回复

使用道具 举报

 楼主| chris_xi 发表于 2013-9-26 23:46:40 | 显示全部楼层
有测试代码吗,我试试
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

i.MX8系列ARM cortex A53 M4 工控板上一条 /1 下一条

Archiver|手机版|小黑屋|天嵌 嵌入式开发社区 ( 粤ICP备11094220号-2 )

GMT+8, 2025-5-1 17:37 , Processed in 2.042558 second(s), 21 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表