1. 先理清需求:工业控制器到底要存什么数据
1.1 四类数据的存储特征完全不一样
工业控制器项目做多了,你会发现一个规律:最不起眼的存储方案,往往是最后翻车最狠的地方。尤其是 STM32+FPGA 这种异构控制架构,参数要掉电不丢,配置要随时能更,日志要连续记录几个月,一个存法根本扛不住。EEPROM、NOR Flash、SD 卡,这三样东西看起来都叫“存储”,但它们的脾气天差地别,用错了就是后期交付现场的火葬场。
工业控制器运行过程中,需要落盘的数据远没有想象中那么单一。我拆开讲讲。
固定标定参数:这是设备出厂时就确定的,比如传感器校准系数、PID 归一化因子、机械零点偏移。这类数据的特征是小——往往只有几百字节,但要求极高可靠性和长寿命。现场设备可能一天要修改几次参数,运行十年,写入次数会积累到几十万次。这类数据用什么存,答案很清楚——EEPROM。
动态配置参数:用户在现场设置的,比如通信地址、波特率、报警阈值、工艺配方。频率介于固定参数和日志之间,可能一天改几次,也可能几个月不动一次。这类数据掉电也要保,但允许一些策略优化。很多设计中把这类参数和固定参数合并放在 EEPROM,或者单独划分 NOR Flash 的某个扇区,通过双区备份来抗干扰。
运行日志与趋势数据:这是工业控制器数据量的大头。设备运行状态、故障报警、温度压力曲线、IO 通断记录。一个 1000 点规模的控制器,按 1 秒 1 次采集原始数据,每秒就是 2KB,一天下来接近 170MB。这种数据量大、允许覆盖、丢失几秒也无所谓的特性,决定了它只能放进大容量存储介质——SD 卡。
固件与 FPGA 配置:STM32 的应用程序固件、FPGA 的 bitstream、设备的型号版本信息。这类数据支持远程升级,升级频率低,但读取频繁。需要存储介质支持快速随机读取,且最好能映射到地址空间。NOR Flash 承担这个角色再合适不过。
1.2 为什么不能靠一颗 Flash 包打天下
很多人刚上手的时候喜欢图省事,单片机内部 Flash 容量不够就外挂一颗 4MB 的 NOR Flash,一存到底。表面上看这颗 Flash 什么都能装:参数也放、日志也放、固件也放。结果用半年问题就来了。
参数每天都由控制逻辑修改,EEPROM 写寿命百万次,NOR Flash 典型擦写寿命 10 万次。把参数放在 NOR Flash 里,每天写 100 次,1000 天——不到 3 年,这颗 Flash 的寿命就被参数写完了。更麻烦的是,NOR Flash 改写之前必须先擦除扇区,而擦除最小单位是 4KB,你改一个字节参数,也要先擦掉 4KB 区域,这中间一旦掉电,整个扇区的数据全丢。所以从寿命和可靠性两个角度看,参数和日志混在 NOR Flash 里就是灾难。
再说速度和功耗。NOR Flash 的随机读取确实快,但 SD 卡在连续写日志上更有优势,而且日志量一旦上了 GB 级别,NOR Flash 的单位容量成本是 SD 卡的几十倍,没有任何算账的意义。
这里就引出了分级存储的核心逻辑:按数据的大小、写入频率、寿命要求去匹配介质,而不是试图用一颗芯片解决所有问题。后面整篇文章,就是围绕这个逻辑展开的。
2. 三种存储介质选型:原理不对等于埋雷
2.1 EEPROM:参数的家,按字节擦写的长寿选手
EEPROM 的存储原理是浮栅晶体管,每个存储单元是一个独立的浮栅晶体管,靠 Fowler-Nordheim 隧穿效应向浮栅注入或者移出电荷,实现 1 和 0 的翻转。因为每个单元都可以独立擦写,EEPROM 才支持按字节操作。这是它和 NOR Flash 最本质的区别。
按字节擦写的代价是单元面积大。一颗 AT24C256 容量 256Kb(32KB),长宽只有几毫米,但已经是 EEPROM 家族里的大块头了。工业控制器里 EEPROM 的容量通常不需要太大,2Kb 到 64Kb 就足够放标定参数和配置参数了。
寿命是 EEPROM 最亮眼的指标。工业级 EEPROM 的擦写寿命普遍在 100 万次以上,数据保持时间在 100 年以上(温度越高保持时间越短,125 度环境下还能保十几年)。100 万次是什么概念?工业设备一年 365 天每天改 20 次,一年 7300 次,100 万次够用 136 年。所以只要不改动太频繁,EEPROM 在工业场景里基本是“一辈子”的存储器件。
EEPROM 的另一个优势是非易失和随机字节访问。断电数据不丢,这是它的基本盘。我在选型时唯一要确认的:总线接口是 I2C 还是 SPI。同样容量下 SPI 的速度稍快;但 I2C 只需两线,接线省两个 IO。工业控制器普遍 IO 紧张,所以 I2C 接口的 EEPROM 用得更多,AT24Cxx 系列几乎成了事实标准。
2.2 NOR Flash:代码与配置的中转站,XIP 是最大价值
NOR Flash 的内部单元虽然也是浮栅管,但为了追求密度,采用了共源极、共漏极的结构,单元之间没有完全隔离。这就导致它没办法按单个字节擦除,只能按扇区——常见的是 4KB 扇区、64KB 块——施加高压脉冲整体擦除。读取方面,NOR Flash 保留了随机地址读取能力,每个字节都能被 CPU 直接访问,所以支持 XIP(片上执行)。
XIP 在工业控制里的意义很直接:程序或配置可以直接在 NOR Flash 里跑,不需要先拷到 RAM。STM32 的 QSPI 接口就可以外挂一片 NOR Flash 做代码映射,FPGA 也可以从 NOR Flash 里读 bitstream 来加载逻辑。
NOR Flash 的擦写寿命在 10 万次级别,不是因为它做不好,而是因为 EEPROM 把“频繁小量改写”的需求承接过来了,NOR Flash 的定位就偏向“代码、配置、静态数据”。另外 NOR Flash 的写操作要先擦后写,擦除时间一个扇区典型需要几十到几百毫秒,如果拿它去记日志,每秒一次扇区擦除,寿命和速度都会成为瓶颈。
选 NOR Flash 时我会重点看几个指标:容量(4MB 到 32MB 是工业控制的常见区间)、擦除时间、SPI 时钟上限、功耗以及有没有做扇区级硬件写保护。国产的 GD25Q64、兆易创新的 GD5F 系列,和原厂华邦 W25Q64、美光 N25Q 系列,这些我都实际用过。只要货源稳定、分级明确(工业级和商业级温度范围不同),国产颗粒在常规项目中完全能替代进口。
2.3 SD 卡:日志的仓库,容量换寿命的块设备
SD 卡的本质是一颗 NAND Flash 加一个控制器芯片。NAND 的存储单元也是浮栅管,但是高密度压缩导致每个单元的擦写寿命远低于 EEPROM 和 NOR Flash。以 MLC 颗粒为例,P/E 次数普遍在 3000 到 10000 次,TLC 更低,只有 1000 到 3000 次。不过 SD 卡内部有控制器做磨损均衡,逻辑上进行扇区分摊,实际寿命比直觉上高不少。
SD 卡的访问模式是块设备,以 512 字节为一个扇区,底层不支持字节寻址和字节改写。所以正常用法是在它上面挂文件系统。工业控制器里基本都是 FatFs 配 SPI 或 SDIO 接口。FatFs 的好处是日志文件可以直接被 PC 读取——现场工程师把卡抽出来插上读卡器,就能用 Excel 或者文本查看器打开日志,这个易用性对售后排查故障极其重要。
SD 卡选型在工业环境里的坑很多:绝大多数消费级卡宣称的高速度都是顺序读的速度,写满随机小文件时掉速严重;另外高温和频繁异常掉电会让消费级卡提前报废。工业级 SD 卡(SLC 颗粒,温度范围 -40 到 85 度)价格是消费级的 3 到 5 倍,如果是批量交付的产品,这部分成本必须算进去。
2.4 一张表看懂三种介质的选型逻辑
| 维度 | EEPROM | NOR Flash | SD 卡 |
|---|---|---|---|
| 典型容量 | 1KB~64KB | 4MB~64MB | 4GB~64GB |
| 最小操作单位 | 字节 | 扇区(4KB) | 扇区(512B) |
| 擦写寿命 | 100 万次 | 10 万次 | 1000~10000 次(P/E) |
| 典型接口 | I2C/SPI | SPI/QSPI | SPI/SDIO |
| 掉电数据保持 | 芯片级保证 | 芯片级保证 | 依赖卡固件 |
| 主要场景 | 参数、标定值 | 固件、FPGA 配置 | 日志、趋势、历史数据 |
| 字节随机改写 | 支持 | 不支持 | 不支持 |
| XIP | 不支持 | 支持 | 不支持 |
这张表是我项目里一直贴着的选型对照。核心判断一句话:越小、越关键、改动越频繁的数据,越要往介质金字塔的顶端放。
3. STM32+FPGA 架构下的存储分工与链路设计
3.1 谁离数据最近,谁负责落盘
STM32 和 FPGA 共存于控制器里,分工是相对清晰的:STM32 擅长跑协议栈、算法、系统管理,负责人机交互和整机控制逻辑;FPGA 擅长并行处理、高实时性的信号采集和高速接口扩展,比如 ADC 数据预处理、编码器信号解析、多路串口的收发,甚至相控阵的相位控制这类前端任务。
但到了存储这一层,很多设计就犯迷糊了。一种常见错误是,FPGA 采集到的数据全部通过接口丢给 STM32,让 STM32 统一写 SD 卡。这在数据量小的时候没问题,一旦数据量大了——比如 FPGA 以 10kHz 采样率连续采多通道信号,每秒钟产生的数据几百 KB 甚至几 MB——STM32 作为转发中途站,既要跑协议又要搬运数据,主频和 DMA 带宽都吃不消,还可能影响控制算法实时性。
正确的思路是看数据的“产生位置”而不是“管理位置”。STM32 侧产生的运行参数、诊断结果、通信数据,交给 STM32 直管的存储链路(EEPROM、NOR Flash);FPGA 侧实时采集到的高速数据,直接由 FPGA 控制 SD 卡或 NOR Flash 写入,STM32 只负责初始化管理和取出汇总。谁离数据最近,谁负责落盘,这样既省掉了中间搬移的带宽开销,也降低了总线拥塞的风险。
3.2 典型拓扑:STM32 管参数、FPGA 管流数据
我在实际项目中用过的典型拓扑可以拆成三路。
第一路:EEPROM 挂在 STM32 的 I2C 总线上。存系统标定参数、设备地址、PID 参数、历史报警记录等小数据。这类数据不频繁写入,但要求绝对可靠。
第二路:NOR Flash 挂在 STM32 的 QSPI/SPI 上。这块 Flash 既当 FPGA 的配置镜像存储,也存 STM32 升级固件备份区。升级时先写入 NOR Flash 的备份区,校验通过后再搬进内部程序区,避免在线升级写一半掉电导致变砖。
第三路:SD 卡由 FPGA 直接管理。FPGA 内部实现 SD 卡控制器(SPI 模式),大量高速采集数据在 FPGA 内部做简单打包,直接以块传输方式写入 SD 卡。STM32 通过一个轻量管理接口(通常是内部寄存器或 SPI)读取写位置、卡状态和日志目录索引,方便用户通过 HMI 查询历史。
这种拓扑下,STM32 与 FPGA 之间只需要交换少量管理信息:写卡指令、文件当前偏移、剩余空间。数据面完全绕开 STM32,带宽瓶颈一下就被解除了。如果项目的数据量没那么大,也可以用更简单的结构——FPGA 把数据通过 FIFO 交给 STM32,STM32 统一写 SD 卡。但要评估好每秒进入 FIFO 的数据量是否超出了 STM32 的 DMA 搬运能力。
3.3 用 STM32 给 FPGA 加载配置:少一颗配置芯片
很多 FPGA 方案的存储设计会额外加一颗配置芯片(比如 Altera 的 EPCS4/EPCS16),这颗芯片本来就是串行 NOR Flash。如果控制器里已经有一颗 STM32 在管 NOR Flash,完全可以省掉这颗专用配置芯片,让 STM32 兼任 FPGA 的“配置加载器”。
具体做法是:FPGA 工作在被动配置模式下,STM32 从 NOR Flash 中读出 bitstream 文件,按 FPGA 手册要求的时序,通过 SPI 或专用配置引脚逐字节推给 FPGA 的 DIN、CCLK、CS_n。我实际用过 Spartan-6 的 SPIFlash 从模式和 Cyclone IV 的 PS 模式,流程都是:先拉低配置引脚,把整个 bitstream 按地址顺序读出来写进去,然后检查 DONE 信号是否拉高,完成后拉高配置引脚完成配置。
这个方案用一颗 NOR Flash 同时装 STM32 的升级固件和 FPGA 的多个配置文件,靠文件头区分类型。好处是省了器件、降低了 BOM 成本,而且支持远程升级 FPGA 逻辑——上位机下发新的 bitstream,写入 NOR Flash 的某个分区,下次上电 STM32 加载的就是新逻辑。缺点是加载时间比专用配置芯片长一点,几十 KB 到几 MB 的 bitstream,在 10MHz SPI 下也就是几秒的事,工业控制器上电启动时间完全能接受。
4. 实操环节:三路存储的电路与代码要点
4.1 EEPROM 接入 STM32:I2C 时序、页写与 CRC
EEPROM 的接线没什么悬念:SDA、SCL 两根线加上拉电阻(通常 4.7k 欧)。AT24C256 的 I2C 从地址是 0xA0(A0、A1、A2 接地),容量大一点的器件会有额外的地址引脚用于多片级联。我习惯把 EEPROM 放在 I2C1 上,时钟设成 400kHz 快速模式,因为它的数据量不大,不需要开 DMA,直接轮询读写即可。
页写是我最提醒新手注意的点。EEPROM 硬件上按页组织数据,AT24C256 一页是 64 字节,跨页写必须切断写指针重新寻址。很多人一次性发 200 字节给 EEPROM,发现后半段数据全是乱的,就是这个原因。正确写法是按页长度拆分:数据地址在页内偏移加上剩余长度超过一页时,先写第一页剩余部分,再跳到下一页继续。
参数读写要带校验。我会在参数区头部放一个魔数(比如 0xA5A55A5A)和一个 CRC16,读取时先校验魔数,再算 CRC,任何一个不对就认为参数损坏,回退到恢复流程。CRC 多项式用 CRC-16/CCITT 就行,153 字节的参数区算一遍 CRC 只要几微秒,完全可接受。掉电可靠性上,我会引入双备份区:参数 A 区和参数 B 区交替使用,每次写入先更新备份区,再更新主区。下次上电发现主区 CRC 不对就从备份区恢复,这个策略基本能把掉电写坏的概率降到零。
// EEPROM 参数读取并校验(伪代码框架) #define PARAM_MAGIC 0xA5A55A5A #define PARAM_REGION_SIZE 153 typedef struct { uint32_t magic; uint16_t crc; uint8_t data[PARAM_REGION_SIZE - 6]; } param_block_t; bool load_param_block(param_block_t *block, uint16_t region_addr) { eeprom_read(region_addr, (uint8_t *)block, sizeof(param_block_t)); if (block->magic != PARAM_MAGIC) { return false; // 魔数不对,参数区未初始化或已损坏 } uint16_t calc = crc16_ccitt((uint8_t *)&block->data[0], sizeof(block->data)); return (calc == block->crc); }4.2 NOR Flash 接入:扇区擦除、状态轮询与写保护
NOR Flash 用 SPI 接口,W25Q 系列是全行业最普遍的。电路上注意 CS 片选引脚必须在 SPI 通信全程拉低,通信结束后必须保持高电平至少一个时钟周期,很多偶发的配置读错就是片选没有完全释放导致的。
初始化和读写流程里,最容易踩的两个大坑是擦除等待和写保护。擦除一个扇区需要几十到几百毫秒,CPU 不能在这里死等,必须轮询状态寄存器的 BUSY 位(SR1 的 bit0)。我的习惯是先发出擦除指令,然后去做其他事,过段时间再回来读状态寄存器,确认擦除完成。这样既不会卡死主循环,也不会提前去写数据导致写失败。
写保护是 W25Q 系列出厂默认开启的。我第一次用这颗芯片时,发了写使能指令却写不进去数据,查了半天发现是状态寄存器里 BP 位把整个芯片都保护了。正确操作是先把状态寄存器里的块保护位清零——用 0x01 写状态寄存器指令,把 BP0/BP1/BP2 全部置 0——之后才能正常擦写。对于量产设备我会反过来做:正常运行时把 BP 位重新置上,防止代码异常时误擦除 Flash,只在执行升级流程时才临时解除保护。这算是一个值得分享的小技巧。
// W25Q64 扇区擦除示例(SPI 驱动层函数省略) void nor_erase_sector(uint32_t addr) { uint8_t cmd[4]; cs_low(); cmd[0] = 0x06; // Write Enable spi_write(cmd, 1); cs_high(); cs_low(); cmd[0] = 0x20; // Sector Erase (4KB) cmd[1] = (addr >> 16) & 0xFF; cmd[2] = (addr >> 8) & 0xFF; cmd[3] = (addr >> 0) & 0xFF; spi_write(cmd, 4); cs_high(); // 轮询 BUSY 位,直到擦除完成 while (nor_read_status() & 0x01) { // 可在此切换线程或任务 } }4.3 SD 卡接入:SPI 模式初始化与 FatFs 落地
SD 卡接入 STM32 常用 SPI 模式,四线:CS、MOSI、MISO、SCLK。SPI 模式节省引脚,单片机的 SPI 控制器直接能用,缺点就是速度上限低。SDIO 接口能跑到几十 MB/s,适合大吞吐场景;但因为 FPGA 内部实现 SDIO 比较复杂,很多 FPGA 直管 SD 卡的方案其实用的还是 SPI 模式,在 10MHz SCLK 下顺序读速度大约 1MB/s 上下,记录工业日志够用。
初始化时序是 SD 卡最容易出问题的地方。SD 卡上电进入 SD 模式,如果要切换到 SPI 模式,必须在 SCLK 空闲时先给至少 74 个时钟脉冲,再发 CMD0(带 CS 拉低)。这条时序在常见代码库和数据手册里都有,但很多人忽略了一个关键细节:初始化的 SPI 时钟必须低,400kHz 以下。我见过太多把初始化时钟设成 8MHz 导致 CMD0 没响应的情况。正确做法是初始化阶段用低速时钟,等 ACMD41 返回就绪后,再切换到高速模式。
文件系统层面我直接用 FatFs。做三层操作就够了:底层的 disk_initialize、disk_read、disk_write 和 disk_status;中间层挂载 f_mount;应用层 f_open、f_write、f_sync。这里特别强调 f_sync——关闭文件前先同步缓存,确保 FAT 表和文件数据都落盘了,再返回“写入完成”。如果不做 f_sync,控制器突然掉电时写了一半的 FAT 表会让整个文件系统损坏。
日志目录建议用循环覆盖策略。我在 SD 卡上建一个 LOG 目录,文件名按“LOG_20250101_0000.CSV”这样带时间的格式命名,写满固定数量后,自动删除最早的文件再创建新文件。这样现场工程师拿到卡就能看到最近一段时间的日志,容量也始终可控。
4.4 掉电保护:工业环境最容易翻车的点
说完上面三路存储,我单开一节专门讲掉电保护。工业控制器的供电环境普遍恶劣:电机启停、大负载切电、线路接头松动,都可能让控制器瞬间断电。而数据落盘的可靠与否,全部体现在掉电的那一刹那。
掉电检测是最关键的环节。我会在电源输入端加一个电压检测引脚,MCU 用 BOD(掉电检测)中断,检测到电压跌到阈值(比如 3.0V)时,立即挂起其他任务,把当前需要保存的关键参数紧急写入 EEPROM。但要注意,从检测到掉电到电压跌破 EEPROM 最低工作电压(常规是 1.8V),通常只有几毫秒。这几毫秒内要完成一次可靠写操作,对电流和时间的要求都很苛刻。
解决手段是储能电容。给 EEPROM 和 NOR Flash 的 VCC 并一个大容量的铝电解或者钽电容,一般是 1000 到 4700μF,具体容量根据写入时间和电流计算。比如 EEPROM 写入一页 64 字节需要 5ms,工作电流 2mA,那么至少需要 2mA 乘以 5ms 等于 10μC 的电荷,理论上 470μF 的电容绰绰有余。但实际考虑到电压跌落和余量,我在设计里不会低于 1000μF。
另一层保护是掉电时只做“最小必要写”——把当前工艺参数、操作模式、报警状态这几百个字节写入 EEPROM,其他日志由 FPGA 侧或下次上电再补。比掉电瞬间写几 MB 日志可靠得多。
5. 调试实录与常见问题排查
5.1 SD 卡不识别、内部寄存器锁死怎么救
SD 卡项目调试中报错最多的问题就是初始化失败。现象分几类:插上没反应、CMD0 没响应、ACMD41 超时。这类问题最先检查的都是 SPI 速率。我会先用逻辑分析仪抓一遍 SD 卡初始化时序,确认初始化阶段的时钟没有超过 400kHz。其次是电源退耦,SD 卡在写操作瞬间的电流可能冲到几十毫安,如果 PCB 上没放一个 100μF 的钽电容,卡会在写大块时直接掉坑。
SD 卡内部寄存器锁死是异常掉电的老毛病。很多卡在写入过程中突然断电,内部的控制器会进入一种保护状态,表现为重新上电后 CMD0 也不响应。我的处理流程是:物理上电复位,等 100ms 以上,再尝试慢速 CMD0,通常能唤醒;不行就给卡重新上电一次,大多数卡能恢复。如果反复上电都唤不醒,那基本可以判定卡固件损坏,只能换卡。所以工业设计里 SD 卡不要“掉电瞬间连续写”——保护逻辑要足够聪明,检测掉电后不再写入,而是尽快进入安全状态。
5.2 EEPROM 写坏参数、写不进数据
EEPROM 写不进数据的现象也常见,九成出在下面三个地方。第一是 WP 写保护引脚被拉高了。AT24C 系列有一个 WP 引脚,拉高时禁止写入,很多人硬件上把它悬空或者误拉高,导致写操作静默失败。第二是 I2C 总线上有从机设备在初始化时把 SDA 拉死,这类问题用逻辑分析仪看波形最直观,地址帧和 ACK 帧是否正常一目了然。第三是页写边界问题,我前面已经强调过,跨页写必须分段,最好把参数对象的大小设计成页对齐,省去很多麻烦。
写坏参数案发现场和掉电相关。EEPROM 写一个字节也是按内部读-改写流程完成的,如果写操作执行到一半电压消失,数据就有概率损坏。从可靠性的角度,我已经不信任“断电前最后几毫秒把参数写完”这个方案了,双备份区加 CRC 才是真正的底。还有一种情况是写入太频繁导致 EEPROM 寿命耗尽,看起来参数会随机丢,用编程器读一遍就会发现数据区全是 0xFF,这种基本没有抢救价值,只能换芯片。
5.3 NOR Flash 擦除超时与数据错乱
NOR Flash 擦除超时,最常见的原因是 SPI 时钟设置太高加上电源纹波大。W25Q64 擦除一个 4KB 扇区典型时间只有 45ms 左右,如果电压不稳或者 EMC 干扰严重,偶发超时很常见。遇到这个问题,我首先把 SPI 频率从 80MHz 降到 20MHz 左右,有很大概率直接解决;其次检查 Flash 的 VCC 退耦电容,建议放 0.1μF 加 10μF 的组合,并紧贴芯片引脚摆放。
还有一种很隐蔽的数据错乱问题来自读操作。NOR Flash 在读取时还有一定的电源电流需求,如果 PCB 上电源走线太窄,高速翻转 I/O 时会造成 VCC 跌落,读出来的字节里就会出现 0 变 1 的翻转。排查这种问题,最有效的工具就是连续读整个区域和已知镜像做比对,出现偶发不一致基本锁定电源问题。如果错误位集中在同一字节的某一位,那就是引脚或电源问题,而不是数据本身损坏。
5.4 日志文件损坏与磨损均衡的那些坑
SD 卡日志文件损坏,是工业现场最容易被客户吐槽的问题——工程师赶到现场,抽出 SD 卡发现文件无法打开。多数是断电瞬间 FAT 表被写坏,修复思路是掉电检测配合 f_sync。我给文件系统加了一个“写入屏障”机制:写文件数据时,先把数据写到临时文件,写完后同步 FAT 表,再把临时文件改名为正式文件。这样即使掉电,最多损失一个临时文件,正式文件永远不会半损。
磨损均衡方面,消费级 SD 卡已经内置了磨损均衡,但工业级更值得关注的是“写入放大”。如果日志文件采用频繁更新文件头部的策略——比如每次都改写文件头部的时间戳或 CRC——那么 SD 卡控制器内部会不断搬移整个块,写入放大系数可高达几十倍,寿命会被迅速吞掉。正确的日志写法是:每秒钟往文件尾部追加一条固定长度的记录,头部信息只在固定间隔才更新。计算下来,一张 SLC 工业级 16GB 卡,在工业现场连续记录三个月,磨损完全在可控范围。
最后再分享一个我个人一直坚持的习惯:所有存储链路都要做开机自检。上电时,STM32 把 EEPROM 的校验、NOR Flash 的版本号、SD 卡的文件系统完整性和剩余容量全部检查一遍,任何一个异常都通过故障指示灯和串口诊断输出报告,而不是等运行到中途才发现存储等关键资源失效。这个习惯帮我在项目现场省下过太多排查时间。
分级存储方案看起来不复杂,真正要在工业现场熬过几年考验,靠的全是这些小细节的堆叠。希望这篇能帮正在做类似架构的朋友少走些弯路。如果大家有更好的存储容错方案,欢迎交流,下一篇硬件篇我计划聊聊控制器的电源系统设计,那个时候我们再见。