☰
工业控制器分级存储设计:EEPROM、NOR Flash与SD卡各司其职
2026/9/29 12:03:51 网站建设 项目流程

做工业控制器这些年,我最大的感触是:怎么把数据存住、存对、存得久,往往比算得准更让人头疼。很多人一上来就想着上大容量Flash,或者干脆把日志直接往SD卡里怼,结果不是掉电丢参数,就是文件系统损坏。这篇文章想聊的,是一套我在STM32+FPGA架构上验证过的分级存储方案:EEPROM、NOR Flash、SD卡各司其职,按数据特点分层存放。内容偏硬件实操,会讲清楚每一级存储的设计逻辑、接口要点和踩过的坑,尤其适合正在做仪器仪表、运动控制、边缘网关这类产品的朋友参考。

1. 为什么工业控制器一定要分级存储:三类数据的命运完全不同

先想一个问题:一块板子上要存的数据,它们的价值一样吗?答案显然是否定的。以我做过的一套伺服控制器为例,板卡上同时存在三种特征完全不同的数据:设备地址、PID校准系数这类配置参数,掉电必须保留,但写入次数极少,一年可能就写那么几十次;Bootloader、固件镜像、滚动运行日志这类数据,更新频率稍高,但要求读取快、可靠性高,不能容忍随时损坏;还有一类是历史趋势曲线、完整事件记录、升级备份包,数据量动辄几十上百MB,需要大容量存储,但对单次写入的可靠性要求相对弹性。

如果把这三类数据统统塞进一个存储介质里,会出现什么局面?用大容量NOR Flash存配置参数,浪费不说,擦写寿命和写入速度都不划算;用SD卡存配置参数,设备一上电就初始化文件系统,结果在振动、掉电的工业现场经常损坏文件分配表,最后连参数都读不出来;用EEPROM存大数据就更离谱了,一片AT24C256也就256Kbit,存几秒波形数据就满了。

所以分级存储本质上不是在"选更贵的芯片",而是在按照数据生命周期和访问频率做匹配。核心原则只有一条:让每一类数据待在最适合它的介质里。配置参数这种高可靠性、低频写入的小数据归EEPROM;固件和近期日志这种中等容量、读多写少、需要快速随机访问的归NOR Flash;海量历史数据这种对容量要求高、对单点可靠性容忍度强的归SD卡。

2. STM32和FPGA怎么分工:存储这件事,CPU不该全包

很多搞纯单片机出身的朋友会习惯性认为,存储嘛,就是MCU挂个I2C或者SPI,读写而已。但在STM32+FPGA的架构里,问题没那么简单。FPGA承担的是实时性极高的任务,比如编码器计数、PWM波形产生、高速ADC采样,这些任务对时序要求苛刻,CPU根本来不及干预。而STM32要管理通信协议栈、运行控制算法、维护人机交互,如果再让它频繁响应存储读写中断,系统实时性必然受影响。

我采用的分工方式是这样的:FPGA负责数据采集和预存储,ADC或者编码器的高速数据流先进FPGA内部的FIFO,做简单的拼帧、滤波、格式整理后,通过并行总线或者SPI接口交给STM32;STM32负责存储系统的管理,包括文件系统、磨损均衡、掉电保护策略和与上位机的交互。听起来好像FPGA只是数据的"搬运工",但恰恰是这个搬运过程,决定了整个存储系统的上限。

举一个实际例子。我之前做过一个8通道同步采集的板卡,每个通道500kSps,16bit,算下来原始数据率是8MB/s。如果让FPGA直接把原始数据写进SD卡,SD卡根本跟不上,而且数据格式完全是裸数据,事后根本没法解析。后来改成FPGA先把数据做缓存和降采样预处理,把有效信息压缩成结构化的事件记录,再按帧发给STM32写入存储介质,压力瞬间小了一个数量级。

这里有个容易被忽略的握手问题:FPGA和STM32之间传递数据的时序,以及存储写失败时的反馈链路。FPGA往FIFO塞数据,如果STM32因为正在处理中断而来不及取走,FIFO就会溢出,数据丢得无声无息。所以我在FPGA里加了一个"水位线"信号,FIFO超过一定阈值就拉高中断通知STM32,同时在STM32侧开了一个DMA通道专门搬运数据。另外,存储介质写失败时,比如SD卡写入返回错误,FPGA侧应该立即收到指令停止发送新数据,而不是继续傻乎乎地丢数据。这个"背压"机制不做好,后面排查问题会非常痛苦。

3. EEPROM:配置参数的保险柜,容量虽小,功夫不少

EEPROM在工业控制器里的地位,有点像家里的保险柜——东西不多,但丢一样就要出大事。设备地址、通信波特率、加减速时间、PID参数、传感器校准系数,这些数据每一条都关系到设备能否正常工作。EEPROM的选择上,我常用的是Microchip的AT24C256和ST的M95640,一个是I2C接口,一个是SPI接口,容量从64Kbit到256Kbit不等,对配置参数来说绰绰有余。

3.1 I2C读写EEPROM的时序要点

AT24C256的I2C时序本身并不复杂,但有三个细节值得留意。第一个是写周期时间:AT24C256每写一页要等5ms左右(tWR),很多人第一次调I2C时发现数据写完立刻读回来不对,就是漏了等待写周期结束。用STM32的硬件I2C外设时,要正确利用I2C的事件中断来判断传输完成,不能在发送完停止条件之后立刻开读。用GPIO模拟I2C时,延时必须留足裕量。

第二个是页写边界:AT24C256的页大小是64字节,如果要写入的数据跨过了页边界,必须拆分成多次写操作,否则地址会自动回卷,把前面的数据覆盖掉。这是我调试时遇到过的典型问题:一个结构体刚好60字节,存在页尾,下一个字段从页边界后开始写,结果每次写入第一个字段都被莫名覆盖。

第三个是地址的16位拆分:256Kbit的EEPROM需要15位地址,I2C协议里分高字节和低字节两次发送。很多新手会漏掉高字节地址,导致写入位置不对。建议把所有EEPROM读写操作封装成统一的驱动接口,传入的地址都是16位整型,内部自动拆分,上层完全不用关心页边界。

3.2 配置参数写入防掉电损坏方案

工业现场最怕的不是写不进去,而是写了一半突然掉电。EEPROM写入过程中如果断电,可能造成一个字节损坏,更严重的是多字节结构体写入中断,导致配置参数内部状态错乱。我的方案是"双缓冲+校验标志"。

具体做法:EEPROM里划分两个区域,Region A和Region B,每个区域开头放一个标志字段和CRC校验值。写入时,先写Region B,写完校验通过后更新标志位;下次上电启动时,先读Region A,如果校验失败再读Region B。这样即使写入过程中掉电,最多损坏一个新区域,旧区域的数据永远是完整的。每次写入即切换活跃区,天然实现了磨损均衡,还能有效抵御"写一半掉电"的极端情况。

4. NOR Flash:固件和日志的中转站,擦除时间是个大坑

NOR Flash在工业控制器里承担的是"二级存储"的角色。相比EEPROM,它容量更大(常见8MB到64MB),读取速度快,支持XIP(片上执行),特别适合存放Bootloader和固件镜像。我常用的芯片是Winbond的W25Q128(16MB)和W25Q64(8MB),通过SPI接口连接。

4.1 SPI NOR Flash的读写架构与扇区规划

W25Q128的存储阵列按**块(Block)、扇区(Sector)、页(Page)**三个层级组织:一块64KB,一扇区4KB,一页256字节。擦除操作的最小单位是扇区,写入则是按页进行。设计时,我会把Flash规划成三个分区:

  • 分区一:Bootloader区,存放引导程序,上电最先执行,只读保护;
  • 分区二:固件运行区,存放主固件;
  • 分区三:日志区,做成环形覆盖的结构,循环写近期运行日志。

最常见的翻车点是擦除速度。W25Q128擦除一个扇区大概耗时40ms到400ms,擦除整块则可能达到700ms。第一次做OTA升级时,固件有4MB,如果用4KB扇区逐个擦除,总耗时接近10秒,升级过程中设备处于不可用状态,这在产线上完全不能接受。所以固件升级尽量用16KB甚至64KB的块擦除模式,并且把擦除和写入操作打成流水线:边擦除下一个扇区,边写入上一个扇区的数据,能省下将近一半时间。

4.2 掉电中断、磨损均衡与双备份设计

NOR Flash的擦写寿命大约在10万次,对于一个每天写100次日志的设备来说,两年多就会达到上限。因此日志区不能简单从头写到尾,我采用的是两个4KB扇区交替活跃(也叫Ping-Pong机制),每次写日志先擦掉不活跃的扇区,写新的,并记录序号。这样两个扇区的磨损是均匀的,寿命翻倍。

掉电保护方面,NOR Flash和EEPROM的问题不太一样。EEPROM按字节写,掉电顶多丢一两个字节;NOR Flash按页写,页大小256字节,写一半掉电可能让整页数据错乱。我的做法是在每条日志前加帧头标记和CRC校验,读取时发现帧头异常或CRC不匹配,就跳过这页,从下一个合法扇区继续读。这样做的代价是单条日志长度变长了,但对系统容错能力的提升是决定性的。

5. SD卡:大气象数据的归档仓库,文件系统是双刃剑

到了SD卡这一级,核心诉求变了。EEPROM和NOR Flash都是裸片,直接管理地址就行;SD卡则要面对文件系统。STM32上跑FATFS(FatFs文件系统模块)是主流方案,但文件系统一旦牵扯到掉电、拔卡、坏块,就会引出很多让人头疼的问题。

5.1 SDIO还是SPI模式,这是一个权衡

STM32访问SD卡有两种模式:SDIO模式和SPI模式。SDIO模式带宽高,能达到几十MB/s,但接线多(CLK、CMD、DAT0-DAT3共6根线),而且在电磁环境恶劣的工业现场,4线并行数据传输更容易受到干扰。SPI模式接线简单(MOSI、MISO、SCK、CS四根线),速度虽然只有SDIO的几分之一,但对大多数工业日志记录的带宽需求完全够用,我实测写1MB/s不成问题。

如果数据率需求确实超过2MB/s,我会选择SDIO模式,但会加厚PCB走线的包地处理,并且在CMD和CLK线上串联22欧姆电阻。另外,STM32F4系列的SDIO外设有几个版本bug,比如在DMA传输完成中断处理不及时时偶发FIFO溢出。我的建议是:能用SPI解决的需求,绝不轻易上SDIO;必须上SDIO时,传输数据块大小固定在512字节的整数倍,能有效绕开不少已知问题。

5.2 FATFS使用中的掉电保护和写性能

FATFS用起来顺手,但它默认对掉电没有太多防护。在工业控制器里,突然断电几乎是常态,文件系统最容易出问题的点有两处:一是FAT文件分配表被写坏,导致整个目录结构无法读取;二是正在写某个文件时掉电,文件大小和目录项不一致,产生损坏的"孤儿"文件。

我的处理方案有三条:

  1. 配置_FS_READONLY设为0,开启_FS_MINIMIZE到合理等级,确保支持f_sync和f_mount的重新挂载。
  2. 每写满一定数据量(比如64KB),调用一次f_sync,把缓存写入物理介质并更新目录项。这么做会牺牲一点写性能,但是换来了可控的数据一致性。如果不需要每次上电都从断电状态恢复,也可以改成在掉电前主动调用f_sync,但工业设备很难保证掉电前有充足的时间完成同步。
  3. 给文件系统加一个"健康标记":每次正常卸载时写入特殊标记;上电挂载时如果发现标记缺失,说明上次是非正常掉电,立即切换到"只读模式",拒绝继续写入,避免二次损坏。

5.3 SD卡的选型、供电和EMC抗干扰

SD卡选型上,我踩过不少坑。工业级SD卡(比如SLC颗粒的)比消费级贵很多,但掉电损坏的概率确实低不少。对于数据价值高的应用,别省这个钱。另外,SD卡的工作电压有3.3V和1.8V两种,STM32几乎都工作在3.3V,但很多SD卡在3.3V下可以工作,在2.7V以下就可能出现莫名其妙的写失败。给SD卡供电的电源芯片要有足够的纹波余量,我实测用AMS1117输出的3.3V在电机启停瞬间纹波能到200mV,SD卡写入偶发报错。后来改成单独的LDO加两级滤波,问题消失。

还有一个容易被忽视的问题:SD卡座的机械可靠性。在振动环境下,卡座簧片接触不良会导致通信错乱。我后来全部换成了带锁定装置的推拉式卡座,并且在做整机测试时,要专门做振动台的误码率测试,因为EMC问题在实验室静态测试时往往测不出来。

6. 实测中的坑:三个排查案例,每一步都值得复盘

这部分聊聊我在实际做这套分级存储方案时,踩过并最终解决的三个具体问题,希望给在做类似项目的朋友一个参考排查路径。

6.1 排查案例一:EEPROM首字节偶发错误

现象:设备上电读写EEPROM,偶尔发现第一个字节变成0xFF或者0x00,概率大概千分之一。

排查链路:第一步,用逻辑分析仪抓I2C波形,对比正常和异常时的时序。发现异常发生时,SCL上有一个多余的低脉冲,说明上电瞬间主机的SCL被外部干扰拉低了,触发了一次伪启动。第二步,检查I2C上拉电阻,发现上拉到3.3V的电阻用的是4.7k欧,电阻偏大,总线抗干扰能力弱。第三步,把上拉电阻改为2.2k欧,并在EEPROM的地址线、写保护引脚上各加一个小电容,问题得到明显缓解。根本原因是IMU附近电机驱动板的开关噪声耦合进I2C总线。测下来,加强总线驱动能力和上拉电阻,比在代码里加软件重试机制更治本。

6.2 排查案例二:NOR Flash擦写超时导致系统卡顿

现象:固件升级过程中,程序卡在Flash擦除步骤,看门狗复位。

排查链路:W25Q128的擦除命令发出了,但状态寄存器一直显示BUSY。用示波器抓SPI时钟和CS脚,发现erase命令发出后,程序没有正确等待BUSY信号清除,而是超时后直接进入了下一个操作,然后死锁。另一种可能性是SPI时钟频率太高。W25Q128擦除操作内部需要稳定电压,我把SPI时钟从18MHz降到9MHz后,问题不再复现。后来查阅芯片手册的参数,擦除命令对时钟频率确实有要求,不能简单越高越好。这个问题让我意识到:NOR Flash的SPI时钟并不是越高越好,擦除期间必须留足电压稳定时间。

6.3 排查案例三:SD卡在柜内EMC环境下频繁文件系统损坏

现象:整机做EMC测试时,ESD打在产品外壳上,SD卡偶尔出现文件系统损坏,数据丢失。

排查链路:一开始怀疑是电源问题,换了隔离电源后改善不明显。后来用仪器定位干扰路径,发现干扰是通过SD卡座的金属外壳耦合到数据线上的。解决措施:一是SD卡数据线加ESD保护阵列(比如USBLC6-2SC6,不一定要指定器件,但必须加);二是SD卡座的固定脚要和主地充分连接,不能浮空;三是整个SD卡区域下方铺完整的地平面,不跨分割区。做了这三项之后,同样测试条件下问题不再出现。这里想提醒一句:SD卡部分不能只当作"低速外设",它在高频通信时对PCB布局的要求,和高速差分接口是一个量级的。

7. 最后想说的几点

分级存储方案说难不难,说简单也不简单,它的本质是用架构思路解决可靠性问题,而不是靠某一颗芯片单打独斗。EEPROM、NOR Flash、SD卡各有各的特性,各有各的短板,把它们按数据特征组合起来,才是一条走得通的路。

从实测来看,这套方案的关键节点是:第一,分清楚每类数据的生命周期和写入频率,别让配置参数和日志挤在同一片介质里;第二,做好STM32和FPGA之间的数据流控制和背压机制,别让高速采集把存储系统冲垮;第三,对掉电场景做最坏的假设,双备份、CRC校验、健康标记这些东西,平时不起眼,关键时刻能救人一命;第四,EMC问题要从布局和器件选型上提前防护,等出了问题再去抓波形,成本往往已经很高了。希望这篇文章对正在做同类产品的朋友有帮助,也欢迎分享你们在设计存储子系统的经历和想法。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询