HC32F460开发之硬件IIC驱动AT24C64

文章目录

  • 前言
  • 一、AT24C64
  • 二、驱动步骤
    • 1.宏定义
    • 2.代码实现
  • 总结


前言

在嵌入式设计中,E2PROM存储芯片常被应用于需要掉电存储,且容量不大的场合。对比flash存储芯片,E2PROM具有擦写次数多,允许字节编程的特点,因此,更适合于数据量存储不大,且更需要频率擦写的应用场景。今天,就以HC32F460为平台,简单介绍下如何驱动E2PROM存储芯片AT24C6。
HC32F460开发之硬件IIC驱动AT24C64_第1张图片


一、AT24C64

从芯片手册我们可以找到关于芯片的引脚图和引脚说明如下
HC32F460开发之硬件IIC驱动AT24C64_第2张图片
HC32F460开发之硬件IIC驱动AT24C64_第3张图片
其中,A0A1A2这三个脚为设备地址输入脚,当有多个E2PROM设备级联时,通过此引脚的定义来实现对不同设备的寻址。SDA和SDL为标志的IIC接口,WP为写保护脚(默认接地即可)。
AT24C64典型的应用电路原理图如下:
HC32F460开发之硬件IIC驱动AT24C64_第4张图片

二、驱动步骤

1.宏定义

关于IIC接口的时序,这个是老生常谈的问题了,在此就不再赘述。这里就直接开始介绍如何通过HC32F460的硬件IIC来驱动AT24C64.

首先是在库函数配置文件ddl_config.h中打开宏定义

#define DDL_I2C_ENABLE                              (DDL_ON)

工程中添加相关的.c文件
HC32F460开发之硬件IIC驱动AT24C64_第5张图片
接着是引脚定义,这里我们选择PC10和PC11脚,并将之复用为IIC接口

/* Define I2C unit used for the example */
#define I2C_UNIT                        (M4_I2C1)

/* Define port and pin for SDA and SCL */
#define I2C_SCL_PORT                    (PortC)
#define I2C_SCL_PIN                     (Pin10)
#define I2C_SDA_PORT                    (PortC)
#define I2C_SDA_PIN                     (Pin11)
#define I2C_GPIO_SCL_FUNC               (Func_I2c1_Scl)
#define I2C_GPIO_SDA_FUNC               (Func_I2c1_Sda)

#define I2C_FCG_USE                     (PWC_FCG1_PERIPH_I2C1)

AT24C64相关的宏定义

/* Define E2PROM device address */
#define E2_ADDRESS                      (0x50u)
/* 24c256 page length */
#define E2_PAGE_LEN                     (32u)
#define E2_MEM_ADR_LEN                  (2u)
/* Define test address for read and write */
#define DATA_TEST_ADDR                  (0x0000u)

这些定义都可以在数据手册中找到相关的说明,但是有一点需要注意的是,这里我们将E2PROM的设备地址定义为0x50,但是实际上在手册中,我们查到的设备地址是0xA0
HC32F460开发之硬件IIC驱动AT24C64_第6张图片
这是因为我们MCU这边设置默认的是7bit的从机地址,这里还有一位是不包括最低位的读写操作位,因此,去掉最低位的读写位,可以得到实际的设备地址是0x50 。

2.代码实现

初始化代码如下:

/**
 ******************************************************************************
 ** \brief  Initialize the I2C peripheral for at24cxx
 ** \param  None
 ** \retval en_result_t           Enumeration value:
 **         - Ok:                 Success
 **         - ErrorTimeout:       Time out
 ******************************************************************************/
en_result_t At24cxx_Initialize(void)
{
    stc_i2c_init_t stcI2cInit;
    en_result_t enRet;
    float32_t fErr;

    /* Initialize I2C port*/
    PORT_SetFunc(I2C_SCL_PORT, I2C_SCL_PIN, I2C_GPIO_SCL_FUNC, Disable);
    PORT_SetFunc(I2C_SDA_PORT, I2C_SDA_PIN, I2C_GPIO_SDA_FUNC, Disable);

    /* Enable I2C Peripheral*/
    PWC_Fcg1PeriphClockCmd(I2C_FCG_USE, Enable);

    I2C_DeInit(I2C_UNIT);

    MEM_ZERO_STRUCT(stcI2cInit);
    stcI2cInit.u32ClockDiv = I2C_CLK_DIV8;
    stcI2cInit.u32Baudrate = 100000ul;
    stcI2cInit.u32SclTime = 0ul;
    enRet = I2C_Init(I2C_UNIT, &stcI2cInit, &fErr);

    I2C_BusWaitCmd(I2C_UNIT, Enable);

    return enRet;
}

AT24C64写:

/**
 ******************************************************************************
 ** \brief  at24cxx memory write
 **
 ** \param  u8DevAddr             The slave address
 ** \param  u16MemAddr            The memory address
 ** \param  pu8Data               Pointer to the data buffer
 ** \param  u32Size               Data size
 ** \param  u32TimeOut            Time out count
 ** \retval en_result_t           Enumeration value:
 **         - Ok:                 Success
 **         - Error:              Receive NACK
 **         - ErrorTimeout:       Time out
 ******************************************************************************/
en_result_t At24cxx_Mem_Write(uint16_t u8DevAddr, uint16_t u16MemAddr, uint8_t *pu8Data, uint32_t u32Size, uint32_t u32TimeOut)
{
    en_result_t enRet;
    uint16_t u16MemAddrTemp;
    u16MemAddrTemp = ((u16MemAddr >> 8) & 0xFFul) + ((u16MemAddr << 8) & 0xFF00ul);

    I2C_Cmd(I2C_UNIT, Enable);

    I2C_SoftwareResetCmd(I2C_UNIT, Enable);
    I2C_SoftwareResetCmd(I2C_UNIT, Disable);
    enRet = I2C_Start(I2C_UNIT,u32TimeOut);
    if(Ok == enRet)
    {
        enRet = I2C_TransAddr(I2C_UNIT, u8DevAddr, I2CDirTrans, u32TimeOut);

        if(Ok == enRet)
        {
            enRet = I2C_TransData(I2C_UNIT, (uint8_t *)&u16MemAddrTemp, E2_MEM_ADR_LEN, u32TimeOut);
            if(Ok == enRet)
            {
                enRet = I2C_TransData(I2C_UNIT, pu8Data, u32Size, u32TimeOut);
            }
        }
    }

    I2C_Stop(I2C_UNIT,u32TimeOut);
    I2C_Cmd(I2C_UNIT, Disable);

    return enRet;
}

AT24C64读:

/**
 ******************************************************************************
 ** \brief  at24cxx memory read
 **
 ** \param  u8DevAddr             The slave address
 ** \param  u16MemAddr            The memory address
 ** \param  pu8Data               Pointer to the data buffer
 ** \param  u32Size               Data size
 ** \param  u32TimeOut            Time out count
 ** \retval en_result_t           Enumeration value:
 **         - Ok:                 Success
 **         - ErrorTimeout:       Time out
 ******************************************************************************/
en_result_t At24cxx_Mem_Read(uint8_t u8DevAddr, uint16_t u16MemAddr, uint8_t *pu8Data, uint32_t u32Size, uint32_t u32TimeOut)
{
    en_result_t enRet;
    uint16_t u16MemAddrTemp;
    u16MemAddrTemp = ((u16MemAddr >> 8) & 0xFFul) + ((u16MemAddr << 8) & 0xFF00ul);

    I2C_Cmd(I2C_UNIT, Enable);

    I2C_SoftwareResetCmd(I2C_UNIT, Enable);
    I2C_SoftwareResetCmd(I2C_UNIT, Disable);
    enRet = I2C_Start(I2C_UNIT,u32TimeOut);
    if(Ok == enRet)
    {
        enRet = I2C_TransAddr(I2C_UNIT, (uint8_t)u8DevAddr, I2CDirTrans, u32TimeOut);

        if(Ok == enRet)
        {
            enRet = I2C_TransData(I2C_UNIT, (uint8_t *)&u16MemAddrTemp, E2_MEM_ADR_LEN, u32TimeOut);
            if(Ok == enRet)
            {
                enRet = I2C_Restart(I2C_UNIT,u32TimeOut);
                if(Ok == enRet)
                {
                    if(1ul == u32Size)
                    {
                        I2C_AckConfig(I2C_UNIT, I2c_NACK);
                    }

                    enRet = I2C_TransAddr(I2C_UNIT, (uint8_t)u8DevAddr, I2CDirReceive, u32TimeOut);
                    if(Ok == enRet)
                    {
                        enRet = I2C_MasterDataReceiveAndStop(I2C_UNIT, pu8Data, u32Size, u32TimeOut);
                    }

                    I2C_AckConfig(I2C_UNIT, I2c_ACK);
                }

            }
        }
    }

    if(Ok != enRet)
    {
        I2C_Stop(I2C_UNIT,u32TimeOut);
    }

    I2C_Cmd(I2C_UNIT, Disable);
    return enRet;
}

测试代码:

void At24cxx_Test(void)
{
    uint8_t u8TxBuf[E2_PAGE_LEN];
    uint8_t u8RxBuf[E2_PAGE_LEN];
    uint32_t i;

    for(i=0ul; i<E2_PAGE_LEN; i++)
    {
        u8TxBuf[i] = (uint8_t)i+1u;
    }
    memset(u8RxBuf, 0x00, E2_PAGE_LEN);

    /* Initialize I2C peripheral and enable function*/
    At24cxx_Initialize();

    /* E2prom byte write*/
    At24cxx_Mem_Write(E2_ADDRESS, DATA_TEST_ADDR, u8TxBuf, 1u, TIMEOUT);

    /* 5mS delay for e2prom*/
    Ddl_Delay1ms(5ul);

    /* E2prom ramdom read*/
    At24cxx_Mem_Read(E2_ADDRESS, DATA_TEST_ADDR, u8RxBuf, 1u, TIMEOUT);

    /* Compare the data */
    if(0x01u != u8RxBuf[0])
    {
        /* e2prom byte write error */
        PRO_LOG(LOG_DEBUG, "at24cxx byte write error! \r\n");
    }

    /* 5mS delay for e2prom*/
    Ddl_Delay1ms(5ul);
    /* E2prom page write*/
    At24cxx_Mem_Write(E2_ADDRESS, DATA_TEST_ADDR, u8TxBuf, E2_PAGE_LEN, TIMEOUT);

    /* 5mS delay for e2prom*/
    Ddl_Delay1ms(5ul);

    /* E2prom sequential read*/
    At24cxx_Mem_Read(E2_ADDRESS, DATA_TEST_ADDR, u8RxBuf, E2_PAGE_LEN, TIMEOUT);

    /* Compare the data */
    for(i=0ul; i<E2_PAGE_LEN; i++)
    {
        if(u8TxBuf[i] != u8RxBuf[i])
        {
            /* e2prom page write error*/
            PRO_LOG(LOG_DEBUG, "at24cxx page write error! \r\n");
        }
    }

}

总结

烧录编译,使用逻辑分析仪查看波形,波形图如下:
HC32F460开发之硬件IIC驱动AT24C64_第7张图片
关于E2PROM的驱动部分就暂时介绍到这里了,若是上述有误,欢迎大家在评论区指出。

你可能感兴趣的:(华大半导体,嵌入式,单片机,os)