• 正文
  • 相关推荐
申请入驻 产业图谱

飞凌嵌入式ElfBoard-i2c与从设备通讯编程示例之i2c-tools工具使用

11小时前
180
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

对于我们ELF2板卡来说,我们前面看到的i2c-0、i2c-5等总线对应着CPU的i2c适配器,作为主设备,而总线上挂载的设备作为从设备。如/dev/i2c-5对应的适配器作主设备,其上面挂载的RTC rx8010就作为从设备。

前面我们了解了i2c的通讯协议,也初步用i2c-tools尝试着读写了一个从设备寄存器。下面我们进入代码,看一下如何用代码读取RTC rx8010中的值。

查看i2c总线节点

Linux内核代码文件include/linux/i2c-dev.h中针对每个i2c总线生成一个设备节点,实现了文件操作接口,用户空间可以通过i2c设备节点访问i2c适配器。适配器的编号从0开始,和适配器的设备节点的次设备号相同。

通过代码操控i2c适配器,必须包含以下头文件:

#include <linux/i2c.h>

#include <linux/i2c-dev.h>

查看i2c设备节点:

root@elf2-buildroot:~# ls /dev/i2c*

/dev/i2c-0  /dev/i2c-10  /dev/i2c-3  /dev/i2c-5  /dev/i2c-9

/dev/i2c-1  /dev/i2c-2   /dev/i2c-4  /dev/i2c-7

i2c设备节点是/dev/i2c-x,其中x是数字,代表i2c总线的编号。

打开设备

需要用到open()函数打开主设备i2c适配器,并获得文件描述符:

#define dev    /dev/i2c-5

i2c_fd = open(dev, O_RDWR);

if (i2c_fd < 0) {

perror(dev);

printf("Can't Open i2c device %s \n", dev);

exit(0);

}

使用open()打开/dev/i2c-5总线,如果打开节点失败,会返回节点名称并输出"Can't Open i2c device"。

写寄存器

int func_write_regs(unsigned char devaddr,unsigned char reg, unsigned char *buf)

{

struct i2c_rdwr_ioctl_data work_queue;

int ret;

work_queue.nmsgs = 1;

work_queue.msgs = (struct i2c_msg *)malloc(work_queue.nmsgs * sizeof(work_queue.msgs));

if (!work_queue.msgs) {

printf("memory alloc failed");

ret = -1;

return ret;

}

work_queue.nmsgs = 1;

(work_queue.msgs[0]).len = 2; // buf的长度,要写的字节数+1字节地址

(work_queue.msgs[0]).flags = 0;          // write

(work_queue.msgs[0]).addr = devaddr;     //设备地址

(work_queue.msgs[0]).buf = (unsigned char *)malloc(2);

(work_queue.msgs[0]).buf[0] = reg;                 //写的地址

memcpy(&work_queue.msgs[0].buf[1], buf, 1); //你要写的数据

ret = ioctl(fd, I2C_RDWR, (unsigned long)&work_queue);

if (ret < 0)

printf("error during I2C_RDWR ioctl with error code %d\n", ret);

free((work_queue.msgs[0]).buf);

free(work_queue.msgs);

return ret;

}

1.创建消息结构体

i2c控制器和从设备之间通讯的消息,通常是储存在一个结构体中,首先,定义了一个i2c_rdwr_ioctl_data结构体,用于存储i2c通信相关的消息,我们需要规定好消息的数量,以及给这个消息申请一块空间。

    struct i2c_rdwr_ioctl_data work_queue;

int ret;

work_queue.nmsgs = 1;

work_queue.msgs = (struct i2c_msg *)malloc(work_queue.nmsgs * sizeof(work_queue.msgs));

2.设置i2c参数

设置要写入数据的相关信息:

work_queue.nmsgs被设置为1,表示只有一个消息要发送;

(work_queue.msgs[0]).len被设置为2,表示要写入的数据长度;

(work_queue.msgs[0]).flags被设置为0,表示写操作;

(work_queue.msgs[0]).addr被设置为devaddr,表示要写入数据的设备地址。

(work_queue.msgs[0]).buf通过动态内存分配了足够的空间,并将数据写入其中。首先在第一个字节位置(work_queue.msgs[0]).buf[0]写入设备地址reg,然后使用memcpy函数将要写入的数据buf拷贝到后续的字节位置。

    work_queue.nmsgs = 1;

(work_queue.msgs[0]).len = 2;

(work_queue.msgs[0]).flags = 0;          // write

(work_queue.msgs[0]).addr = devaddr;     //设备地址

(work_queue.msgs[0]).buf = (unsigned char *)malloc(2);

(work_queue.msgs[0]).buf[0] = reg;                 //写的地址

memcpy(&work_queue.msgs[0].buf[1], buf, 1); //你要写的数据

3.写入数据

调用ioctl函数执行i2c写操作,并将返回值赋给ret。如果返回值小于0,则打印错误信息。

释放动态分配的内存,因为前面有两处调用了malloc(),所以这里需要释放两次内存,包括(work_queue.msgs[0]).buf和work_queue.msgs,然后返回ret。

 ret = ioctl(fd, I2C_RDWR, (unsigned long)&work_queue);

if (ret < 0)

printf("error during I2C_RDWR ioctl with error code %d\n", ret);

free((work_queue.msgs[0]).buf);

free(work_queue.msgs);

return ret;

读寄存器

int func_read_regs(unsigned char devaddr,unsigned char reg, unsigned char *read_data)

{

struct i2c_rdwr_ioctl_data work_queue;

int ret;

work_queue.nmsgs = 1;

/* 消息数量 */

work_queue.msgs = (struct i2c_msg *)malloc(work_queue.nmsgs * sizeof(work_queue.msgs));

if (!work_queue.msgs) {

printf("Memory alloc error\n");

close(fd);

return -1;

}

(work_queue.msgs[0]).len = 1;

(work_queue.msgs[0]).flags = 0;         //写数据的标志位

(work_queue.msgs[0]).addr = devaddr;

(work_queue.msgs[0]).buf = (unsigned char *)malloc(1);

(work_queue.msgs[0]).buf[0] = reg;

ret = ioctl(fd, I2C_RDWR, (unsigned long)&work_queue);

if (ret < 0) {

printf("error during I2C_RDWR ioctl with error code %d\n", ret);

return ret;

}

(work_queue.msgs[0]).len = 1;

(work_queue.msgs[0]).flags = 1;  //读数据的标志位

(work_queue.msgs[0]).addr = devaddr;

ret = ioctl(fd, I2C_RDWR, (unsigned long) &work_queue);

if (ret < 0) {

printf("Error during I2C_RDWR ioctl with error code: %d\n", ret);

return ret;

} else {

// printf("read val:%02x\n", (work_queue.msgs[0]).buf[0]);

*read_data=work_queue.msgs[0].buf[0];

}

free(work_queue.msgs[0].buf);

free(work_queue.msgs);

return ret;

}

1.创建消息结构体

i2c控制器和从设备之间通讯的消息,通常是储存在一个结构体中,首先,定义了一个i2c_rdwr_ioctl_data结构体,用于存储i2c通信相关的消息,我们需要规定好消息的数量,以及给这个消息申请一块空间。

    struct i2c_rdwr_ioctl_data work_queue;

int ret;

work_queue.nmsgs = 1;

work_queue.msgs = (struct i2c_msg *)malloc(work_queue.nmsgs * sizeof(work_queue.msgs));

2.写寄存器地址

设置要写入数据的相关信息:

1)work_queue.nmsgs被设置为1,表示只有一个消息要发送;

2)(work_queue.msgs[0]).len被设置为1,表示要写入的数据长度;

3)(work_queue.msgs[0]).flags被设置为0,表示写操作;

4)(work_queue.msgs[0]).addr被设置为devaddr,表示要写入数据的设备地址。

5)(work_queue.msgs[0]).buf通过动态内存分配了足够的空间,并将寄存器地址写入其中。

(work_queue.msgs[0]).len = 1;

(work_queue.msgs[0]).flags = 0;         //写数据的标志位

(work_queue.msgs[0]).addr = devaddr;

(work_queue.msgs[0]).buf = (unsigned char *)malloc(1);

(work_queue.msgs[0]).buf[0] = reg;

调用ioctl函数执行i2c写操作,并将返回值赋给ret。如果返回值小于0,则打印错误信息。

ret = ioctl(fd, I2C_RDWR, (unsigned long)&work_queue);

if (ret < 0) {

printf("error during I2C_RDWR ioctl with error code %d\n", ret);

return ret;

}

3.读寄存器

储存的i2c通讯所需信息:

设置要写入数据的相关信息:

1)(work_queue.msgs[0]).len被设置为1,表示要写入的数据长度。

2)(work_queue.msgs[0]).flags被设置为1,表示读数据的标志位。

3)(work_queue.msgs[0]).addr被设置为devaddr,表示要写入数据的设备地址。

(work_queue.msgs[0]).len = 1;

(work_queue.msgs[0]).flags = 1;  //读数据的标志位

(work_queue.msgs[0]).addr = devaddr;

调用ioctl函数执行i2c读操作,并将返回值赋给ret。如果返回值小于0,则打印错误信息。

释放动态分配的内存,因为前面有两处调用了malloc(),所以这里需要释放两次内存,包括(work_queue.msgs[0]).buf和work_queue.msgs,然后返回ret。

ret = ioctl(fd, I2C_RDWR, (unsigned long) &work_queue);

if (ret < 0) {

printf("Error during I2C_RDWR ioctl with error code: %d\n", ret);

return ret;

} else {

// printf("read val:%02x\n", (work_queue.msgs[0]).buf[0]);

*read_data=work_queue.msgs[0].buf[0];

}

free(work_queue.msgs[0].buf);

free(work_queue.msgs);

return ret;

关闭设备

需要用到close()函数关闭主设备i2c适配器。

相关推荐