没有合适的资源?快使用搜索试试~ 我知道了~
首页linux下使用IIC总线读写EEPROM
1,本文给出了linux 下使用IIC总线读写EEPROM 的实现程序。 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的地址(或寄存器地址)
资源详情
资源评论
资源推荐
Linux 下使用IIC总线 读写 EEPROM
by 韩大卫 @吉林师范大学
handawei@jusontech.com
转载请务必表明出处
******************* **********************************************
2012.7.16
1,本文给出了 linux 下使用 IIC 总线读写 EEPROM 的实现程序。
2, 本文给出了在编程中遇到的几种非常隐蔽的错误的解决方法。
3,本文的读写程序非常通用:
i2c -d /dev/i2c-1 -s 0x51 0x05 18 -----Write 18 to the register: 0x05 of the i2c-slave address: 0
x51
i2c -d /dev/i2c-10 0x57 0x05 ------Read the register: 0x05 of the i2c-slave address: 0x57
i2c 0x40 0x0f ----- 在默认路径下读 i2c 从设备地址为 0x40 的 0x0f 的地址(或寄存器地址)
我们嵌入式系统中的 E2PROM 是 24C02.先简单了解一下这款芯片:
AT24C02 的存储容量为 2Kb,内容分成 32 页,每页 8B,共 256B,操作时有两种寻址方式:芯片寻址和片
内子地址寻址。
(1)芯片寻址:AT24C02 的芯片地址为 1010 ,其地址控制字格式为 1010A2A1A0R/W。其中 A2,A
1,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 中。而 fl
ash 作为存储程序的存储器,存放操作系统代码等需要快速读写的,经常访问的数据。
************** ******************************************************
**** *******************************************************
先介绍下遇到的一些问题:
问题一: 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 l
ong 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 的时候出现:
Input/output error
同样的,执行一次 write 后再执行 read 也有这样的错误。
我将 addr 改为 0x90,0x10 。运行结果都是报错: Input output error
找到报错的位置:
是在 XXX_i2c_xfer () 中下的一的执行函数: octeon_i2c_simple_write()
cmd = __raw_readq(i2c->twsi_base + SW_TWSI);
printk(KERN_DEBUG "%s:after readq cmd = %llx\n",__func__,cmd);
if ((cmd & SW_TWSI_R) == 0) {
if (octeon_i2c_lost_arb(cmd))
goto retry;
ret = -EIO;
这个 EIO 在用户层上
printf("%s:error = %s\n",__FUNCTION__,strerror(errno));
会显示 input/output error
观察 dmesg:
[ 2656.285759] octeon_i2c_xfer: num = 1
[ 2656.285769] octeon_i2c_xfer:msgs[0].addr = 57, msgs[0].flags = 0, msgs[0].len = 2
[ 2656.285780] octeon_i2c_xfer:msgs[0].buf[0] = 0
[ 2656.285789] octeon_i2c_simple_write:
[ 2656.285797] octeon_i2c_simple_write:cmd = 8090570000000000
[ 2656.285808] octeon_i2c_simple_write:msgs[0].buf[1] = 10,cmd = 8090570000000010
[ 2656.285820] octeon_i2c_simple_write:msgs[0].buf[0] = 0,cmd = 8090570000000010
[ 2656.285948] octeon_i2c_simple_write:after readq cmd = 090570000000020
[ 2656.285955]
我将正确执行的程序 dmesg 打印出来作为对比:
[ 4312.259857] octeon_i2c_xfer: num = 1
[ 4312.259866] octeon_i2c_xfer:msgs[0].addr = 51, msgs[0].flags = 0, msgs[0].len = 2
[ 4312.259878] octeon_i2c_xfer:msgs[0].buf[0] = 2
[ 4312.259887] octeon_i2c_simple_write:
[ 4312.259895] octeon_i2c_simple_write:cmd = 8090510000000000
[ 4312.259906] octeon_i2c_simple_write:msgs[0].buf[1] = 30,cmd = 8090510000000030
[ 4312.259918] octeon_i2c_simple_write:msgs[0].buf[0] = 02,cmd = 8090510000000230
[ 4312.260227] octeon_i2c_simple_write:after readq cmd = 01905100ffffffff
第一次 write 执行成功,这说明代码没有问题,那么第二次执行失败,应该是有别的原因,上网查了一下 24C
02 的资料,原来是这样:
“数据写完之后,给一个停止信号后一定要延时 10MS,24C02 ”需要这么久载入数据
这是 24C02 的电气特性。
在 write 函数使一次用 usleep(10000) 。
补充一下:我们的 CPU 为 6 内核 500M 主频,计算处理能力极强。如果在用户层写一般的延时
程序根本不起作用,一般使用 2 个 for,一个 for 执行 10000 次,在 PC 上就有会明显的延时。 但
是在我们的嵌入式系统中,使用 8 个 for 语句,每个 for 执行 10000 次,丝毫没有影响,起不到
一丝的延时作用。另外,单纯的使用 for 作用延时,会将 CPU 处于满负荷阻塞状态,
剩余10页未读,继续阅读
韩大卫
- 粉丝: 119
- 资源: 21
上传资源 快速赚钱
- 我的内容管理 收起
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
会员权益专享
最新资源
- 2023年中国辣条食品行业创新及消费需求洞察报告.pptx
- 2023年半导体行业20强品牌.pptx
- 2023年全球电力行业评论.pptx
- 2023年全球网络安全现状-劳动力资源和网络运营的全球发展新态势.pptx
- 毕业设计-基于单片机的液体密度检测系统设计.doc
- 家用清扫机器人设计.doc
- 基于VB+数据库SQL的教师信息管理系统设计与实现 计算机专业设计范文模板参考资料.pdf
- 官塘驿林场林防火(资源监管)“空天地人”四位一体监测系统方案.doc
- 基于专利语义表征的技术预见方法及其应用.docx
- 浅谈电子商务的现状及发展趋势学习总结.doc
- 基于单片机的智能仓库温湿度控制系统 (2).pdf
- 基于SSM框架知识产权管理系统 (2).pdf
- 9年终工作总结新年计划PPT模板.pptx
- Hytera海能达CH04L01 说明书.pdf
- 数据中心运维操作标准及流程.pdf
- 报告模板 -成本分析与报告培训之三.pptx
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论14