【STM32开发之寄存器版】(十二)-I2C基础知识详解
一、前言
本文主要参考了NXP恩智浦公司发布的UM10204_I2C-bus specification and user manual,该手册详细介绍了I2C通讯协议的设计和使用规范。
为了深入理解I2C的时序逻辑,本文并不选择使用STM32F103ZET6的硬件I2C,而是使用软件模拟I2C。本文着重介绍I2C的基础知识,为I2C读取MPU6050六轴惯性传感器打好基础。
二、I2C基础知识
2.1 I2C简介
在普通消费电子领域,几乎每个系统都包括控制系统(如MCU)、通用电路(如EEPROM、AD/DA转换器)、面向应用的电路(如信号处理电路、温度传感器)。为了保证通讯接口的相似性,最大限度提升硬件效率和电路的简洁性。Philips Semiconductors (现在的NXP Semiconductors)开发了一种简单的双向双线总线,用于不同IC之间的高效控制,这种总线被命名为I2C总线。I2C总线的设计理念解决了设计数字控制电路时遇到的很多接口问题,其电路应用场景如下图所示:
2.2 I2C的主要特性
I2C总线具备以下特性:
- 只需要两条总线;一条串行数据线(SDA)和一条串行时钟线(SCL)。
- 连接到总线的每个设备都可以通过一个唯一的地址进行软件寻址,控制器既可以作为发送端也可以作为接收端使用。
- 属于多控制器总线,如果多个控制器同时启动数据传输,可以进行碰撞检测和仲裁,以防止数据损坏。
- 一种串行的双向数据传输总线,一般包含8个数据位。在标准模式下传输速度高达100Kbps,快速模式下传输速度高达400Kbps,快速Plus模式下传输速度高达1Mbps,高速模式下传输速度高达3.4Mbps。
- 可连接到同一总线的IC数量仅受最大总线电容的限制(一般来讲标准模式负载电容不超过400pF,快速模式负载电容不超过200pF)。
2.3 I2C硬件结构分析
2.3.1 I2C硬件接线方式
I2C一般包含VDD、VSS、SCL和SDA这四根线,SCL和SDA需要通过上拉电阻Rp与VDD相接,如下图所示:
2.3.2 I2C IO口配置
I2C协议规定,连接到总线的设备必须将IO口配置为开漏模式(OD)或开集模式(OC),这两种模式可以执行 线与 功能。以STM32为例,配置为开漏模式后,GPIO内部原理图如图所示:
开漏模式下的GPIO内部相当于一个NMOS直接接地。此时,配置为开漏模式的GPIO只有两种状态:低电平和高阻态。当内部NMOS的G极为低电平,NMOS关闭,IO状态为高阻态。当内部NMOS的G极为高电平,NMOS开启,IO状态为低电平。此时的IO口无法获得高电平状态,不能满足I2C通讯协议的电平要求(I2C电平要求:高电平大于0.7VDD,低电平低于0.3VDD)。因此需要外接上拉电阻获得高电平状态。
此时,当内部NMOS的G极为低电平,NMOS关闭,IO状态为高阻态,但由于外部上拉电阻的作用,I2C信号线上的电平为高电平,Multisim仿真如下图所示:
当内部NMOS的G极为高电平,NMOS开启,IO状态为低电平,I2C信号线上的电平为低电平,Multisim仿真如下图所示:
综上所述,在OD模式下,SCL或SDA通过外部上拉电阻获得正常的高低电平信号。
2.3.3 线与逻辑
在存在多控制器的I2C总线上,开漏模式下的GPIO很容易组成“线与逻辑”,当多个SCL或SDA中有某一个处于逻辑“0”,状态,就会将整个线路置为低电平,由此可以实现多控制器下的时钟同步和数据仲裁(本文不再详细介绍)。
当多线路的逻辑均为高电平时,该条线路有效电平为高(1&1&... ... &1 = 1)。 Multisim仿真如下图所示:
当多线路的逻辑中某些为低电平,该条线路有效电平为低(1&...&0& ... &1 = 0)。 Multisim仿真如下图所示:
2.3.4 I2C上拉电阻计算
由2.3.2可知,上拉电阻对于实现I2C通讯的高电平逻辑非常关键。但上拉电阻的阻值并不是随意选取的。
2.3.4.1 上拉电阻最大值
I2C总线电容包含导线电容、连接器电容以及引脚电容,总线电容通过影响信号上升时间限制了上拉电容的最大值。为了计算上拉电容的最大值,需要考虑时间常数RC对于信号上升时间的影响,联立以下3式:
其中,VIH为信号有效高电平阈值,VIL为信号有效低电平阈值。RC为时间常数,VDD为上拉电阻供电电压。联立结果可得:
其中,Rp(max)为上拉电阻最大值,Cb为总线电容。由此可以得到上拉电阻最大值:
在标准模式、快速模式和快速模式PLUS下,I2C总线协议对总线电容Cb的要求如下:
在标准模式、快速模式和快速模式PLUS下,I2C总线协议对上升时间tr的要求如下:
在标准模式、快速模式和快速模式PLUS下,上拉电阻最大值与总线电容Cb之间的关系图如下:
2.3.4.2 上拉电阻最小值
电源电压VDD通过影响引脚灌电流(sink current)进而限制了上拉电阻的最小值。在标准模式、快速模式和快速模式PLUS下,I2C总线协议对引脚灌电流的要求如下:
则上拉电阻最小值可以按照如下公式进行计算:
2.3.5 I2C layout guidence
一般来说,在布线时必须尽量减少总线线路之间的串扰和干扰。总线线路在高电平时最容易受到串扰和干扰,因为上拉器件的阻抗相对较高。
如果印刷电路板上的总线线路长度超过 10 厘米,且包括 VDD 和 VSS 线路,则布线模式应为:
若仅仅包含VSS线路,则布线模式应为:
这种布线模式可以使 SDA 和 SCL 线路具有相同的电容负载。
- 如果使用多层PCB(其中包含单独的VSS或VDD层),则可以省略 VSS 和 VDD 线路。
- 如果总线线路是双绞线,则每条总线线路都必须与 VSS 回线绞合。或者,SCL 线与 VSS 回线绞合,SDA 线与 VDD 回线绞合。后者必须使用电容器在扭绞线对的两端对 VDD 线路与 VSS 线路去耦。
- 如果对总线线路进行屏蔽(屏蔽层与 VSS 相连),则可将干扰降至最低。不过,屏蔽电缆的 SDA 和 SCL 线路之间必须具有低电容耦合,以尽量减少串扰。
2.4 I2C时序逻辑分析
对于I2C的时序逻辑分析主要包括数据有效性、开始/停止信号、字节格式、应答/非应答信号。本文对于I2C时序逻辑分析主要以I2C的标准模式为例。
2.4.1 数据有效性
在SCL时钟的高电平期间,SDA 线路上的数据必须保持稳定大于5us。只有当 SCL 线上的时钟信号处于低电平时,数据线的高电平或低电平状态才能发生变化。每传输一个数据位会产生一个时钟脉冲。具体时序逻辑如下图所示。
2.4.2 开始/停止信号
所有传输都以 START (S) 开始,以 STOP (P) 结束。当 SCL 为高电平时,SDA 线上从高电平到低电平的转换定义为启动条件。当 SCL 为高电平时,SDA 线路上从低电平到高电平的转换定义了 STOP 条件。
开始信号时序逻辑如下所示:
停止信号时序逻辑如下所示:
2.4.3 字节格式
SDA 的每个字节长度必须为 8 位。每次传输的字节数不受限制。每个字节后必须有一个确认位。数据传输时,最高位 (MSB) 优先。如果接收端在执行其他功能(例如处理内部中断)之前无法接收或传输一个完整字节的数据,它可以将时钟线 SCL 保持在低电平,迫使发送端进入等待状态。当接收端准备好接收一个字节的数据并释放时钟线 SCL 时,数据传输将继续进行。时序逻辑如下图所示:
2.4.4 应答/非应答信号
每个字节之后都要进行应答。应答位允许接收器向发送器发出信号,表明已成功接收字节,可以发送另一个字节。
应答信号的定义如下:发送器在应答时钟脉冲期间释放 SDA 线,以便接收器将 SDA 线拉至低电平,并在该时钟脉冲的高电平期间保持稳定的低电平。
应答信号的时序逻辑如下所示:
当 SDA 在第九个时钟脉冲期间保持高电平时,这被定义为 “非应答 ”信号。此时,控制器可产生一个停止(STOP)条件以中止传输,或产生一个重复开始(START)条件以开始新的传输。有五种情况会导致产生 NACK:
1. 传输地址的总线上没有接收器,因此没有设备响应确认。
2. 接收器无法接收或发送,因为它正在执行某些实时功能,尚未准备好开始与控制器通信。
3. 在传输过程中,接收器收到了它无法理解的数据或命令。
4. 在传输过程中,接收器无法接收更多数据字节。
5. 控制器-接收器必须向目标发送器发出传输结束信号。非应答信号的时序逻辑如下所示:
2.5 I2C目标地址与读写位
在启动条件 (S) 之后,会发送一个目标地址。数据传输总是由控制器产生的停止条件 (P) 终止。但是,如果控制器仍希望在总线上进行通信,它可以重复产生一个 START(开始)条件 (Sr),并寻址另一个目标,而无需先产生一个 STOP(停止)条件。这样就可以在传输过程中实现各种读/写格式组合。数据传输格式如下图所示。
目标地址长度为 7 位,后面的第 8 位为数据方向位 (R/W)--“0 ”表示传输(写入),“1 ”表示数据请求(读取),如下图所示:
例如:当六轴姿态传感器MPU6050的AD0脚(用于确认地址的引脚)为0时,此时MPU6050的I2C目标地址为0b1101000(共7位),对MPU6050执行写入操作时,命令为0b11010000(0XD0),对MPU6050执行读取操作时,命令为0b11010001(0XD1)。
2.6 I2C读写逻辑分析
I2C 通信流程按照以下步骤进行:
- 主控向总线发送开始信号。
- 主控将要通信的设备地址和读写位(R/W)发送到总线上。
- 设备接收到地址后发送应答信号,主控接收到应答信号后发送数据或继续发送地址。
- 设备接收到数据后发送应答信号,主控接收到应答信号后可以继续发送数据或者停止通信。
- 主控向总线发送停止信号。
I2C发送数据流程如下:
I2C接收数据流程如下:
三、软件模拟I2C
软件模拟I2C主要包括起始信号、停止信号、等待应答信号到来、产生应答信号、产生非应答信号、I2C发送一个字节、I2C读取一个字节。具体代码如下所示:
//产生IIC起始信号
void IIC_Start(void)
{SDA_OUT();IIC_SDA=1; IIC_SCL=1;delay_us(5);IIC_SDA=0;delay_us(5);IIC_SCL=0; delay_us(5);
}
//产生IIC停止信号
void IIC_Stop(void)
{SDA_OUT();IIC_SCL=0;IIC_SDA=0;delay_us(5);IIC_SCL=1; delay_us(5);IIC_SDA=1;delay_us(5);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 IIC_Wait_Ack(void)
{u8 ucErrTime=0;SDA_IN(); //SDA设置为输入 IIC_SDA=1;delay_us(1); IIC_SCL=1;delay_us(1); while(READ_SDA){ucErrTime++;if(ucErrTime>250){IIC_Stop();return 1;}}IIC_SCL=0;//时钟输出0 return 0;
}
//产生ACK应答
void IIC_Ack(void)
{SDA_OUT();IIC_SDA=1;IIC_SCL=0;delay_us(2);IIC_SDA=0;IIC_SCL=1;delay_us(5);IIC_SCL=0;IIC_SDA=1;
}
//不产生ACK应答
void IIC_NAck(void)
{SDA_OUT();IIC_SDA=0;IIC_SCL=0;delay_us(2);IIC_SDA=1;IIC_SCL=1;delay_us(5);IIC_SCL=0;IIC_SDA=0;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(u8 txd)
{ u8 t; SDA_OUT(); IIC_SCL=0;for(t=0;t<8;t++){ IIC_SDA=(txd&0x80)>>7;txd<<=1; delay_us(2); IIC_SCL=1;delay_us(5); IIC_SCL=0; delay_us(5);}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 IIC_Read_Byte(unsigned char ack)
{unsigned char i,receive=0;SDA_IN();//SDA设置为输入for(i=0;i<8;i++ ){IIC_SCL=0; delay_us(2);IIC_SCL=1;receive<<=1;if(READ_SDA)receive++; delay_us(1); } if (!ack)IIC_NAck();//发送nACKelseIIC_Ack(); //发送ACK return receive;
}