[产品应用] CW32单片机I2C接口读写EEPROM芯片介绍

[复制链接]
1840|31
 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:08 | 显示全部楼层 |阅读模式
一、概述

CW32L083 内部集成 2 个 I2C 控制器,能按照设定的传输速率(标准,快速,高速)将需要发送的数据按照 I2C 规范串行发送到 I2C 总线上,或从总线上接收数据,并对通信过程中的状态进行检测,另外还支持多主机通信中的总线冲突和仲裁处理。

二、主要功能

• 支持主机发送 / 接收,从机发送 / 接收四种工作模式

• 支持时钟延展 ( 时钟同步 ) 和多主机通信冲突仲裁

• 支持标准 (100Kbps)/ 快速 (400Kbps)/ 高速 (1Mbps) 三种工作速率

• 支持 7bit 寻址功能

• 支持 3个从机地址

• 支持广播地址

• 支持输入信号噪声过滤功能

• 支持中断状态查询功能


 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:36 | 显示全部楼层
1.协议介绍

I2C 总线使用两根信号线(数据线 SDA 和时钟线 SCL)在设备间传输数据。SCL 为单向时钟线,固定由主机驱动。SDA 为双向数据线,在数据传输过程中由收发两端分时驱动。I2C 总线上可以连接多个设备,所有设备在没有进行数据传输时都处于空闲状态(未寻址从机接收模式),任一设备都可以作为主机发送 START 起始信号来开始数据传输,在 STOP 停止信号出现在总线上之前,总线一直处于 被占用状态。I2C 通信采用主从结构,并由主机发起和结束通信。主机通过发送 START 起始信号来发起通信,之后发送 SLA+W/R 共 8bit 数据(其中,SLA 为 7bit 从机地址,W/R 为读写位),并在第 9个SCL 时钟释放 SDA 总线, 对应的从机在第 9个SCL 时钟占用 SDA 总线并输出 ACK 应答信号,完成从机寻址。此后根据主机发送的第 1 字 节的 W/R 位来决定数据通信的发端和收端,发端每发送 1个字节数据,收端必须回应 1个ACK 应答信号。数据传输完成后,主机发送 STOP 信号结束本次通信。
 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:36 | 显示全部楼层
1.协议介绍

I2C 总线使用两根信号线(数据线 SDA 和时钟线 SCL)在设备间传输数据。SCL 为单向时钟线,固定由主机驱动。SDA 为双向数据线,在数据传输过程中由收发两端分时驱动。I2C 总线上可以连接多个设备,所有设备在没有进行数据传输时都处于空闲状态(未寻址从机接收模式),任一设备都可以作为主机发送 START 起始信号来开始数据传输,在 STOP 停止信号出现在总线上之前,总线一直处于 被占用状态。I2C 通信采用主从结构,并由主机发起和结束通信。主机通过发送 START 起始信号来发起通信,之后发送 SLA+W/R 共 8bit 数据(其中,SLA 为 7bit 从机地址,W/R 为读写位),并在第 9个SCL 时钟释放 SDA 总线, 对应的从机在第 9个SCL 时钟占用 SDA 总线并输出 ACK 应答信号,完成从机寻址。此后根据主机发送的第 1 字 节的 W/R 位来决定数据通信的发端和收端,发端每发送 1个字节数据,收端必须回应 1个ACK 应答信号。数据传输完成后,主机发送 STOP 信号结束本次通信。
 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:39 | 显示全部楼层
2.功能框图

I2C 模块主要包括时钟发生器、输入滤波器、地址比较器、协议控制逻辑、仲裁和同步逻辑、以及相关寄存器等。 110.png
 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:39 | 显示全部楼层
本帖最后由 铁血丹心LLLL 于 2023-4-26 10:42 编辑

CW32L083 支持用户灵活选择 GPIO 作为 I2C 通信引脚,如下表所示: 10110.jpg
 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:39 | 显示全部楼层
2.功能框图

I2C 模块主要包括时钟发生器、输入滤波器、地址比较器、协议控制逻辑、仲裁和同步逻辑、以及相关寄存器等。
110.png
 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:42 | 显示全部楼层
3.I2C中断

I2C 控制寄存器 I2Cx_CR 的 SI 位域为中断标志位。当 I2C 状态寄存器 I2Cx_STAT 的 STAT 位域值发生改变(变成 0xF8 除外)时,I2Cx_CR.SI 标志位就会被置位,同时产生中断请求。在用户 I2C 中断服务程序中,应查询 I2C 状态寄存器 I2Cx_STAT 的 STAT 位域值获取 I2C 总线的状态,以确定中断产生原因。设置 I2Cx_CR.SI 为 0 清除该标志位。
 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:42 | 显示全部楼层
4.工作模式

I2C 控制器支持 4 种工作模式:主机发送模式、主机接收模式、从机发送模式、从机接收模式。另外还支持广播 接收模式,其工作方式和从机接收模式类似。

 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:42 | 显示全部楼层
三、EEPROM(CW24C02AD)

1.功能简介

CW24C02是一个2Kbit的串行EEPROM存储芯片,可存储256个字节数据。芯片内部分为32页,每页8字节。工作电压范围为1.7V到5.5V,I2C接口时钟频率为 1MHz (5V,3V),400 KHz (1.7V)。器件地址为1010 A2 A1 A0,对于我们单板A2 A1 A0引脚全部接GND,故器件地址为1010000,即0x50。器件内部存储空间地址长度8 bit。
 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:43 | 显示全部楼层
2.读写时序

字节写操作时序:起始信号+器件地址(7bit)+读写指示(1bit)+存储空间地址(8bit)+写入数据(8bit)+停止信号,即可完成指定字节写入操作。 052.jpg
 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:43 | 显示全部楼层
页写操作时序:起始信号+器件地址(7bit)+读写指示(1bit)+存储空间地址(8bit)+写入数据(8bit*8)+停止信号,即可完成指定地址(必须是页起始地址)的页写入操作。
54.jpg
 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:44 | 显示全部楼层
随机读操作时序:起始信号+器件地址(7bit)+读写指示(1bit)+存储空间地址(8bit)+重复起始信号+器件地址(7bit)+读写指示(1bit),之后器件会返回1字节数据,主机收到后发送停止信号,即可完成指定字节读取操作。


653.jpg
 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:44 | 显示全部楼层
顺序读操作时序:和随机读时序类似,只是在主机接收到1字节数据后,不发送停止信号,而是继续发送时钟进行下一个字节数据的接收,直到所有所需读取的数据全部读取,之后再发送停止信号。、
36587.jpg
 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:45 | 显示全部楼层
四、硬件连接

如下图所示,MCU和EEPROM通过I2C总线互连。
65847.jpg
 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:46 | 显示全部楼层
五、实例演示:MCU采用页写和顺序读操作时序完成EERPOM的访问。

1.I2C读写EEPROM芯片中断函数(I2C分为I2C1和I2C2)
  1. void I2c1EepromReadWriteInterruptFunction(void)

  2. {

  3.     u8State = I2C_GetState(CW_I2C1);// I2C:获取状态寄存器函数

  4.     switch(u8State)

  5.     {

  6.         case 0x08:     //发送完START信号

  7.             I2C_GenerateSTART(CW_I2C1, DISABLE);// 发送START信号

  8.             I2C_Send7bitAddress(CW_I2C1, I2C_SLAVEADDRESS,0X00);// 做主时发送从机地址字节

  9.             break;

  10.         case 0x10:     //发送完重复起始信号

  11.             I2C_GenerateSTART(CW_I2C1, DISABLE);

  12.             if(0 == Send**)

  13.             {

  14.          I2C_Send7bitAddress(CW_I2C1, I2C_SLAVEADDRESS,0X00);    //写命令

  15.             }

  16.             else

  17.             {

  18.          I2C_Send7bitAddress(CW_I2C1, I2C_SLAVEADDRESS,0X01); //读命令,eeprom 随机读

  19.             }

  20.             break;

  21.         case 0x18:    //发送完SLA+W/R字节

  22.             I2C_GenerateSTART(CW_I2C1, DISABLE);

  23.             I2C_SendData(CW_I2C1, u8Addr);   //发送访问EEPROM的目标地址字节

  24.             break;

  25.         case 0x20:    //发送完SLA+W后从机返回NACK

  26.         case 0x38:    //主机在发送 SLA+W 阶段或者发送数据阶段丢失仲裁  或者  主机在发送 SLA+R 阶段或者回应 NACK 阶段丢失仲裁

  27.         case 0x30:    //发送完一个数据字节后从机返回NACK

  28.         case 0x48:    //发送完SLA+R后从机返回NACK

  29.             I2C_GenerateSTOP(CW_I2C1, ENABLE);

  30.             I2C_GenerateSTART(CW_I2C1, ENABLE);

  31.             break;

  32.         case 0x58:    //接收到一个数据字节,且NACK已回复

  33.             u8Recdata[u8RecvLen++] = I2C_ReceiveData(CW_I2C1);//所有数据读取完成,NACK已发送

  34.             receivedflag =1;

  35.             I2C_GenerateSTOP(CW_I2C1, ENABLE);//发送停止条件

  36.             break;

  37.         case 0x28:     //发送完1字节数据:发送EEPROM中memory地址也会产生,发送后面的数据也会产生

  38.             if(0 == Send**)

  39.             {

  40.                 if(u8SendLen <WRITELEN)

  41.                 {

  42.                     I2C_SendData(CW_I2C1,u8Senddata[u8SendLen++]);

  43.                 }

  44.                 else

  45.                 {

  46.                     u8SendLen = 0;

  47.                     Comm_** = 1;

  48.                     Send** = 1;

  49.                     I2C_GenerateSTOP(CW_I2C1, ENABLE);//发送完数据,发送停止信号

  50.                 }

  51.             }

  52.          else//Send**=1为读,Send**=0为写。读数据发送完地址字节后,重复起始条件

  53.             {

  54.                 CW_I2C1->CR_f.STA = 1;  //set start       //发送重复START信号,START生成函数改写后,会导致0X10状态被略过,故此处不调用函数

  55.                 I2C_GenerateSTOP(CW_I2C1, DISABLE);

  56.             }

  57.             break;

  58.         case 0x40:     //发送完SLA+R信号,开始接收数据

  59.             u8RecvLen = 0;

  60.             if(READLEN>1)

  61.             {

  62.             I2C_AcknowledgeConfig(CW_I2C1,ENABLE);//读取数据超过1个字节才发送ACK

  63.             }

  64.             break;

  65.         case 0x50:     //接收完一字节数据,在接收最后1字节数据之前设置AA=0;

  66.             u8Recdata[u8RecvLen++] = I2C_ReceiveData(CW_I2C1);

  67.             if(u8RecvLen==READLEN-1)

  68.             {

  69.                 I2C_AcknowledgeConfig(CW_I2C1,DISABLE);;

  70.             }

  71.             break;

  72.     }

  73.     I2C_ClearIrq(CW_I2C1);

  74. }
 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:46 | 显示全部楼层
  1. 2.设置系统时钟

  2. void RCC_Configuration(void)

  3. {

  4.     CW_SYSCTRL->APBEN1_f.I2C1 = 1U;   

  5. }
 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:46 | 显示全部楼层
  1. 3.设置GPIO口

  2. void GPIO_Configuration(void)

  3. {

  4.     GPIO_InitTypeDef GPIO_InitStructure = {0};

  5.     CW_SYSCTRL->AHBEN_f.GPIOA  = 1;

  6.     CW_SYSCTRL->AHBEN_f.GPIOB  = 1;

  7.     CW_SYSCTRL->AHBEN_f.GPIOC  = 1;

  8.     CW_SYSCTRL->AHBEN_f.GPIOD  = 1;

  9.     CW_SYSCTRL->AHBEN_f.GPIOE  = 1;

  10.     CW_SYSCTRL->AHBEN_f.GPIOF  = 1;

  11.     PB10_AFx_I2C1SCL();

  12.     PB11_AFx_I2C1SDA();

  13.     GPIO_InitStructure.Pins = I2C1_SCL_GPIO_PIN | I2C1_SDA_GPIO_PIN;

  14.     GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD;

  15.     GPIO_Init(I2C1_SCL_GPIO_PORT, &GPIO_InitStructure);

  16. }
 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:46 | 显示全部楼层
  1. 4.配置嵌套矢量中断控制器

  2. void NVIC_Configuration(void)

  3. {

  4.     __disable_irq();

  5.     NVIC_EnableIRQ(I2C1_IRQn);

  6.     __enable_irq();

  7. }

  8. void I2C1_IRQHandler(void)

  9. {

  10.     I2c1EepromReadWriteInterruptFunction();

  11. }
 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:47 | 显示全部楼层
  1. 5.定义常量

  2. #define  I2C1_SCL_GPIO_PORT       CW_GPIOB

  3. #define  I2C1_SCL_GPIO_PIN        GPIO_PIN_10   

  4. #define  I2C1_SDA_GPIO_PORT       CW_GPIOB

  5. #define  I2C1_SDA_GPIO_PIN        GPIO_PIN_11   

  6. //EEPROM内部地址

  7. uint8_t u8Addr = 0x00;        //地址字节

  8. #define WRITELEN   8          //写数据长度

  9. #define READLEN   8           //读数据长度

  10. #define WriteReadCycle  35    //写读次数,每次写入数据为n+i(n为次数,i=0~7)

  11. uint8_t u8Senddata[8] = {0x66,0x02,0x03,0x04,0x05,0x60,0x70,0x20};

  12. uint8_t u8Senddata2[8] = {0x55,0xAA,0xAA,0x55,0x55,0xAA,0x55,0xAA};

  13. uint8_t u8Recdata[16]= {0x00};

  14. uint8_t u8SendLen=0;

  15. uint8_t u8RecvLen=0;

  16. uint8_t Send** = 0,Comm_** = 0;

  17. uint8_t u8recv**=0;

  18. uint8_t u8State = 0;

  19. uint8_t receivedflag = 0;    //读取完成标志

 楼主| 铁血丹心LLLL 发表于 2023-4-26 10:47 | 显示全部楼层
  1. 6.主程序:利用I2C接口,采用中断方式读写EEPROM芯片(CW24C02)。

  2. int32_t main(void)

  3. {

  4.     I2C_InitTypeDef I2C_InitStruct = {0};

  5.     uint16_t tempcnt = 0 ;

  6.     RCC_Configuration();//时钟初始化

  7.     GPIO_Configuration();//IO口初始化

  8.     //I2C初始化

  9.     I2C_InitStruct.I2C_Baud = 0x01;//500K=(8000000/(8*(1+1)) ,波特率计数器配置

  10.     I2C_InitStruct.I2C_BaudEn = ENABLE;// 波特率计数器使能

  11.     I2C_InitStruct.I2C_FLT = DISABLE; //<FLT配置

  12.     I2C_InitStruct.I2C_AA =  DISABLE; //<ACK配置

  13.     I2C1_DeInit();

  14.     I2C_Master_Init(CW_I2C1,&I2C_InitStruct);//初始化模块

  15.     NVIC_Configuration();//中断设置

  16.     //I2C模块开始工作

  17.     I2C_Cmd(CW_I2C1,ENABLE);  //模块使能

  18.     tempcnt =0;

  19.     for(uint8_t i=0; i<8; i++)

  20.     {

  21.         u8Senddata[i] = i;

  22.     }

  23.     while(1)

  24.     {

  25.         I2C_GenerateSTART(CW_I2C1, ENABLE); //开始信号

  26.         while(1)

  27.         {

  28.            

  29.             while(!Comm_**) ; //等待数据发送完成

  30.             FirmwareDelay(3000);

  31.          

  32.             Comm_** = 0; //启动读数据过程

  33.             receivedflag=0;

  34.             I2C_GenerateSTART(CW_I2C1, ENABLE); //开始信号

  35.             while(!receivedflag) ; //等待数据读取完成

  36.             receivedflag = 0; //初始化下一次写数据

  37.             Send** = 0;

  38.             u8RecvLen = 0;

  39.             tempcnt++;

  40.             for(uint8_t i=0; i<8; i++)

  41.             {

  42.                 u8Senddata[i] =tempcnt+i;

  43.             }

  44.             break;

  45.         }

  46.         

  47.         if(tempcnt >=WriteReadCycle) //测试次数完成,退出

  48.         {

  49.             break;

  50.         }

  51.     }

  52.     while(1);

  53. }
您需要登录后才可以回帖 登录 | 注册

本版积分规则

76

主题

543

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部