Linux i2c 连续 写长数据,「正点原子Linux连载」第六十一章Linux I2C驱动实验(二)...

本文详细介绍了Linux环境下I2C驱动的使用,特别是如何利用i2c_transfer函数进行连续写长数据操作。通过分析`i2c_msg`结构体和`i2c_transfer`函数,展示了读写I2C设备多个寄存器的步骤,并给出了读取和写入AP3216C传感器数据的示例代码。同时,文章还涵盖了设备树配置以及I2C设备驱动的probe和remove函数,提供了驱动程序和测试应用的编写方法。
摘要由CSDN通过智能技术生成

1)实验平台:正点原子Linux开发板

2)摘自《正点原子I.MX6U嵌入式Linux驱动开发指南》

关注官方微信号公众号,获取更多资料:正点原子

jishu_1911969_1_1.html

61.3.2 I2C设备数据收发处理流程在61.1.2小节已经说过了,I2C设备驱动首先要做的就是初始化i2c_driver并向Linux内核注册。当设备和驱动匹配以后i2c_driver里面的probe函数就会执行,probe函数里面所做的就是字符设备驱动那一套了。一般需要在probe函数里面初始化I2C设备,要初始化I2C设备就必须能够对I2C设备寄存器进行读写操作,这里就要用到i2c_transfer函数了。i2c_transfer函数最终会调用I2C适配器中i2c_algorithm里面的master_xfer函数,对于I.MX6U而言就是i2c_imx_xfer这个函数。i2c_transfer函数原型如下:

int i2c_transfer(struct i2c_adapter *adap,

struct i2c_msg *msgs,

int num)

函数参数和返回值含义如下:

adap:所使用的I2C适配器,i2c_client会保存其对应的i2c_adapter。

msgs:I2C要发送的一个或多个消息。

num:消息数量,也就是msgs的数量。

返回值:负值,失败,其他非负值,发送的msgs数量。

我们重点来看一下msgs这个参数,这是一个i2c_msg类型的指针参数,I2C进行数据收发说白了就是消息的传递,Linux内核使用i2c_msg结构体来描述一个消息。i2c_msg结构体定义在include/uapi/linux/i2c.h文件中,结构体内容如下:

示例代码61.3.2.1 i2c_msg结构体

68struct i2c_msg {

69 __u16 addr; /* 从机地址 */

70 __u16 flags; /* 标志 */

71 #define I2C_M_TEN 0x0010

72 #define I2C_M_RD 0x0001

73 #define I2C_M_STOP 0x8000

74 #define I2C_M_NOSTART 0x4000

75 #define I2C_M_REV_DIR_ADDR 0x2000

76 #define I2C_M_IGNORE_NAK 0x1000

77 #define I2C_M_NO_RD_ACK 0x0800

78 #define I2C_M_RECV_LEN 0x0400

79 __u16 len; /* 消息(本msg)长度 */

80 __u8 *buf; /* 消息数据 */

81};

使用i2c_transfer函数发送数据之前要先构建好i2c_msg,使用i2c_transfer进行I2C数据收发的示例代码如下:

示例代码61.3.2.2 I2C设备多寄存器数据读写

1 /* 设备结构体 */

2struct xxx_dev {

3 ......

4 void*private_data;/* 私有数据,一般会设置为i2c_client */

5};

6

7/*

8 * @description : 读取I2C设备多个寄存器数据

9 * @param – dev : I2C设备

10 * @param – reg : 要读取的寄存器首地址

11 * @param – val : 读取到的数据

12 * @param – len : 要读取的数据长度

13 * @Return : 操作结果

14 */

15staticint xxx_read_regs(struct xxx_dev *dev, u8 reg,void*val,

int len)

16{

17 int ret;

18 struct i2c_msg msg[2];

19 struct i2c_client *client =(struct i2c_client *)

dev->private_data;

20

21 /* msg[0],第一条写消息,发送要读取的寄存器首地址 */

22 msg[0].addr = client->addr; /* I2C器件地址 */

23 msg[0].flags =0; /* 标记为发送数据 */

24 msg[0].buf =® /* 读取的首地址 */

25 msg[0].len =1; /* reg长度 */

26

27 /* msg[1],第二条读消息,读取寄存器数据 */

28 msg[1].addr = client->addr; /* I2C器件地址 */

29 msg[1].flags = I2C_M_RD; /* 标记为读取数据 */

30 msg[1].buf = val; /* 读取数据缓冲区 */

31 msg[1].len = len; /* 要读取的数据长度 */

32

33 ret = i2c_transfer(client->adapter, msg,2);

34 if(ret ==2){

35 ret =0;

36 }else{

37 ret =-EREMOTEIO;

38 }

39 return ret;

40}

41

42/*

43 * @description : 向I2C设备多个寄存器写入数据

44 * @param – dev : 要写入的设备结构体

45 * @param – reg : 要写入的寄存器首地址

46 * @param – val : 要写入的数据缓冲区

47 * @param – len : 要写入的数据长度

48 * @return : 操作结果

49 */

50static s32 xxx_write_regs(struct xxx_dev *dev, u8 reg, u8 *buf,

u8 len)

51{

52 u8 b[256];

53 struct i2c_msg msg;

54 struct i2c_client *client =(struct i2c_client *)

dev->private_data;

55

56 b[0]= reg; /* 寄存器首地址 */

57 memcpy(&b[1],buf,len); /* 将要发送的数据拷贝到数组b里面 */

58

59 msg.addr = client->addr; /* I2C器件地址 */

60 msg.flags =0; /* 标记为写数据 */

61

62 msg.buf = b; /* 要发送的数据缓冲区 */

63 msg.len = len +1; /* 要发送的数据长度 */

64

65 return i2c_transfer(client->adapter,&msg,1);

66}

第2~5行,设备结构体,在设备结构体里面添加一个执行void的指针成员变量private_data,此成员变量用于保存设备的私有数据。在I2C设备驱动中我们一般将其指向I2C设备对应的i2c_client。

第15~40行,xxx_read_regs函数用于读取I2C设备多个寄存器数据。第18行定义了一个i2c_msg数组,2个数组元素,因为I2C读取数据的时候要先发送要读取的寄存器地址,然后再读取数据,所以需要准备两个i2c_msg。一个用于发送寄存器地址,一个用于读取寄存器值。对于msg[0],将flags设置为0,表示写数据。msg[0]的addr是I2C设备的器件地址,msg[0]的buf成员变量就是要读取的寄存器地址。对于msg[1],将flags设置为I2C_M_RD,表示读取数据。msg[1]的buf成员变量用于保存读取到的数据,len成员变量就是要读取的数据长度。调用i2c_transfer函数完成I2C数据读操作。

第50~66行,xxx_write_regs函数用于向I2C设备多个寄存器写数据,I2C写操作要比读操作简单一点,因此一个i2c_msg即可。数组b用于存放寄存器首地址和要发送的数据,第59行设置msg的addr为I2C器件地址。第60行设置msg的flags为0,也就是写数据。第62行设置要发送的数据,也就是数组b。第63行设置msg的len为len+1,因为要加上一个字节的寄存器地址。最后通过i2c_transfer函数完成向I2C设备的写操作。

另外还有两个API函数分别用于I2C数据的收发操作,这两个函数最终都会调用i2c_transfer。首先来看一下I2C数据发送函数i2c_master_send,函数原型如下:

int i2c_master_send(const struct i2c_client *client,

const char *buf,

int count)

函数参数和返回值含义如下:

client:I2C设备对应的i2c_client。

buf:要发送的数据。

count:要发送的数据字节数,要小于64KB,以为i2c_msg的len成员变量是一个u16(无符号16位)类型的数据。

返回值:负值,失败,其他非负值,发送的字节数。

I2C数据接收函数为i2c_master_recv,函数原型如下:

int i2c_master_recv(const

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值