snifer

【原创】I2C总线通信方法

0
阅读(1800)


我们需要为特定的I2C适配器实现其通信方法,主要实现i2c_algorithm的master_xfer()函数和functionality()函数。
functionality()函数非常简单,用于返回algorithm所支持的通信协议,如I2C_FUNC_I2C、I2C_FUNC_10BIT_ADDR、I2C_FUNC_SMBUS_READ_BYTE、
I2C_FUNC_SMBUS_WRITE_BYTE等。

master_xfer()函数在I2C适配器上完成传递给它的i2c_msg数组中的每个I2C消息,代码清单15.11给出了xxx设备的master_xfer()函数模板。
代码清单:

I2C总线驱动master_xfer函数模板

1  static int i2c_adapter_xxx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
2    int num)
3  {
4    ...
5    for (i = 0; i < num; i++)
6    {
7      i2c_adapter_xxx_start(); /*产生开始位*/
8      /*是读消息*/
9      if (msgs[i]->flags & I2C_M_RD)
10     {
11       i2c_adapter_xxx_setaddr((msg->addr << 1) | 1); /*发送从设备读地址*/
12       i2c_adapter_xxx_wait_ack(); /*获得从设备的ack*/
13       i2c_adapter_xxx_readbytes(msgs[i]->buf, msgs[i]->len); /*读取msgs[i]
14              ->len长的数据到msgs[i]->buf*/
15     }
16     else
17      /*是写消息*/
18     {
19       i2c_adapter_xxx_setaddr(msg->addr << 1); /*发送从设备写地址*/
20       i2c_adapter_xxx_wait_ack(); /*获得从设备的ack*/
21       i2c_adapter_xxx_writebytes(msgs[i]->buf, msgs[i]->len); /*读取msgs[i]
22         ->len长的数据到msgs[i]->buf*/
23     }
24   }
25   i2c_adapter_xxx_stop(); /*产生停止位*/
26 }


上述代码实际上给出了一个master_xfer()函数处理I2C消息数组的流程,对于数组中的每个消息,判断消息类型,若为读消息,则赋从设备地址为
(msg->addr << 1) | 1,否则为msg->addr << 1。对每个消息产生1个开始位,紧接着传送从设备地址,然后开始数据的发送或接收,对最后的消息
还需产生1个停止位。图15.3描述了整个master_xfer()完成的时序。 图15.3 algorithm中master_xfer的时序

master_xfer()函数模板中的i2c_adapter_xxx_start()、i2c_adapter_xxx_setaddr()、i2c_adapter_xxx_wait_ack()、i2c_adapter_xxx_readbytes()、
i2c_adapter_xxx_writebytes()和i2c_adapter_xxx_stop()函数用于完成适配器的底层硬件操作,
与I2C适配器和CPU的具体硬件直接相关,需要由工程师根据芯片的数据手册来实现。

i2c_adapter_xxx_readbytes()用于从从设备上接收一串数据,
i2c_adapter_xxx_writebytes()用于向从设备写入一串数据,这两个函数的内部也会涉及到I2C总线协议中的ACK应答。

master_xfer()函数的实现在形式上会很多样,即便是Linux内核源代码中已经给出的一些I2C总线驱动的master_xfer()函数,
由于由不同的组织或个人完成,风格上的差别也非常大,