AT24C16 读写注意点

开篇一张时序图镇楼:

这篇文章介绍了AT24C16的页写、连续读、写保护功能:AT24C16 读写_D.luffy的博客-CSDN博客_at24c16

页写算法我是参考这篇文章的:https://acuity.blog.csdn.net/article/details/78550427?utm_

char ee_24clxx_writebytes(u16 write_addr, char* pwrite_buff, u16 writebytes)  

{  

    u8   write_len,page_offset;  

    char error = 0;  

      

    while(writebytes > 0)  

    {  

        page_offset = EE24CLXX_PAGESIZE - (write_addr % EE24CLXX_PAGESIZE); /*EE24CLXX_PAGESIZE为页大小,如24c16为16*/  

        write_len   = writebytes > page_offset ? page_offset : writebytes;  

        i2c_24clxx_write(write_addr,pwrite_buff, write_len);           /*写一页函数*/  

        writebytes   = writebytes - write_len;  

        if(writebytes > 0)  

        {  

            pwrite_buff = pwrite_buff + write_len;  

            write_addr  = write_addr + write_len;  

            i2c_24clxx_waitstandby(0);                  /*页写判忙,FRAM则不用*/  

        }  

    }  

    return error;  

}  

AT24C16 內部有 2048*8 位的存储容量,即可以存储 2K 字节的数据。这 2K 字节被放在 128 个页内,每页存放 16 个字节。所以对 AT24C16 內部的访问需要 11 位地址(0~0x7ff)

总的来说虽然最后也实现了,但eeprom里有的坑似乎也全被我踩遍了。从只能写一页大小,到可以页写,再到可以实现随机写,还是蛮曲折并且浪费了我不少时间的。废话不多讲,下面介绍下我最终的成果:

eeprom页写接口:

每次写入,都要偏移 eeprom 內部的字地址和发送字串的地址。

/*********************************************************************************************************
** 函数名称: at24cxxWrite
** 功能描述: 驱动 write 函数
** 输 入  : pdevHdr    设备
**           pvBuf      写缓冲
**           stLen      写数据长度
** 输 出  : 成功读取数据字节数量
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static ssize_t  at24cxxWrite (PLW_DEV_HDR  pdevHdr, PVOID  pvBuf, size_t  stLen)
{
    INT             iError;
    AT24CXX_DEV    *pat24cxx   = (AT24CXX_DEV  *)pdevHdr;
    UINT8           ucOffset[1];
    UINT8           ucPageOffset;
    UINT8           ucWriteLen;
    INT             iTemp      = 0;
    
    ucOffset[0] = pat24cxx->AT24CXX_iOffset;                            /*  获得偏移量                  */

    if (stLen > __AT24XX_BYTES_SIZE) {
        I2C_DBG("stLen(%d) too long!\n",stLen);
        return (PX_ERROR);
    }

    while(stLen > 0) {
        ucPageOffset = __PAGE_OFFSET;                                   /*  计算页偏移                  */
        ucWriteLen   = stLen > ucPageOffset ? ucPageOffset : stLen;     /*  写的偏移                    */

        LW_I2C_MESSAGE  i2cMsgs[2] = {
            {
                .I2CMSG_usAddr    = __AT24XX_IIC_ADDR,
                .I2CMSG_usFlag    = 0,
                .I2CMSG_usLen     = 1,
                .I2CMSG_pucBuffer = ucOffset,                           /*  eeprom 内(字地址)寻址               */
            },
            {
                .I2CMSG_usAddr    = __AT24XX_IIC_ADDR,
                .I2CMSG_usFlag    = LW_I2C_M_NOSTART,
                .I2CMSG_usLen     = ucWriteLen,
                .I2CMSG_pucBuffer = pvBuf,                              /*  发送的字串寻址              */
            }
        };

        iError = API_I2cDeviceTransfer(pat24cxx->AT24CXX_pI2cDev, i2cMsgs, 2);
        if (iError < 0) {
            I2C_DBG("%s: __i2cByteDataWrite[0x%x 0x%x] error!\n\r", __func__, ucOffset, stLen);
            return  (PX_ERROR);
        }

        stLen -= ucWriteLen;                                            /*  更新剩余长度                */
        iTemp += 1;

        if (stLen > 0) {
            pvBuf                     += ucWriteLen;                    /*  写的字串地址要偏移          */
            pat24cxx->AT24CXX_iOffset += ucWriteLen;                    /*  写的eeprom 地址也要偏移     */
            ucOffset[0]                = pat24cxx->AT24CXX_iOffset;
        }

        if (iTemp > 124) {
            I2C_DBG("current stLen             == %ld\n", stLen);
            I2C_DBG("current position          == %08xx\n", pat24cxx->AT24CXX_iOffset);
            I2C_DBG("current msgAddrusleep     == %08xx\n", pvBuf);
            I2C_DBG("current __AT24XX_IIC_ADDR == %08xx--------------\n", __AT24XX_IIC_ADDR);
        }

        usleep(10 * 1000);                                              /*  eeprom内部写循环最大持续时间*/
    }

    return  (iTemp * __AT24XX_BYTES_PER_PAGE + stLen);
}

eeprom页读接口(之所以做成页读是因为本人在测试发大于1024个字节时,IIC驱动中的pend接口会报错传输超时,导致读取失败。不知道大家有没有遇到过这个问题。):

/*********************************************************************************************************
** 函数名称: at24cxxRead
** 功能描述: 驱动 read 函数
** 输 入  : pdevHdr   设备
**           pvBuf     读缓冲
**           stLen     读数据长度
** 输 出  : 成功数码管值的个数
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static ssize_t  at24cxxRead (PLW_DEV_HDR  pdevHdr, PVOID  pvBuf, size_t  stLen)
{
    INT             iError;
    AT24CXX_DEV    *pat24cxx   = (AT24CXX_DEV  *)pdevHdr;
    UINT8           ucOffset[1];
    UINT8           ucPageOffset;
    UINT8           ucWriteLen;
    INT             iTemp      = 0;
    
    ucOffset[0] = pat24cxx->AT24CXX_iOffset;                            /*  获得偏移量                  */

    if (stLen > __AT24XX_BYTES_SIZE) {
        I2C_DBG("stLen(%d) too long!\n",stLen);

        return (PX_ERROR);
    }

    while (stLen > 0) {
        ucPageOffset = __PAGE_OFFSET;                                   /*  计算页偏移                  */
        ucWriteLen   = stLen > ucPageOffset ? ucPageOffset : stLen;     /*  写的偏移                    */

        LW_I2C_MESSAGE  i2cMsgs[2] = {
            {
                .I2CMSG_usAddr    = __AT24XX_IIC_ADDR,
                .I2CMSG_usFlag    = 0,
                .I2CMSG_usLen     = 1,
                .I2CMSG_pucBuffer = ucOffset,                           /*  eeprom 内寻址               */
            },
            {
                .I2CMSG_usAddr    = __AT24XX_IIC_ADDR,
                .I2CMSG_usFlag    = LW_I2C_M_RD,                        /*  为读操作                    */
                .I2CMSG_usLen     = ucWriteLen,
                .I2CMSG_pucBuffer = pvBuf,                              /*  发送的字串寻址              */
            }
        };

        iError = API_I2cDeviceTransfer(pat24cxx->AT24CXX_pI2cDev, i2cMsgs, 2);
        if (iError < 0) {
            I2C_DBG("%s: __i2cByteDataRead[0x%x] error!\n\r", __func__, ucOffset);
            return  (PX_ERROR);
        }

        stLen -= ucWriteLen;                                            /*  更新剩余长度                */
        iTemp += 1;

        if (stLen > 0) {
            pvBuf                     += ucWriteLen;                    /*  读的字串地址要偏移          */
            pat24cxx->AT24CXX_iOffset += ucWriteLen;                    /*  读的eeprom 地址也要偏移     */
            ucOffset[0] = pat24cxx->AT24CXX_iOffset;
        }

        usleep(10 * 1000);                                              /*  eeprom内部写循环最大持续时间*/
    }

    return  (iTemp * __AT24XX_BYTES_PER_PAGE + stLen);
}

关于usleep 这个延时:

eeprom芯片中有一块缓存,数据是先写到这块缓存中,最终写到eeprom的存储空间还需要一点时间。从datasheet可以看到AT24C16的内部写循环最大持续时间为10ms.

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值