OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 20747|回复: 13

AT24CXX EEPROM页写入疑问

[复制链接]

51

主题

214

帖子

0

精华

高级会员

Rank: 4

积分
561
金钱
561
注册时间
2011-4-11
在线时间
43 小时
发表于 2012-12-6 15:43:29 | 显示全部楼层 |阅读模式
     今天下午看了好久的EEPROM技术手册,对页写入有点疑问。技术手册上说:

 “接收到每个数据后,字地址的低3位(24C02)或4位(24C04/08/16)或5位(24C32/64)
内部自动加1,高位地址位不变,维持在当前页内。当内部产生的字地址达到该页边界地址时,
随后的数据将写入该页的页首。如果超过8个(24C02)或16个(24C04/08/16)或32个
(24C32/64)数据传送给了EEPROM,字地址将回转到该页的首字节,先前的字节将会被覆盖。


        上面技术手册上说,在页写入的时候就是低几位地址会递增,高位地址是保存不变的。我的疑问就是是不是每一页的地址是固定的呀??
如AT24C02,容量为2Kbit的,32页,每页8字节,子地址长度是8位。是不是0x00--0x07为第一页的地址范围 0x08--0x0f为第二页范围???.......
这些范围是固定的吗??  意思就是第二页的开始地址只能是从0X80开始,不能是别的。
        由于每页最大字节数是8个,所以页写入的时候超过8字节,它就会从该页的开始地址开始。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

51

主题

214

帖子

0

精华

高级会员

Rank: 4

积分
561
金钱
561
注册时间
2011-4-11
在线时间
43 小时
 楼主| 发表于 2012-12-6 16:01:37 | 显示全部楼层
还有一个,就是顺序读的问题,在当前页里面读技术手册上说“当读到某页尾的最后一个字节,地址会回转到该页的首地址”。如果执行顺序读,那么读很多数据(超过一页的字节范围)就会在一页内总重复读吗??不会跳转到下一页吗??
回复 支持 反对

使用道具 举报

105

主题

522

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1386
金钱
1386
注册时间
2012-10-23
在线时间
97 小时
发表于 2012-12-6 21:47:46 | 显示全部楼层
回复【楼主位】Julius007:
---------------------------------
资料太杂了,我也搞球不懂了。24c02就一页,256字节,每字节8位,想怎么写就怎么写。什么分32页什么的我完全看不懂。
回复 支持 反对

使用道具 举报

21

主题

35

帖子

0

精华

初级会员

Rank: 2

积分
152
金钱
152
注册时间
2012-8-28
在线时间
2 小时
发表于 2012-12-6 21:58:18 | 显示全部楼层
给你个函数,我有很详细的注释,希望对你有帮助,我当初也研究了阵子,才把所有的24Cxx搞明白,
24C32读写又有些不同,看看SPEC.吧、
void i2c_WriteTBL(BYTE u8DeviceID, WORD u8Addr, BYTE *pu8Buffer, BYTE u8Count)
{
    BYTE u8SlaveAddr;
    BYTE u8WordAddr;
    BYTE u8Offset=0;
    BYTE u8TempSize;
    //Bool succ=TRUE;
    BYTE u8ErrCount=0;

    while (u8Count)//當有連續PAGE要訪問時需要的循環條件。
    {
        u8SlaveAddr=I2C_SLAVE_ADDR(u8DeviceID, u8Addr+u8Offset);
        u8WordAddr=I2C_WORD_ADDR(u8Addr+u8Offset);//u8Addr是小於 等於11位的地址。
        if (i2c_MasterStart(I2C_WRITE, u8SlaveAddr)==FALSE)
        {
          if(u8ErrCount <I2C_ERR_TOLERANCE)
          {
            u8ErrCount++;
            ForceDelay1ms(1);
            continue;
          }
          break;
        }
        if (i2c_BurstWrite(1, &u8WordAddr)==FALSE)
            break;
        //u8TempSize:當前PAGE的剩餘length。
        u8TempSize=0x10-(u8WordAddr&0xF);//0x10即16,是24C16 page write的字节数
        //(u8WordAddr&0xF)的意思是u8WordAddr 除以16餘多少。再用
        //PAGE LENGTH(0x10)相減得到當前PAGE的剩餘的length。
        if (u8Count>u8TempSize)//如果要連續讀寫的u8Count大於當前Page的剩餘length
        {//那麼就先讀寫當前PAGE的剩餘length。然後根據while (u8Count)循環用u8Count減去前面PAGE已經
         //讀寫完的length得到還沒有讀寫的length。
            if (i2c_BurstWrite(u8TempSize, (BYTE*)(pu8Buffer+u8Offset))==FALSE)
                break;
            i2c_Stop();
            u8Count-=u8TempSize;//根據while (u8Count)循環用u8Count減去前面PAGE已經
         //讀寫完的length得到還沒有讀寫的length。
            u8Offset+=u8TempSize;//下一次循環時要保存的pu8Buffer的地址偏移量。
        }
        else if (u8Count>0x10)
        {//如果要讀寫的length大於PAGE Length,那麼先訪問一個PAGE的全部length。
            if (i2c_BurstWrite(0x10, (BYTE*)(pu8Buffer+u8Offset))==FALSE)
                break;
            i2c_Stop();
            u8Count-=0x10;//然後再讀寫剩餘的長度,while (u8Count)之。。
            u8Offset+=0x10;//消息郵箱while (u8Count)后的地址偏移量.
        }
        else
        {//要讀寫的u8Count即不大於PAGE LENGTH,也不需要翻頁。
            if (i2c_BurstWrite(u8Count, (BYTE*)(pu8Buffer+u8Offset))==FALSE)
                break;
            i2c_Stop();
            u8Count=0;//這個很重要,因為當前PAGE剩餘的長度讀寫完後,如果剩餘還要讀寫的
            //長度小於PAGE_LENGTH,那麼在這裡就能讀寫完,所以要將u8Count等於零,
            //來跳出while(u8Count)循環。
        }
        u8ErrCount = 0;
      #if (SICODE_IS_B)
        ForceDelay1ms(6);
      #elif 1
        ForceDelay1ms(15);
      #else
        ForceDelay1ms(10);
      #endif
    }
    i2c_Stop();
  #if (SICODE_IS_B)
        ForceDelay1ms(6);
  #elif 1//(SICODE_IS_B)
    ForceDelay1ms(15); 
  #else
    ForceDelay1ms(10);
  #endif
}
回复 支持 反对

使用道具 举报

51

主题

214

帖子

0

精华

高级会员

Rank: 4

积分
561
金钱
561
注册时间
2011-4-11
在线时间
43 小时
 楼主| 发表于 2012-12-7 09:05:07 | 显示全部楼层
回复【4楼】lhchen922:
---------------------------------
呵呵.....谢谢你的回复,有些看的不是很懂。
我想问的是:“是不是每页的地址是固定的呀?对于特定的容量EEPROM。”
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2012-12-7 10:21:04 | 显示全部楼层
当然是固定的了,别说每页了,每个地址都是固定的,哪有地址变化的?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

51

主题

214

帖子

0

精华

高级会员

Rank: 4

积分
561
金钱
561
注册时间
2011-4-11
在线时间
43 小时
 楼主| 发表于 2012-12-10 08:52:06 | 显示全部楼层
回复【6楼】正点原子:
---------------------------------
呵呵.....不好意思,我的意思可能没有表达清楚。
我说每页地址是固定的意思是。如AT24C02,容量为2Kbit的,32页,每页8字节,子地址长度是8位。是不是0x00--0x07为第一页的地址范围,0x08--0x0f为第二页范围??? 
因为看技术手册说,跨页写和读好像要做一定的处理。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2012-12-10 09:43:39 | 显示全部楼层
是的。
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
21
金钱
21
注册时间
2013-8-5
在线时间
0 小时
发表于 2013-8-5 11:28:08 | 显示全部楼层
回复【4楼】lhchen922: 
有点不解
-----------------------------


u8TempSize=0x10-(u8WordAddr&0xF); 

说明u8WordAddr&0xF==0时, u8TempSize 最大 =0x10.


        if (u8Count>u8TempSize) 
        { 
           
            if (i2c_BurstWrite(u8TempSize, (BYTE*)(pu8Buffer+u8Offset))==FALSE) 
                break; 
            i2c_Stop(); 
            u8Count-=u8TempSize;//根據while (u8Count)循環用u8Count減去前面PAGE已經 
          
            u8Offset+=u8TempSize;//下一次循環時要保存的pu8Buffer的地址偏移量。 
        } 
        else if (u8Count>0x10) 


那么只有(u8Count<=u8TempSize) 时,才能扏行else if (u8Count>0x10) .

而u8TempSize 最大 =0x10.    怎样扏行    if (u8Count>0x10) .

不知我理解是否错了,请指点
回复 支持 反对

使用道具 举报

10

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
87
金钱
87
注册时间
2013-3-28
在线时间
0 小时
发表于 2013-8-5 22:44:25 | 显示全部楼层
这个例子我也看的云里雾里,但是这里判断条件if (u8Count>u8TempSize)和else if (u8Count>0x10) 有点重叠,应该是
if (0x10>u8Count>u8TempSize)才对,是这样吧
回复 支持 反对

使用道具 举报

0

主题

4

帖子

0

精华

新手入门

积分
24
金钱
24
注册时间
2014-8-14
在线时间
0 小时
发表于 2014-8-14 10:30:18 | 显示全部楼层
AT24C02是不用区分页写入的,一次可以写入256字节=2Kbit,刚好写满,所以不用去区分页写入,但是AT24C04/8/16……就有点麻烦了

3楼的代码我也有点没有看懂
回复 支持 反对

使用道具 举报

28

主题

218

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
498
金钱
498
注册时间
2013-11-19
在线时间
92 小时
发表于 2015-7-23 10:34:13 | 显示全部楼层
这个跟24C02的生产厂商有关系,进口原装芯片不会出现问题。
我公司的24C02不知道是哪个国产的,现象很诡异,连续读8个字节大部分地址是正常的,但是有小部分如09、19、29地址连续读8个字节时,最后一个字节就出错
回复 支持 反对

使用道具 举报

23

主题

40

帖子

0

精华

初级会员

Rank: 2

积分
159
金钱
159
注册时间
2015-6-4
在线时间
10 小时
发表于 2015-9-17 08:50:19 | 显示全部楼层
回复【11楼】超酷小子:
---------------------------------
@正点原子  可以一次性写入256个字节??
回复 支持 反对

使用道具 举报

0

主题

7

帖子

0

精华

初级会员

Rank: 2

积分
68
金钱
68
注册时间
2012-4-10
在线时间
7 小时
发表于 2017-11-16 17:58:49 | 显示全部楼层
本帖最后由 nos001 于 2017-11-16 18:14 编辑

[mw_shl_code=c,false]
/************************************************************************************************************
* @brief     eeprom多字节连续写入函数
*                      采用页写方式,自行换页,一个程序循环周期写一页数据,减小对系统实时性的影响,同时减少写入过程被中断打断的情形。
* @note      自行换页,就是写入到达页边界后重新发送“器件地址”和“写入地址”。               
* @Param   \sla:        eeprom器件从地址,高7位是地址,bit0是读写控制位,0表示写,1表示读。
*                      \suba:       eeprom器件子地址,即eeprom的数据写入地址,读写操作时自动增加。
*                      \*pBuffer:   待写数据缓存的指针
*                     \Len:        字节数据长度
*                      \EepromType: enum{ _24C01, _24C02, _24C04, _24C08, _24C16, _24C32, _24C64,_24C128, _24C256 }
* @retval   1: 写入成功;0:写入失败。   
***********************************************************************************************************/
BOOL EE_WriteBytes( UINT8 sla, UINT16 suba, UINT8 *pBuf, UINT16 len, EE_TYPE EepromType )
{
    static UINT16 WriteAddr;
    static UINT16 WriteLen;
    static UINT16 Length;
    static UINT8  rw_state = EE_IDLE;   

    if( rw_state == EE_IDLE )
    {
        rw_state = EE_BUSY;
        WriteAddr = suba;
        WriteLen = 0;
        Length = len;
        I2C_Stop( );  
    }   
    if( rw_state == EE_BUSY )
    {
        I2C_Start( );                                 // 启动总线
        I2C_SendByte( sla );                          // 发送器件地址
        if( I2C_WaitAck() )
        {
            I2C_Stop( );                              // 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备
            return( 0 );
        }
        /* 发送待存储数据的eeprom存储地址,\M24C02只有256字节,发送1个字节地址,如果是\M24C04以上,那么此处需要连发多个地址 */
        if( EepromType > _24C02 )            
        {
            I2C_SendByte( WriteAddr >> 8 );           // 2字节数据写入地址高8位
            if( I2C_WaitAck() )
            {
                I2C_Stop( );               
                return( 0 );
            }               
        }
        I2C_SendByte( ( UINT8 )WriteAddr );           // 2字节数据写入地址低8位,或者1字节数据写入地址
        if( I2C_WaitAck() )
        {
            I2C_Stop( );                    
            return( 0 );
        }  
        pBuf += WriteLen;                            // 待写数据缓存首指针加已写入数据长度,等于换页操作后待写数据缓存指针当前值
        while( Length > 0 )                  
        {                                                   
            I2C_SendByte( *pBuf );                   // 发送数据
            if( I2C_WaitAck() )
            {
                I2C_Stop( );
                return( 0 );
            }
            pBuf++;                                  // 待发送数据缓存指针增加
            WriteAddr++;                             // eeprom存储地址增加
            WriteLen++;                              // 已写入字节数
            Length--;
            if( ( WriteAddr & ( EE_PAGE_SIZE - 1 ) ) == 0 )
            {   
                /* 到达页边界时,跳出循环,结束本次页写操作。
                    * 换页操作,就是重新发送器件地址SLA、数据写入地址,
                    * 退出函数后再次进入就达到了换页操作的目的。
                    */
                I2C_Stop( );                         // 每次页写后结束总线
                break;                          
            }
        }
        if( Length == 0 )
        {                  
            I2C_Stop( );
            rw_state = EE_IDLE;
            return( 1 );
        }
    }
    return( 0 );
}[/mw_shl_code]

是不是简洁明了,数据长度取决于数据缓存的大小,一个系统滴答周期只写一页,一页64字节的话写入时间大概2ms左右。
10ms系统滴答周期的话,写eeprom根本不影响实时性。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-8 10:13

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表