硬件基础知识(5):I2C协议及eeprom
一、I2C协议简介:
I2C (Inter-Integrated Circuit) 是一种串行通信协议,是 Philips 公司 (现在是 NXP 公司) 基于 CMOS 技术开发的。I2C 协议可以用于在微控制器 (MCU)、传感器、存储器、显示屏等各种硬件设备之间进行简单、高效的数据传输和通信。
1.1 I2C物理层特点:
- 它是一个支持设备的总线。“总线”指多个设备共用的信号线,在一个I2C通信总线中,可以连接多个I2C通讯设备,支持多个通讯主机及多个通讯从机。
- 一个I2C总线只使用两条总线线路,一条双向串行数据线(SDA),一条串行时钟线(SCL)。数据线即用来表示数据,时钟线用来数据收发同步。` • 每一个连接总线的设备都有一个独立的地址,主机可以通过这个地址进行选择总线的设备与之通信。
- 总线通过上拉电阻接到电源,当I2C设备空闲时,会输出高阻态,当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。
- 当多个主机同时使用总线时,为了防止多个设备发送数据冲突,会利用仲裁方式决定哪个设备占用总线。
- 具有三种传输模式:标准模式传输速率为100kbit/s,快速模式为400kbit/s,高速模式可达3.4Mbit/s。
- 连接到相同总线的IC(连接到I2C的独立设备)数量受到总线最大电容400pF限制。
1.2 仲裁:
SDA线的仲裁也是建立在总线具有线“与”逻辑功能(线与逻辑,即两个以上的输出端直接互连就可以实现“AND”的逻辑功能。两个一出一,一个一出零、没有一出零)的原理上的。节点在发送1位数据后,比较总线上所呈现的数据与自己发送的是否一致。是,继续发送;否则,进行比较,输出低电平进行发送,输出高电平退出。SDA线的仲裁可以保证I2C总线系统在多个主节点同时企图控制总线时通信正常进行并且数据不丢失。总线系统通过仲裁只允许一个主节点可以继续占据总线。
1.3 I2C协议层
- S:由主机的 I2C 接口产生的传输起始信号(S),这时连接到 I2C 总线上的所有从机都会接收到这个信号。
- SLAVE ADDRESS:从机地址信号。 在 I2C 总线上,每个设备的地址都是唯一的, 当主机广播的地址与某个设备地址相同时,这个设备就被选中了,没被选中的设备将会忽略之后的数据信号。从机地址一般是 7 位或 10 位。
- R/W:是传输方向的选择位,该位为 0 时,表示后面的数据传输方向是由主机传输至从机,即主机向从机写数据。该位为 1 时,则相反,即主机由从机读数据。
-A | A/:一个应答(ACK)或非应答(NACK)信号。 - P:停止传输信号。
- 图中背景有填充的矩形表示 数据由主机传输至从机
1.3.1 写数据:
主机发送信息、从机阅读信息。配置为方向为“写数据”方向,接受的数据包大小为8位(一个byte),主机每发送完一个字节数据,都要等待从机的应答信号(ACK),重复这个过程,数据的多少可以理论是可以随便的。
1.3.2 读数据:
主机阅读信息、从机发送信息。若配置的方向传输位为“读数据”方向,发送的数据包大小也为 8 位,从机每发送完一个数据,都会等待主机的应答信号(ACK),重复这个过程,数据的多少可以理论也是可以随便的。当主机希望停止接收数据时,就向从机返回一个非应答信号(NACK),则从机自动停止数据传输。
1.3.3 读和写数据:
I2C 通讯更常用的是复合格式,该传输过程有两次起始信号(S)。一般在第一次传输中,主机通过 SLAVE_ADDRESS 寻找到从设备后,发送一段“数据”,这段数据通常用于表示从设备内部的寄存器或存储器地址(注意区分它与 SLAVE_ADDRESS 的区别);在第二次的传输中,对该地址的内容进行读或写。也就是说,第一次通讯是告诉从机读写地址,第二次则是读写的实际内容。
1.3.4 通讯的起始和停止信号:
当 SCL 线是高电平时, SDA 线从高电平向低电平切换,这个情况表示通讯的起始。(S)
当 SCL 线是高电平时, SDA线由低电平向高电平切换,表示通讯的停止。(P)
起始和停止信号一般由主机产生。
1.3.5 时钟控制逻辑:
SCL 线的时钟信号,由 I2C 接口根据时钟控制寄存器(CCR)控制,控制的参数主要为时钟频率。
通过CCR的值去控制通讯速率(影响占空比)
1.4 I2C驱动相关:
1.4.1 I2C驱动框架:
I2C总线包括I2C设备(i2c_client)和I2C驱动(i2c_driver),当向linu中注册设备或驱动的时候,需要按照i2c总线的匹配规则进行配对,配对成功。则可以通过i2c_driver中的probe函数创建具体的设备驱动。
当设备驱动创建成功后,需要实现设备的文件操作接口(file_operations),file_operations中使用到内核中i2c核心函数。在使用这些函数时回涉及到i2c的控制器。由于i2c控制器有不同的配置,所以linux会将每一个i2c控制器抽象成i2c适配器对象。其中,包含一个很重要的成员变量Algorithm,Algorithm中存在一系列函数指针,这些函数指针指向真正硬件操作代码。
//i2c_imx.c
/* Setup i2c_imx driver structure */
strscpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name));
i2c_imx->adapter.owner = THIS_MODULE;
i2c_imx->adapter.algo = &i2c_imx_algo;
i2c_imx->adapter.dev.parent = &pdev->dev;
i2c_imx->adapter.nr = pdev->id;
i2c_imx->adapter.dev.of_node = pdev->dev.of_node;
i2c_imx->base = base;
ACPI_COMPANION_SET(&i2c_imx->adapter.dev, ACPI_COMPANION(&pdev->dev));
这个过程发生在probe过程中,可以看到上面有将 i2c_imx_algo函数指针指向i2c_imx->adapter.algo中。
具体的Algorithm就是以下结构体:
static const struct i2c_algorithm i2c_imx_algo = {
.master_xfer = i2c_imx_xfer,
.master_xfer_atomic = i2c_imx_xfer_atomic,
.functionality = i2c_imx_func,
.reg_slave = i2c_imx_reg_slave,
.unreg_slave = i2c_imx_unreg_slave,
}; //这些函数指针将指向真正的硬件操作代码
1.5 Linux下I2C调试工具:
i2cdetect -y -r 0(扫描i2c-0 总线上所有已连接的 I2C 设备及其地址)
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: – – – – – – – – – – – – –
10: – – – – – – – – – – – – – – – –
20: – – – – – – – – – – – – – – – –
30: – – – – – – – – – – – – – – – –
40: UU – – – – – – – – – – – – – – –
50: – – – – – – – – – – – – – – – –
60: – – – – – – – – – – – – – – – –
70: – – – – – – – –
注:i2cdetect是一个用来扫描I2C总线上连接的从设备的工具。i2cdetect工具的输出中,如果显示的位置是UU,表示该设备已经被内核驱动程序占用,它不能被用户空间的应用程序访问。当一个设备被内核驱动程序占用时,它不能同时被用户空间的应用程序访问。如果需要访问该设备,请先释放被占用的资源。
所以您在扫描 I2C 总线时遇到 UU 表示该设备已被占用,不能访问,需要先释放该设备资源,才能进行读或写操作。
i2cdump -f -y 0 0x50 w(扫描i2c-0 总线上0x50设备中的数据)
i2cget -y 0 0x50 0x00(读取0x50设备下0x00地址上的内容,-f强制读)
i2cset -y 0 0x50 0x00 0x99(写0x50设备下0x00地址上的内容,-f强制写)
1.6 常见I2C下挂设备EEPROM简介:
EEPROM(Electrically Erasable Programmable Read-Only Memory)通常被作为一种非易失性存储器件使用,用于存储持久化的数据和程序。EEPROM直接和CPU通信,所以它不是块设备也不是字符设备。EEPROM更多的是通过I2C、SPI等总线来连接到外部的MCU中,并通过底层驱动来实现读写功能。在Linux中,EEPROM通常被视为一种I2C或SPI设备,其底层驱动必须实现标准的Linux设备驱动接口,而Linux又将其视作字符设备或块设备来进行管理,以便提供统一的读写接口。在Linux中,EEPROM通常被作为字符设备或块设备来使用,通过读写文件的方式来进行读写操作。对于基于I2C或SPI的EEPROM,可以使用I2C驱动或SPI驱动来实现底层的数据读写和操作控制。
EEPROM是一种掉电后数据不丢失的存储器,常用来存储一些配置信息,以便系统重新上电的时候加载。EEPROM是一个元件(从机),只是这个元件采用了IIC协议的接口与主机相连。
1.6.1 器件地址:
AT24C64EEPROM存储芯片有一个IP地址即器件地址,它的目的就是为了IIC总线能识别总线上的从机,IIC下挂设备一般不止一个。它有7位地址,同时包括一位的读/写位(R/W),1为读操作0为写操作,24C64的前四位被厂家固化为1010,所以芯片管脚上只剩3个地址管脚(A0,A1,A2)。
1.6.2 器件存储地址:
内部包含一些需要进行读/写配置的寄存器,只有向对应寄存器写入正确参数,才能被正 确使用,即需要存储的数据按照地址写入对应的存储单元。AT24C64的存储空间为64Kbit(8Kbyte),需要13位存储地址才能满足所有存储单元的寻址,存储地址为2字节。
具体EEPROM的细节参考
嵌入式硬件入门——EEPROM(AT24C02+I2C协议)