News Detail

华芯微特屏驱MCU SWM341 I2C 接口应用

华芯微特MCU 相关咨询

87
Issuing time:2023-11-24 16:32Author:glochip.comSource:www.globalizex.com/news/Link:https://www.glochip.com/news/
文章附图

1

I2C 简介


物理连接

图片

I2C总线由时钟线SCL、数据线SDA两根线构成,连接在其上的设备分为主机和从机两种,I2C上的通信全部由主机发起。

I2C设备对总线的输出采用开漏输出结构,即它只有在总线和GND之间的NMOS管,没有总线和VDD之间的PMOS管。输出0时通过开启NMOS管将总线与GND短接;输出1时无法像推挽输出那样开启PMOS管将总线与VDD短接,而是只能通过关闭NMOS从而由外接的上拉电阻将总线拉到高电平。

由于上拉电阻阻值一般比较大(10K欧姆),因此如果此时有其他I2C设备输出0,总线会被拉到低电平。只有当总线上的所有设备都不输出0时,总线才是高电平;只要有一个设备输出0,总线就是低电平,这也就是所谓的“线与”。这是I2C总线应答与多主机通信的基础。


协议格式

图片

0、空闲时总线上所有设备都不驱动总线,即都不开启NMOS管,总线由外部上拉电阻拉到高电平。

1、I2C上的通信全部由主机发起,主机通过发送起始位启动传输,起始位由SCL为高时SDA线上的下降沿产生。

2、起始位后面跟7位地址和1位读写方向指示(0表示主机向从机写入,1表示主机从从机读取),主机发送完这8位后停止驱动总线,总线由外部上拉电阻拉到高电平,被寻址的从机输出0将总线拉低。主机检测到这个低电平,就知道从机可以相应主机请求,可以进行数据传输。

3、数据传输阶段,若R/W=0,则主机发送数据,从机发送响应;若R/W=1,则从机发送数据,主机发送响应,每传输一个字节数据,后面都跟一个响应位。

4、数据传输完成后,主机发送停止位终止传输,终止位由SCL为高时SDA线上的上升沿产生。

5、由于SCL为高时,SDA的上升沿、下降沿均有特殊含义,因此I2C中数据传输时,SDA只在SCL为低时变化,在SCL为高时保持不变。即发送方在SCL为低时改变SDA状态,接收方在SCL上升沿读取SDA状态。


02

SWM341 I2C 接口

功能框图

图片

SWM341 I2C 的核心是一个双向移位寄存器,发送时,数据通过TXDATA寄存器写入移位寄存器,然后按位移除到SDA引脚;接收时,将SDA引脚状态移入移位寄存器,通过RXDATA寄存器读出。

移位寄存器的移位节拍来自内部I2C时钟分频器(主机模式下)或SCL引脚(从机模式下),主机模式下时钟分频器产生的时钟同时输出到SCL引脚,驱动总线上的I2C从机的移位寄存器。


使用示例:读写 EEPROM AT24C024

int main(void)

{

         uint32_t i;

         uint8_t ack;


         SystemInit();

         SerialInit();

         I2CMstInit();


         while(1==1)

         {

              /*************** EEPROM Write ***************/  

              ack = I2C_Start(I2C0, (SLV_ADDR << 1) | 0, 1);

              if(ack == 0)

         {

                     printf("Slave send NACK for address\r\n");

                     goto nextloop;

          }


          ack = I2C_Write(I2C0, MEM_ADDR, 1);

          if(ack == 0)

         {

                    printf("Slave send NACK for memory address\r\n");

                    goto nextloop;

          }


         for(i = 0; i < 4; i++)

         {

                    ack = I2C_Write(I2C0, txbuff[i], 1);

                    if(ack == 0)

                    {

                            printf("Slave send NACK for data\r\n");

                            goto nextloop;

                     }

          }


          I2C_Stop(I2C0, 1);


          printf("Master Write %X %X %X %X @ %X\r\n", txbuff[0], txbuff[1], txbuff[2], txbuff[3], MEM_ADDR);



          for(i = 0; i < 1000000; i++) __NOP(); // 延时等待内部写入操作完成



          /*************** EEPROM Read ***************/

          ack = I2C_Start(I2C0, (SLV_ADDR << 1) | 0, 1);

          if(ack == 0)

          {

                   printf("Slave send NACK for address\r\n");

                   goto nextloop;

           }


           ack = I2C_Write(I2C0, MEM_ADDR, 1);

           if(ack == 0)

          {

                    printf("Slave send NACK for memory address\r\n");

                    goto nextloop;

          }


          for(i = 0; i < CyclesPerUs; i++) __NOP(); // 不加此延时,系统主频高于 100MHz 时,re-start 发不出来


           ack = I2C_Start(I2C0, (SLV_ADDR << 1) | 1, 1);

           if(ack == 0)

           {

                     printf("Slave send NACK for address\r\n");

                     goto nextloop;

           }


           for(i = 0; i < 3; i++)

           {

                      rxbuff[i] = I2C_Read(I2C0, 1, 1);

           }

           rxbuff[i] = I2C_Read(I2C0, 0, 1);

           printf("Master Read %X %X %X %X @ %X\r\n", rxbuff[0], rxbuff[1], rxbuff[2], rxbuff[3], MEM_ADDR);


           if((txbuff[0] == rxbuff[0]) && (txbuff[1] == rxbuff[1]) && (txbuff[2] == rxbuff[2]) && (txbuff[3] == rxbuff[3]))

                  printf("Success\r\n");

           else

                  printf("Fail\r\n");


nextloop:

           I2C_Stop(I2C0, 1);

           for(i = 0; i < SystemCoreClock/3; i++) __NOP();

      }

}

I2C_Start()的参数是7位从机地址和读写方向选择位,调用该函数在I2C总线上产生起始位,然后发送地址和方向位,读取从机响应位ACK并返回。执行该函数后需要检查返回的从机响应ack,若有从机相应,则继续后续读写操作;若没有从机相应,则打印调试信息然跳转到程序末尾。

EEPROM AT24C02 的 Page Write 帧格式如下:

图片

设备地址后,需要发送要将数据写入EEPROM的位置(Word Address),然后再发送要写入的数据。程序中首先执行 I2C_Write(I2C0, MEM_ADDR, 1) 发送数据在EEPROM中的存储位置,然后执行 I2C_Write(I2C0, txbuff[i], 1) 将要写入 EEPROM的数据逐个发出。最后执行 I2C_Stop(I2C0, 1) 在总线上产生停止条件,终止数据传输。

需要注意的是,以上操作只是将要写入EEPROM的数据通过I2C接口写入EEPROM内部缓存中,EEPROM还需要一定时间将缓存中的数据写入实际存储介质中。若此时立即读取EEPROM,读取到的依然会是写入之前的数据。查手册可知,AT24C02 的写入时间大概 5ms。

AT24C02 的读取操作与上述的写入操作类似,唯一不同的是,在读取操作中,响应ACK由主机发送、从机检查,I2C_Read()调用中需要给出本次读取后响应ACK还是NAK(即不响应,不在ACK位时将SDA拉低)。在读取前面的数据时,需要响应ACK,以通知从机准备好后续数据;读取最后一个数据时,最好响应NAK,通知从机主机不再需要后续数据。


Home                                    Product                                        News                                   About                                        Contact
Tel: +86-0755-84866816  
Tel: +86-0755-84828852
Mail:  kevin@glochip.com
Web:  www.chip.com.hk
Rm401.1st Building, Dayun software Longgang Avenue, Longgang district,Shenzhen
全球芯微信公众号
Samsung Micron SKhynix Kingston Sandisk  Kioxia Nanya Winbond MXIC ESMT Longsys Biwin HosgingGlobal  BoyaMicro  Piecemakers Rayson  Skyhigh  Netsol

SRAM MRAM SDRAM DDR1 DDR2 DDR3 DDR4 DDR5 LPDDR3 LPDDR4 LPDDR4X LPDDR5 LPDDR5X NAND NOR eMMC UFS eMCP uMCP SSD Module