免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 6300 | 回复: 11
打印 上一主题 下一主题

I2C RepStart Mode 的编写 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-03-05 11:09 |只看该作者 |倒序浏览
10可用积分
请问如何在应用层使用I2C_RDWR的ioctl 读的操作, 操作内核层的i2c dev.c结构。
如实现fun_read(int slave, int addr, uint8_t *rx, int rxlen) 对salve的设备对addr地址进行读取操作。
  work_queue.nmsgs = 2;
    work_queue.msgs = (struct i2c_msg*)malloc(work_queue.nmsgs * sizeof(struct i2c_msg));
        (work_queue.msgs[0]).len = 1;
        (work_queue.msgs[0]).addr = slave>>1;
        (work_queue.msgs[0]).flags=0;
        (work_queue.msgs[0]).buf = &addr;

        (work_queue.msgs[1]).len = rxlen;
        (work_queue.msgs[1]).addr = slave>>1;
        (work_queue.msgs[1]).flags=1;
        (work_queue.msgs[1]).buf = rx;
    ret = ioctl(fd, I2C_RDWR, (unsigned long)&work_queue);
    free(work_queue.msgs);
if(ret<0)
        {
           printf("Error dring I2C_RDWR ioctl with error code: %d\n",ret);
        return ret;
        }
    return ret;

1. 请问 为什么要用2个msg? 不是一个吗?
2. 请问如何写操作是使用i2cdev_write()(即是直接fd=open /dev/i2c.  然后write(fd...))会有问题吗?

最佳答案

查看完整内容

1.如果才一个msgs 那么offset command放在哪个变量呢?都往msg[0].buff里放。目前你的代码只放了address, 而且buff是个指针,指向了slave_address.你需要申请一个buffer, 用来暂存slave_address & offset, 然后把这个buffer的地址赋给msg[0].buff2.单独write是没有问题的。 操作了read(re-start模式)后在写就有问题了。 why? investigating..如果单独write没问题, 你试试write + read呢,是否正常?或者说,你的单独的read正常 ...

论坛徽章:
5
2 [报告]
发表于 2009-03-05 11:09 |只看该作者
原帖由 studyboy_3w 于 2009/3/5 11:54 发表
1.如果才一个msgs 那么offset command放在哪个变量呢?
2.单独write是没有问题的。 操作了read(re-start模式)后在写就有问题了。 why? investigating...



1.如果才一个msgs 那么offset command放在哪个变量呢?
都往msg[0].buff里放。

目前你的代码只放了address, 而且buff是个指针,指向了slave_address.
你需要申请一个buffer, 用来暂存slave_address & offset, 然后把这个buffer的地址赋给msg[0].buff

2.单独write是没有问题的。 操作了read(re-start模式)后在写就有问题了。 why? investigating..
如果单独write没问题, 你试试write + read呢,是否正常?
或者说,你的单独的read正常吗?

评分

参与人数 1可用积分 +15 收起 理由
dreamice + 15 我很赞同,感谢解决问题

查看全部评分

论坛徽章:
5
3 [报告]
发表于 2009-03-05 11:23 |只看该作者
原帖由 studyboy_3w 于 2009/3/5 11:09 发表

1. 请问 为什么要用2个msg? 不是一个吗?
2. 请问如何写操作是使用i2cdev_write()(即是直接fd=open /dev/i2c.  然后write(fd...))会有问题吗?




1. 请问 为什么要用2个msg? 不是一个吗?
读操作, 是从哪个设备地址,哪个偏移,用什么读命令,来进行操作。对于读操作,其实包含两个过程:
a. master把设备相关的一些信息发过去,即往总线上发slave address, slave offset, command(command为可选项)
b. 再从slave读取数据。

2. 请问如何写操作是使用i2cdev_write()(即是直接fd=open /dev/i2c.  然后write(fd...))会有问题吗?
不是太肯定。可以试一下。你要保证:
a. 参数传递正确。
b. i2cdev_write能最终调用i2c的write命令。
加点调试信息,确保上面两步无误。

论坛徽章:
5
4 [报告]
发表于 2009-03-05 11:25 |只看该作者
补充一下,

从下面的代码来看,
        (work_queue.msgs[0]).len = 1;
        (work_queue.msgs[0]).addr = slave>>1;
        (work_queue.msgs[0]).flags=0;
        (work_queue.msgs[0]).buf = &addr;

你的I2C设备,读命令时,只传递了slave address而已,不需要传递offset, command等。

论坛徽章:
5
5 [报告]
发表于 2009-03-05 11:32 |只看该作者
问一下LZ,
I2C RepStart Mode, 这里的RepStart是I2C的Re-start吗?

论坛徽章:
0
6 [报告]
发表于 2009-03-05 11:54 |只看该作者
原帖由 yidou 于 2009-3-5 11:32 发表
问一下LZ,
I2C RepStart Mode, 这里的RepStart是I2C的Re-start吗?



是的。 repeat-start 重复开始模式。 就是I2C模式2.
要求时序为:   Start | Slave_Address | 0 | Ack | Register_Address_MSB | Ack | Register_Address_LSB | Ack |
  Re-start | Slave_Address | 1 | Ack | XXXX_MSB | Ack | XXXX_LSB | NAck or Stop.

1. 请问 为什么要用2个msg? 不是一个吗?
读操作, 是从哪个设备地址,哪个偏移,用什么读命令,来进行操作。对于读操作,其实包含两个过程:
a. master把设备相关的一些信息发过去,即往总线上发slave address, slave offset, command(command为可选项)
b. 再从slave读取数据。
从下面的代码来看,
        (work_queue.msgs[0]).len = 1;
        (work_queue.msgs[0]).addr = slave>>1;
        (work_queue.msgs[0]).flags=0;
        (work_queue.msgs[0]).buf = &addr;

你的I2C设备,读命令时,只传递了slave address而已,不需要传递offset, command等。
>>offset 是需要的。 但是offset是通过那个变量来储存和发送呢?是否msgs·[0]通过写发送addr=slave address   buf=&addr偏移量(offset)。然后msgs[1]通过读操作读addr=slave 读到buf上去?

如果才一个msgs 那么offset command放在哪个变量呢?


2. 请问如何写操作是使用i2cdev_write()(即是直接fd=open /dev/i2c.  然后write(fd...))会有问题吗?
不是太肯定。可以试一下。你要保证:
a. 参数传递正确。
b. i2cdev_write能最终调用i2c的write命令。
加点调试信息,确保上面两步无误。
》单独write是没有问题的。 操作了read(re-start模式)后在写就有问题了。 why? investigating...

论坛徽章:
0
7 [报告]
发表于 2009-03-05 13:25 |只看该作者
原帖由 yidou 于 2009-3-5 12:48 发表



1.如果才一个msgs 那么offset command放在哪个变量呢?
都往msg[0].buff里放。

目前你的代码只放了address, 而且buff是个指针,指向了slave_address.
你需要申请一个buffer, 用来暂存slave_address  ...



1.如果才一个msgs 那么offset command放在哪个变量呢?
都往msg[0].buff里放。

目前你的代码只放了address, 而且buff是个指针,指向了slave_address.
你需要申请一个buffer, 用来暂存slave_address & offset, 然后把这个buffer的地址赋给msg[0].buff
>>你的意思是说:
        (work_queue.msgs[0]).len = 1;
        (work_queue.msgs[0]).addr = slave>>1;
        (work_queue.msgs[0]).flags=0;
        (work_queue.msgs[0]).buf = slave_address & offset 还是 只是offset?


2.单独write是没有问题的。 操作了read(re-start模式)后在写就有问题了。 why? investigating..
如果单独write没问题, 你试试write + read呢,是否正常?
或者说,你的单独的read正常吗?
>> write->read 是成功的。 读不了数据的。 因为read是mode 1.   时序不对。



参考代码  http://blog.chinaunix.net/u3/91468/showart_1798987.html
linux下24c08的i2c读写程序

#include <stdio.h>
#include <linux/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <assert.h>
#include <string.h>

#define MAX_I2C_MSG 2
#define I2C_RETRIES 0x701
#define I2C_TIMEOUT 0x702
#define I2C_RDWR 0x707
#define    I2C_M_RD 0x1

struct i2c_msg
{
    __u16    addr;
    __u16    flags;
    __u16    len;
    __u8 *buf;
};

struct i2c_rdwr_ioctl_data
{
    struct i2c_msg *msgs;
    int nmsgs;
};

void clear_whole_eeprom();
void set_whole_eeprom();
void read_whole_eeprom();
void print_usage(__u8 *argv)
{
    printf("\nUsage: %s [-c\\-s\\-r]\n",argv);

}
int main(int argc, char **argv)
{
    int cmd;
    if (argc!=2)
    {
        print_usage(argv[0]);
        return 0;
    }
    if(strcmp(argv[1],"-c") == 0)
        cmd=1;
    else if(strcmp(argv[1],"-s")==0)
        cmd=2;
    else if(strcmp(argv[1],"-r")==0)
        cmd=3;
    else
    {
        print_usage(argv[0]);
        return 0;
    }

    int fd;
    fd = open("/dev/i2c/0",O_RDWR);
    if(fd<=0)
    {
        printf("ERROR on opening the device file,fd=%d\n",fd);
        return 0;
    }
    switch(cmd)
    {
        case 1:
            clear_whole_eeprom();
            break;
        case 2:
            set_whole_eeprom();
            break;
        case 3:
            read_whole_eeprom();
            break;
        default:
            break;
    }
    close(fd);            
    return 0;
}
__s32 write_eeprom(__s32 fd,__u32 offset,__u32 len,__u8 *buf)
{
    __s32 ret;
    struct i2c_rdwr_ioctl_data work_queue;
    __u8 tmp[24];
    __u32 i,bytes;
    bytes=len;
    if((offset+len)>1024)
    {
        printf("write too long than 1024\n");
        return -1;
    }
    work_queue.nmsgs = 1;
    work_queue.msgs = (struct i2c_msg*)malloc(work_queue.nmsgs * sizeof(struct i2c_msg));

    do{
        work_queue.msgs->len=len>(16-offset%16)?(16-offset%16+1):len+1;
        work_queue.msgs->addr=0x50+offset/256;
        work_queue.msgs->flags=0;//write

        tmp[0]=offset%256;
        memcpy(tmp+1,buf,16);
        work_queue.msgs->buf = tmp;
#if 0
        printf("buf=%x,offset=%u,len=%u,addr=%x\n",buf,tmp[0],work_queue.msgs->len,work_queue.msgs->addr);
        printf("tmp=");
        for(i=0;i<(work_queue.msgs->len-1);i++)
        {
            printf("%u ",tmp[i+1]);
        }
        printf("\n");
#endif
        ret = ioctl(fd, I2C_RDWR, (unsigned long)&work_queue);
        if(ret<0)
        {
            printf("Error dring I2C_RDWR ioctl with error code: %d\n",ret);
            return ret;
        }
        len = len - (work_queue.msgs->len-1);
        buf=buf+16-offset%16;
        offset=offset+(16-offset%16);
//        usleep(1);

    }while(len>0);

    return bytes;
}
__s32 read_eeprom(__s32 fd,__u32 offset,__u32 len,__u8 *buf)
{
    struct i2c_rdwr_ioctl_data work_queue;
    __u8 tmp[24];
    __s32 ret=0,bytes;
    if((offset+len)>1024)
    {
        printf("read too long than 1024\n");
        return -1;
    }

    bytes=len;
    work_queue.nmsgs = 2;
    work_queue.msgs = (struct i2c_msg*)malloc(work_queue.nmsgs * sizeof(struct i2c_msg));
        (work_queue.msgs[0]).len = 1;
        (work_queue.msgs[0]).addr = 0x50 + offset/256;
        (work_queue.msgs[0]).flags=0;
    tmp[0]=offset%256;
        (work_queue.msgs[0]).buf = tmp;

        (work_queue.msgs[1]).len = len;
        (work_queue.msgs[1]).addr = 0x50 + offset/256;
        (work_queue.msgs[1]).flags=1;
        (work_queue.msgs[1]).buf = buf;
    ret = ioctl(fd, I2C_RDWR, (unsigned long)&work_queue);
    if(ret<0)
        {
           printf("Error dring I2C_RDWR ioctl with error code: %d\n",ret);
        return ret;
        }
    return len;
}

void clear_whole_eeprom(int fd)
{
    __s32 ret;
    __u8 buf[1024];
    bzero(buf,1024);
    ret=write_eeprom(fd,0,1024,buf);
    if(ret<0)
        printf("write eeprom error\n");
    else
        printf("clear %u bytes\n",ret);
}

论坛徽章:
5
8 [报告]
发表于 2009-03-05 13:39 |只看该作者
撞头ing

论坛徽章:
0
9 [报告]
发表于 2009-03-05 14:30 |只看该作者
粗略看了内核i2c操作,应该这样
buf=malloc((rxlen)*sizeof(uint8_t));
memcpy(buf, &address, 2)
        (work_queue.msgs[0]).len = rxlen;
        (work_queue.msgs[0]).addr = slave>>1;
        (work_queue.msgs[0]).flags=1;
        (work_queue.msgs[0]).buf =buf;
ioctl(...)
memcpy(rx,buf,rxlen);
free

论坛徽章:
5
10 [报告]
发表于 2009-03-05 14:51 |只看该作者
94. 你找个例子多好。 比我一步一步解释强多了。

还有问题时, 你三方面下手:
1. slave datasheet. 理解slave的时序,
2. kernel中i2c的框架, i2c module本身会帮你做哪些,
3. i2c master driver, 这是你要准备或处理的数据。
i2c module会把你准备好的数据,按固有的时序发出去,这个master时序严格匹配slave时序就能工作了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP