I2C部分已经接近尾声了,接下来我们回过头来看一下剩下的一些小知识点。如 I2C 仲裁、Linux I2C 工具查看配置I2C设备、什么是漏极开路等等。
一、动手画出I2C时序图
看了那么多东西,都记不牢的或者理解不透。只有亲自画出时序图,你才能明白的。
就画 MT9P031 写操作,设备写地址为0xBA,片内寄存器地址为0x09,发送数据 0000 0010 和 1000 0100
我只画了起始位、设备写地址为0xBA、ACK 这几部分,详细的看下图。
当你画的时候,你就会注意到I2C协议的一些知识了:
1、SCL 为低电平,SDA 可以进行修改;
2、SCL 为高电平,SDA 保持稳定不变;
3、SCL 为高电平时,如果 SDA 有变动则视为特殊状况:启动(启始,SDA 由高转为低)或停止(结束,SDA 由低转为高)。
上面三条定义刚好把SCL和SDA三条讯号线会发生的讯号全部都包括了。
4、除了Start(启始)和Stop(结束)二个讯号之外,所有的信号传输固定8 bits(1 字节)为一组,这一个字节可能是一个设备地址,寄存器地址或写入或读取从机的数据,数据首先传输最高有效位(MSB)。
5、发送端在每组(8位)信号发出后,需读取接收端所回应的一个 ACK 位(信号为低)或 NACK 位(信号为高)。 (注意:发送端不一定是master。例如:读取资料时,发送端为slave)。
6、设备地址读/写位,0 表示主设备向从设备写数据,1 表示主设备向从设备读数据。
以AT24C02存储器为例:
通过芯片手册,得到设备地址相关的内容:
1010A2A1A0R/W:设备地址不包含读写位,右移1位,高位补0 =》 01010A2A1A0(A2A1A0都接地)=01010000=》AT24C02在开发板上的设备地址为0x50
读设备地址 = 设备地址 << 1 | 读写位(1) = 0xA1
写设备地址 = 设备地址 << 1 | 读写位(0) = 0xA0
二、I2C仲裁机制
我们晓得 I2C 允许多个主设备和多个从设备。如果两个或两个以上的主设备同时向总线上发送启动信号并开始传送数据,这样就形成了冲突。要解决这种冲突,就要进行仲裁的判决,这就是 I2C 总线上的仲裁。
I2C总线上的仲裁分两部分:SCL线的同步和SDA线的仲裁。
(1)同步
所有主机在 SCL 线上产生它们自己的时钟来传输 I2C 总线上的报文。数据只在时钟的高电平周期有效。因此,需要一个确定的时钟进行逐位仲裁。
时钟同步通过 线“与”(Wired-AND)连接 I2C 接口到 SCL 线来执行。这就是说: SCL 线的高到低切换会使器件开始数它们的低电平周期,而且一旦器件的时钟变低电平,它会使 SCL 线保持这种状态直到到达时钟的高电平。但是,如果另一个时钟仍处于低电平周期,这个时钟的低到高切换不会改变 SCL 线的状态。因此,SCL 线被有最长低电平周期的器件保持低电平。此时,低电平周期短的器件会进入高电平的等待状态。
当所有有关的器件数完了它们的低电平周期后,时钟线被释放并变成高电平。之后,器件时钟和 SCL 线的状态没有差别。而且所有器件会开始数它们的高电平周期。首先完成高电平周期的器件会再次将 SCL 线拉低。
这样,产生的同步 SCL 时钟的低电平周期由低电平时钟周期最长的器件决定,而高电平周期由高电平时钟周期最短的器件决定。
(2)仲裁
主机只能在总线空闲的时侯启动传输。两个或多个主机可能在起始条件的最小持续时间(tHD;STA)内产生一个起始条件,结果在总线上产生一个规定的起始条件。
当 SCL 线是高电平时,仲裁在 SDA 线发生;这样,在其他主机发送低电平时,发送高电平的主机将断开它的数据输出级,因为总线上的电平与它自己的电平不相同。
仲裁可以持续多位。它的第一个阶段是比较地址位。如果每个主机都尝试寻址相同的器件,仲裁会继续比较数据位(如果是主机-发送器)或者比较响应位(如果是主机-接收器)。因为 I2C 总线的地址和数据信息由赢得仲裁的主机决定,在仲裁过程中不会丢失信息。丢失仲裁的主机可以产生时钟脉冲直到丢失仲裁的该字节末尾。
由于 Hs 模式的主机有一个唯一的 8 位主机码,因此一般在第一个字节就可以结束仲裁。如果主机也结合了从机功能 而且在寻址阶段丢失仲裁,它很可能就是赢得仲裁的主机在寻址的器件。因此,丢失仲裁的主机必须立即切换到它的从机模式。
下图显示了两个主机的仲裁过程。当然,可能包含更多的内容(由连接到总线的主机数量决定)。此时,产生 DATA1 的主机的内部数据电平与 SDA 线的实际电平有一些差别,如果关断数据输出,这就意味着总线连接了一个高输出电平。这不会影响由赢得仲裁的主机初始化的数据传输。
由于 I2C 总线的控制只由地址或主机码以及竞争主机发送的数据决定,没有中央主机,总线也没有任何定制的优先权。
必须特别注意的是:在串行传输时,当重复起始条件或停止条件发送到 I2C 总线的时侯,仲裁过程仍在进行。如果可能产生这样的情况,有关的主机必须在帧格式相同位置发送这个重复起始条件或停止条件。也就是说,仲裁不能在下面的情况之间进行:
1、重复起始条件和数据位
2、停止条件和数据位
3、重复起始条件和停止条件
4、从机不被卷入仲裁过程
I2C 仲裁机制,理解了 线“与”(Wired-AND),就一目了然了。
或者再简单说,它遵循“低电平优先”的原则,即谁先发送低电平谁就会掌握对总线的控制权。
三、Linux I2C 工具查看配置I2C设备
(1)下载安装
参看:i2c-tools -- 维基百科
i2c-tools软件包包含一组用于Linux的异构I2C工具:
总线探测工具,芯片翻转器,寄存器级SMBus访问助手,EEPROM解码脚本,EEPROM编程工具以及用于SMBus访问的python模块。 只要内核包含I2C支持,所有版本的Linux都受支持。
下载:i2c-tools 下载
修改 Makefile ,编译器改为交叉编译:
COMPILE_PREFIX := /home/tarena/esd1503/arm-2009q3/bin/
CC := $(COMPILE_PREFIX)arm-none-linux-gnueabi-gcc
AR := $(COMPILE_PREFIX)arm-none-linux-gnueabi-ar
生成 i2cdetect, i2cdump, i2cget, i2cset,i2ctransfer
使用 file 指令检查一下:
# file i2cdetect
i2cdetect: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.16, not stripped
(2)使用
使用 tftp 将 i2cdetect, i2cdump, i2cget, i2cset,i2ctransfer 拷贝到开发板中。
然后执行 i2cdetect,出现错误:
# ./i2cdetect -l
./i2cdetect: error while loading shared libraries: libi2c.so.0: cannot open shared object file:
No such file or directory
缺少共享库 libi2c.so.0,将i2c-tools-4.0/lib/libi2c.so.0.1.0 拷贝到开发板 lib 目录下,然后增加权限 chmod 777 libi2c.so.0.1.0,然后重命名为 libi2c.so.0。
PS:本来想拷贝libi2c.so.0的,但是它和libi2c.so.0.1.0是硬链接关系,拷贝出现错误。
# stat libi2c.so.0
文件:"libi2c.so.0" -> "libi2c.so.0.1.0"
大小:15 块:0 IO 块:4096 符号链接
设备:801h/2049d Inode:2128654 硬链接:1
权限:(0777/lrwxrwxrwx) Uid:( 0/ root) Gid:( 0/ root)
最近访问:2017-12-20 10:31:47.155123897 +0800
最近更改:2017-12-20 10:24:43.174893417 +0800
最近改动:2017-12-20 10:24:43.174893417 +0800
创建时间:-
然后直接用 libi2c.so.0.1.0 也不行,需要重命名为 libi2c.so.0
到此可以在开发板上执行 i2cdetect:
]# ./i2cdetect -l
i2c-0 i2c s3c2410-i2c I2C adapter
i2c-1 i2c s3c2410-i2c I2C adapter
i2c-2 i2c s3c2410-i2c I2C adapter
(3)详解指令
现在挨个来看一下这些指令都该如何使用。
参看:Configuring_Aptina_MT9P031_using_i2c-tools
因为我购买的 S5PV210 开发板没有 AT24C02 和 S3C2410 芯片,所以没法测试。为了测试,找出尘封了好久的 DM368 开发板,主要看MT9P031。
1、i2cdetect 指令
查看它的选项:
# i2cdetect
Error: No i2c-bus specified!
Usage: i2cdetect [-y] [-a] [-q|-r] I2CBUS [FIRST LAST]
i2cdetect -F I2CBUS
i2cdetect -l
I2CBUS is an integer or an I2C bus name
If provided, FIRST and LAST limit the probing range.
首先在你的主板的终端中运行 i2cdetect -l 命令:
# i2cdetect -l
i2c-1 i2c DaVinci I2C adapter I2C adapter
该命令将显示任何可用的I2C总线。而输出的结果告诉我们有一个 I2C 总线,其ID是 i2c-1
一旦获得了I2C总线名称,就可以通过运行 i2cdetect -y I2CBUS 得到总线上都挂载的所有设备的设备地址
其中,I2CBUS 是一个整数或I2C总线名称。
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』