4、EEPROM与FRAM:I2C EEPROM工作原理、FRAM技术特点、在消防报警中的选型对比

4.1 先聊聊I2C EEPROM

EEPROM这东西,做嵌入式的基本都打过交道。说白了,它就是一块掉电不丢数据的存储芯片。我最早接触是在做消防报警主机的时候,用来存系统配置参数。

I2C EEPROM的工作原理,其实不复杂。它通过两根线——SCL(时钟)和SDA(数据)——跟MCU通信。每次读写,都得先发一个设备地址,再发一个寄存器地址,然后才能读写数据。嗯,这里要注意:写操作是页写入,不是字节写入。我见过不少新手一上来就逐字节写,结果写一个字节等5ms,64字节的数据愣是写了300多ms。

核心要点: I2C EEPROM的写操作,一定要用页写入模式。以AT24C256为例,一页64字节,写一页只需要5ms。比逐字节写快了64倍。

读操作就简单多了。随机读、顺序读都行。我习惯用顺序读,一次性把整个配置表读出来,省事。

但EEPROM有个硬伤——写寿命。一般标称100万次,实际上我测过,到80万次左右就开始出现位翻转。消防报警设备要求10年以上的使用寿命,你想想看,如果频繁写日志,EEPROM撑不了多久。

4.2 FRAM是个什么玩意儿?

FRAM,铁电存储器。我第一次用FRAM是给一个客户做火灾报警控制器,对方要求记录最近5000条报警事件。用EEPROM?写一次擦一次,5000条写完,芯片也快废了。

FRAM的技术特点,我总结了几条:

  • 写入速度快: 没有页写入的概念,直接写,跟读一样快。我实测过,写一个字节不到100ns。
  • 写寿命极长: 标称100万亿次。什么概念?每秒写1000次,能用3万年。消防报警设备那点写入量,根本不用担心。
  • 低功耗: 待机电流微安级,写入电流也就毫安级。电池供电的设备很友好。
  • 数据保持: 一般10年以上,跟EEPROM差不多。
我的经验: FRAM的写入不需要先擦除再写。EEPROM写之前得先擦除整页,FRAM直接覆盖写。这个特性在记录实时报警事件时特别有用。

不过FRAM也有短板。容量做不大,市面上常见的也就64Kb到2Mb。价格也比EEPROM贵不少。我算过一笔账,同样1Mb的容量,FRAM比EEPROM贵3到5倍。

4.3 消防报警场景下的选型对比

做消防报警产品,选存储芯片不能光看参数。我踩过坑,也总结了一些经验。

对比项 I2C EEPROM FRAM
写入速度 慢(页写入5ms) 快(纳秒级)
写寿命 100万次 100万亿次
功耗 中等
容量 最大4Mb 最大2Mb
价格 便宜 贵3-5倍
数据保持 10年 10年
适用场景 配置参数、固件升级 频繁写入的事件日志

我个人习惯这样选型:

  • 存配置参数: 用EEPROM。比如探测器地址、灵敏度阈值、联动逻辑。这些数据写入一次,后面基本不改。EEPROM便宜,够用。
  • 存事件日志: 用FRAM。比如报警记录、故障记录、操作记录。消防主机一天可能产生几百条事件,EEPROM扛不住。
避坑指南: 我曾经在一个项目里,用EEPROM存报警日志。结果用了半年,芯片写坏了,日志全丢。后来换成FRAM,再没出过问题。记住:频繁写入的场景,别省那几块钱。

还有一个细节——I2C总线冲突。消防报警系统里,MCU可能同时挂多个I2C设备。EEPROM和FRAM的I2C地址可以配置,但要注意别冲突。我一般把EEPROM设成0xA0,FRAM设成0xA2,错开。

4.4 代码示例:FRAM写入与读取

下面是我常用的FRAM驱动代码,以FM24CL64为例。注意看,写入不需要页操作,直接写就行。

// FRAM写入函数
void FRAM_Write(uint16_t addr, uint8_t *data, uint16_t len)
{
    I2C_Start();
    I2C_SendByte(0xA2);  // FRAM设备地址
    I2C_WaitAck();
    I2C_SendByte(addr >> 8);  // 高8位地址
    I2C_WaitAck();
    I2C_SendByte(addr & 0xFF);  // 低8位地址
    I2C_WaitAck();
    
    for(uint16_t i = 0; i < len; i++)
    {
        I2C_SendByte(data[i]);
        I2C_WaitAck();
    }
    I2C_Stop();
}

// FRAM读取函数
void FRAM_Read(uint16_t addr, uint8_t *buf, uint16_t len)
{
    I2C_Start();
    I2C_SendByte(0xA2);  // 写地址
    I2C_WaitAck();
    I2C_SendByte(addr >> 8);
    I2C_WaitAck();
    I2C_SendByte(addr & 0xFF);
    I2C_WaitAck();
    
    I2C_Start();
    I2C_SendByte(0xA3);  // 读地址
    I2C_WaitAck();
    
    for(uint16_t i = 0; i < len; i++)
    {
        buf[i] = I2C_ReadByte();
        if(i != len - 1)
            I2C_SendAck();
        else
            I2C_SendNack();
    }
    I2C_Stop();
}
提示: FRAM的写入不需要延时等待。EEPROM写完后要等5ms,FRAM写完立刻就能读。这个特性在实时性要求高的消防报警系统里,非常实用。

最后说一句,选型没有绝对的对错。关键看你的应用场景。如果只是存配置参数,EEPROM完全够用。如果要频繁写日志,别犹豫,上FRAM。我见过太多人为了省几块钱,最后花大价钱返工。

嗯,今天就聊到这儿。下一节我们讲SPI Flash,它在消防报警里也有不少应用场景。