1. 工业控制器存储方案的整体设计思路
做过工业控制器的人都有一个共识:数据存储这件事,看起来简单,真到落地的时候坑特别多。你可能会想,不就是存个数据吗,挂个EEPROM或者SD卡不就完了?但工业现场的要求跟消费电子完全不是一个量级——掉电不能丢参数、日志要能追溯半年以上、固件升级包得能本地缓存、还要考虑振动、高低温、电磁干扰这些恶劣条件。单一存储介质根本扛不住这种多维度的需求,所以分级存储几乎是工业控制器绕不开的架构选择。
我这次做的方案是STM32加FPGA的异构架构,存储介质分了三级:EEPROM负责关键参数和校准数据,NOR Flash负责固件备份和启动配置,SD卡负责大容量日志和升级包缓存。为什么这么分?核心逻辑就一条——按数据的生命周期和访问频率来匹配介质的特性。EEPROM写入寿命长、字节级擦写方便,适合存那些不常改但绝对不能丢的参数;NOR Flash支持XIP(eXecute In Place),可以存FPGA的配置文件和STM32的固件备份,读取速度快、可靠性高;SD卡容量大、成本低,适合存日志这种写入频繁但单条价值不高的数据。
这个分级思路不是拍脑袋想出来的。我早期做过一个项目,所有数据都往SD卡里塞,结果现场跑了三个月,SD卡文件系统直接崩了,参数全丢,客户产线停了半天。后来复盘发现,SD卡在频繁小数据写入场景下的寿命和稳定性远不如EEPROM和NOR Flash。从那以后我就坚定了分级存储的路线。
STM32和FPGA在这个架构里的分工也很明确。STM32作为主控,负责系统调度、通信协议处理和文件系统管理;FPGA负责高速数据采集和预处理,同时通过SPI接口直接访问NOR Flash,实现快速启动配置加载。两者之间通过FSMC或SPI通信,STM32把FPGA采集的数据打包后写入SD卡,同时把关键状态参数同步到EEPROM。
注意:分级存储的核心不是“多挂几个存储芯片”,而是要根据数据的写入频率、生命周期、可靠性要求和访问速度来分配介质。分配错了,再好的硬件也白搭。
2. 三级存储介质的选型依据与核心参数
2.1 EEPROM:关键参数的保险箱
EEPROM选的是ST的M24C64,64Kbit容量,I2C接口,100kHz到400kHz速率可调。为什么选它?几个硬指标:擦写寿命100万次,数据保持40年,工作温度范围-40到85度,工业级。这些参数看着普通,但放到工业现场就是刚需。你想想,一个参数可能每天改几次,一年下来几千次,普通Flash早就挂了,EEPROM还能扛。
I2C接口的好处是引脚少,两根线搞定,PCB布线简单。但坑也在这里——I2C总线上如果挂多个设备,地址冲突和总线锁死是常见问题。我的做法是EEPROM单独走一路I2C,不跟其他低速外设共享,避免互相干扰。地址引脚A0-A2全部接地,设备地址固定为0xA0,简单粗暴但稳定。
写入策略上,我没有用页写入模式,而是逐字节写入。为什么?页写入虽然快,但一旦在写入过程中掉电,整页数据可能全部损坏。逐字节写入虽然慢一点,但每次只影响一个字节,配合双备份机制(同一参数存两个地址,读取时校验),可靠性高得多。实测下来,写一个32字节的参数结构体大概需要15ms,对于工业控制器的参数更新频率来说完全够用。
2.2 NOR Flash:固件与配置的可靠仓库
NOR Flash选的是Winbond的W25Q128,128Mbit容量,SPI接口,支持最高104MHz时钟。这颗芯片在工业领域用得很多,主要是因为它支持XIP,FPGA可以直接从NOR Flash读取配置数据,不需要先搬到RAM里。对于FPGA来说,启动配置文件的加载速度直接影响系统上电时间,XIP模式能省掉搬运环节,上电到FPGA开始工作的时间能压缩到200ms以内。
NOR Flash的分区规划很关键。我把128Mbit分成四个区:前16Mbit存FPGA配置文件,接下来16Mbit存STM32固件备份,再32Mbit存系统配置和校准数据,最后64Mbit留给历史数据归档。每个区都有独立的擦除和写入策略,互不干扰。分区表存在NOR Flash的第一个扇区,上电时STM32先读分区表,再根据分区表加载对应数据。
SPI接口的时序配置也有讲究。W25Q128支持Mode 0和Mode 3,我选的是Mode 0(CPOL=0,CPHA=0),因为STM32的SPI外设在Mode 0下最稳定。时钟分频设置为2分频,STM32F4系列的主频168MHz,SPI时钟84MHz,实际测试下来读写都稳定。如果你用的是F1系列,主频72MHz,SPI时钟36MHz,也没问题。
2.3 SD卡:大容量日志的性价比之选
SD卡选的是工业级MicroSD卡,8GB容量,Class 10速度等级。为什么不用消费级的?工业级卡在控制器固件层面做了磨损均衡和坏块管理,寿命比消费级卡长得多。消费级卡在频繁写入场景下,可能几个月就出现坏块,工业级卡能扛几年。
SD卡的接口模式有两种:SDIO和SPI。我选的是SDIO 4位模式,理论速度能到48MHz,实际写入速度在10MB/s左右。SPI模式虽然引脚少,但速度慢,只有几MB/s,对于日志写入来说勉强够用,但如果你要存高速采集数据,SPI模式就是瓶颈。SDIO的坑在于PCB布线要求高,CLK、CMD、DAT0-DAT3这六根线要等长,阻抗控制在50欧姆,否则高速通信时容易出错。
文件系统用的是FatFs,R0.14版本。为什么不用LittleFS或SPIFFS?因为SD卡经常需要插到电脑上读取日志,FatFs兼容性最好,Windows、Linux、macOS都能直接识别。LittleFS虽然掉电安全性更好,但需要专门的工具才能读取,现场维护不方便。FatFs的掉电安全问题通过定期同步(f_sync)来缓解,每写100条日志调用一次f_sync,把缓存刷到卡里,最多丢100条,对于工业日志来说可以接受。
3. STM32与FPGA的存储访问架构实现
3.1 硬件连接与总线分配
STM32和FPGA之间的通信走的是FSMC(Flexible Static Memory Controller)总线,STM32作为主机,FPGA作为从机。FSMC的好处是速度快,16位数据总线,地址和数据复用,理论带宽能到100MB/s以上。FPGA内部实现了一个双口RAM,STM32通过FSMC直接读写这个RAM,实现数据交换。
存储介质的连接是这样的:EEPROM挂在STM32的I2C1上,NOR Flash挂在STM32的SPI2上,SD卡挂在STM32的SDIO接口上。FPGA通过SPI1直接访问NOR Flash,用于加载配置文件和读取校准数据。为什么FPGA要单独走一路SPI?因为FPGA的配置加载需要在STM32启动之前完成,如果共用SPI2,STM32还没初始化,FPGA就没法加载配置。所以SPI1专门给FPGA用,STM32不干预。
电源设计上,EEPROM和NOR Flash用3.3V供电,SD卡用3.3V但需要额外的去耦电容,因为SD卡在写入时电流波动比较大,不加电容容易导致电压跌落,写入失败。我在SD卡电源引脚旁边放了两个10uF的钽电容和一个0.1uF的陶瓷电容,实测写入稳定性提升明显。
3.2 STM32端的存储驱动实现
STM32端的存储驱动分三层:底层硬件驱动、中间层设备抽象、上层应用接口。底层驱动直接操作寄存器或调用HAL库,中间层把不同存储介质统一成统一的读写接口,上层应用不用关心具体是EEPROM还是SD卡,调用统一的API就行。
EEPROM的驱动比较简单,I2C读写函数封装好就行。关键是写入超时处理,M24C64的写入周期是5ms,写入后需要轮询ACK或者延时等待。我用的方法是写入后延时6ms,再读回来校验,如果校验失败就重写,最多重试3次。这个逻辑虽然简单,但实测下来比轮询ACK更稳定,因为工业现场干扰大,ACK信号可能被噪声淹没。
NOR Flash的驱动复杂一些,需要处理扇区擦除、页写入、状态轮询。W25Q128的扇区是4KB,页是256字节。写入前必须先擦除,擦除一个扇区需要约50ms。我的做法是维护一个写入缓存,攒够4KB再擦除写入,减少擦除次数。但这样有个风险——掉电时缓存数据丢失。所以缓存里的数据同时会在EEPROM里存一份索引,上电时根据索引恢复未完成的写入。
SD卡的驱动用FatFs,底层是SDIO。SDIO的初始化流程比较长,需要发送CMD0、CMD8、ACMD41、CMD2、CMD3等一系列命令,每一步都要检查响应。我踩过的坑是CMD8的电压检查,如果SD卡不支持2.7-3.6V电压范围,CMD8会返回错误,这时候需要回退到SD 1.x协议。工业级卡一般都支持,但消费级卡不一定,所以代码里要做兼容处理。
3.3 FPGA端的NOR Flash直接访问
FPGA访问NOR Flash的目的是快速加载配置文件和读取校准数据。FPGA内部实现了一个SPI主机控制器,用Verilog写的,支持Mode 0,时钟分频可配置。上电后,FPGA首先发送0x03命令(Read Data)读取NOR Flash的第一个扇区,解析分区表,然后根据分区表加载配置文件到内部RAM。
SPI主机控制器的状态机设计是关键。我用了三段式状态机:IDLE、CMD、DATA、DONE四个状态。IDLE状态下等待启动信号,CMD状态下发送命令和地址,DATA状态下接收数据,DONE状态下拉高完成信号。时钟分频通过一个计数器实现,输入时钟50MHz,分频系数设为4,SPI时钟12.5MHz。这个速度对于配置加载来说够用了,加载16Mbit的配置文件大概需要1.3秒。
注意:FPGA访问NOR Flash时,STM32不能同时访问,否则SPI总线冲突。我的做法是在FPGA访问期间,STM32把SPI2的CS拉高,禁止访问。两者通过一个GPIO信号握手,FPGA开始访问前拉低请求信号,STM32释放总线后拉低应答信号,FPGA检测到应答后才开始SPI通信。
4. 分级存储的数据调度与掉电保护策略
4.1 数据分类与存储路由
数据分类是分级存储的第一步。我把系统数据分成四类:关键参数、系统配置、运行日志、升级包。关键参数包括校准系数、PID参数、设备ID等,这些数据写入频率低但绝对不能丢,存EEPROM。系统配置包括通信协议参数、IO映射表等,写入频率中等,存NOR Flash。运行日志包括传感器数据、报警记录、操作记录,写入频率高,存SD卡。升级包是固件升级文件,写入频率极低但容量大,存SD卡。
存储路由的实现是在应用层做一个路由表,根据数据类型选择对应的存储介质。路由表存在NOR Flash里,上电时加载到RAM。每次写入数据时,先查路由表,再调用对应的驱动函数。这个设计的好处是灵活,如果以后要调整存储策略,只需要改路由表,不用改代码。
4.2 掉电检测与数据保护
掉电保护是工业控制器的生命线。我的方案是两级掉电检测:第一级是电源电压监测,用STM32的ADC监测24V输入电压,当电压低于18V时触发掉电中断;第二级是超级电容储能,在掉电后维持系统运行约200ms,足够完成关键数据的保存。
掉电中断的处理流程是这样的:检测到掉电后,立即停止所有非关键任务,把EEPROM的写入缓存刷到芯片里,把NOR Flash的写入缓存刷到芯片里,SD卡调用f_sync同步文件系统。整个过程需要在200ms内完成,所以缓存不能太大。我的EEPROM缓存是64字节,NOR Flash缓存是256字节,SD卡缓存是512字节,实测下来150ms左右能完成。
超级电容的选型也有讲究。我用的是5.5V 1F的法拉电容,配合一个升压电路,在掉电后把电压稳定在3.3V。法拉电容的容量计算是这样的:系统功耗约200mA,需要维持200ms,所需电荷量Q=0.2A×0.2s=0.04C,电容电压从5.5V降到3.3V,可用电压差2.2V,所需容量C=Q/ΔV=0.04/2.2≈0.018F。1F的电容远远够用,留了足够的余量。
4.3 数据校验与恢复机制
数据校验用的是CRC32,每个数据块写入时计算CRC,读取时校验。如果CRC不匹配,说明数据损坏,触发恢复机制。恢复机制分两种情况:如果是EEPROM数据损坏,从备份地址读取;如果是NOR Flash数据损坏,从SD卡的备份文件恢复;如果是SD卡数据损坏,从NOR Flash的历史归档恢复。
双备份机制在EEPROM上用得最多。每个关键参数存两个地址,地址A和地址B,写入时先写A再写B,读取时如果A的CRC正确就用A,否则用B。如果A和B都损坏,就用默认值,并记录一条报警日志。这个机制虽然简单,但实测下来能解决90%以上的数据损坏问题。
5. 实操过程中的常见问题与排查技巧
5.1 EEPROM读写失败排查
EEPROM读写失败是最常见的问题,原因通常有三个:I2C总线锁死、设备地址错误、写入超时。I2C总线锁死表现为SCL被拉低,SDA一直高电平,这时候需要发送9个时钟脉冲解锁。设备地址错误通常是A0-A2引脚接错,用示波器看I2C波形,如果地址字节不对,就是引脚问题。写入超时一般是延时不够,M24C64的写入周期是5ms,但工业级芯片在低温下可能延长到10ms,所以延时设15ms比较保险。
我遇到过一个奇葩问题:EEPROM在高温下写入失败。后来查资料发现,M24C64的写入周期在85度时会延长到10ms,我原来的延时是6ms,不够。改成15ms后问题解决。所以工业级应用一定要看数据手册的温度特性曲线,不能只看常温参数。
5.2 NOR Flash擦除失败排查
NOR Flash擦除失败通常表现为状态寄存器一直忙,或者擦除后数据不是0xFF。原因可能是SPI时序不对、电源电压不稳、芯片损坏。SPI时序问题用逻辑分析仪抓波形,看CLK、MOSI、MISO的相位关系,Mode 0要求CLK空闲低电平,第一个边沿采样。电源问题用示波器看VCC引脚,擦除时电流会增大,如果电压跌落超过0.3V,就会导致擦除失败。
我踩过的坑是SPI时钟太快。W25Q128标称支持104MHz,但实际在80MHz以上时,如果PCB走线不好,就会出现误码。后来把时钟降到42MHz,问题解决。所以标称参数是理想条件下的,实际应用要留余量。
5.3 SD卡写入失败排查
SD卡写入失败的原因比较多:文件系统损坏、卡寿命到期、电源不稳、SDIO时序问题。文件系统损坏用chkdsk修复,或者重新格式化。卡寿命到期看写入速度,如果写入速度明显下降,或者出现坏块,就要换卡。电源问题加电容,SDIO时序问题调整时钟分频。
我遇到过一个诡异问题:SD卡在低温下写入失败。后来发现是卡的工业级温度范围是-25到85度,我用的卡是-10到70度,低温下性能下降。换成宽温卡后问题解决。所以选卡的时候一定要看温度范围,别只看容量和速度。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| EEPROM读写失败 | I2C总线锁死 | 示波器看SCL/SDA | 发送9个时钟脉冲解锁 |
| EEPROM写入超时 | 延时不够 | 查数据手册温度特性 | 延时改为15ms |
| NOR Flash擦除失败 | SPI时序不对 | 逻辑分析仪抓波形 | 调整Mode和时钟分频 |
| NOR Flash数据错误 | 时钟太快 | 降低SPI时钟测试 | 降到42MHz |
| SD卡写入失败 | 电源不稳 | 示波器看VCC | 加10uF钽电容 |
| SD卡低温失败 | 卡温度范围不够 | 查卡规格书 | 换宽温卡 |
| 掉电数据丢失 | 超级电容容量不够 | 计算功耗和维持时间 | 换1F法拉电容 |
| 文件系统损坏 | 未同步就掉电 | 检查f_sync调用频率 | 每100条日志同步一次 |
提示:工业现场的问题往往不是单一原因,而是多个因素叠加。比如SD卡写入失败,可能是电源不稳加上时序不对,再加上卡寿命到期。排查的时候要一个一个排除,别想着一步到位。
6. 性能实测与优化经验分享
6.1 各介质读写速度实测
EEPROM的写入速度实测下来,单字节写入约5ms,32字节结构体写入约15ms,读取速度约1ms。NOR Flash的页写入速度约0.7ms每256字节,扇区擦除约50ms,读取速度约0.1ms每256字节。SD卡的写入速度约10MB/s,读取速度约20MB/s。这些数据是在常温下测的,低温下会有所下降,EEPROM和NOR Flash下降约20%,SD卡下降约50%。
从数据可以看出,EEPROM适合存小数据,NOR Flash适合存中等数据,SD卡适合存大数据。分级存储的意义就在这里——把合适的数据放到合适的介质上,整体性能最优。
6.2 系统上电时间优化
系统上电时间直接影响客户体验。我的优化目标是上电到系统就绪控制在500ms以内。实际测下来,FPGA配置加载约200ms,STM32固件启动约100ms,EEPROM参数加载约50ms,NOR Flash配置加载约100ms,总共约450ms。SD卡不参与上电加载,因为日志和升级包不需要立即读取。
优化上电时间的关键是并行加载。FPGA配置加载和STM32固件启动可以并行,EEPROM和NOR Flash的加载也可以并行。我的做法是STM32启动后立即触发FPGA配置加载,同时自己加载EEPROM参数,两者互不干扰。这样能把上电时间压缩到300ms左右。
6.3 长期运行稳定性测试
长期运行稳定性是工业控制器的核心指标。我做了连续30天的老化测试,每天写入10万条日志,擦写EEPROM 1000次,擦写NOR Flash 100次。测试结果:EEPROM无坏块,NOR Flash无坏块,SD卡出现2个坏块但被控制器自动替换,文件系统正常。数据校验全部通过,无数据丢失。
这个测试结果说明分级存储方案是可靠的。但要注意,SD卡的坏块是不可避免的,工业级卡虽然寿命长,但长期高频写入还是会出坏块。所以日志文件要定期归档,把旧日志从SD卡转移到NOR Flash或外部服务器,减少SD卡的写入压力。
6.4 成本与可靠性平衡
分级存储方案的成本比单一大容量存储要高,但可靠性提升明显。EEPROM约2元,NOR Flash约8元,SD卡约30元,总共约40元。如果只用SD卡,成本约30元,但可靠性差很多。对于工业控制器来说,40元的存储成本完全可以接受,因为现场停机的损失远不止40元。
我的经验是,存储方案的成本要算总账,不能只看器件成本。EEPROM和NOR Flash的可靠性高,能减少现场维护次数,降低售后成本。SD卡容量大,能减少数据归档频率,降低人工成本。综合下来,分级存储的性价比是最高的。
7. 方案扩展与后续优化方向
这个方案目前跑在STM32F407加Xilinx Spartan-6的平台上,后续可以考虑升级到STM32H7加Zynq,性能会有大幅提升。STM32H7的SDIO支持更高时钟,写入速度能到30MB/s以上;Zynq的PS端直接支持SD卡和NOR Flash,PL端可以硬件加速CRC校验和磨损均衡算法。
另一个优化方向是引入文件系统的掉电保护机制。FatFs本身不支持掉电保护,但可以结合日志式文件系统的思路,在写入前先写日志,掉电后根据日志恢复。这个改动比较大,但能进一步提升SD卡数据的可靠性。
还有一个方向是增加无线传输模块,把日志实时上传到云端。这样SD卡只做本地缓存,数据主要存在云端,SD卡的写入压力会小很多。但无线传输的可靠性在工业现场是个问题,需要做冗余设计。
我个人在实际操作中的体会是,分级存储方案的核心不是硬件堆砌,而是数据分类和调度策略。硬件选型只要满足工业级要求就行,关键是软件层面要把数据管好。数据分类清楚了,调度策略合理了,系统自然就稳定了。踩过几次坑之后,我越来越觉得,工业控制器的存储设计,七分靠软件,三分靠硬件。软件做得好,普通硬件也能跑出高可靠性;软件做得差,再好的硬件也白搭。