Linux下使用I2C总线读写 EEPROM(读写i2c从设备通用程序)

 Linux下使用IIC总线 读写i2c从设备寄存器

by 韩大卫 @吉林师范大学

handawei@jusontech.com

                  转载请务必表明出处
******************* **********************************************

2012.7.16

1,本文给出了linux 下使用IIC总线读写i2c从设备的实现程序。
2,  本文给出了在编程中遇到的几种非常隐蔽的错误的解决方法。
3,本文的读写程序非常通用:

i2c -d /dev/i2c-1 -s 0x51 0x05 18    -----Write 18 to the register: 0x05 of the i2c-slave address: 0x51

i2c -d /dev/i2c-10 0x57 0x05           ------Read the register: 0x05 of the i2c-slave address: 0x57

i2c 0x40 0x0f  ----- 在默认路径下读 i2c 从设备地址为0x40的 0x0f的地址(或寄存器地址)

4,本程序以EEPROM为例,最后出了如何读写i2c下的从设备的通用程序,而不是针对于EEPROM这一种芯片。另篇文章《linux下使用i2c总线与E2PROM通信》中有针对

EEPROM的一些操作。但原理是与本文相同的。

 我们嵌入式系统中的E2PROM 是 24C02.先简单了解一下这款芯片:

AT24C02的存储容量为2Kb,内容分成32页,每页8B,共256B,操作时有两种寻址方式:芯片寻址和片内子地址寻址。 
  (1)芯片寻址:AT24C02的芯片地址为1010,其地址控制字格式为 1010A2A1A0R/W。其中A2,A1,A0可编程地址选择位。A2,A1,A0引脚接高、
低电平后得到确定的三位编码,与1010形成7位编码, 即为该器件的地址码。R/W为芯片读写控制位,该位为0,表示芯片进行写操作。 
  (2)片内子地址寻址:芯片寻址可对内部256B中的任一个进行读/写操作,其寻址范围为00~FF,共256个寻址单位。

我们采用的是第2种 寻址方式。


另外,有一个问题需要了解一下,就是EEPROM 与flash , 什么时候使用EEPROM,什么时候用FLASH合适。
********************

 From Www.baidu.com :

 Flash存储器又称闪存,它结合了ROM和RAM的长处,不仅具备电子可擦除可编程(EEPROM)的性能,还可以快速读取数据(NVRAM的优势),使数据不会因为断电而
丢失。U盘和MP3里用的就是这种存储器。用作存储Bootloader以及操作系统或者程序代码,或者直接当硬盘使用(U盘)。 

一, EEPROM以单字节读写,FLASH部分芯片只能以块方式擦除(整片擦除),部分芯片可以单字节写入(编程),一般需要采用块写入方式; 


二,FLASH比EEPROM读写速度更快,可靠性更高。

三,价格方面比较,FLASH比EEPROM贵。 

So,我们的版卡参数信息,等一些固定的,小量的,不需要经常修改资料信息放在EEPROM中。而flash作为存储程序的存储器,存放操作系统代码等需要快速读写的,
经常访问的数据。


************** ******************************************************


**** *******************************************************

先介绍下遇到的一些问题:

问题一: Bad address

在使用ioctl 在用户层将包装好的data 发送给内核,但是运行结果显示:

 error = Bad address
我原来以为是不是给我访问地址不对, 可是地址是正确的。

后来看到了报错的位置:

在内核代码 driver/i2c/i2c-dev.c ,函数i2cdev_ioctl_rdrw()中

if (copy_from_user(&rdwr_arg,
				(struct i2c_rdwr_ioctl_data __user *)arg,
				 sizeof(rdwr_arg)))
 			 return -EFAULT;

这条语句返回了错误提示bad address 。
经过查资料,出错的非常原因隐蔽又非常简单:
  copy_to_user的定义是:    
  copy_to_user ( void  __user  *  to ,   const   void   *  from ,   unsigned   long  n );  
   
 可是这个unsigned long 在32bit的处理器上是等于 unsigned int 的,都是4个字节,32bit。
所以我最初在eeprom_io.h中有这样的定义:typedef unsigned long u32;
在eeprom_io.c中:ioctl(fd, I2C_RDWR, (u32)iocs);

我们的版卡的处理器是64bit mips系列处理器,unsigned long 就是8个字节,64bit。交叉编译器不会报错的。但运行后就会由于字节的问题一直有 Bad address的
错误反馈。这误导我单纯了认为是地址不对。
后来我将typedef unsigned long u32 改为 typedef unsigned long u64;
ioctl(fd, I2C_RDWR, (u64)iocs) 。才将这个问题解决。


************** ***************************************************************

问题二,程序执行一次write 后再执行write的时候出现:

<
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值