linux 下i2c读写命令,S3C2440 Linux下的I2C驱动以及I2C体系下对EEPROM进行读写操作

成员。我们可以看到消息结构体里面有从设备地址,读写标志,数据长度以及存储数据buf。这些成员我们看完之后会发现它大致符合先给设备地址,然后给写信号以及数据的时序。其实但我们写代码的时候并不一定是addr非得定义在flags前面,因为内核会自动帮助我们完成这些具体的时序操作。但有一点,我们必须要填充好nmsgs以及i2c_msg中的成员。

那么我们具体的i2c下的 ioctl 函数是怎么样的呢?我们暂且把i2c-dev.c看作一个设备驱动。里面的fops结构体显示

929b0450869c4b025267d71cfefccc0f.png

我们继续追踪看看i2cdev_ioctl这个函数

static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

{

struct i2c_client *client = file->private_data;

unsigned long funcs;

dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",

cmd, arg);

switch (cmd) {

case I2C_SLAVE:

case I2C_SLAVE_FORCE:

/* NOTE:  devices set up to work with "new style" drivers

* can't use I2C_SLAVE, even when the device node is not

* bound to a driver.  Only I2C_SLAVE_FORCE will work.

*

* Setting the PEC flag here won't affect kernel drivers,

* which will be using the i2c_client node registered with

* the driver model core.  Likewise, when that client has

* the PEC flag already set, the i2c-dev driver won't see

* (or use) this setting.

*/

if ((arg > 0x3ff) "|

(((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))

return -EINVAL;

if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))

return -EBUSY;

/* REVISIT: address could become busy later */

client->addr = arg; //设置addr

return 0;

case I2C_TENBIT://设置10 bit地址模式

if (arg)

client->flags |= I2C_M_TEN;

else

client->flags &= ~I2C_M_TEN;

return 0;

case I2C_PEC://设置传输后增加PEC标志

if (arg)

client->flags |= I2C_CLIENT_PEC;

else

client->flags &= ~I2C_CLIENT_PEC;

return 0;

case I2C_FUNCS://获取函数支持

funcs = i2c_get_functionality(client->adapter);

return put_user(funcs, (unsigned long __user *)arg);

case I2C_RDWR://读取和发送数据

return i2cdev_ioctl_rdrw(client, arg);

case I2C_SMBUS: //SMBUS协议数据传输

return i2cdev_ioctl_smbus(client, arg);

case I2C_RETRIES://设置重试次数

client->adapter->retries = arg;

break;

case I2C_TIMEOUT://设置超时时间

/* For historical reasons, user-space sets the timeout

* value in units of 10 ms.

*/

client->adapter->timeout = msecs_to_jiffies(arg * 10);

break;

default:

/* NOTE:  returning a fault code here could cause trouble

* in buggy userspace code.  Some old kernel bugs returned

* zero in this case, and userspace code might accidentally

* have depended on that bug.

*/

return -ENOTTY;

}

return 0;

}

对于简单使用来说,我现在并没有全深入整明白,所以暂且知道:

ioctl是设备驱动程序中对设备的I/O通道进行管理的函数。

在驱动程序中实现的ioctl函数体内,实际上是有一个switch{case}的结构,每一个case对应一个cmd操作命令,并有相对应的操作。

我这里cmd参数使用的是I2C_RDWR这个命令码,根据i2c-dev.c里的源码看i2cdev_ioctl_rdrw结构体可知

I2C 设备的写操作经历了如下几个步骤。

(1) 从用户空间到字符设备驱动写函数接口,写函数构造 I2C 消息数组。

(2) 写函数把构造的 I2C 消息数组传递给 I2C 核心的传输函数 i2c_transfer()。

(3) I2C 核心的传输函数 i2c_transfer()找到对应适配器 algorithm 的通信方法函数 master_xfer()去最终完成 I2C 消息的处理。

PS:I2c_transfer这个函数实现了core与adapter的联系。想更深入的探究,可以自己去看看I2C总线驱动中的I2C_algorithm结构以及其中的s3c24xx_i2c_xfer(),s3c24xx_i2c_doxfer()和s3c24xx_i2c_message_start()函数和i2c_transfer()函数。

下面我们看看代码在开发板中运行的现象:

1.在把可执行文件放入开发板启动之前我们先检查下I2C控制器s3c2410-i2c节点是否配置好。

56cc5a8bf667c75bf47f6e187640789a.png

上面的i2c_dev/i2c-0是在注册i2c-dev.c后产生的,代表一个可操作的适配器。如果不使用i2c-dev.c的方式,就没有,也不需要这个节点。

2.确保出现I2C控制器s3c2410-i2c后即可通过交叉编译器将编译后可执行文件放入开发板中执行。

c517032c9bb9951c712565817d88af90.png

仔细看上面的结果。可以看到我们原本的数据test1234\n在上面的显示中出了点问题。后来我又测试一次test123\n与test12345678

44dd896ba2e900102c5df5540e525e18.png

我第一次是通过at24.c的read和write以及lseek直接对eeprom读写,所以可以一次写入超过8个字节,第二次通过内部i2c控制器的ioctl来间接读写eeprom时则遭遇了阻击,一次时序,若超过8个字节,超过的字节数自动将前面的数据覆盖掉。然后我想到at24c02是32个页,一页8个字节。通过网上查阅知:

===================================================================================================

287b98cbf7e8318f175c27008e3960a2.png

================================================================================================================================

由于E2PROM的半导体工艺特性,对E2PROM的写入时间要5~10ms,但AT24CXX系列串行E2PROM芯片内部设置了一个具有SRAM性质的输入缓冲器,称为页写缓冲器。CPU对该芯片写操作时,AT24CXX系列芯片先将CPU输入的数据暂存页写缓冲器内,然后,慢慢写入E2PROM中。因此,CPU对AT24CXX系列E2PROM一次写入的数据,受到该芯片页写缓冲器容量的限制。页写缓冲器的容量:AT24C01A/02为8B,AT24C04/08/16为16B,AT24C32/64为32B。

====================================================================================================

注意:

写AT24CXX应用时,若CPU需写入超过芯片页写缓冲器容量的字节数据,应在一页写完后,隔5~10ms重新启动一次写操作。其次,若不是从页写缓冲器零地址(指AT24CXX片内末位地址0或8)写起,一次写入不能超出页内地址111,若超出页写缓冲器最大地址时,也应将超出部分,隔5~10ms重新启动一次写操作。

最后通我们回顾AT24C02的官方datasheet来看看本质:

Byte write:

f9279884eb94d7dceec8f951e54b21a3.png

fc513faacd6999f23647a9f192899b2d.png

==================================================================================================================

Byte write的操作时序如上图所示。主机在发送device address,并且接受到确定回应Ask后再接着发送需要写的地址(把这个数据写到芯片的哪个地址上),然后收到确定回应ask后再发送数据。当AT24C02接受完毕这个数据时会输出一个确认回应Ack,此时主机发送一个停止信号Stop,然后AT240C2进入写时序,将刚才接受到的数据从缓冲器写到存储单元中,并在此期间不响应任何输入,直到操作完成。

==================================================================================================================

Pagewrite:

44c9f79e23c2b73f7d9539937528c3e2.png

8d90b25797ee20f442bd73a2c5ac9c01.png

==================================================================================================================

Page write前面几步的操作和Bytewrite操作类似,只是在成功发送第一个数据之后,主机在收到AT24C02的确认回应Ask之后不会发送停止信号Stop而是继续发送剩余的7个字节数据。直到一个page的8字节数据发送完毕之后才发送停止信号Stop。在页操作的时候word address用与表示业内的低地址的低3bit会每收到一个数据就自动增长,页地址维持不变。所以,当业内地址到顶端时,此时假如还有数据,则数据将会被放到页的起始地址处,页起始地址中之前存放的数据也将会被覆盖。即AT24C02页操作时,写入的数据大于8byte,则大于8byte的数据将重新从此页起始处存放,并覆盖掉之前写入的的数据

==================================================================================================================

另外我们再说一下随机读取:

da8903d984a9f9733af574caeedd1514.png

c155112499ec7d5301f307dea3c8074f.png

==================================================================================================================

随机读写的操作就是主机先用一个写操作来骗过AT24C02器件,使AT24C02内部的data word address中的地址值修改,然后再通过current ad

c2c9ed493cd281aa86d8a6f5178c4c01.gif [1] [2] [3] [4] 610626052e95c7fbe3d254abc769d9ad.gif

本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值