资讯动态

STM32+FPGA架构下的分级存储方案:EEPROM、NOR Flash与SD卡的设计取舍与掉电保护

发布时间:2026/9/27 1:57:35 来源:尧图企业网站定制
1. 数据分级的依据三类数据对存储介质的要求完全不同1.1 设备参数、固件、日志先分清谁容易丢、谁容量大、谁寿命短工业控制器里需要保存的数据表面上看都一样是“往存储器里写东西”实际上拆开看它们的要求完全相反。我自己在做这块的时候把要存的东西分成三类每一类的保存逻辑都不一样。第一类是设备参数。温度补偿系数、PID 参数、IP 地址、通道使能配置、校准数据这些加起来往往还不到 1KB。特征很明确单次数据量极小但修改频率可能很高而且每一次修改都要求在掉电瞬间能立刻保住。它最怕的是“写了半个字节就没电了”其次是“写坏了还不知道下次上电读出个野值”。这类数据对应的存储介质必须是按字节或者按小页可写的必须有确定的写周期最好还能做到掉电瞬间完成写入。第二类是固件和配置文件。一个固件 bin 少说几百 KB多的几 MB通过 Bootloader 从 SD 卡或者上位机拿过来然后放到外部 Flash 里。平时几乎不写但只要写就是大块、连续、必须一次成功。最怕的是擦到一半断电导致引导区损坏或者 Flash 擦写次数到了导致某个扇区变成“只读”甚至“写不进也读不出”。这类数据的核心诉求是容量适中、随机读速度快、支持扇区擦除并且愿意牺牲一部分擦写寿命来换取可靠性和简单性。第三类是运行日志。采集终端连续跑几天每秒钟可能就有几十条记录一条记录如果是几十个字节一天下来就是几百 MB 的量。这类数据量最大、价值密度最低、但持续时间最长。工业现场要求它“能存得下、坏了能换、格式化之后继续跑”但允许丢失最后一两条允许文件系统出现轻微脏标记后做修复。它压根就不应该占用 EEPROM也不能全部留在 NOR Flash 上因为容量和寿命都扛不住。当这三类需求同时压在一块板子上而且主控还是 STM32FPGA 的组合分级存储就是不可避免的选择。1.2 EEPROM、NOR Flash、SD 卡的物理特性决定了它们各自的生态位很多人分不清 EEPROM 和 Flash 到底有什么区别。一句话说清楚EEPROM 的最小擦写单位是字节或者一个很小的页NOR Flash 的最小擦写单位是扇区NAND Flash 的最小单位是块而且写入还要求先整块擦除。工业控制器里我们最常见的组合就是用 EEPROM 存参数、NOR Flash 存固件和配置、SD 卡存日志背后的原因就在这张表里。介质擦写单位典型擦写寿命单次写入速度掉电安全性容量区间EEPROM字节 / 页10万到100万次几十 KB/s写周期几毫秒高可逐字节原子写入2Kbit 到 1MbitNOR Flash扇区常见 4KB/32KB通常10万次擦除慢写入页约0.5ms中擦除过程不可打断1MB 到 32MBSD 卡块寿命离散大看控制器和颗粒每秒几 MB 到几十 MB低依赖文件系统完整性几百 MB 到 TB从这张表能看出的门道是没有一种介质能同时满足“小、准、快、大、久”。EEPROM 虽然按字节写很方便但容量做不大价格也不便宜NOR Flash 容量大一些但每个扇区只能擦写十万次左右如果每秒写一次日志几天就把寿命耗完了SD 卡容量最大但它的块写入和文件系统机制决定了它不适合当参数存储器而且掉电瞬间正好在更新文件分配表的话损坏概率会明显上升。1.3 在 STM32FPGA 架构里为什么必须做分级这块板子同时有 STM32 和 FPGA原因很直白STM32 擅长跑协议栈和逻辑控制FPGA 擅长并行采集和信号处理。存储系统也必须跟这个分工匹配。FPGA 内部有大量 Block RAM 和 FIFO天然适合做数据的中间缓冲。采集的数据先落到 FPGA 内部 FIFO再由 STM32 周期性搬走这本身就是一个“内存级”的存储层。内存往下的第二层是 Nor Flash 这类片上非易失存储用来放 Bootloader 参数副本和固件最底层是 SD 卡这种海量存储承接日志和升级包。三层之间通过合理的缓冲和掉电时序串起来才是一套完整的方案。如果不分级把所有东西都塞给 EEPROM第一周就会发现 64Kbit 的容量根本放不下日志如果全塞给 SD 卡你会发现一个参数写操作被文件系统放大成了好几倍而且掉电瞬间很容易把 FAT 表写坏。分级不是设计洁癖是每种介质都只能干自己擅长的那点活。2. 存储职责划定STM32 管参数FPGA 管数据流通2.1 总线连接和数据流向设计这一版方案的硬件连接是这样的STM32 用 I2C 总线挂 EEPROM用 SPI 总线挂 NOR FlashSD 卡先用 SDIO 跑 4 位模式必要的时候降级到 SPI 模式做兼容。FPGA 不直接连接任何非易失存储芯片它只通过并行总线或者 SPI 口跟 STM32 做数据交换。最开始我也想过让 FPGA 直接接管 NOR Flash理由听起来很合理FPGA 可以自己组织写入时序减轻主控负担。但仔细推敲之后放弃了这个念头原因不是性能而是逻辑控制复杂度。NOR Flash 的擦除、编程、状态轮询、写保护、扇区管理每一件都需要一套状态机如果把固件升级、配置存档、掉电恢复这些逻辑全压到 FPGA 里工作量直接翻倍而且调试手段远不如 STM32 上跑代码来得方便。所以最终的数据流是单方向的FPGA 把采集到的数据打包通过并行接口送进 STM32 的 DMA 缓冲区STM32 根据数据类型判断该走哪条路参数则直接落 EEPROM日志则先缓存一段再成批写入 SD 卡固件升级时STM32 从 SD 卡或者串口拿到 bin 文件边校验边写入 NOR Flash。这套设计的最大优点在于存储系统的所有故障点都收敛在 STM32 这一侧。现场出了问题我只要盯着一块主控的日志和状态寄存器就能定位不用在 FPGA 的时序仿真里猜哪一拍出了问题。这也是我在多个项目里一直保持“FPGA 不做持久化存储、只做缓冲和搬运”这个习惯的原因。2.2 存储接口的仲裁与互斥STM32 同时挂了三类存储接口不同天然不会冲突但有一个容易被忽略的细节I2C 和 SPI 在 STM32 内部可能共享某些中断优先级和资源尤其是当你开了 DMA 的时候。我的做法是给每条存储总线分配一个明确的优先级等级。EEPROM 写参数优先级最高因为它操作量极小必须在几十毫秒内完成NOR Flash 擦写优先级其次因为擦除过程不可中断需要独占 CPU 时间片SD 卡日志写入优先级最低可以被打断但必须保证每次数据块写入要么完整、要么不做绝不允许写半个块。实际操作里我还会给这三个外设分别挂不同的 DMA 通道并且把 EEPROM 的 I2C 中断优先级设得比 SD 卡初始化中断更高。这个细节在大多数教程里不会提但现场如果日志写入特别频繁而参数保存刚好被延迟就会出现“掉电瞬间参数没写进去”的隐蔽问题。这个问题到后面掉电保护部分我再展开。3. EEPROM 与 NOR Flash 选型和驱动硬细节3.1 EEPROM 容量、I2C 地址和页面操作EEPROM 选型上我推荐先按“参数区 备份区 版本区”三个区域来算容量。比如你的设备有 200 个参数每个参数平均 4 字节加上校验和、序号一个参数镜像算 1KB那主备双份就是 2KB。这种量级下一颗 64Kbit 也就是 8KB 的 EEPROM 已经绰绰有余除非你要存几十个通道的校准曲线否则没必要上 1Mbit 的大容量型号。接线方面I2C 的地址线 A0/A1/A2 不能悬空。很多新手直接把这三个引脚空着结果发现设备挂在总线上时地址偶发不对。实际上地址引脚悬空在外界干扰下可能读到随机电平导致 I2C 寻址失败。正确做法是统统接地或接 VCC并且在评估板上预留跳线方便同一颗料挂多路总线扩展容量时改地址。页面操作是 EEPROM 最容易出问题的地方。以常见的 AT24C02 为例它内部页面大小是 8 字节也就是说一次连续写最多写 8 字节超出页面边界时地址会自动回卷到本页首地址如果你不知道这个特性连续写 16 个字节前 8 个字节很可能会把本页前面的数据覆盖掉。必须做的处理是每次写入前计算当前地址在页内的偏移量分多次写入或者干脆每次只写一个页面对齐块。我在驱动里通常封装了一个函数输入起始地址、缓冲区长度自动把写操作拆成若干个页面块每块之间等待写周期完成。这个函数几乎每个项目都能复用。写周期等待也是关键。大多数 I2C EEPROM 的单页编程时间是 5ms 左右写入完成后才允许继续操作。判断的方法有两个最简单粗暴的是 HAL_Delay(5)但这样会白白浪费 CPU更高效的是“写后轮询”即发送器件的“当前地址读”指令如果器件返回 ACK说明写周期已经结束如果返回 NACK说明还在忙。工业场景下我用轮询方式能省下一次 sysTick 中断的开销同时更可靠。3.2 I2C 时序和地址位宽的几个硬坑I2C EEPROM 的地址位宽有讲究。24C02 这类 2Kbit 容量只有 8 字节页地址是 8 位而 24C256 这样的 256Kbit 容量地址就是 16 位。不管用哪种务必统一封装成 Mem_Write/Mem_Read 的写法并且确认 HAL 库里的 MemAddressSize 参数正确。另一个真实遇到过的坑是时序重合。如果系统里还挂了 FPAG 或其他传感器I2C 总线上设备多了之后总线电容会明显上升。上升沿变缓会导致信号在边沿处落入不确定区表现就是“偶尔读到错误字节但频率不高”。解决办法不是改软件而是把 I2C 速率从 400kHz 降到 100kHz并且串接一个几百欧的电阻做边沿整形。工业控制器可靠性优先400kHz 和 100kHz 的差别在实际使用里几乎感知不到。3.3 NOR Flash扇区管理、配置存档和固件搬运NOR Flash 型号用得最多的是 W25Q 系列比如 W25Q64JV 这类的 8MB 容量。选型上我主要看三个指标擦除粒度、擦除时间和是否支持 QSPI。如果 STM32 支持内存映射式 QSPI可以把外部 NOR 直接映射到地址空间做 XIP省去拷贝到内部 RAM 的步骤。但如果用的是入门级 STM32F1/F4 系列老老实实采用“Bootloader 把外部 NOR 固件拷贝到内部 Flash/RAM再跳转执行”的方式即可。NOR Flash 不能按字节改它的扇区擦除是最基本的操作。比如 4KB 扇区擦除典型耗时 50 到 400ms不同批次差异很大页面编程一次最多写 256 字节。驱动里要严格遵循“先擦除再写入”的顺序擦除之后如果写入中断再次擦除之前不要假设扇区内容为空。配置存档方面我的做法不是把最新配置永远放在同一个扇区而是做一个“环形配置槽”。比如分配 8 个扇区每次保存配置时写入下一个扇区并且记录一个递增的序号读取时扫描所有扇区找到序号最大且 CRC 校验通过的那个。这样既避免了对固定扇区的集中擦写又天然实现了掉电恢复如果最后一个扇区写了一半导致校验失败就自动回退到上一个完好扇区。成本只是多占用几个扇区但换来的可靠性提升非常明显。固件跳转方面还有一个容易踩的坑从外部 NOR 拷贝固件到内部 Flash 时如果内部 Flash 容量不够或者代码本身包含中断向量、加解密校验段拷贝长度算错会导致跳转之后 HardFault。所以我在 Bootloader 里维护了一个固定长度的固件头包含魔数、版本、长度和 CRC每次升级先校验头部再把固件搬进内部 Flash最后再做一次整体校验确认无误才跳转。这个过程虽然慢了几百毫秒但能避免“升级变成砖”的现场悲剧。3.4 擦除期间的看门狗处理这是很多同事栽过跟头的地方。NOR Flash 擦除需要几百毫秒而独立看门狗的超时时间可能只有几十到一百多毫秒。如果你在擦除期间忘了喂狗系统会在擦除过程中复位导致 Flash 扇区处于半擦除状态数据直接报废。我有一次在调试固件升级时就是这么炸的。固件写到一半看门狗复位Bootloader 重新启动后发现扇区擦除标记不完整固件区内容乱成一团板子完全起不来。后来通过示波器抓擦除期间的复位波形才确认是看门狗惹的祸。处理方式有三种第一擦除期间直接关掉或者暂停看门狗升级完成后重新初始化第二把擦除过程拆成小扇区每擦完一个扇区喂一次狗第三用窗口看门狗而不是独立看门狗把刷新窗口设计在擦除的某一帧内。三种方式我实际都试过推荐第二种因为它不影响看门狗的保护作用只是把喂狗时机放在扇区边界这种安全点上。如果 Bootloader 本身对时间不敏感用第一种最省心但要注意别把看门狗禁得时间过长。4. SD 卡日志系统容量、文件系统与掉电安全的平衡4.1 工业现场用 SD 卡不是抠成本是换可维护性很多人说工业环境不应该用 SD 卡因为振动、温度、湿度和掉电都会影响它。但实际项目里如果数据量到了几百 MB 级别不用 SD 卡就得用 eMMC而 eMMC 的焊接和量产成本都更高且现场调试人员更习惯直接拔卡导出数据。所以我的选择是控制好使用方式让 SD 卡承担日志存储这个角色但绝不让它承担参数存储的职能。选卡方面我优先选“工业级”或者至少是“高耐久”的卡连续写入寿命要求而不是看标称读写速率。普通消费卡在高温和连续长时间写入下寿命衰减很厉害工业卡本质上是控制器厂商对坏块管理和固件做了针对性优化能在频繁断电时更好地保护映射表。4.2 SDIO 还是 SPI我为什么坚持保留双模式STM32 的 SDMMC 接口用 4 位模式写入速度能到几 MB/s但代价是初始化时序比 SPI 复杂而且不同卡对上电延时、CMD0 重试次数的容忍度不同。硬件上我把 SD 卡座的 DAT3 引脚做了上拉上电后先等至少 1ms 再做 CMD0然后做 ACMD41 循环查询直到卡返回空闲状态。这个流程不能省略很多卡初始化失败就是因为在卡内部上电稳定之前发命令太急。软件上我保留了 SPI 模式作为降级方案。SDIO 初始化失败三次后自动切到 SPI 模式重新识别。虽然 SPI 模式写入速度慢得多但胜在兼容性最好调试阶段能排查是不是 4 位数据线里的某根线断了。实际项目中这个降级机制救过我很多次尤其是线缆接触不良的现场。4.3 文件系统损坏的根本矛盾FAT 表更新和掉电不同步SD 卡上做日志最麻烦的是文件系统。FatFS 这类库用起来方便但你必须理解它写文件时的真实过程数据先写到数据区然后更新 FAT 表里的簇链信息最后更新目录项的文件大小。这三个动作不是原子的任何一个环节断电都可能让文件读不出来甚至让整个目录簇链断裂。最理想的做法是“裸写日志区”。我会在 SD 卡上划出一段专用区域不经过 FAT 文件系统直接按块地址写入原始数据。每块头部写一个序列号这样即使最后一块写了一半启动时也能通过序列号判断哪些块有效。这个区域可以看作一个大环形缓冲存满后从最旧的数据开始覆盖。缺点是无法直接插到电脑上读但现场可以通过一个配套导出工具把裸数据解析成 CSV。如果确实需要 FatFS我的折中方案是“双文件交替写入”。日志写到 log_a.txt写满 32MB 或者达到设定时间后关闭然后切到 log_b.txt第二次切换时再覆盖 log_a。这样做的目的很简单任何时候都只有一个文件处于打开状态掉电最多损坏当前文件另一个文件至少是完整的。每次打开日志文件之前我会检查有没有残留的“未关闭标记”如果检测到上次异常断电就先对这个文件做一次全盘簇链扫描修复再做追加写。不管哪种方式日志数据结构里都建议带一个 4 字节的时间戳、一个 2 字节的采样周期编号和一个 2 字节的通道号后续分析离线文件的时候这几项字段能帮你省掉大量对齐时间。4.4 FPGA 数据如何搬到 SD 卡批量缓冲优于逐条写入如果一条日志来一次就写一次 SD 卡性能是绝对不够的。我实践的流程是FPGA 采集数据进入内部 FIFO满了之后向 STM32 发一个 DMA 请求STM32 通过并行接口把 FIFO 里的一段突发数据搬到内存环形缓冲然后等到环形缓冲积累到 512 字节对齐的倍数时一次性往 SD 卡写入一个块。这样既保证了写入效率又利用块对齐减少了“写半个块”的撕裂概率。调试中我还发现了一个细节FPGA FIFO 的读信号和并行总线的时序如果不匹配会出现 FIFO 空读数导致日志里多出一段全 0xFF 的数据。排查方式是用逻辑分析仪同时抓 FIFO 空标志和并行总线读信号确认“芯片确实提供了数据”这个前提下才启动 DMA 传输。别盲目相信 FIFO 计数寄存器它有时候在时钟域交叉时会有延迟。5. 掉电保护设计分层存储方案真正的命门5.1 从电源监控到掉电中断检测前面所有存储结构如果没有一个可靠的掉电检测和保持机制都是空中楼阁。工业控制器的电源来自 24V 开关电源LDO 输出 3.3V 给核心系统当外部 24V 断开时LDO 不会立刻掉到 0而是缓慢下降这个窗口期就是我们保存数据的黄金时间。我习惯的做法是在 24V 输入端分压后接一个 ADC 通道同时用一颗电源监控芯片比如 TPS3808在电压低于阈值时输出一个掉电中断信号。不要等 3.3V 已经塌陷了才做处理而是在 24V 刚有跌落趋势时就触发中断这样利用后端电容存储的能量还能维持几十毫秒到上百毫秒的整体工作。另一种很实用的方式是直接用 STM32 的 PVD可编程电压检测器。把 PVD 阈值设到 3.06V 左右当 VDD 低于该值时触发中断。但要注意 PVD 触发时 3.3V 通常已经掉了不少留给你的时间窗口很短我建议只把它作为第二道防线主防线还是监控输入电压。5.2 维持时间和储能电容的经验公式如果要计算掉电后能维持多久最常用的是电容电荷公式I × t C × ΔV。假设掉电触发后系统仍然消耗 50mA允许电压从 3.3V 降到 2.8V那么 ΔV 就是 0.5V。如果希望维持 100ms需要 C I × t / ΔV 0.05 × 0.1 / 0.5 0.01F也就是 10000μF。这个容值对一块板子来说相当大了。所以更合理的做法是掉电后立即关闭无关外设把电流降下来。如果只保留 STM32 核心、RTC、EEPROM 写入所需的少量电流大约 20mA 就够。那么维持 50ms 只需要 C 0.02 × 0.05 / 0.5 2000μF。这个容值用几颗钽电容或者一颗电解电容就能实现体积上完全可以接受。经验上我会把目标窗口定在 50ms 到 100ms并留出两倍余量。因为写入 EEPROM 页面、刷 NOR Flash 扇区、关闭 SD 卡文件这三步加起来最坏情况会超过 30ms。如果哪个环节多浪费了一点时间余量不够就可能导致参数丢失。设计时不要只算“理想最快时间”要按最恶劣参数来算。5.3 分级断电动作顺序掉电中断到来之后动作顺序必须固定并且每一步都要有状态记录。我的实际顺序是这样的掉电中断触发立即停止接收新的数据请求并把状态寄存器置为“掉电处理中”。这一步相当于给整个系统拉了一个闸避免运行中的任务继续写 EEPROM 或 SD 卡。让 FPGA 清空内部 FIFO 中尚未搬走的有效数据通过并行接口快速发到 STM32 内存缓冲。这一步的窗口只有几毫秒所以 FPGA 一侧要预先实现“掉电快速排空”模式优先传输有效块跳过空标记块。将参数镜像写入 EEPROM。如果正在保存半条流水线数据则先放弃不完整的块重点保证参数完整。我的做法是先把最新的参数打包成一份带 CRC 的镜像写入主区再把主区的前一版本复制到备份区。虽然会占用两个写周期但掉电恢复时最稳妥。如果 NOR Flash 正在执行扇区擦除必须等待当前扇区擦除完成再写入一个“擦除完成”标记位。如果没有在擦除直接跳过不强行启动新的擦除。关闭 SD 卡当前日志文件。如果关闭动作来不及就在固定裸块里写一个“掉电关闭失败”标记下次启动时通过该标记决定是否对日志文件执行修复。不要为了关闭文件而死磕那会消耗太多时间。写入完成后设置“存储完成”状态位然后让系统进入低功耗或者直接复位。下次上电时Bootloader 先检查这个状态位决定是做正常启动还是做恢复流程。这个顺序看起来琐碎但每一步都有实操依据。最经典的教训是很多人会在掉电时先抢救日志数据结果日志没写完参数还丢了。工业控制器里参数的价值永远高于日志这个优先级一定不能在软件里写反。5.4 参数存储的最后一手FRAM 和 STM32 备份寄存器如果项目算力允许我强烈建议把关键参数所在的 EEPROM 换掉或者至少并行放一颗 FRAM。FRAM 写入速度是纳秒级不需要等待写周期而且写入过程中即使掉电数据也已经稳定保存了。它的擦写寿命高达 100 亿次比 EEPROM 高好几个数量级。工业控制器的参数存储场景FRAM 几乎是为它量身定做的。STM32 的备份寄存器也是一个救急手段。掉电时如果连写 EEPROM 的时间都没有至少可以把关键的运行状态、时间戳和参数镜像临时存在备份寄存器里因为 RTC 域由 VBAT 供电掉电后仍然不丢。等下次上电后再从备份寄存器恢复到正式参数区。这个方案无法替代 EEPROM但可以作为最后一道保险特别适合“突然断电但没来得及保存”的场景。6. 实测中踩过的坑存储模块调试排查手记6.1 EEPROM 读回全 0xFF最先查的不是驱动是硬件第一次调试 I2C EEPROM 时读出来的数据全是 0xFF我以为代码写错了结果查了整整两天才发现是 I2C 上拉电阻没焊。很多 STM32 开发板的 I2C 引脚内部根本没有带得上拉的可配置能力必须外接 2.2kΩ 到 10kΩ 的上拉电阻。芯片内部的上拉只是弱上拉不足以稳定驱动 EEPROM 的 SDA/SCL。另外还要检查 A0/A1/A2 地址脚。如果这三个引脚悬空芯片地址可能落在非预期范围而你的代码却按预期地址寻址自然读不到数据。解决办法是在硬件原理图上把地址脚通过电阻固定到 GND再在软件里读一遍器件地址确认。6.2 NOR Flash 擦写被看门狗打断固件区彻底损坏这个坑在前面已经提到但值得再说一次完整排查过程。现象是固件升级后再次上电 Bootloader 能运行但跳转到 App 时直接 HardFault。用调试器看 App 区前几十字节发现全是 0xFFFF说明 App 区根本没写入成功。用示波器挂 NOR Flash 的 CS 和复位引脚发现擦除过程中 MCU 的复位脚拉低了正是独立看门狗超时。修复方案分两层第一层在固件升级入口关闭 IWDG升级完成后重新初始化第二层把升级流程改成“小扇区擦除 边擦边喂狗”并且每擦一个扇区都把当前进度写进 EEPROM。这样即使中途异常复位下次启动也能从上次进度继续而不是重新擦整片固件区。这个机制目前已经在我所有涉及外部 Flash 的项目里固化了下来。6.3 SD 卡长时间运行后挂载失败不要忽视安全卸载项目现场反馈某台设备运行两周后 SD 卡读不出来。拿回实验室检查发现文件系统里多个目录项损坏FatFS 的 mount 流程在挂载时反复超时。根因就是现场在运行中停电次数太多而我用的 FatFS 配置没有开拆装日记导致 FAT 表损坏后没有自愈能力。我在软件里做了两个修改一是每次写日志时先写入块头序列号并在文件末尾写一个“文件关闭”标志二是启动扫描时如果检测到标志缺失自动进入“读取日志修复模式”通过扫描数据区重建 FAT 链。同时建议用户在拔出 SD 卡之前先通过设备管理界面做一次“卸载存储卡”操作。这两个修改做下来系统稳定性提升了一个量级。6.4 掉电瞬间参数“半写”务必带 CRC 而不是只靠累加和有一次偶发故障是参数读到某个极不合理的大数导致控制器动作异常。查 EEPROM 数据区发现目标参数的值介于新旧值之间累加和校验刚好通过。原因是累加和的碰撞概率太高在掉电导致半个字节翻转时累加和可能恰好仍然匹配。从那以后所有参数存储我都改用 CRC16并且把参数的版本字段单独放在一个固定地址。读取时先校验版本、再校验 CRC最后比对主备区。只要主区 CRC 失败就自动倒到备区并且后台生成一个“参数区异常”报警。这个机制看着简单但在现场排查时能救回大量不必要的停机。6.5 FPGA 侧数据在掉电时丢尾巴不是存储介质的问题还有一次故障让我印象深刻SD 卡日志文件读出来很正常最后一条记录的时间明显早于实际断电时间中间少了一段采集数据。给 SD 卡和数据库做了各种读写测试都没问题后来才定位到是 FPGA 的 FIFO 在掉电时没有及时清空掉电中断的优先级又被一个日志 DMA 任务挡着导致 FIFO 里的尾巴数据没机会搬走。解决方法是给掉电中断设最高中断优先级并且在掉电处理第一步就屏蔽所有 DMA 请求只保留 FPGA 排空通道。同时 FPGA 侧实现一个“突发排空”状态机一旦收到掉电信号就把 FIFO 剩余有效数据连续读出直到空标志拉高或窗口期超时。日志丢尾巴的问题基本就没有再出现过了。这套存储方案在板子上跑了两轮迭代之后我最大的体会是分级存储不是硬件选型的堆砌而是把数据可靠性按价值分层的结果。参数数据该用 EEPROM 加主备镜像固件该用 NOR Flash 加引导复制日志该用 SD 卡加大块缓冲和异常恢复。每一层都不需要追求全能只需要把自己那部分职责守好最后整个系统的可靠性就自然成立了。如果你也在做 STM32FPGA 的控制器建议把掉电时序图和存储粒度表打印出来放在调试台旁边排查问题时能少走很多弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑