嵌入式 I2C总线协议

2019-07-13 02:18发布

制作嵌入式linux文件系统(ramdisk,cramfs,squashfs) Linux驱动程序框架

I2C总线详细介绍

2010-10-30 18:26:44| 分类: 面试总结 | 标签: |字号 订阅 I2C是一种串行总线的外设接口,它采用同步方式串行接收或发送信息,两个设备在同一个时钟下工作。I2C总线只用两根线:串行数据SDASerial Data)、串行时钟SCLSerial Clock)。 由于I2C只有一根数据线,因此其发送信息和接收信息不能同时进行。信息的发送和接收只能分时进行。I2C串行总线工作时传输速率最高可达400K bit/s I2C总线上的所有器件的SDA线并接在一起,所有器件的SCL线并接在一起,且SDA线和SCL线必须通过上拉电阻连接到正电源。 I2C总线的数据传输协议要比SPI总线复杂一些,因为I2C总线器件没有片选控制线,所以I2C总线数据传输的开始必须由主器件产生通信的开始条件(SCL高电平时,SDA产生负跳变);通信结束时,由主器件产生通信的结束条件(SCL高电平时,SDA产生正跳变)。 SDA线上的数据在SCL高电平期间必须保持稳定,否则会被误认为开始条件或结束条件,只有在SCL低电平期间才能改变SDA线上的数据。I2C总线的数据传输波形图如下图所示。 I2C总线详细介绍 - kmustchenb - 楚天碧 I2C应用实例 AT24C系列为美国ATMEL公司推出的串行COMSE2PROM,具有功耗小,宽电压范围等优点。下图为AT24C系列E2PROM的引脚图。图中A0A1A2为器件地址引脚,Vss为地,Vcc为正电源,WP为写保护,SCL为串行时钟线,SDA为串行数据线。AT24C系列E2PROM采用I2C总线,I2C总线上可挂接多个接口器件,在I2C总线上的每个器件应有唯一的器件地址,按I2C总线规则,器件地址为7位二进制数,它与一位数据方向位构成一个器件寻址字节。器件寻址字节的最低位(D0)为方向位(读/写),最高4位(D7~D4)为器件型号地址(不同的I2C总线接口器件的型号地址由厂家给定,AT24C系列E2PROM的型号地址都为1010);其余3位(D3~D1)与器件引脚地址A2A1A0相对应。器件地址格式: 1010 A2A1A0 I2C总线详细介绍 - kmustchenb - 楚天碧 对于E2PROM的片内地址,AT24C01AT24C02由于芯片容量可用一个字节表示,故读写某个单元前,先向E2PROM写入一个字节的器件地址,再写入一个字节的片内地址。而AT24C04AT24C08AT24C16分别需要9位、10位和11位片内地址,所以AT24C04把器件地址中的A0作为片内地址的最高位,AT24C08把器件地址中的A1A0作为片内地址的最高两位,AT24C16把器件地址中的A2A1A0作为片内地址的最高三位。凡在系统中把器件的引脚地址用作片内地址后,该引脚在电路中不得使用,做悬空处理。AT24C32AT24C64AT24C128AT24C256AT24C512的片内地址采用两个字节。 AT24C系列E2PROM的读写操作原理 下列读写操作中SDA线上数据传送状态标记注释如下: Start为启动信号(SCL为高电平,SDA产生负跳变),由主机发送。 Stop为结束信号(SCL为高电平,SDA产生正跳变),由主机发送。 AddressByteAddreeeByte HAddreeeByte L为地址字节,指定片内某单元地址,由主机发送。 data为数据字节,由数据发送方发送。 0 为肯定应答信号,由数据接收方发送。 1 为否定应答信号,由数据接收方发送。 主机控制数据线SDA时,在SCL高电平期间必须保持SDA线上的数据稳定,否则会被误认为对从机的起始条件或结束条件。主机只能在SCL低电平期间改变SDA线上的数据。主机写操作期间,用SCL的上升沿写入数据;主机读操作期间,用SCL的下降沿读出数据。 AT24C系列AT24C01~AT24C16中读n个字节的数据格式: I2C总线详细介绍 - kmustchenb - 楚天碧 AT24C系列AT24C32~AT24C512中读n个字节的数据格式: I2C总线详细介绍 - kmustchenb - 楚天碧 AT24C系列AT24C01~AT24C16中写n个字节的数据格式(n<=页长,且n个字节不能跨页): I2C总线详细介绍 - kmustchenb - 楚天碧 AT24C系列AT24C32~AT24C512中写n个字节的数据格式(n<=页长,且n个字节不能跨页): I2C总线详细介绍 - kmustchenb - 楚天碧 应答信号 I2C总线数据传送时,每成功地传送一个字节数据后,接收器都必须产生一个应答信号。应答的器件在第9个时钟周期时将SDA线拉低,表示其已经收到一个8位数据。 I2C器件在接收到起始信号和从器件地址之后响应一个应答信号,如果器件已选择了写操作,则在每接收一个8位字节之后响应一个应答信号。 I2C器件工作在读模式时,在发送一个8位数据后释放SDA线(SDA置为高电平)并监视一个应答信号,一旦接收到主器件的应答信号,I2C器件则继续发送数据,如果主器件没有发送应答信号(发送非应答信号,即SDA为高电平),器件停止传送数据且等待一个停止信号。 1.I2C协议
2条双向串行线,一条数据线SDA,一条时钟线SCL。
SDA传输数据是大端传输,每次传输8bit,即一字节。
支持多主控(multimastering),任何时间点只能有一个主控。
总线上每个设备都有自己的一个addr,共7个bit,广播地址全0.
系统中可能有多个同种芯片,为此addr分为固定部分和可编程部份,细节视芯片而定,看datasheet。

1.1 I2C位传输
数据传输:SCL为高电平时,SDA线若保持稳定,那么SDA上是在传输数据bit;
若SDA发生跳变,则用来表示一个会话的开始或结束(后面讲)
数据改变:SCL为低电平时,SDA线才能改变传输的bit
I2C学习笔记 - dp - dp: 生活的脚步,进步的点滴... 1.2 I2C开始和结束信号
开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。
I2C学习笔记 - dp - dp: 生活的脚步,进步的点滴... 1.3 I2C应答信号
Master每发送完8bit数据后等待Slave的ACK。
即在第9个clock,若从IC发ACK,SDA会被拉低。
若没有ACK,SDA会被置高,这会引起Master发生RESTART或STOP流程,如下所示: I2C学习笔记 - dp - dp: 生活的脚步,进步的点滴... 1.4 I2C写流程
写寄存器的标准流程为:
1. Master发起START
2. Master发送I2C addr(7bit)和w操作0(1bit),等待ACK
3. Slave发送ACK
4. Master发送reg addr(8bit),等待ACK
5. Slave发送ACK
6. Master发送data(8bit),即要写入寄存器中的数据,等待ACK
7. Slave发送ACK
8. 第6步和第7步可以重复多次,即顺序写多个寄存器
9. Master发起STOP

写一个寄存器 I2C学习笔记 - dp - dp: 生活的脚步,进步的点滴... 写多个寄存器 I2C学习笔记 - dp - dp: 生活的脚步,进步的点滴... 1.5 I2C读流程

读寄存器的标准流程为:
1. Master发送I2C addr(7bit)和w操作1(1bit),等待ACK
2. Slave发送ACK
3. Master发送reg addr(8bit),等待ACK
4. Slave发送ACK
5. Master发起START
6. Master发送I2C addr(7bit)和r操作1(1bit),等待ACK
7. Slave发送ACK
8. Slave发送data(8bit),即寄存器里的值
9. Master发送ACK
10. 第8步和第9步可以重复多次,即顺序读多个寄存器

读一个寄存器 I2C学习笔记 - dp - dp: 生活的脚步,进步的点滴... 读多个寄存器 I2C学习笔记 - dp - dp: 生活的脚步,进步的点滴... 2. PowerPC的I2C实现
Mpc8560CCSR中控制I2C的寄存器共有6个。 I2C学习笔记 - dp - dp: 生活的脚步,进步的点滴... 2.1 I2CADR 地址寄存器
CPU也可以是I2C的Slave,CPU的I2C地址有 I2CADR指定 I2C学习笔记 - dp - dp: 生活的脚步,进步的点滴... 2.2 I2CFDR 频率设置寄存器 I2C学习笔记 - dp - dp: 生活的脚步,进步的点滴... The serial bit clock frequency of SCL is equal to the CCB clock divided by the divider.
用来设置I2C总线频率

2.3 I2CCR 控制寄存器
I2C学习笔记 - dp - dp: 生活的脚步,进步的点滴...
MEN: Module Enable. 置1时,I2C模块使能
MIEN:Module Interrupt Enable. 置1时,I2C中断使能。
MSTA:Master/slave mode. 1 Master mode,0 Slave mode.
当1->0时,CPU发起STOP信号
当0->1时,CPU发起START信号
MTX:Transmit/receive mode select.0 Receive mode,1 Transmit mode
TXAK:Transfer acknowledge. 置1时,CPU在9th clock发送ACK拉低SDA
RSTA:Repeat START. 置1时,CPU发送REPEAT START
BCST:置1,CPU接收广播信息(信息的slave addr为7个0)

2.4 I2CSR 状态寄存器
I2C学习笔记 - dp - dp: 生活的脚步,进步的点滴... MCF:0 Byte transfer is in process
1 Byte transfer is completed

MAAS:当CPU作为Slave时,若I2CDR与会话中Slaveaddr匹配,此bit被置1

MBB:0 I2C bus idle
1 I2C bus busy

MAL:若置1,表示仲裁失败
BCSTM:若置1,表示接收到广播信息

SRW:When MAAS is set, SRW indicates the value of the R/W command bit of the calling address, which is sent from the master.
0 Slave receive, master writing to slave
1 Slave transmit, master reading from slave

MIF:Module interrupt. The MIF bit is set when an interrupt is pending, causing a processor interrupt request(provided I2CCR[MIEN] is set)

RXAK:若置1,表示收到了ACK

2.5 I2CDR 数据寄存器
I2C学习笔记 - dp - dp: 生活的脚步,进步的点滴...
这个寄存器储存CPU将要传输的数据。

3. PPC-Linux中I2C的实现

内核代码中,通过I2C总线存取寄存器的函数都在文件drivers/i2c/busses/i2c-mpc.c中
最重要的函数是mpc_xfer.

  1. static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
  2. {
  3. struct i2c_msg *pmsg;
  4. int i;
  5. int ret = 0;
  6. unsigned long orig_jiffies = jiffies;
  7. struct mpc_i2c *i2c = i2c_get_adapdata(adap);

  8. mpc_i2c_start(i2c); // 设置I2CCR[MEN], 使能I2C module


  9. //一直读I2CSR[MBB],等待I2C总线空闲下来
  10. while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
  11. if (signal_pending(current)) {
  12. pr_debug("I2C: Interrupted ");
  13. writeccr(i2c, 0);
  14. return -EINTR;
  15. }
  16. if (time_after(jiffies, orig_jiffies + HZ)) {
  17. pr_debug("I2C: timeout ");
  18. if (readb(i2c->base + MPC_I2C_SR) ==
  19. (CSR_MCF | CSR_MBB | CSR_RXAK))
  20. mpc_i2c_fixup(i2c);
  21. return -EIO;
  22. }
  23. schedule();
  24. }

  25. for (i = 0; ret >= 0 &