做工业控制器,最容易翻车的地方往往是存储。很多项目一开始图省事,把配置参数、日志、算法系数全塞进 STM32 内部 Flash,现场跑一段时间就发现问题:改一次参数要擦掉整个扇区,日志还没记几天就担心把程序区也拖下水,FPGA 那边采回来的高速数据更是没地方倒。后来我把整套数据拆成 EEPROM、NOR Flash、SD 卡三级,STM32 负责按数据的“脾气”分派存储介质,FPGA 负责把高速采集的数据平稳交给 CPU,这才算把存储这口锅彻底端稳了。这篇文章就把这套分级存储方案的关键设计和盘托出,适合正在做工业控制器、运动控制板、边缘网关,或者 STM32+FPGA 双芯方案的工程师参考。
1. 存储分级为什么是工业控制器的刚需
1.1 三种存储介质的本质差异
先别急着写代码,得先把三类介质的“性格”摸清楚。EEPROM 像便利贴,可以随时擦掉改写一小块,按字节操作,擦写寿命通常在 100 万次级别,但容量很小,几百千字节就算顶天了。NOR Flash 像打印好的手册,读取可以按字节或按页高速访问,甚至支持 XIP(片上执行),但写入必须先擦除整个扇区,寿命一般是 10 万次左右,容量能从几兆字节做到几百兆字节。SD 卡则是移动硬盘,容量以 GB 计,适合大量数据堆放,但写寿命、实时性和可预测性都受文件系统和卡本身的 FTL 管理限制。
这三者不是替代关系,而是互补关系。工程上最常见的错误,是希望一颗芯片干完所有事:小容量记不下日志,大容量又舍不得频繁擦写,最后两边都受害。分级存储的本质,是让每一类数据落在“它最擅长”的介质上。
| 数据类别 | 典型内容 | 单个大小 | 写频率 | 可靠性要求 | 推荐介质 |
|---|---|---|---|---|---|
| 关键配置 | PID 参数、设备地址、校准系数 | 几十字节 | 低,仅更改时写 | 掉电不能丢,不能损坏 | EEPROM |
| 运行状态小变量 | 当前批次号、故障累计次数 | 几字节 | 中,定时/掉电写 | 尽量不丢 | EEPROM |
| 启动代码/位流 | 应用程序镜像、FPGA bitstream | 几百千字节到几兆 | 极低,升级时写 | 完整性要求极高 | NOR Flash |
| 运行日志/历史数据 | 报警记录、采样波形、温湿度曲线 | 连续追加 | 高,每秒甚至毫秒级 | 允许丢失最近几秒数据 | SD 卡 |
| 临时高速缓存 | FPGA 采样帧、网络上传缓冲 | 几兆到几十兆 | 极高 | 允许重启后丢失 | DDR/SDRAM |
注意表格里我特意把“掉电不能丢”和“允许丢几秒”分开。工业现场判断存储方案好不好,第一个标准不是容量多大,而是掉电那一瞬间数据是否还在预期位置。
1.2 分级原则:按数据生命周期和可靠性需求分配
分级不是拍脑袋,而是按两个维度去分:数据生命周期,以及数据对完整性的敏感度。
数据生命周期看的是“多久变一次”。PID 参数可能几天甚至几个月才调一次,传感器零点校准值只有开机标定时才更新,这些属于低频写入。报警日志可能每分钟都在产生,波形采样数据更是毫秒级刷新,这些属于高频写入。让高频数据去写 EEPROM,就是把便利贴当草稿本用,寿命撑不过现场运行几个月。反过来,把低频但至关重要的参数丢来 SD 卡,万一卡上文件系统损坏,设备可能连启动配置都没了,这是不可接受的。
可靠性敏感度更关键。启动代码如果读出来错 1 bit,整个系统可能就起不来,所以对 NOR Flash 里的镜像要做 CRC 校验。设备地址、MAC 地址这类参数如果写坏一位,设备会从网络上“消失”,所以更适合放 EEPROM,再加上双备份和校验字。日志类数据的要求是“尽量多、尽量全”,偶尔丢几个字节反而可以接受,SD 卡的适用场景就在这里。
1.3 STM32 和 FPGA 在这个方案里各自扮演什么角色
很多朋友对 STM32+FPGA 的分工理解成“STM32 管存储,FPGA 管逻辑”,这没错,但太粗了。实际项目里,FPGA 往往是数据生产者,而且生产速度远高于 STM32 能直接消费的速度。例如 FPGA 做多通道 ADC 同步采样,单通道 1 kHz、16 bit,多通道一秒就是几十千字节;如果做图像采集或者振动分析,数据率能到几兆字节每秒。STM32 去轮询读这些数据再逐个写卡,主频再高也扛不住。
所以我的做法是:FPGA 先把数据收进片内 FIFO 或片外 DDR,然后通过并行总线、SPI 或 UART 以批量突发方式交给 STM32,STM32 利用 DMA 接收后,再按前面表格的规则分别写入不同介质。STM32 是整个存储系统的“调度中心”,FPGA 是“数据中继站”,两边各管一头,再用帧协议把中间链路兜住。
这种架构最大的好处是解耦:FPGA 不需要关心数据最终落在哪个介质上,只需要保证“我发出去的数据不丢、有序”;STM32 不需要关心采样时序和高速缓存,只需要从队列里取数据做分级落盘。哪一侧出了问题,都能单独定位、单独测试。
2. 硬件电路与接口选型细节
2.1 EEPROM 选型与接线
EEPROM 最常见的是 AT24C 系列,从 AT24C01 到 AT24C256,I2C 接口,容量从 1Kbit 到 256Kbit。工业控制器里我一般选 AT24C64 或者 AT24C128,64KB 的配置空间足够放几十组配方了。选型时注意几点:
- 芯片的 A0/A1/A2 地址引脚:实际 I2C 设备地址是 0xA0 | (A2<<2) | (A1<<1) | A0,如果板上只放一颗,把三个引脚统一接地即可。
- SCL/SDA 上拉电阻:典型 4.7kΩ,总线速度快或者节点多的时候减小到 2.2kΩ。上拉电阻太大会导致上升沿过缓,I2C 波形识别失败;太小会增大功耗,注意别超过芯片规格。
- WP 写保护引脚:要接地,或者拉到 IO 口控制。我踩过一次坑,原理图上 WP 悬空,结果写入操作偶发失败,查了半天才发现是引脚浮空导致写保护状态不稳定。
- STM32 的 I2C 外设:老库在部分芯片上有“死锁”毛病,如果你用的芯片型号比较老,图省事可以直接用软件模拟 I2C,代码量不大但可靠得多。新的 Cube HAL 硬件 I2C 通常没问题,但还是要做超时和复位处理。
电源上,EEPROM 对噪声不算敏感,但建议在 VCC 和 GND 之间放一个 100nF 陶瓷电容,尽量靠近芯片引脚。工业环境下如果总线长度超过十几厘米,SCL/SDA 上还可以各串一个 100Ω 电阻,降低振铃。
2.2 NOR Flash 选型与接线
NOR Flash 我用得最多的是 W25Q 系列,比如 W25Q32、W25Q64、W25Q128,SPI/QSPI 接口。它们容量 4MB 到 16MB,页编程一般 256B,扇区擦除 4KB,块擦除 64KB,支持最大 80MHz 左右的 SPI 时钟。工业控制器里放 FPGA bitstream、字库、启动镜像,16MB 绰绰有余。
接线有几个细节容易出问题。一个是 /WP 和 /HOLD 引脚,数据手册经常写“内部默认上拉”,但在实际布板上很多芯片引脚的内部上拉并不稳定,强烈建议外部接 10kΩ 上拉到 VCC。否则 /HOLD 被拉低时 Flash 会暂停所有操作,写一半停在半空,你查代码真查不出原因。另一个是片选引脚 /CS,必须由主控明确控制,而且在整个写入序列期间保持低电平,不能中途拉高去响应别的中断延时,这也是测试环境里最容易忽略的问题。
SPI 引脚分配上,建议把 CS 用普通 GPIO 控制而不是硬件外设自动控制,这样时序更可控,排查问题时直接读 GPIO 电平就能确认。SCK、MOSI、MISO 优先用硬件 SPI 的片选引脚映射,但 CS 手动控制反而更稳。驱动能力上,如果 SCK 频率超过 20MHz,最好在主控端串 10~22Ω 电阻,走线长度别超过 5cm,否则高速振铃会让 Flash 读回随机 bit 反转。
2.3 SD 卡接口设计
SD 卡有 SDIO 和 SPI 两种最常见模式。STM32 如果资源允许,优先选 SDIO 4-bit 模式,速度快,适合日志流量大的场景;如果引脚吃紧,SPI 模式也可以用,但速度要打折,通常能到 10~20 Mbps 就很好了。很多小批量产品里我用 SPI 模式省引脚,日志吞吐量足够,代码还简单。
卡座选择上,我习惯用带卡检测引脚的自弹式 microSD 卡座,CD 脚连一个 GPIO 做热插拔检测。注意给卡座预留足够的机械空间和接地支撑,震动环境里卡座焊盘容易裂。
供电是重灾区。SD 卡的闪存颗粒在写入时会有电流尖峰,如果 3.3V 电源没有足够储能电容,尖峰一拉低电压,卡就复位,也就是现场常见的“写日志写到一半卡没了”。我一般在 SD 卡座 VCC 附近放一个 100μF 钽电容加 100nF 陶瓷电容的组合,钽电容 ESR 低,扛瞬态能力好;再远一点在板级 3.3V 母线处加 100μF 电解。信号线上按高速数字规则处理,能短则短,MISO/MOSI/CLK 可以串 22Ω 电阻。
如果系统里同时接了 NOR Flash 和 SD 卡,建议把两者的时钟源分开考虑,避免 SPI 高速时钟辐射干扰 SD 卡线。有些板子为了走线好看,把 W25Q 和 SD 卡共用一组 SPI,只靠 CS 区分,从功能上没问题,但从时序和调试复杂度上讲,不如各自独立总线来得干净。
2.4 加入 FPGA 后的总线架构
STM32 和 FPGA 之间怎么连,直接决定这套存储方案能不能跑得动。按数据吞吐量,我把它分成三类:
- 低速物理量,比如几个串口数据、开关量、温度采样,吞吐在每秒几 KB 以内,STM32 和 FPGA 之间用普通 UART 或 SPI 即可,FPGA 侧只需要简单的 FIFO。
- 中速数据,比如多通道 ADC 同步采样,吞吐几十到几百 KB/s,SPI 加 DMA 能解决,FPGA 侧数据要打成帧,帧头加 CRC,STM32 收完一帧再批处理。
- 高速数据,比如图像、整帧振动波形、光纤通信,吞吐几 MB/s 以上,这时候不能让 FPGA 往 STM32 内部 SRAM 里塞了,必须用 DDR 做中转,FPGA 写 DDR,STM32 通过 DMA 从 DDR 读出来再落盘。这个场景通常还要配合“多端口 DDR”设计,后续我会单独写一篇,这里先不展开。
无论哪种,核心原则都一句话:FPGA 不直接操作存储介质,STM32 是唯一存储主控。为什么?因为文件系统、掉电时序、磨损均衡这些逻辑在 CPU 上做太成熟了,比如 FatFS 写 SD 卡,重试和缓存管理都很完善;非要在 FPGA 里实现 FatFS,不仅代码量爆炸,出问题之后调试手段也非常有限。维持这条分工线,FPGA 侧只专心做数据搬运和协议解包,STM32 侧专心做媒体管理,两侧都清爽。
3. 软件与 FPGA 逻辑的核心实现
3.1 STM32 侧驱动设计
EEPROM 驱动要重点理解“页写边界”。AT24C 系列一页通常是 8 字节或 32 字节,I2C 连续写数据如果跨页,写入会被截断。高字节地址翻转之后实际上又写回页内偏移 0,数据全乱。所以写 EEPROM 的标准做法是:先计算当前页剩余空间,超过一页就拆分多次写。比如写 64 字节配置,一页 32B,就拆成 32B+32B,每次写完等待 5ms 写周期,或者用 ACK 轮询方式判断。
NOR Flash 驱动比 EEPROM 复杂一个维度,核心是“写前必须擦”。NOR Flash 存储单元只能从 1 变成 0,所以要让任意字节变成 0xFF 再写入新值,必须先把扇区擦除。也就是说,你只想改某扇区里的 4 字节,也得先把整个扇区读到内存,修改,再擦除整扇区,然后写回。代码逻辑上分四步:
- 发送 Write Enable (0x06),并对返回状态确认 WEL 位已置位。
- 发 Page Program (0x02),一次最多写 256B,地址不能跨页,跨页要拆。
- 轮询状态寄存器 (0x05),等 BUSY 位清零。
- 读回校验,避免总线时序问题导致静默写错。
擦除也分扇区擦除 (0x20)、块擦除 (0xD8)、整片擦除 (0xC7)。整片擦除别在产品代码里轻易调用,万一手滑,配置全没了。擦除耗时较长,我的建议是把它放到后台任务里,或者进掉电保存流程之前单独处理,不要在定时中断里做。
SD 卡这边,用 FatFS 会省很多事。但要注意 f_write 之后数据不一定真正落到了物理扇区,文件系统只是把数据写进了 FatFS 的缓冲区和卡的内部 DRAM,得 f_sync 之后才保证落盘。周期性调用 f_sync 是保命操作,后面排查章节我会详细说。还有一点,写日志文件时尽量用追加模式打开,不要每写一行就打开关闭一次,否则卡上的 FAT 表会被反复更新,目录项碎裂,文件操作越跑越慢。
3.2 FPGA 侧数据通路
FPGA 侧的数据通路设计,核心是 FIFO 和双缓冲。
先说 FIFO。ADC 采样时钟和 STM32 SPI 读时钟肯定不是同一个时钟域,必须有异步 FIFO 做跨时钟域缓冲。FIFO 深度要按“最恶劣突发”估算:假设采样 8 通道、每通道 16bit、1 kHz,即 16KB/s;SPI 时钟 8MHz,差不多 1MB/s 读取能力,看起来富裕。但假如 STM32 正在写 SD 卡,写卡导致 SPI 读请求被暂停 100ms,这 100ms 里 FIFO 至少要吸收 1.6KB 数据,所以深度不能小于 2KB,我实际给到 4KB,留出裕量。深度取 2 的幂,反正 FPGA 内部 BRAM 按块分配。
双缓冲比单一 FIFO 更适合“批量搬运”场景。FPGA 侧每采满 1KB 数据,就在 A、B 两块缓冲之间切换:A 填满后立即使能 STM32 的 DMA 读取,同时 FPGA 往 B 里继续填;STM32 读完 A 后切换到读 B,形成乒乓。这样带宽利用率更高,也不会因为 FPGA 写 FIFO 和 CPU 读 FIFO 的竞争导致卡顿。
帧协议上,我通用格式是:2B 帧头 (0xAA55)、1B 通道号、2B 数据长度、长度字节数据、4B CRC32。STM32 收到帧先查帧头,长度超限则丢帧,CRC 不对则请求重发。如果您做的是 UDP 或 TCP 上行转发,这个帧格式还可以原样向上透传,省一套打包逻辑。
3.3 “分级”落库策略
驱动写好了,数据通路也通了,接下来就是落库策略。这一部分最有工程味道,因为要回答“什么数据写哪里、多久写一次”。
我习惯先建一张数据映射表,每类数据占多少字节、多久产生一级、掉电能不能丢、允许的最大写入延迟。拿一个典型的控制器举例:
| 数据项 | 大小 | 产生频率 | 掉电策略 | 存储介质 | 落盘触发 |
|---|---|---|---|---|---|
| PID 参数组 | 128B | 修改时一次 | 必须保存 | EEPROM | 收到写配置命令后立即写 |
| 零点校准值 | 8B/通道 | 开机标定 | 必须保存 | EEPROM | 标定完成后立即写 |
| 配方表 | 2KB | 修改时一次 | 必须保存 | NOR Flash | 收到配方上传命令后视频擦写 |
| FPGA bitstream | 600KB | 升级时一次 | 必须保存且完整 | NOR Flash | 升级工具整包写入 + CRC 回读 |
| 运行日志 | 128B/秒 | 1Hz | 允许丢 30 秒 | SD 卡 | 每 30 秒 f_sync 一次 |
| 事件记录 | 64B/条 | 随机 | 尽可能保存 | SD 卡 | 事件触发后 200ms 内写入并 sync |
这张表有两点我很强调:一是 EEPROM 里只放“改了就立刻要保命”的数据,像累计运行时间这种,一分钟更新一次就不该放 EEPROM,直接落 SD 卡日志,反正掉了也无所谓;二是 SD 卡日志允许丢 30 秒,这是设计出来的容忍度,有了容忍度,f_sync 频率就可以降到 1/30s,卡磨损和 CPU 负担都小很多。工程上最怕的是一拍脑袋“每个数据都要实时落盘”,最后哪一块都没落好。
3.4 掉电保护与一致性设计
掉电保护是工业控制器存储方案的生死线。你不能假设现场停电总是“温柔”的,更多时候是断路器直接跳闸、整柜瞬间断电。这时候所有存储系统都必须在“最后几毫秒”里处理好该处理的数据。
硬件侧我强烈建议加一个外部掉电检测复位芯片,比单纯用 STM32 内部 BOR 更可靠。典型接法:电源监控芯片检测 3.3V 降到阈值以下时,立刻向 STM32 的 EXTI 脚输出中断,同时把 NOR Flash 和 SD 卡置于写保护或低功耗模式。STM32 收到中断后,从正常工作流切到一个极简保存上下文函数里,只把最关键的几十字节 EEPROM 数据写完,其他一律不管。这里的关键是 EEPROM 写一个页只需 5ms 左右,掉电保持时间通常有 20ms 以上,足够完成。NOR Flash 就不适合在这种场景下紧急写,因为擦除太慢,大概率写一半掉电,反倒把好数据都破坏了。
数据一致性上,所有介质上的数据都要带“头+数据+校验”的结构。我在 EEPROM 和 NOR Flash 中都固定放一个 16 字节的头部:4B Magic、2B 版本号、4B 数据长度、4B CRC32、2B 预留。上电时先读头部,Magic 不对、CRC 不对、长度异常,就把备份区的数据搬回来。备份区可以简单理解成“同一数据写两份”,一份主区一份备份区,写入顺序先备份后主区,这样即使写到一半掉电,主区还留着旧版本,等下次上电校验过不了就会自动回滚。
SD 卡的一致性主要靠 Flush 策略。日志数据不要实时写,而是攒到一定量再写,默认定时 30 秒 f_sync 一次;正常关机时先 unmount,确保 FAT 表落盘完整。针对突发断电,我还会在日志文件里每行加序列号和 CRC,开机后扫描最后一个有效序列号,从此处恢复追加,这样即使文件系统元数据有轻微损坏,也能通过应用层协议把日志内容尽可能救回来。
4. 实操中踩过的坑与排查方法
4.1 I2C 死锁和 EEPROM 写入不稳定的排查
EEPROM 项目里最经典的问题,是 I2C 总线死锁,现象是 SDA 被拉低,SCL 还在正常跳,STM32 的 I2C 外设状态寄存器停在忙状态,所有读写全部卡住。
根因通常是主机时序在传输中途被打断,比如写 EEPROM 时来了一个更高优先级的中断,导致 SCL 停止翻转,此时 EEPROM 在等待 9 个时钟完成内部状态机复位,恰好 SDA 又处于从机输出位,于是总线被堵死。解决思路是加一个 I2C 总线恢复函数:当检测到 SDA 一直为低或外设超时,就强制拉 SCL 产生 9 个时钟脉冲,让从机释放 SDA,然后再重新初始化 I2C。这个函数要在每次传输失败后调用,并且设置足够短的超时时间。
写入不稳定的另一个常见原因是地址页跨越。AT24C64 一页是 32B,如果写 64B 配置没做拆分,第二页实际上写不进,读出来全是 0xFF。排查时先读回刚写入的区域,看看是不是前 32B 正常、后 32B 全 FF,基本一抓一个准。另外,上拉电阻质量差也会偶发写入失败,如果你用逻辑分析仪抓到 SCL/SDA 上升沿有明显爬坡,把上拉电阻从 10kΩ 换到 4.7kΩ 或 2.2kΩ 往往能直接解决。
4.2 NOR Flash 擦写错位、数据反转的根因分析
NOR Flash 最常见的故障是“写进去的东西变了样”,在线下测试环境里表现为:写入 0x55,读出来是 0xAA;或者写 128B,读回时后面的数据出现在前面。
第一个根因是跨页编程。和 EEPROM 的道理一样,W25Q 的页是 256B,页编程命令不能跨页。假如你要写 300B,地址从页内偏移 200 开始,一次发 300B,Flash 会从页边界处“回卷”,把后面 44B 写到页开头,直接覆盖掉前面的内容。排查方法很简单:把所有写操作统一封装成“拆分到页边界”的函数,再写长度任意测试数据回读校验,就能暴露。
第二个根因是硬件引脚干扰。/HOLD 和 /WP 引脚如果悬空或走线过长,在高速 SPI 时钟下体会被串扰拉低,导致 Flash 暂停或进入写保护。我遇到过一板子量产时偶发数据反转,最后用示波器抓 /HOLD,发现波形上有毛刺跌到低电平,重新布局并接上拉后彻底解决。排查这类问题,最好的办法是一边用逻辑分析仪抓 SPI 四根线、一边反复读写固定 pattern,同时观察 /CS 高低电平和 /HOLD 状态。
第三个根因是擦除和写入没有充分等待 BUSY。W25Q 页编程一般在几十微秒到几毫秒,扇区擦除要几百毫秒。如果你发完 0x02 觉得“应该写完了”,立刻去读数据,很可能读到 0xFF,因为芯片内部还没忙完。所有写和擦操作后,必须轮询读状态寄存器的 BUSY 位,直到它清零。
4.3 SD 卡日志丢失、文件系统损坏的处理
SD 卡日志我踩过最大的坑,是设备在雷雨天气里频繁断电,一个月后拔卡回来读文件,发现目录能打开,但日志文件的大小只有预期的三分之一,中间还夹杂着 FF 填充的乱码区域。
原因就是频繁断电时,FatFS 只是把内容写进了文件系统的缓存和卡的内部缓存,没有及时 f_sync,暴露电瞬间 FAT 表没有完整写卡,导致文件簇链断裂。格式还能认到,但有效数据丢了。解决办法已经在落库策略里讲过了:周期性 f_sync,日志文件固定大小,不加不加新的目录项,同时应用层协议加序列号和 CRC。上电后做一个“日志恢复”流程,扫描最后有效记录,把损坏的尾部直接截断,不再追加到坏数据后面。
另一个容易被低估的问题是 SD 卡的供电。卡在写操作时的瞬态电流可以达到 100mA 以上,如果电源压降超过 200mV,卡内部逻辑就可能复位。表现很迷惑:写日志卡初始化正常,但一执行 f_write 就返回错误,连格式化和读卡都正常。用示波器看卡 VCC,如果能观察到写入瞬间电压跌到 3.0V 以下,那就是电容不够,把 100μF 钽电容加上去基本就完事。
4.4 STM32 与 FPGA 联调时常见通信问题
STM32 读 FPGA 数据时最典型的现象是“第一个字节丢、后面全乱套”,十次里有八次是 SPI 模式没对上。FPGA 如果按 Mode 0 发数据,STM32 配成 Mode 3,边沿差一个相位,第一个字节往往会被吞掉。排查时我先用固定帧 0x55AA55AA 去灌,让 FPGA 循环发送,STM32 只捕获并打印,立刻就能看出是极性还是相位问题。
第二个高频问题是 MISO 三态控制。FPGA 的 MISO 引脚必须在 CS 拉低时才驱动总线,CS 拉高时必须置高阻,否则多个 SPI 设备在 MISO 线上打架,读出来的数据会被拉到不定电平。检查 FPGA 代码里 MISO 的赋值条件是否只依赖 CS,是这一问题的标准切入点。
第三个问题是 FIFO 溢出。STM32 接收速度低于 FPGA 产生速度时,FIFO 满了之后新的采样帧只能被丢弃。我的处理方式是 FPGA 在 FIFO 满时把状态寄存器的一个标志位置位,STM32 每个周期来读这个标志;如果发现溢出,就重启 SPI DMA,并从最后一包完整数据继续。这样虽然丢了几个采样周期,但不会导致整段数据协议错位,比“被动等CPU来读”稳健得多。
4.5 实测经验小结
我做这套方案时,有一组数据可以用数字直观说明为什么这么设计不会亏:
- EEPROM 存 64B 关键配置,按每天写 100 次算,100 万次寿命可以撑约 27 年,整个设备寿命周期内根本不用考虑磨损耗尽。
- NOR Flash 存 FPGA bitstream,平时只有升级才写一次,寿命压力完全不在擦写上;读取走了 XIP 或者内存映射,速度足够。
- SD 卡按 1KB/s 写日志,一张 32GB 卡理论上能写约 1.3 年;现场用循环覆盖策略后,实际卡的寿命瓶颈反而是磨损失效,不是容量。
所以存储分级的价值不在于选多高级的硬件,而在于把有限资源用在最需要的地方,让每类介质都工作在它擅长的频率和容量区间里。这个思路和选芯片、调 SPI 时序同等重要,但容易被经验不足的工程师忽略。
我个人在实际操作中的体会是:设计这套方案最值得投入精力的不是写驱动,而是画“数据映射表”和“掉电时序图”。你在板子还没焊好、FPGA 代码还没编译之前,先把哪类数据落到哪个介质、写入频率是多少、掉电时允许丢多少都列清楚,后面做驱动和调试会少走一大半弯路。最后分享一个救过我几次现场的小技巧:给 EEPROM 和 NOR Flash 的数据块统一加一个 magic 字加 CRC 的版本头,上电后先校验主区,不匹配就自动从备份区恢复。这功能只有几行代码,却是整个存储系统最后一道安全网。