注:本文所涉及EEPROM仅为Atmel公司AT24Cxx系列部分产品(I2C接口),若使用其它公司EEPROM,请参考相应SPEC文档。
常用AT24Cxx系列EEPROM,根据容量大小,有AT24C01(1kb)、AT24C02(2kb)、AT24C04(4kb)、AT24C08(8kb)、AT24C16(16kb)、AT24C32(32kb)、AT24C64(64kb)、AT24C128(128kb)、AT24C512(512kb)、AT24C1024(1024kb)。
之所以说它们有趣,是因为虽然所有EEPROM结构相同(8pin)且接口相同(I2C),但却有一些不同的小细节,使用时如果不注意,很容易出问题。
小细节1. I2C地址
下图为AT24C01~16地址定义,高4bit为芯片固定(1010),此处不做赘述,低3bit中,AT24C01/02定义为A2/A1/A0,4K定义为A2/A1/P0,8K……
为什么会有A和P两种定义呢,其实,这是芯片容量和寄存器地址寻址空间导致的,在AT24C01-16中,寄存器地址为8bit,也即是说,其最大寻址空间2^8=256Byte=2Kb,当芯片容量超过2kb后,8bit寄存器地址已经无法覆盖所有存储空间,因此,寄存器地址就向芯片地址“借位”,每借1bit地址,寻址空间增加1倍,这就出现了4Kb芯片的设备地址中,有1bit P0(2^9=512Byte=4kb),8kb芯片的设备地址中,有2bit P1/P0(2^10=1024Byte=8kb)……
当设备地址被寄存器地址“借”走之后,此地址即被寄存器地址占用,以AT24C04为例,寄存器地址将设备地址A0“借走”,当A2=A1=0时,此时AT24C04实际占用2个设备地址1010000/1010001,这就是EEPROM的第1个小细节,更换不同容量的EEPROM时,需特别注意,否则容易出现地址冲突问题。
到此可以看出,当EEPROM容量达到16kb时,设备地址的3bit均被寄存器“借走”,那么超过16kb的EEPROM,怎么继续寻址呢,这就是下边要介绍的另一个小细节。
小细节2. 16bit寄存器地址
通过上述介绍可以看出,当EEPROM容量超过16kb时,8bit寄存器地址即使将3bit设备地址全部“借走”,也已经无法寻址所有存储空间,因此,16kb以上的EEPROM,其寄存器地址增加到16bit(2Byte),寻址空间随之扩展到2^16=65536Byte=512kb,所以,在编写EEPROM驱动代码时,需注意AT24C01~16寄存器地址为8bit,AT24C32~1024寄存器地址为16bit。
同时,AT24C32/64,设备地址定义如下:
AT24C128~512,设备地址定义如下:
AT24C1024,设备地址定义如下:
由于16bit寄存器地址寻址空间只有512kb,AT24C1024的设备地址又被寄存器地址“借”走1bit。
为什么寄存器地址向设备地址“借位”,是P(Page)而不是R(Register)呢,这就需要介绍第3个小细节。
小细节3. 页写
EEPROM的读操作,与其它I2C器件没有区别,可以从任意地址开始读取任意字节长度数据(只要不超过其最大容量边界),但是EEPROM的写操作,不是直接写到ROM中,而是先写入RAM,当本次写操作完成后,芯片再将RAM中的数据写入ROM,根据RAM的大小,我们将EEPROM的存储空间划分为不同的页。
不同容量的EEPROM,页的大小不同,以AT24C01为例,页的大小为8Byte,即1kb=128Byte=16Page,页0就是00-07,页1就是08-15,页2-页15依次类推。需要注意的是,在进行写操作时,是不能跨页写入的,即每次最大只能写入8Byte数据(页大小),而且,8Byte数据的寄存器起始地址必须为该页的首地址时才能写入8Byte,否则会出现“回卷”问题,例如:从00开始,写入8Byte数据到00-07为正常操作,若写入9Byte数据,第9个数据会回卷(覆盖)00中的数据,同理,若从01开始写入9Byte数据,第8个数据会回卷00中的数据,第9个数据会回卷01中的数据。
因此,在对EEPROM进行连续写操作时,既要考虑EEPROM页的大小,保证每次写入的字节数不超过页的容量,也要考虑每次写入的起始地址,保证写入的数据不会回卷。