开篇一张时序图镇楼:
这篇文章介绍了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.