打印
[CW32F030系列]

【CW32F030CxTx StartKit测评】04.I2C主从机功能验证

[复制链接]
1624|22
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 xld0932 于 2022-7-9 16:18 编辑

【CW32F030CxTx StartKit测评】04.I2C主机模式读写EEPROM、I2C从机模式多地址通讯


概述
本文来学习一下CW32F030系列MCU的硬件I2C通讯接口功能:通过I2C1主机模式实现对板载EEPROM(CW24C02A)的读写操作、通过I2C2从机模式实现多从机地址的通讯功能,使用外部的I2C主机设备进行测试。除此之外,本篇将会附带一些Letter-shell的调试功能实操,Letter-shell不会专门讲解,大家可以通过实操来了解Letter-shell的功能,当然有兴趣的可以自己研究其强大的功能,主要还是将Letter-shell当作在线调试工具来使用、方便调试实现功能。


EEPROM
CW32F030CxTx StartKit开发板上板载了一颗芯源的串行电可擦除只读存储器(EEPROM):CW24C02A,两线串行接口方式,通过I2C协议实现双向数据传输;其容量大小为2K位(256字节);支持1.7V至5.5V的宽范围工作电压,当工作在1.7V电压时I2C最大传输速率可达到400KHz,当工作在3V或者5V电压时I2C最大传输速率可达到1MHz;CW24C02A通过页写的方式写入数据,每页大小为8个字节,共有32个页面,且内部最大写周期不超过4ms;其本身的高可靠性,被广泛应用在智能化仪器仪表、家用电器、汽车电子、通讯设备、消费类电子等众多领域。


EEPROM原理图
CW24C02A作为I2C从设备,本身的器件硬件地址由芯片A0/A1/A2这三个引脚电平的高低状态决定的,如下原理图所示A0/A1/A2这三个引脚都连接到GND,所以CW24C02A的I2C器件地址为0xA0;原理图中CW24C02A的WP引脚提供硬件数据的写保护功能,当前设计也是连接到GND,指示当允许正常的读写数据,假若WP连接VCC时,芯片就会启动写保护功能,无法将数据正常写入到芯片内部存储空间进行存储了。需要注意的是,开发板上EEPROM电路是一个独立的模块,提供操作接口CN11,当我们需要实现EEPROM实验操作时,需要将CN11上的VDDE连接到VDD电源,将SCL与SDA连接到MCU的I2C端口引脚上。


CW32F030 I2C
CW32F030内部集成了2个I2C控制器(I2C1和I2C2),这两个接口的时钟源将挂载在APB总线上(PCLK),这个在设置I2C通讯速率的计算公式中会乃至哦……CW32F030 I2C接口能够按照设定的传输速率将需要发送的数据按照I2C规范串行发送到I2C总线上,并对通讯过程中的状态进行侦测,另外还支持多主机通讯中的总线冲突和仲裁处理功能。主要特性如下:
  • 支持主机发送/接收、从机发送/接收四种工作模式
  • 支持时钟延展(时钟同步)和多主机通讯冲突仲裁
  • 支持标准(100Kbps)、快速(400Kbps)、高速(1Mbps)三种工作速率
  • 支持7-bit寻址功能
  • 支持3个从机地址
  • 支持广播地址
  • 支持输入信号噪声过滤功能
  • 支持中断状态查询功能


I2C主机模式读写EEPROM存储器
在CW32F030在I2C作为主机设备操作EEPROM设备时,在官方库函数中提供了直接操作EEPROM的函数接口:
void I2C_MasterWriteEepromData(I2C_TypeDef *I2Cx,uint8_t u8Addr,uint8_t *pu8Data,uint32_t u32Len)

void I2C_MasterReadEepomData(I2C_TypeDef *I2Cx,uint8_t u8Addr,uint8_t *pu8Data,uint32_t u32Len)
我们只需要调用这两个函数接口,传递相应的参数就可以完成对EEPROM的读写操作了,而对于EEPROM器件地址的定义我们可以在cw32f030_i2c.h这个头文件中对I2C_SLAVEADDRESS这个宏定义的数值直接修改即可,实现代码如下:
void EEPROM_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    I2C_InitTypeDef  I2C2_InitStructure;

    RCC_AHBPeriphClk_Enable( RCC_AHB_PERIPH_GPIOB, ENABLE);
    RCC_APBPeriphClk_Enable1(RCC_APB1_PERIPH_I2C2, ENABLE);

    PB10_AFx_I2C2SCL();
    PB11_AFx_I2C2SDA();

    GPIO_InitStructure.Pins  = GPIO_PIN_10 | GPIO_PIN_11;
    GPIO_InitStructure.Mode  = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
    GPIO_Init(CW_GPIOB, &GPIO_InitStructure);

    I2C2_DeInit();

    I2C2_InitStructure.I2C_BaudEn = ENABLE;
    I2C2_InitStructure.I2C_Baud   = RCC_Sysctrl_GetPClkFreq() / 1000000 - 1;
    I2C2_InitStructure.I2C_FLT    = DISABLE;
    I2C2_InitStructure.I2C_AA     = DISABLE;
    I2C_Master_Init(CW_I2C2, &I2C2_InitStructure);

    I2C_Cmd(CW_I2C2, ENABLE);
}

void EEPROM_SHELL_Handler(uint8_t Mode, uint8_t Page)
{
    uint8_t wBuffer[EEPROM_PAGE_SIZE];
    uint8_t rBuffer[EEPROM_PAGE_SIZE];

    memset(wBuffer, 0, sizeof(wBuffer));
    memset(rBuffer, 0, sizeof(rBuffer));

    if(Page < EEPROM_PAGE_NUMBER)
    {
        if(Mode == 1)   /* Write */
        {
            srand(GetTick());

            for(uint8_t i = 0; i < sizeof(wBuffer); i++)
            {
                wBuffer[i] = rand() % 256;
            }

            printf("\r\nEEPROM Write...");

            for(uint8_t i = 0; i < sizeof(wBuffer); i++)
            {
                if((i % 16) == 0) printf("\r\n");
                printf("0x%02x ",    wBuffer[i]);
            }

            printf("\r\nPage    : %d", Page);
            printf("\r\nAddress : %d", Page * EEPROM_PAGE_SIZE);
            printf("\r\nLength  : %d", sizeof(wBuffer));

            I2C_MasterWriteEepromData(CW_I2C2, Page * EEPROM_PAGE_SIZE, wBuffer, sizeof(wBuffer));

            printf("\r\nEEPROM Write OK");
            printf("\r\n");
        }
        else            /* Read  */
        {
            printf("\r\nEEPROM Read....");

            printf("\r\nPage    : %d", Page);
            printf("\r\nAddress : %d", Page * EEPROM_PAGE_SIZE);
            printf("\r\nLength  : %d", sizeof(rBuffer));

            I2C_MasterReadEepomData(CW_I2C2, Page * EEPROM_PAGE_SIZE, rBuffer, sizeof(rBuffer));

            for(uint8_t i = 0; i < sizeof(rBuffer); i++)
            {
                if((i % 16) == 0) printf("\r\n");
                printf("0x%02x ",    rBuffer[i]);
            }

            printf("\r\n");
        }
    }
    else
    {
        printf("\r\nInvalid EEPROM Page!\r\n");
    }
}
SHELL_EXPORT_CMD(
SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN|SHELL_CMD_PARAM_NUM(2),
EEPROM, EEPROM_SHELL_Handler, EEPROM Write And Read);


硬件连接图


在线调试
在PC端口使用MobaXterm终端调试软件,打开对应的串口,正确设置串口通讯参数;输入EEPROM命令,这个命令带有两个参数:第一个参数0表示读取EEPROM数据,1表示将数据写入到EEPROM;第二个参数表示EEPROM PAGE编号,此编号范围为0到31。运行结果如下图:

实测通讯速率


I2C从机模式多地址通讯
CW32F030 I2C工作在从机模式时,同时支持3个从设备地址,这三个从设备地址可以通过cw32f030_i2c.h这个头文件中OwnSlaveAddress0/OwnSlaveAddress1/OwnSlaveAddress2这3个宏进行修改,我们使用查询的方式配合外部的I2C主机来进行测试,从机代码实现如下:
void sEEPROM_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    I2C_InitTypeDef  I2C1_InitStructure;

    RCC_AHBPeriphClk_Enable( RCC_AHB_PERIPH_GPIOB, ENABLE);
    RCC_APBPeriphClk_Enable1(RCC_APB1_PERIPH_I2C1, ENABLE);

    PB06_AFx_I2C1SCL();
    PB07_AFx_I2C1SDA();

    GPIO_InitStructure.Pins  = GPIO_PIN_6 | GPIO_PIN_7;
    GPIO_InitStructure.Mode  = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
    GPIO_Init(CW_GPIOB, &GPIO_InitStructure);

    I2C1_DeInit();

    I2C1_InitStructure.I2C_OwnSlaveAddr0 = OwnSlaveAddress0;
    I2C1_InitStructure.I2C_OwnSlaveAddr1 = OwnSlaveAddress1;
    I2C1_InitStructure.I2C_OwnSlaveAddr2 = OwnSlaveAddress2;
    I2C1_InitStructure.I2C_OwnGc         = DISABLE;
    I2C1_InitStructure.I2C_FLT           = DISABLE;
    I2C1_InitStructure.I2C_AA            = DISABLE;
    I2C_Slave_Init(CW_I2C1, &I2C1_InitStructure);

    I2C_Cmd(CW_I2C1, ENABLE);

    I2C_AcknowledgeConfig(CW_I2C1, ENABLE);
}

void sEEPROM_SHELL_Handler(uint8_t Times)
{
    uint8_t  Buffer[100];
    uint32_t rLength = 0, wLength;

    while(Times--)
    {
        printf("\r\nWait I2C Master Write Data...\r\n");

        /* 等待主机写入数据 */
        I2C_SlaveRecDataFromMaster(CW_I2C1, Buffer, &rLength);

        printf("\r\nI2C Receive :");

        for(uint8_t i = 0; i < rLength; i++)
        {
            if((i % 16) == 0) printf("\r\n");
            printf("0x%02x ", Buffer[i]);
        }

        printf("\r\n");
        printf("\r\nWait I2C Master Read Data...\r\n");

        /* 等待主机读取数据 */
        I2C_SlaveSendDataToMaster(CW_I2C1, Buffer, &wLength);

        printf("\r\nI2C Master Read %d Bytes!\r\n", wLength);
    }
}
SHELL_EXPORT_CMD(
SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN|SHELL_CMD_PARAM_NUM(1),
SEEPROM, sEEPROM_SHELL_Handler, sEEPROM Write And Read);


硬件连接

在线调试
首先在MobaXterm终端软件上输入sEEPROM的SHELL命令,我们可以理解为I2C从机当作是模拟EEPROM设备;后面跟着一个参数,意思是读写操作需要循环几次完成;因为I2C从机设备支持3个地址,我们为了把地址都测试一遍,我们这边输入的SHELL命令为sEEPROM 3,在输入完命令后,MCU就进入到等待I2C主机操作的状态了。

我们打开Toomoss的上位机软件,选择USB2I2C功能,如下界面所示;因为我们是直接将调试工具与MCU引脚连接在一起的,所以建议将内部上拉使能,这样可以保证高通讯速率下的波形正常、稳定;然后在从机地址栏依次输入0x50、0x58、0x60,点击下方的写数据和读数据来测试通讯结果,如下图所示:


附件
程序源代码:
Template.zip (5.09 MB) (仅I2C主机模式)
Template.zip (5.09 MB) (I2C主从机模式)
CW24C02A: CW24C02A.pdf (1.06 MB)

使用特权

评论回复
沙发
海滨消消| | 2022-7-13 15:57 | 只看该作者
最近论坛里测评贴很多了

使用特权

评论回复
板凳
huquanz711| | 2022-7-13 18:19 | 只看该作者
letter shell看起来不错啊

使用特权

评论回复
地板
NOo02| | 2022-7-13 19:10 | 只看该作者
楼主这个读IIC的上位机软件怎么下载啊,给个链接

使用特权

评论回复
5
xld0932|  楼主 | 2022-7-13 20:44 | 只看该作者
NOo02 发表于 2022-7-13 19:10
楼主这个读IIC的上位机软件怎么下载啊,给个链接

图莫斯官方上有下载,需要有配套的工具的

使用特权

评论回复
6
www5911839| | 2022-7-13 23:56 | 只看该作者
感谢大佬分享,授人以渔,非常感谢

使用特权

评论回复
7
minzisc| | 2022-10-10 20:56 | 只看该作者
两个不同的芯片之间用IIC通信,如何实现?

使用特权

评论回复
8
claretttt| | 2022-10-10 21:06 | 只看该作者
I2C的主从模式怎么切换              

使用特权

评论回复
9
yeates333| | 2022-10-10 21:23 | 只看该作者
软件模拟IIC主从机可以产生中断吗

使用特权

评论回复
10
loutin| | 2022-10-10 21:49 | 只看该作者
iic总线实现双机通信               

使用特权

评论回复
11
jackcat| | 2022-10-11 21:41 | 只看该作者

I2C设备主机与从机地址设置   

使用特权

评论回复
12
mattlincoln| | 2022-11-1 10:03 | 只看该作者
如何使用dma mode进行i2c传输

使用特权

评论回复
13
robincotton| | 2022-11-1 10:23 | 只看该作者
i2c协议的问题,请问主机如果读从机的数据,怎么知道从机是否响应  

使用特权

评论回复
14
eefas| | 2022-11-1 11:00 | 只看该作者
I2C的从模式与主模式的区别是什么?

使用特权

评论回复
15
uiint| | 2022-11-1 11:35 | 只看该作者
I2C总线的应答信号是从器件发出的么?

使用特权

评论回复
16
primojones| | 2022-11-1 15:12 | 只看该作者
对于没有IIC接口的CPU,如何连接IIC设备?

使用特权

评论回复
17
eefas| | 2022-11-1 15:59 | 只看该作者
一个MCU有两组I2C,那这个MCU可以做主机的同时也可以做从机吗

使用特权

评论回复
18
claretttt| | 2022-11-1 16:49 | 只看该作者
I2c总线一般拿来实现什么功能?

使用特权

评论回复
19
maudlu| | 2022-11-1 17:56 | 只看该作者
如何检测i2c的开始条件和结束条件

使用特权

评论回复
20
robertesth| | 2022-11-1 18:47 | 只看该作者
i2c总线中从机地址怎么设置  

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:上海灵动微电子股份有限公司资深现场应用工程师
简介:诚信·承诺·创新·合作

70

主题

3001

帖子

31

粉丝