MM32与STM32的IIC协议学习

 

       荷兰的Philips实验室开发了 ‘Inter-Integrated Circuit’,IIC 或 IIC ,一种只使用二根线接连所有外围芯片的总线协议。最初的标准定义总线速度为100kbps。经历几次修订,主要是1995年的400kbps,1998的3.4Mbps。

IIC协议规定:

 

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

 

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

 

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

IIC 数据传输速率有标准模式(100 kbps)、快速模式(400 kbps)和高速模式(3.4 Mbps),另外一些变种实现了低速模式(10 kbps)和快速+模式(1 Mbps)。


MM32的IIC的主要特征:

• 并行总线I2C 总线协议转换器
• 半双工同步操作
• 支持主从模式
• 支持7 位地址和10 位地址
• 支持标准模式100 Kbps,快速模式400 Kbps
• 产生Start、Stop、重新发Start、应答Acknowledge 信号检测
• 在主模式下只支持一个主机
• 分别有2 字节的发送和接收缓冲
• 在SCLI 和SDAI 上增加了无毛刺电路
• 支持DMA 操作
• 支持中断和查询操作


起始和停止条件

当总线处于空闲状态时,SCL 和SDA 同时被外部上拉电阻拉为高电平。

当主机启动数据传输时,必须先产生一个起始条件。在SCL 线是高电平时,SDA 线从高电平向低电平切
换表示起始条件。

当主机结束传输时要发送停止条件。在SCL 线是高电平,SDA 线由低电平向高电平切换表示停止条件

MM32与STM32的IIC协议学习_第1张图片


IIC的从机寻址协议有两种:

7位地址格式

10位地址格式

7位地址格式:

下图中显示在起始条件(S)后发送的一个字节的前7 位(bit 7:1)为从机地址,最低位(bit 0)是数据方向位,当bit 0 为0,表示主机写数据到从机,1 表示主机从从机读数据。

MM32与STM32的IIC协议学习_第2张图片

起始信号:在无数据通信时,IIC总线的SCL和SDA都是高电平;当主机要发送数据时,SDA在SCL为高电平时拉低发送起始信号
  从机地址:而后,主机在SDA上发出从机的7位地址(高位在前、低位在后)。这里只是以7位地址从设备为例,目前IIC总线支持7位地址和10位地址两种设备
  写标志:起始信号后的首字节的最低位(第8位)是读/写信号,其中0表示写数据到从机、1表示由从机读数据
  应答信号:当从机接收到主机发出的从机地址后,与自己的地址做比较,若发现呼叫的是自己,则在SCL的第9个时钟信号时拉低SDA,以表示应答(ACK)
  数据传输:主机收到应答信号后,接下来发送要传输的数据给从机,每次从机收到数据后,发送一个应答信号确认收到数据。
  停止信号:数据发送完成之后,主机发出停止信号,告诉从机数据通信结束。

起始信号 → 从机地址 → 读标志"1" → 从机应答 → 从机发送数据 →主机应答 → … →从机发送数据 → 主机无应答 → 主机发送停止信号

10位地址格式:

 在10 位的地址格式中,发送2 个字节来传输10 位地址。发送的第一个字节的位的描述如下:第一个5 位(bit 7:3)用于告示从机接下来是10 位的传输。第一个字节的后两个字节(bit 2:1)位从机地址的bit 9:8,最低位(bit 0)是数据方向位(R/W)。传输的第二个字节为10 位地址的低八位。

上面的为官方的解释,本人的理解为这个数据包是分两次发送的

第一,地址帧为两个字节长,原来的是一个字节;

第二,第一个字节前五位最高有效位用作10位地址标识,约定是“11110”。

除了10位地址标识,标准还预留了一些地址码用作其它用途

 

 

 

 

 

MM32与STM32的IIC协议学习_第3张图片


主机初始化数据传输并且从总线上发送或接收数据,作为主发送或者主接收。从机响应主
机的请求来发送或接收数据,作为从发送或从接收器。

主发送协议:

MM32与STM32的IIC协议学习_第4张图片

所有数据都是以字节格式传输,且不限制每次传输的字节数。当主机发送完地址和R/W 位或者主机发送一个字节的数据到从上,从接收器必须产生一个响应信号(ACK)。当从接收器不能产生ACK 响应信号,主机将会产生一个停止条件中止传输。从机不能响应时,必须释放SDA 为高电平才能使得主机产生停止条件。当主发送器传输数据如下图所示,从接收器在接收到的每个字节后产生一个ACK 来响应主发送器。


主接受从发送协议:

MM32与STM32的IIC协议学习_第5张图片

当主机接收数据如下图所示,主机必须在每次接收到一个字节数据后响应从发送器,除了最后一个字节。通过这种方式,主接收器能通知从发送器是否是最后一个字节。从发送器在检测到NACK 时必须释放SDA,这样主机可以产生停止条件。


起始字节传输协议:

 起始字节传输协议是用来给没有专用的I2C 硬件模块的系统使用。当I2C 模块作为主机时,在每次传输开始可以给需要的从机产生起始字节输出。该协议由7 个0 以及一个1 组成,如下图所示。处理器可以在地址阶段用低速采样0 来查询总线。一旦检测到0,处理器可以从低速采样切换到主机的正常速率。

MM32与STM32的IIC协议学习_第6张图片

起始字节程序流程如下:
1. 主机产生一个起始条件
2. 主机发送起始字节(0000 0001)
3. 主机发送ACK 时钟脉冲(ACK)
4. 没有从机响应ACK 信号
5. 主机产生重复起始条件(RESTART)
硬件I2C 接收器不需要响应开始字节,因为这是一个保留地址,而且地址会在RESTART后复位。

发送缓冲管理以及起始,停止和重复发送起始条件的产生

当工作在主机模式,每当发送为空时I2C 模块就在总线上产生一个停止条件。如果重复起始产生功能使能(IC_RESTART_EN = 1),则传输方向从读变为写或者写变为读时产生重复起始条件。如果没有使能重复起始条件,则会在停止条件后产生一个起始条件。下图显示了IC_DATA_CMD 寄存器的位。

MM32与STM32的IIC协议学习_第7张图片

下面的时序图描述了I2C 模块工作在主发送模式下Tx FIFO 变为空时行为。

MM32与STM32的IIC协议学习_第8张图片

下面的时序图描述了I2C 模块工作在主接收模式下当Tx FIFO 变为空时行为。

MM32与STM32的IIC协议学习_第9张图片


I2C 接口可以以下述4 种方式中的一种运行:
• 从发送器模式
• 从接收器模式
• 主发送器模式
• 主接收器模式

下面介绍从模式的程序流程图:

初始化配置:

1. 写0 到IC_ENABLE 寄存器位0 禁止I2C。
2. 通过初始化IC_SAR 寄存器来配置从机地址。该地址为I2C 接口所响应的地址。
3. 配置IC_CON 寄存器指定地址格式(设置bit 3 来选择7 位或10 位地址格式)。写0 到寄
存器IC_CON 寄存器的位6(IC_SLAVE_DISABLE)和写0 到位0(MASTER_MODE)。
4. 写1 到IC_ENABLE 寄存器中位0 来使能I2C 接口模块。

从发送单字节操作:

当I2C 接口被其他I2C 主机寻址并请求数据的时候,I2C 接口工作在从发送模式,步骤如
下:
1. 其他I2C 主机器件初始化I2C 传输,发送地址与IC_SAR 寄存器中的从机地址匹配。
2. I2C 接口响应发送的地址,识别传输的方向是工作在从发送模式。
3. I2C 接口产生RD_REQ 中断(寄存器IC_RAW_INTR_STAT 位5),并且将SCL 线拉
低。总线一直处于等待状态直到软件响应。
如果RD_REQ 中断被屏蔽(寄存器IC_INTR_MASK[5] = 0),建议CPU 定期查询IC_RAW_INTA_STAT
寄存器。
1. IC_RAW_INTR_STAT 位5 置位等效于产生了一个RD_REQ 中断。
2. 软件必须满足I2C 传输的要求。
3. 时间间隔通常在10 个SCL 时钟周期左右。例如,对于400kbps,时间间隔是25us。
4. 如果在接收读请求之前Tx FIFO 仍然有数据,I2C 接口就会产生一个TX_ABRT 中断
(IC_RAW_INTR[6]),清空Tx FIFO 中的数据。
5. 软件写数据到IC_DATA_CMD 寄存器(其中位8 设置为0)。
6. 软件必须先清除IC_RAW_INTA_STAT 寄存器RD_REQ 和TX_ABRT 中断(分别为
bit5,6)
7. I2C 接口释放SCL,并发送数据字节。
8. 主机器件发送重复起始条件控制总线或者发送停止条件释放总线。

从接受单字节操作:

当其他主机器件寻址I2C 接口并且发送数据,I2C 接口工作在从接收模式,步骤如下:
1. 其他I2C 主机器件初始化I2C 传输,发送地址与IC_SAR 寄存器中的从机地址匹配。
2. I2C 接口响应发送的地址,识别传输的方向是工作在从接收模式。
3. I2C 接口收到主机发送的数据并将数据存储在接收缓冲中。
4. I2C 接口产生RX_FULL 中断(IC_RAW_INTR_STAT[2]). 如果RX_FULL 中断被屏蔽
(IC_INTR_MASK[2]=0),建议软件定期查询IC_STATUS 寄存器中。读到IC_STATUS
寄存器位3(RFNE)为1 时等效于RX_FULL 中断产生。
5. 软件通过读IC_DATA_CMD 寄存器中的bit 7:0 来获得接收到的数据。
6. 主机器件发送重复起始条件控制总线或者发送停止条件释放总线。

从机块传输操作:

标准的I2C 协议中,所有的数据处理都是单个字节的处理,程序通过写一个字节到从机的Tx FIFO 响应主机的读请求。当一个从机(从发送)接收到主机(主接收)的读请求(RD_REQ)时,最少有一个数据放到从发送的Tx FIFO。这个I2C 接口模块可以处理TxFIFO 中有多个数据,所以接下来的读请求不需要再产生中断来取数据。最终,这极大的减少了因为每次数据中断导致等待时间。该模式仅存在当I2C 接口作为从发送模式。如果主机发送响应从发送传输的数据,从机的TX FIFO 中没有数据,I2C 接口将拉低I2C 总线的SCL 线直到读请求中断(RD_REQ)产生并且TX FIFO 的数据准备好后才释放SCL 线。如果RX_REQ 中断被屏蔽(IC_INTR_STAT[5]=0),软件可以定期查询读IC_RAW_INTR_STAT寄存器。当读到IC_RAW_INTR_STAT[5] 返回为1 等效于产生了RX_REQ 中断。RD_REQ 中断由于读请求产生,像中断一样须退出中断服务程序(ISR)时清除。在中断服务程序中(ISR)可以写一个或多个字节的数据到TX FIFO。在这些字节传输给主机的过程中,如果主机响应了最后一个字节,从机将必须再次产生RD_REQ 中断请求。这是因为主机要求更多的数据。如果主机接收了来自I2C 接口的n 字节,但是程序写到Tx FIFO 中的数据个数大于n,从机在完成要求的n 字节的数据发送后,将会清空Tx FIFO 并且忽略额外的字节。

 主模式:

初始化配置

1. 通过设置IC_ENABLE[0]=0 来禁止I2C 接口
2. 配置IC_CON 寄存器的bit 2:1 设置I2C 工作的速率模式(标准模式、快速模式)。同
时确保bit 6(IC_SLAVE_DIASBLE)为1,且bit 0(MASTER_MODE)为1。
3. 往IC_TAR 寄存器写入I2C 器件地址。设置该寄存器可配置为广播地址或起始字节命
令。
4. 置位IC_ENABLE[0] 使能I2C 接口。
5. 将传输的数据以及传输方向写入到IC_DATA_CMD 寄存器中。如果在使能I2C 接口之
前配置了IC_DATA_CMD 寄存器,数据和命令都会丢失,这是因为在I2C 接口禁止的
情况下缓冲是清空的。
以上的步骤将会使得I2C 接口产生一个起始条件并发送地址字节数据到I2C 总线上。

主发送与接收:
I2C 接口支持读写的动态切换。当发送数据时,写数据到I2C RX/TX 数据缓冲和命令寄存
器的低字节中(IC_DATA_CMD),配置CMD 位为0 产生写操作。接下来的读命令,不需
要设置IC_DATA_CMD 寄存器的低字节,只需要确保CMD 位为1。如果发送FIFO 为空,
I2C 模块拉低SCL 直到下个命令写入到发送FIFO 中。

实例代码如下:

void I2C_Master_Init()//初始化gpio
{
    RCC->APB2ENR|=RCC_APB2ENR_IOPBEN;   //使能GPIOB时钟	   	 
    RCC->APB1ENR|=RCC_APB1ENR_I2C1EN;   //使能I2C1时钟	   	 
    RCC->APB2ENR|=RCC_APB2ENR_AFIOEN;   //RCC->APB2ENR|=1<<3;  
    
    AFIO->MAPR|=1<<1;
    GPIOB->CRH=0x000000ff;//PB8和PB9复用开漏输出
    
    I2C1->IC_CON = 0x163;
    I2C1->IC_TAR = FLASH_DEVICE_ADDR>>1;
    I2C1->IC_SS_SCL_HCNT = 0x77;
    I2C1->IC_SS_SCL_LCNT = 0x55;
    I2C1->IC_RX_TL=0x0;//set Rx FIFO threshold level 
    I2C1->IC_TX_TL=0x1;//set Tx FIFO threschold level 
    I2C1->IC_INTR_MASK=0;//disable all inttrupt
    I2C1->IC_ENABLE=0x1;
    
}	

void I2CTXEmptyCheck()
{
    while(1)
    {
        if((I2C1->IC_RAW_INTR_STAT & I2C_RAW_INTR_MASK_TX_EMPTY))//发送缓冲区空
            break; 
    }
}

void I2CRXFullCheck()//判断是否为空
{
    
    I2C1->IC_DATA_CMD = I2C_DATA_CMD_CMD;//读数据指令,不可省略
    
    while(1)
    {
        if((I2C1->IC_RAW_INTR_STAT & I2C_RAW_INTR_MASK_RX_FULL))//接收缓冲区非空
            break; 
    }
    
}



void I2CTXByte(u8 data)//IIC发送函数
{
    
    
    I2C1->IC_DATA_CMD = data;//发送数据 
    while( (I2C1->IC_STATUS & 0x0004) == 0 );
    //I2CTXEmptyCheck();
}


unsigned char I2CRXByte()//IIC接收函数
{
    unsigned char temp;
    I2CRXFullCheck();
    temp=I2C1->IC_DATA_CMD;
    return temp;
}

void i2cStop(void)//IIC停止函数
{
    u16 overTime = 3000;
    
    I2C1->IC_ENABLE |= 0x02;
    
    while(I2C1->IC_ENABLE&0x02)
    {
        if(0 == overTime-- )
        {
            break;
        }			
    }
    
    I2C1->IC_CLR_TX_ABRT;
}



void I2CMasterWrite(unsigned short mem_byte_addr, unsigned short tx_count, unsigned char *tx_data)
{
    unsigned short temp;
    unsigned short i;
    unsigned char *p;
    p = tx_data;
    temp = ((mem_byte_addr) & 0xff);
    I2CTXByte(temp);  //tx memory addr
    
    for(i=0;i

时钟拉伸

在 IIC 通信中,主设备决定了时钟速度。因为时钟脉冲信号是由主设备显式发出的。但是,当从设备没办法跟上主设备的速度时,从设备需要一种机制来请求主设备慢一点。这种机制称为时钟拉伸,而基于I²C结构的特殊性,这种机制得到实现。当从设备需要降低传输的速度的时候,它可以按下时钟线,逼迫主设备进入等待状态,直到从设备释放时钟线,通信才继续。

 

 

 

你可能感兴趣的:(MM32)