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