I2C协议概述

1.I2C协议概述

I2C总线是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备,具有接口线少、控制简单、器件封装形式小、通信速率较高等优点。I2C只要求两条双向线路:串行数据线(serial data  SDA)与串行时钟线SCL(serial clock  SCL),两条线都是双向传输的。每个连接到总线的器件都有唯一的地址,主控制器发出的控制信息分为地址码控制量两部分,地址码用来选择需要控制的I2C设备,控制量包含类别(比如亮度、模式等)及该类别下的控制值。I2C总线在传输过程中一共有三种类型的信号,分别为开始信号、结束信号及应答信号

2.I2C协议内容

I2CSPI的单主设备不同,I2C 是多主设备的总线,I2C没有物理的芯片选择信号线,没有仲裁逻辑电路,只使用两条信号线—— ‘serial data’ (SDA) 和 ‘serial clock’ (SCL)

IIC协议规定:

  • 第一,每一个IIC设备都有一个唯一的七位设备地址

  • 第二,数据帧大小为8位的字节

  • 第三,数据(帧)中的某些数据位用于控制通信的开始、停止、方向(读写)和应答机制;

  • 第四,支持多主控(multimastering), 其中任何能够进行发送和接收的设备都可以成为主总线;一个主控能够控制信号的传输和时钟频率。当然,在任何时间点上只能有一个主控占用IIC总线;IIC协议标准规定发起通信的设备称为主设备,主设备发起一次通信后,其它设备均为从设备,这点与SPI有很大不同!

下图是一个嵌入式系统中处理器仅通过2根线的IIC总线控制多个IIC外设的典型应用图:

 

图中处理器是IIC主机,它仅仅通过两根信号就可以控制IO扩展器,各种不同的传感器,EEPROM,AD/DAs等设备,这也是IIC总线协议相较于其他协议最有优势的地方。 

     IIC 通信过程大概如下,首先,主设备发一个START信号,这个信号就像对所有其它设备喊:请大家注意!然后其它设备开始监听总线以准备接收数据。接着,主设备发送一个7位设备地址加一位的读写操作的数据帧。当所设备接收数据后,比对地址自己是否为目标设备。如果比对不符,设备进入等待状态,等待STOP信号的来临;如果比对相符,设备会发送一个应答信号——ACKNOWLEDGE作回应。当主设备收到应答后便开始传送或接收数据。数据帧大小为8位,尾随一位的应答信号。主设备发送数据,从设备应答;相反主设备接数据,主设备应答。当数据传送完毕,主设备发送一个STOP信号,向其它设备宣告释放总线,其它设备回到初始状态。

总的来说,IIC总线在通信的过程中一共有一下几种状态:

  1、空闲状态

  IIC 总线的 SDA 和 SCL 两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。

  2、起始状态和结束状态

  在时钟线 SCL 保持高电平期间,数据线 SDA 上的电平被拉低(即负跳变),定义为 I2C 总线总线的起始信号,它标志着一次数据传输的开始。起始信号是由主控器主动建立的,在建立该信号之前 I2C 总线必须处于空闲状态。

  在时钟线 SCL 保持高电平期间,数据线 SDA 被释放,使得 SDA 返回高电平(即正跳变),称为 I2C 总线的停止信号,它标志着一次数据传输的终止。停止信号也是由主控器主动建立的,建立该信号之后,I2C 总线将返回空闲状态。

 

     3、有效的数据位传输

  在 IIC 总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在 SCL 串行时钟的配合下,数据在 SDA 上从高位向低位依次串行传送每一位的数据。进行数据传送时,在 SCL 呈现高电平期间,SDA 上的电平必须保持稳定,低电平为数据 0,高电平为数据 1。只有在 SCL 为低电平期间,才允许 SDA 上的电平改变状态。下图是0xaa在IIC总线上有效传输(有效传输是指第9个时钟的高电平期间,从机给主机反馈了一个有效的应答位0)的图示:

 

4、应答信号与非应答信号

  I2C 总线上的所有数据都是以 8 位字节传送的,发送器(主机)每发送一个字节,就在第9个时钟脉冲期间释放数据线,由接收器(从机)反馈一个应答信号。应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。对于反馈有效应答位 ACK 的要求是,接收器在第 9 个时钟脉冲之前的低电平期间将 SDA 线拉低,并且确保在该时钟的高电平期间为稳定的低电平

    对非应答位(NACK)还要特别说明的是,还有以下四种情况IIC通信过程中会产生非应答位:

   1、接收器(从机)正在处理某些实时的操作无法与主机实现IIC通信的时候,接收器(从机)会给主机反馈一个非应答位(NACK)

   2、主机发送数据的过程中,从机无法解析发送的数据,接收器(从机)也会给主机反馈一个非应答位(NACK)

   3、主机发送数据的过程中,从机无法再继续接收数据,接收器(从机)也会给主机反馈一个非应答位(NACK)

   4、主机从从机中读取数据的过程中,主机不想再接收数据,主机会给从机反馈一个非应答位(NACK),注意,这种情况是主机给从机反馈一个非应答位(NACK)

关于有效应答位的图示在上一传输0xaa的图中可以清楚的看到,关于非应答位的图示见下图:

 

2.1 握手与结束

握手与结束它们都是属于控制总线一块儿的,抽象出来说,它是做通信的控制的,跟数据是如何交换的区分开来。

I2C协议有规定,在SCL和SDA均为高电平的前提下,检测到SDA有下降沿信号,则建立I2C的通信开始;同样的,在SCL为高电平,SDA为低电平的前提下,检测到SDA有上升沿信号,则I2C通信正式结束

首先看看总线闲,也就是总线上没有通信,这两根信号线的电平状态;从图中可以看到,通信的开始之前,SCL和SDA均为高电平;再看看通信正式结束后,SCL和SDA信号均为高电平;也就是说,总线闲的时候,两根信号线都是高电平的。再看看通信的建立和正式结束的时候,这两根信号线的电平变化特点。由图中虚线框中引出的,不管是通信建立和通信结束阶段,SCL都是高电平,SDA的变化控制着通信的建立与结束;这一点尤为重要,或许换一种说法更为适合,在SCL为高电平的情况下,SDA信号的转变就对通信起着强制性作用,要么通信建立,要么通信正式结束,有且仅有这两种情况!也就是说,在数据交换的过程中,要对SCL这根信号线尤为注意,在数据变化的时候,一定要保证SCL是为低电平!让数据的变化在SCL的“安全”状态下进行,所以需要牢记一点,数据变化,时钟线低电平先行如下图所示

 基于IIC总线的物理结构,总线上的START和STOP信号必定是唯一的。另外,IIC总线标准规定SDA线的数据转换必须在SCL线的低电平期,在SCL线的高电平期,SDA线的上数据是稳定的

2.2 应答信号ACK

 Master每发送完8bit数据后等待Slave的ACK; 即在第9个clock,若从IC发ACK,SDA会被拉低;
   若没有ACK,SDA会被置高,这会引起Master发生RESTART或STOP流程;

2.3 写流程

主机通过IIC总线往从机中写数据的时候,主机首先会发送一个起始信号,接着把IIC从机的7位设备地址后面添一个0(设备地址后面的0表示主机向从机写数据,1表示主机从从机中读数据)组成一个8位的数据,把这个8位的数据发给从机,发完这8位的数据以后主机马上释放SDA信号线等待从机的应答,如果从机正确收到这个数据,从机就会发送一个有效应答位0给主机告诉主机自己已经收到了数据,主机收到从机的有效应答位以后 ,接下来主机会发送想要写入的寄存器地址,寄存器发送完毕以后主机同样会释放SDA信号线等待从机的应答,从机如果正确收到了主机发过来的寄存器地址,从机会再次发送一个有效应答位给主机,主机收到从机的有效应答位0以后,接下来主机就会给从机发送想要写入从机的数据,从机正确收到这个数据以后仍然像之前两次一样会给主机发送一个有效应答位,主机收到这个有效应答位以后给从机发送一个停止信号,整个传输过程就结束了。下图是整个传输过程的示意图:

 

特别注意:上图中灰色的地方表示主机正在控制SDA信号线,白色的地方表示从机正在控制SDA信号线。 

写寄存器的标准流程为:
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: 生活的脚步,进步的点滴...

 

2.4 读流程

主机通过IIC总线从从机中读数据的过程与写数据的过程有相似之处,但是读数据的过程还多了一些额外的步骤。主机从从机读数据时主机首先会发送一个起始信号,接着把IIC从机的7位设备地址后面添一个0(设备地址后面的0表示主机向从机写数据,1表示主机从从机中读数据),把这个8位的数据发给从机,发完这8位的数据以后主机马上释放SDA信号线等待从机的应答,如果从机正确收到这个数据,从机就会发送一个有效应答位0给主机告诉主机自己已经收到了数据,主机收到从机的有效应答位以后 ,接下来主机会发送想要读的寄存器地址,寄存器发送完毕以后主机同样会释放SDA信号线等待从机的应答,从机如果正确收到了主机发过来的寄存器地址,从机会再次发送一个有效应答位给主机,主机收到从机的有效应答位0以后,主机会给从机再次发送一次起始信号,接着把IIC从机的7位设备地址后面添一个1(设备地址后面的0表示主机向从机写数据,1表示主机从从机中读数据),注意,第一次是在设备地址后面添0,这一次是在设备地址后面添1,把这个8位的数据发给从机,发完这8位的数据以后主机马上释放SDA信号线等待从机的应答,如果从机正确收到这个数据,从机就会发送一个有效应答位0给主机告诉主机自己已经收到了数据,接着从机继续占用SDA信号线给主机发送寄存器中的数据,发送完毕以后,主机再次占用SDA信号线发送一个非应答信号1给从机,主机发送一个停止信号给从机结束整个读数据的过程。下图是整个读数据过程的示意图 :

 特别注意:上图中灰色的地方表示主机正在控制SDA信号线,白色的地方表示从机正在控制SDA信号线。

读寄存器的标准流程为:
1.    Master发送I2C addr(7bit)和w操作0(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发送NACK
10.    第8步和第9步可以重复多次,即顺序读多个寄存器

 

读多个寄存器

I2C学习笔记 - dp - dp: 生活的脚步,进步的点滴...

3 I2C vs SPI

对比一下IIC 和 SPI的一些关键点:

第一,总线拓扑结构/信号路由/硬件资源耗费

IIC 只需两根信号线,而标准SPI至少四根信号,如果有多个从设备,信号需要更多。一些SPI变种虽然只使用三根线——SCLK, SS和双向的MISO/MOSI,但SS线还是要和从设备一对一根。另外,如果SPI要实现多主设备结构,总线系统需额外的逻辑和线路。用IIC 构建系统总线唯一的问题是有限的7位地址空间,但这个问题新标准已经解决——使用10位地址。从第一点上看,IIC是明显的大赢家

第二,数据吞吐/传输速度

如果应用中必须使用高速数据传输,那么SPI是必然的选择。因为SPI是全双工,IIC 的不是。SPI没有定义速度限制,一般的实现通常能达到甚至超过10 Mbps。IIC 最高的速度也就快速+模式(1 Mbps)和高速模式(3.4 Mbps),后面的模式还需要额外的I/O缓冲区,还并不是总是容易实现的

第三,优雅性

IIC 常被称更优雅于SPI。公正的说,我们更倾向于认为两者同等优雅和健壮。IIC的优雅在于它的特色——用很轻盈的架构实现了多主设备仲裁和设备路由。但是对使用的工程师来讲,理解总线结构更费劲,而且总线的性能不高。SPI的优点在于它的结构相当的直观简单,容易实现,并且有很好扩展性。SPI的简单性不足称其优雅,因为要用SPI搭建一个有用的通信平台,还需要在SPI之上构建特定的通信协议软件。也就是说要想获得SPI特有而IIC没有的特性——高速性能,工程师们需要付出更多的劳动。另外,这种自定的工作是完全自由的,这也说明为什么SPI没有官方标准。IIC和SPI都对低速设备通信提供了很好的支持,不过,SPI适合数据流应用,而IIC更适合“字节设备”的多主设备应用

下面来看具体实例:

1、编写IIC总线主机给从机发送数据的代码,实现FPGA(主机)往EEPROM(从机)的0x23这个地址写入0x45这个数据

2、编写IIC总线主机从从机接收数据的代码,实现FPGA(主机)从EEPROM(从机)的0x23这个地址读出0x45这个数据,并用0x45这个数据的低四位驱动4个LED

IIC发送模块的接口定义与整体设计

  Verilog编写的IIC发送模块除了进行IIC通信的两根信号线(SCL和SDA)以外还要包括一些时钟、复位、使能、并行的输入输出以及完成标志位。其框图如下所示

 

其中:

  I_clk是系统时钟;

  I_rst_n是系统复位;

  I_iic_send_en发送使能信号,当I_iic_send_en为1时IIC主机(FPGA)才能给IIC从机发送数据;

  I_dev_addr[6:0]是IIC从机的设备地址;

  I_word_addr[7:0]是字地址,也就是我们想要操作的IIC设备的内部存储地址;

  I_write_data[7:0]是主机(FPGA)要往IIC字地址中写入的数据;

  O_done_flag是主机(FPGA)发送一个字节完成标志位,发送完成后会产生一个高脉冲;

  O_scl是IIC总线的串行时钟线;

  IO_sda是IIC总线的串行数据线;

  要想实现iic_send模块的功能,还是先得抽象出发送一个字节数据时序的状态机,这里把24LC04B发送过程的时序贴一遍

注意,上图中的控制字节(CONTROL BYTE)实际上就是代码里面定义的7-bit设备物理地址与最后1-bit的读写控制位拼接组成的。

  通过观察上面的时序图可以看出,发送一个字节的数据之前必须要先发送起始位,然后发送控制字节,接着等待应答,然后在发送字地址,接着在等待应答。数据发送完毕以后,在等待最后一个应答,应答成功后发送停止信号结束整个过程。所以,根据这个流程,可以归纳出如下几个状态:

  状态0:空闲状态,用来初始化各个寄存器的值

  状态1:加载IIC设备的物理地址

  状态2:加载IIC设备的字地址

  状态3:加载要发送的数据

  状态4:发送起始信号

  状态5:发送一个字节,从高位开始发送

  状态6:接收应答状态的应答位

  状态7:校验应答位

  状态8:发送停止信号

  状态9:IIC写操作结束

  需要注意的是上面的各个状态并不是按照顺序执行的,有些状态要复用多次,比如状态5发送字节的状态就需要复用三次用来发送三个8-bit的数据;同样,状态6和状态7也要复用多次。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值