ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

工业控制器存储分级:EEPROM、NOR Flash、SD卡与STM32/FPGA

工业控制器存储分级:EEPROM、NOR Flash、SD卡与STM32/FPGA 这一篇接着聊工业控制器硬件设计。前面的文章把FPGA和STM32的职责边界、通信背板、IO扩展都捋了一遍这次轮到很多人一做到存储就含糊的地方——控制器里那股数据到底放哪的问题。早期我做第一版控制器时性价比极高地踩了个典型的坑参数、报警记录、历史曲线全塞进一颗大容量NOR Flash里逻辑上好像一块存储搞定一切实际上一跑起来全是毛病——频繁擦写把Flash寿命耗得飞快参数掉电丢失处理得战战兢兢等到要导出几个月的趋势数据才发现容量和文件系统完全跟不上。后来拆成EEPROM NOR Flash SD卡三级存储才算把这件事理顺。这篇文就把这套方案从选型、接口设计到驱动实现、掉电保护、磨损均衡的完整链路摊开讲涉及STM32、FPGA、EEPROM、NOR Flash、SD卡这套组合给准备做类似控制器或者在做毕业设计、项目实战的同仁一个可落地的参考。1. 为什么要分级存储工业数据的三种生命周期与对应介质1.1 参数到底该放哪EEPROM、NOR Flash、SD卡的分工逻辑工业控制器里跑的数据从生命周期和访问特征上看其实能分成非常清晰的三大类。第一类是配置参数类。比如PID整定值、IP地址、校准系数、运行模式。这类数据的特征是单条数据极小以字节或者几个字节为单位总量在几KB到几十KB封顶改写的频率不高一天可能也就几次但一旦丢失设备现场就得停机重配损失惨重。它们需要的是极高的可靠性、可预期的擦写寿命、简单的随机字节访问能力。第二类是运行状态与日志类。比如每次报警的事件记录、运行时长、开关机日志、操作审计记录。这类数据总量中等几十MB量级写入频率比参数高得多可能是每分钟几条甚至报警瞬间连续几十条。它们需要随机读写、中等擦写寿命而且最好支持掉电快速恢复。第三类是海量过程数据类。比如连续采集的电压电流波形、温度趋势曲线、故障前后的录波数据。这类数据的特点非常狠高速写入、容量大、需要按时间段查询和导出而且通常要离线分析。它们需要的是一块大的、方便移动的、有人能插拔拿走读的介质。第三类基本只有一个现实答案——SD卡。而这个判断标准出来以后前面两类的介质归属也顺理成章了参数类交给EEPROM容量小、按字节访问、擦写寿命长、掉电数据保持可达几十年。工业级EEPROM在-40°C到85°C范围里数据保持通常能到100年规格书上这么写的实际咱们按保守50年评估抗辐射能力和静电能力也比Flash强。状态日志和生产秒级数据交给NOR Flash容量几十MB到几百MB支持XIP片上执行、擦除粒度可以做到4KB扇区比NAND更耐操写入速度足够处理秒级日志。大容量连续记录交给SD卡几百MB到几十GB随便造还可以拔卡带走。这里有一个重点要正过来不是所有数据都适合分是不同数据对存储的物理约束天然不同。把参数和日志放一起、又和录波抢存储空间是嵌入式控制器最常见的存储混乱根源。分级不是堆三层硬件是给每类数据匹配它真正需要的存储约束。我用一张表把三类介质的特征对照放在下面方便选型时直接对号入座对比维度EEPROMNOR FlashSD卡典型容量2Kb ~ 1Mb4MB ~ 128MB512MB ~ 32GB以上擦写寿命100万次以上1万 ~ 10万次视制程和牌子取决于内部闪存管理通常几十万次以上访问粒度按字节读取按字节擦除按扇区/块按扇区512B写入速度慢约3~5ms/页页写几十μs擦除几百ms连续写几MB/s到几十MB/s掉电数据保持非常强强依赖文件系统和掉电保护策略适用数据参数、校准值、关键配置日志、运行记录、程序XIP录波、历史趋势、大数据导出1.2 STM32与FPGA在存储链路里的角色切分三级存储对应到主控侧就牵扯到STM32和FPGA的活儿怎么分。早期我看过不少方案是让STM32一个人扛所有存储接口——I2C读EEPROM、SPI读Flash、SDIO吃SD卡。这在数据量小、时序松的场景没问题但一旦跑起连续高速采集SPI总线吃满、CPU中断风暴、DMA和文件系统打架整个系统性能会非常难看。分级方案里我推荐的切法是EEPROM是纯配置通道可以从STM32直接管NOR Flash由FPGA做SPI主站承接SD卡走STM32的SDIO或者另一条SPI配合文件系统使用。理由很直白。EEPROM访问频率低STM32随便用两个GPIO模拟I2C或者复用I2C外设就够软件上使用轮询或者少量中断也毫无压力。NOR Flash这一层写日志通常意味着数据从传感器/ADC来经过FPGA预处理再入库。如果让STM32先从FPGA取数再写Flash等于把高速数据流绕了一个CPU的大圈实时性和CPU占用率都会很难看。FPGA本身就是干数据流的活儿让它直接接收ADC数据、拼装成日志帧、再推到NOR Flash的写状态机里这是顺路的事。SD卡这边由于涉及文件系统管理FAT类、目录项、各种元数据操作逻辑复杂、状态多这不适合放到FPGA的Verilog状态机里去硬怼让STM32跑文件系统是明智的。STM32处理完之后也可以把写文件A的第X扇区这个指令下给SD卡SD卡本身就有SDIO和SPI两种接口实测SPI模式降到25MHz时钟也有大约3MB/s的写入吞吐对工业日志记录够用了。所以最终存储架构是这样的STM32是管理大脑负责策略和文件系统FPGA是数据搬运干将负责高速数据流的NOR Flash入库EEPROM是现场记忆直接挂在STM32的I2C口上随时出没于掉电保存的瞬间。2. EEPROM层设计别让记参数这个动作成为系统短板2.1 选型参数怎么定容量、寿命和地址规划EEPROM的选型看着简单但其实有几个细节特别容易翻车。先说容量。做工业控制器参数总量得认真估算——把每路通道的满量程、零点、校准斜率、滤波系数、单位、启用标志全列出来按实际数据类型算字节数再乘以冗余量和服务用参数序列号、生产日期、装配校准状态通常4Kb到64Kb就覆盖绝大多数场景了。我常用的是一颗256Kbit32KB的工业级EEPROM够一整套多通道采集控制器用了还能留一半做掉电时关键变量的镜像区。寿命筛选EEPROM标准品擦写寿命一般是100万次。注意很多实际产品标的是整个芯片寿命而不是每个地址单元。单字节连续写和整页写磨损行为完全不一样。设计上要避免出现某个字节被高频写的局部磨损解决办法是参数区整体轮转后面我会讲双备份的时候细说。I2C地址规划EEPROM芯片通常会有一根到三根地址引脚允许在同一条I2C总线上挂多颗。做设计时一定要想清楚——同一条总线上还挂了谁。传感器、RTC、EEPROM地址要是冲突那调试的时候别提多酸爽了。常见EEPROM的基地址是0x507位地址RTC常见的是0x68比如DS3231或者0x32PCF8563很多温度传感器是0x48LM75系列。规划地址的时候先把整条总线所有器件的地址做成一张表再分配EEPROM的A2 A1 A0引脚。我见过有同学在板子上把两片EEPROM的地址引脚都接地结果总线挂了两颗同地址芯片读出来数据一高一低现场排查了两天才反应过来。写周期时间也是选型必看的参数——目前主流EEPROM页写时间大约5ms。这个值看起来不起眼但在掉电保存参数、写EEPROM不能让系统等太久的场景里它就是瓶颈所在。选tWR更短的型号有些能做到2.5ms或者干脆用写入完成后立刻进掉电流程的策略会显著改善控制器断电重启的速度体验。2.2 驱动细节页写、跨页拆分与WP引脚的正确用法EEPROM驱动看着就是I2C读写但真正写过多通道参数的小伙伴一定都踩过写入越写越乱的坑。九成的原因出在页写和跨页地址的处理上。大多数工业EEPROM的页大小是32字节或64字节。所谓页是指一次写操作允许连续写入的上限。你超了页边界器件会卷绕回页首覆盖数据不会帮你扩展到下一页。所以驱动里必须做自动拆分往任意地址写N个字节时先算出当前页还剩多少位置拆成一小段一小段写。简单描述这个问题的代码逻辑如下uint16_t page_size 64; // 取决于具体型号 uint16_t wbuf[128]; void eeprom_write_bytes(uint16_t addr, uint8_t *buf, uint16_t len) { while (len 0) { uint16_t page_room page_size - (addr % page_size); // 本页剩多少空间 uint16_t chunk len page_room ? len : page_room; // 拆分步长 i2c_start_cmd(...); i2c_send_byte(dev_addr | WRITE); i2c_send_byte(addr 8); i2c_send_byte(addr 0xFF); for (uint16_t i 0; i chunk; i) i2c_send_byte(buf[i]); i2c_stop_cmd(); delay_ms(EEPROM_TWR_MS); // 等内部写完成典型值 5ms addr chunk; buf chunk; len - chunk; } }这段代码虽然简单却回答了一个几乎必考的问题EEPROM驱动为什么不能直接for循环把数据全丢完。量大、地址不连续、跨页的时候拆分逻辑没写好轻则数据错乱重则EEPROM被写废个别型号连续超页写会破坏内部行缓冲。WPWrite Protect引脚值得多说一句。工业控制器最怕的是程序跑飞时对EEPROM一顿乱写把唯一的参数表冲掉。哪怕你MCU代码写得再自信也无法100%保证上电瞬间、电源不稳时I2C总线不误触发。常规的设计是让WP引脚默认拉高、只在执行参数写入的短时间内拉低void eeprom_enter_write(void) { GPIO_WriteBit(WP_PORT, WP_PIN, 0); // 解除写保护 } void eeprom_leave_write(void) { GPIO_WriteBit(WP_PORT, WP_PIN, 1); // 恢复写保护 }这个方案的实际收益非常大调试时程序反复异常重启EEPROM里数据从来没被冲掉过。过去不做保护的时候哪怕一个月只遇到一次意外写坏现场损失都远超这一点电路成本。2.3 掉电安全双备份与启动校验的真正做法EEPROM存储最容易忽视的问题就是写了一半掉电。工业现场电压波动、人拔电源、电源老化重启这些都不可控。写EEPROM的过程一旦掉电可能留下一个半新半旧、校验不过的参数区。业内成熟做法就是双备份。把参数区划分成Slot A和Slot B各存一份完整参数每条参数除了值字段还带CRC16校验和区。写入顺序是先写Slot B下一次生效等写完后写一个状态标记表示B已就绪主程序启动时读优先级最高的有效区。如果B写一半掉电CRC校验失败启动时自动回退到A区同时上报一个参数区回退告警而不是参数全丢。我习惯在EEPROM参数区的头部安排一个4字节的启动序号Boot Counter每次成功完成一遍双区刷新后递增。启动流程按如下逻辑判断读A区CRC通过则优先用A。若A区CRC失败继续读B区CRC通过则用B并自动从A区恢复数据。双区都失败载入出厂默认参数并置参数异常标志位。这套逻辑里Boot Counter非常重要它能区分正常双区一致和发生过回退。我见过有人只存两遍参数结果A/B各自因为掉电各坏了一半启动时两边CRC都不过直接进了默认参数模式现场设备参数悄无声息被重置——这比明显报错还要危险。EEPROM驱动还可以加一个细节写后读回校验。写完每一块后回读对照不一致立刻重写并累计重试计数。掉电、总线干扰导致的偶发写坏重试一次就能救回来重试超过3次就要上报硬件告警了。这块逻辑虽然增加几十行代码但对整机的参数可靠性提升非常明显。3. NOR Flash层的正确姿势FPGA主控的接口设计与磨损问题3.1 为什么NOR Flash这一层让FPGA来管NOR Flash放进工业控制器承担两类活一是放程序镜像、FPGA配置文件支持XIP掉电不丢二是放频次中等的日志记录。对于后者很多人的第一反应是STM32开个SPI读写不就行了吗。单看某一帧数据确实行但看整体数据流的时候就发现不对劲了。设想一个实时采集的工业控制器FPGA以100kHz的采样率从ADC收数据做数字滤波、阈值判断然后要写进Flash。如果让STM32来做搬运工就得FPGA把数据放进FIFO、拉一个中断通知STM32STM32进中断后DMA搬运到内存再开Flash写操作SPI时钟二十五兆忙忙碌碌——每一帧状态切换都要消耗CPU时间。等到STM32还要同时跑通信协议栈、人机界面、开环控制算法的时候这个搬运工角色就很吃力了。让FPGA直接承接NOR Flash主站的优势在这里数据写Flash完全在FPGA内部流水线里完成不占用STM32任何资源。FPGA里维护一个SPI主站外设、一个128深度FIFOSTM32只需要把日志帧的头部信息数据填充好推到FIFOFPGA自动完成NOR Flash的页编程时序写完后回一个完成标志。这是一个典型的任务解耦也是STM32FPGA方案在工业控制器里最核心的价值。实测下来这套方案在没有RTOS、单核STM32F407、主频168MHz的情况下同样一段50KB日志数据用STM32直接SPI写NOR Flash需要大约80ms的CPU忙占用而FPGA代劳后CPU侧只需要往FIFO塞数据大约15ms剩下全部是DMA在干活CPU可以干别的事。这个效率差异在高响应性控制任务现场是非常值钱的。3.2 SPI主站状态机与页编程时序FPGA里做一个NOR Flash SPI主站核心是一个按状态跳转的状态机外加一个写命令时序生成器。典型三层命令序列是这样的以常见的Winbond W25Q系列为例写使能发送0x06等Flash把状态寄存器里的WEL位置1。页编程发送0x02跟随24位地址和最多256字节数据。读状态寄存器0x05轮询BUSY位直到变0。在FPGA里实现时要注意的坑有两个。第一个是时钟极性极性和相位。W25Q系列在Mode 0和Mode 3下都能工作CPOL0/CPHA0或者CPOL1/CPHA1但FPGA作为主站一定要和从器件匹配。我习惯锁死在Mode 0所有时序都以SCK空闲为低电平为基准设计。第二个坑是状态机的等待逻辑。Flash页编程发起后需要轮询状态寄存器的BUSY位。这个轮询不能粗暴地靠延时凑数——因为不同批次、不同温度下的Flash擦写时间差异很大延时短了会误判完成延时长了浪费性能。正确的做法是页编程命令发出后循环发送读状态寄存器命令直到返回字节的bit0为0。一个简化但完整的FPGA顶层接口示意如下module spi_nor_flash_ctrl #( parameter CLK_DIV 16 // SPI 时钟分频系数 )( input wire clk, input wire rst_n, // CPU侧FIFO接口 input wire [7:0] tx_data_in, input wire tx_valid, output wire tx_ready, output wire write_done, output wire [31:0] dbg_state, input wire start_page_program, input wire [23:0] target_addr, input wire [7:0] page_buf_data[0:255], // SPI物理接口 output reg spi_cs_n, output reg spi_sck, output reg spi_mosi, input wire spi_miso );实际使用时FPGA内部可以维护一个环形页缓冲区STM32把一页数据填好再触发一次页编程命令。配合双缓冲交替可以达到写Flash的同时继续收下一帧数据的效果让写入吞吐不被等待时间打断。3.3 磨损均衡与伪坏块的真实处理经验NOR Flash的额定擦写寿命通常在1万到10万次之间——听上去不少但日志型写入不均衡时一个热区可能几天就被写穿了。磨损均衡Wear Leveling是NOR Flash作为日志存储必须考虑的问题。我的实践经验是把NOR Flash分成三个区头16KB留给启动代码和生产校准信息只读区中间一部分是参数镜像和配置映射区低频率改写剩下的70%做成日志环形区。日志环形区按扇区做顺序写入每256页即每个4KB扇区写满后自动跳到下一个扇区。等到写满整个环形区再从头擦除使用。这样一个25MHz的FPGA SPI口、4MB的NOR Flash按每秒钟写一条512字节记录来算寿命能到百万条记录以上足够覆盖一台控制器好多年的日志需求。真正的坑出现在伪坏块上。控制器运行中突然断电正在执行擦除或页编程的NOR Flash扇区会变得半擦半写。个别Flash在这个状态下会返回编程失败。第一次遇到时我很慌以为是Flash芯片体质差后来查了W25Q系列的规格书和数据手册才搞清楚只要在擦除后重新写入前做一次全扇区擦除这个扇区往往能完全恢复。所以FPGA端的Flash写状态机里一定要有擦除重试逻辑页编程失败。对目标扇区执行擦除。重新写入。连续失败3次以上才标记为坏扇区并跳过。这个策略在实际生产环境里能把闪存损坏率降到极低。因为工业现场的掉电不是罕见事件那个伪坏块排查过程是真的花了我一整天所以特别想分享出来。再有就是NOR Flash的写保护寄存器。很多型号上电后默认状态是写保护开启的比如W25Q的CMP位、BP0-BP3位限制某些地址区不可写。FPGA控制或STM32控制都必须在每次上电初始化流程里先解锁写保护再写日志。少做这一步日志区写到某个扇区就开始静默失败项目现场要查很久。4. SD卡层大容量存储的便利与工业环境的不便4.1 文件系统选型FAT的妥协与代价到了大容量历史数据这一层SD卡是最实用的载体。但在工业控制器里直接上FAT文件系统其实是一个充满妥协的决定。SD卡内部控制器已经做了Flash管理包括磨损均衡和坏块映射所以SD卡寿命反而不是最大的短板。最大的短板是FAT文件系统掉电一致性极差。控制器正在持续写文件突然掉电FAT表、目录项可能处于中间状态轻则当前文件损坏重则目录链断裂导致整个分区在Windows上弹出需要格式化。我的方案是文件系统照用FAT但把掉电安全从文件系统层面搬到了应用协议层面。具体干法分为三步第一日志文件采用固定大小分块比如每块4MB。当前活动日志写入REC0001.BIN写满后自动改名成ARCH0001.BIN同时新建REC0002.BIN。这样即使掉电最多损失当前写法中的那一条记录之前那些完整块的目录项在改名过程中是原子的几乎不会坏。第二每次写完一条记录就主动执行一次f_sync()强制把文件buffer刷进SD卡物理扇区。这会显著降低写吞吐但换回来的是掉电后最多丢当前这一条记录。工业日志对吞吐要求低、对可靠性要求高值得。第三除了FAT之外我在SD卡保留了一个小的损坏恢复索引区。每写满一块时往这个索引区记一条本块从逻辑记录号X到Y的映射。上电时如果发现FAT目录异常可以直接从索引区恢复出哪一块是完整的、哪一块可能残缺。这个设计帮我从SD卡拔出来数据损坏一大片的泥潭里跳出来了很多次。顺便提一句FAT的簇大小要选对。工业SD卡普遍是8GB到32GB如果格式化成默认的64KB簇那么一条512字节的日志记录会占掉64KB有效空间浪费率超过99%。正确的做法是把每个分区保持在2GB以内用FAT16或者小簇FAT32簇大小设置为4KB。这样同样容量能存的记录数量多得多而且FAT表也小读目录速度快很多。SD卡量产格式化的时候我会专门写一个批处理保证每张卡都按这个规范来。4.2 SPI模式和SDIO模式的取舍与信号完整性SD卡物理接口有SDIO和SPI两种模式。SDIO带宽高但接线多DAT0-DAT3、CLK、CMD、电源、地驱动复杂度也高SPI模式只有MOSI、MISO、SCK、CS四根线驱动逻辑简单协议简单可靠但在4线SDIO面前带宽要低不少。工业控制器写日志速度要求通常没那么夸张——每秒写几条记录每条512字节到1KB每秒总写入量几KB而已。这种情况下我强烈建议用SPI模式。SPI模式有三大好处一是引脚少PCB布线压力小二是STM32的SPI口可以直接跑不需要专门的SDMMC外设三是SPI协议时序更简单问题排查容易。实测STM32F4的SPI工作在25MHz实际受限于GPIO翻转速度SD卡端可能降到12MHz连续写SD卡大约能到3MB/s这比工业现场最激进的需求还省富余。真要把吞吐推到SDIO模式比如要用控制器直接记录高速波形、4条通道20kHz采样16位每秒就是160KB的数据量SPI模式就吃力了。这时候启用SDIO的4位模式是必要的。但启用SDIO的同时信号完整性问题就浮现出来最典型的是SD卡座和卡本身接触不良。工业设备有振动SD卡座接触弹片在振动下容易瞬时断开结果就是CRC错误、数据错乱。解决手段有三个选带锁扣的推推式卡座而不是廉价的翻盖式或压入式卡座。SDIO的CLK、CMD、DAT线各加33Ω串联电阻并在卡座侧加一个小电容滤波。关键项目做整机振动测试实测判断到底要不要加额外的机械固定支架。我有一块早期板子卡座用的是翻盖式一到有振动环境的现场就报SD卡初始化失败后来换成推推式卡座弹簧片支撑故障立刻消失。这个坑看起来是软件问题根子其实在机械结构。4.3 拔卡、掉电与目录破坏文件系统级防御策略工业控制器最让人头疼的另一个场景是维护人员直接拔SD卡。SD卡协议设计上支持热拔插但文件系统并不支持写一半被拔走。FAT文件系统在写操作中间被拔卡错误甚至比掉电更严重。防御的第一道防线是硬件写保护开关。大部分SD卡适配器和卡座都有写保护口软件上读这个状态位如果处于只读状态控制器禁止任何写操作。这个最简单也最有效。第二道防线是写访问互斥。在控制器代码里写入SD卡时用一个全局标志SD_CARD_BUSY用户界面若检测到该标志就显示存储忙碌请勿拔卡。这看起来像笨办法但它是唯一能阻止非技术用户在手忙脚乱时拔掉正在写入的卡的办法。我在HMI上加了这一条后现场存储丢失投诉骤降。第三道防线是目录项的双份冗余。很多精简FAT实现不支持FAT1/FAT2互为镜像它们在标准FAT规范里本来就是双份但部分嵌入式实现只写了FAT1或写了两份但坑道没对齐。选型FAT库时尽量选那些遵循FAT规范的、真正写双FAT的实现。Lexin的FatFs默认双FAT都写被广泛验证过工业上用它比较多。如果自己做文件系统切记把FAT1和FAT2作为独立两个区域对待不要共用缓冲区乱写。实际操作上FatFs的配置项FF_FS_TINY和FF_FS_LOCK值得认真调。Tiny模式减少SRAM用量LOCK开启后允许应用程序打开多个文件句柄。但注意打开文件句柄数越多掉电后恢复的一致性风险越高。控制器除非必要否则绝对不要同时打开两个以上文件写。这个教训来自一次自己写的多通道记录逻辑4个文件同时写掉电后几乎是100%损坏。防御策略里还有一个容易被忽略的细节——上电自检要扫描SD卡上最近文件的文件头和文件尾魔数。每次上电后读最后一块的末尾检查是否有本块结束标记没有则说明上次写操作被中断把这个文件标记为可能截断下次写入时从最后一个完整块之后续写而不是直接在文件尾追加这会造成中间空洞文件系统读起来没问题但数据分析时会有黑洞。这个续写检测逻辑虽然只有几十行代码却是把SD卡应用从可以跑提升到能在现场可靠跑的关键一步。5. 数据流的完整通路与整机掉电时序设计三个存储层各自讲完了把整条数据通路串起来看一遍很多单层看不出的问题就暴露了。正常运行时控制器的主数据流是这样的ADC持续采样送入FPGAFPGA做实时数据处理后一路把实时状态通过总线发给STM32用于显示和通信另一路在FPGA内部把数据按日志帧格式拼好写入NOR Flash的日志区。每条日志帧在NOR Flash里积累到一定量比如1MB后由STM32把这段数据读出并转存到SD卡的归档文件里。EEPROM里的参数只在上电、配置修改、掉电前这几个关键时刻参与。这个多级缓存的架构对应了物理介质的特性NOR Flash负责突发性记录SD卡负责长期归档。即便SD卡出现故障或者被拔出NOR Flash至少能保证最近几个小时的数据不丢。拔卡维护后重新插卡系统能自动把NOR Flash里的记录补归档到SD卡里。整机掉电时序是存储设计里最后一道关键流程。控制器检测到掉电信号比如电源监控芯片拉低INT后按照优先级顺序执行立即停止数据采集和通信保存CPU寄存器和关键变量。把当前FPGA的FIFO剩余数据排出到NOR Flash时间窗口约几十ms。把关键运行参数写入EEPROM双区。关闭SD卡当前文件写目录项执行f_sync。关中断进入最深度睡眠或复位。这个流程每一项都要严格计算耗时。例如EEPROM写32字节需要大约10msNOR Flash写完残留的1KB日志需要大约20msSD卡写一条带sync的日志需要约30ms。整机从检测到掉电到完成全部保存动作大约60到80ms。如果掉电检测滞后或者电源掉电斜率太陡、还没有保存完就断电了所有努力都会白费。我的经验是掉电检测不要直接接MCU的供电轨要用一个独立的电源监控芯片或者比较器监测的是输入侧的直流母线电压电压掉到阈值比如正常值的85%立刻触发。这样能争取到几十到几百毫秒的黄金时间对于上述整个掉电保存流程是决定性的。另外掉电时SD卡写操作要有一个提前量设计。我习惯在正常运行中每30秒做一次背景sync确保当前文件的FAT表不是长期停留在缓冲而未落盘的状态。真实发生过调度不当、掉电时候FAT表数据还悬在SRAM里的悲剧。定期sync看似多花了点时间但极大压缩了掉电时必须做的SD卡工作量。这样完整走一圈从哪个数据放哪到掉电时怎么保数据整条存储链路的逻辑就自洽了。这套分级存储方案经过固件迭代和现场验证在温度、振动、掉电多重折磨下的稳定表现验证了当初分层的判断是值得的。最后分享一个具体的调试心得我在整机驱动里为每一层都加了独立的健康状态寄存器分别是EEPROM_ERR_CNT、NOR_ERR_CNT、SDCARD_ERR_CNT。每次发生写失败、重试、回退都会累加。设备维护时把这个健康值读出来可以直观判断哪一层存储正在濒临寿命极限提前换件而不是等到现场彻底罢工再救火。这个寄存器组只要几十字节堪称整条存储链路里最划算的投资。
返回列表