ARTICLE DETAIL

资讯详情

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

STM32+FPGA工业控制器分级存储设计:EEPROM、NOR Flash与SD卡协同方案

STM32+FPGA工业控制器分级存储设计:EEPROM、NOR Flash与SD卡协同方案 1. 工业控制器存储方案的整体设计思路工业控制器和消费类电子产品最大的区别在于它得在强电磁干扰、宽温、频繁掉电、长期无人值守的环境里把关键数据一个字节都不能丢地存下来。我做过好几个PLC类、边缘网关类的项目存储设计几乎每次都是评审会上被反复追问的点。这次要聊的这套方案是STM32加FPGA双核架构下的分级存储设计用EEPROM、NOR Flash、SD卡三层介质分别承接不同量级、不同读写频率、不同可靠性要求的数据。先说清楚这套方案解决什么问题。工业现场的数据大致分三类第一类是标定参数、设备序列号、通信地址、校准系数这类数据量极小通常几百字节到几KB但要求掉电绝对不能丢写入次数可能很频繁第二类是运行日志、故障录波、配方数据量级在几十KB到几MB写入频率中等需要掉电保护第三类是历史趋势数据、大批量采集记录动辄几百MB甚至上GB写入频繁但可以容忍偶尔丢一两个点。这三类数据如果都往一个介质里塞要么成本爆炸要么寿命不够要么速度跟不上。分级存储的核心逻辑就是让合适的介质干合适的事。为什么是STM32加FPGA这个组合STM32负责系统控制、协议栈、文件系统管理和人机交互FPGA负责高速数据采集、实时预处理和DMA搬运。存储这块STM32是主控FPGA是数据源和加速器。EEPROM挂在STM32的I2C上NOR Flash走SPI或者QSPISD卡走SDIO。FPGA这边如果需要缓存大批量数据可以挂一片DDR做乒乓缓冲再通过FSMC或者SPI把数据交给STM32落盘。这个分工不是拍脑袋定的而是根据各介质的物理特性和总线带宽算出来的。选型背后的账得算清楚。EEPROM我一般选AT24C系列或者FM24系列铁电前者便宜但写入寿命100万次左右后者贵但几乎无限次写入且写入速度极快。工业场景里如果参数需要频繁更新比如每次停机都写一次计数值铁电是更稳的选择虽然单价贵几块钱但省掉了磨损均衡的软件复杂度。NOR Flash选W25Q系列或者S25FL系列容量从几MB到几十MB擦写寿命10万次左右适合存日志和配方。SD卡选工业级pSLC卡别用普通消费卡消费级TLC卡在频繁小文件写入下几个月就挂了工业级卡能扛几年。这个成本差异在批量生产时很敏感但返修率降下来之后总体是赚的。提示分级存储不是简单地把数据分到三个地方而是要设计统一的数据管理层。我见过不少项目三个介质各自为政最后数据一致性一塌糊涂。建议在STM32上跑一个轻量级的分区管理模块对上提供统一的读写接口对下屏蔽介质差异。这套方案适合谁参考做工业控制器、边缘网关、数据采集终端、电力监测设备的嵌入式工程师都能用。如果你正在做基于STM32的毕业设计想加点工业级的存储设计进去这套分级思路也能让你的方案看起来更专业。下面我按介质逐个拆解把原理、电路、代码和踩过的坑都讲透。2. EEPROM层小参数的高可靠存储2.1 EEPROM的存储原理与工业场景适配EEPROM的全称是电可擦除可编程只读存储器它的存储单元是浮栅MOS管。每个bit靠浮栅上有没有电荷来表示0和1擦除和写入都通过隧穿效应完成。这个原理决定了它的两个特点一是按字节读写不需要像Flash那样先擦后写二是擦写次数有限典型值100万次。工业场景里EEPROM最适合存那些小、关键、偶尔写的数据比如设备ID、通信波特率、传感器校准系数、报警阈值。但这里有个坑很多人把EEPROM当RAM用主循环里每次状态变化都写一次结果不到一年芯片就写坏了。我实测过AT24C02在每天写1000次的情况下大概三年左右开始出现写入失败。所以EEPROM的使用必须做写入频率控制。我的做法是在RAM里维护一份参数镜像只有检测到参数真正变化且稳定超过一定时间比如5秒才触发写入同时记录写入次数超过阈值就告警。铁电存储器FRAM是EEPROM的升级替代方案。它的写入原理是铁电晶体的极化方向不需要隧穿所以写入速度快总线速度级、寿命几乎无限10的14次方次、功耗极低。缺点是容量小、单价高。在需要高频写入计数值或者掉电瞬间保存状态的场景FRAM是唯一靠谱的选择。我有个项目做流量计每次脉冲都要累加计数用EEPROM根本扛不住换成FM24CL64之后问题彻底解决。2.2 I2C读写EEPROM的实操要点STM32读写EEPROM走I2C硬件上注意两点上拉电阻和地址配置。上拉电阻一般4.7K到10K总线电容大的话取小一点。AT24C系列有A0/A1/A2三个地址引脚可以挂8片同型号芯片地址从0x50到0x57。如果挂多片注意地址别冲突。软件层面HAL库的I2C函数用起来简单但有几个细节容易翻车。第一EEPROM的页写边界。AT24C02的页大小是8字节AT24C256是64字节。跨页写入会回卷覆盖必须分页处理。第二写周期时间。EEPROM写完一个字节后需要5ms左右内部擦写这期间不响应总线如果连续写必须加延时或者用应答轮询。第三时钟频率。工业环境干扰大I2C时钟别拉太高100kHz到400kHz比较稳长走线建议100kHz。下面是我常用的EEPROM读写封装基于HAL库带页写处理和写周期等待#define EEPROM_ADDR 0xA0 #define PAGE_SIZE 8 HAL_StatusTypeDef EEPROM_Write(uint16_t memAddr, uint8_t *data, uint16_t len) { HAL_StatusTypeDef status; uint16_t written 0; while (written len) { uint16_t pageRemain PAGE_SIZE - (memAddr % PAGE_SIZE); uint16_t chunk (len - written) pageRemain ? (len - written) : pageRemain; status HAL_I2C_Mem_Write(hi2c1, EEPROM_ADDR, memAddr, I2C_MEMADD_SIZE_16BIT, data written, chunk, 100); if (status ! HAL_OK) return status; HAL_Delay(6); memAddr chunk; written chunk; } return HAL_OK; }注意HAL_Delay(6)是保守值实际AT24C02的写周期最大5ms留1ms余量。如果系统对实时性要求高可以用应答轮询替代固定延时但代码复杂度会上升。2.3 参数存储的可靠性设计EEPROM存参数最怕的是写一半掉电导致参数区变成半新半旧的乱码。解决办法是双备份加校验。我把参数区分成A、B两个块每块前面加一个头结构包含魔数、版本号、长度和CRC32。写入时先写B块校验通过后再更新A块的有效标志。读取时优先读A块A块校验失败读B块。这样即使写入过程中掉电至少有一个块是完整的。CRC32的计算可以用STM32硬件CRC外设速度快且不占CPU。如果没有硬件CRC用软件查表法也行但要注意表要放在Flash里别占RAM。我一般用多项式0x04C11DB7初始值0xFFFFFFFF结果异或0xFFFFFFFF和标准CRC32一致。参数区的布局我习惯这样设计前16字节是块头后面是参数数据最后4字节是块尾魔数。块头里记录写入次数方便做寿命预警。读取时先检查头尾魔数和CRC三者都对才认为数据有效。这个设计看起来啰嗦但在现场救过我好几次——有次客户设备频繁重启就是靠双备份机制发现A块损坏自动切到B块数据一点没丢。3. NOR Flash层日志与配方的可靠落盘3.1 NOR Flash的特性与分区规划NOR Flash和NAND Flash的区别简单说就是NOR可以按字节随机读速度快适合存代码和关键数据NAND按页读写容量大成本低适合存大文件。工业控制器里用NOR Flash主要是看中它的可靠性和随机读取能力。W25Q128是常见型号16MB容量SPI接口擦写寿命10万次数据保持20年。分区规划是NOR Flash使用的第一步。我一般把16MB分成几个区0到1MB存FPGA配置文件和Bootloader备份1MB到2MB存系统参数备份2MB到10MB存运行日志10MB到16MB存配方和录波数据。每个区独立管理日志区用循环覆盖的方式配方区用追加写入加索引的方式。分区表本身存在Flash的第一个扇区上电时读出来建立内存映射。为什么日志区要循环覆盖因为工业设备的日志是持续产生的不可能无限存。循环覆盖的策略是维护一个写指针写到区尾就回到区头覆盖最老的数据。同时维护一个索引表记录每条日志的起始地址和时间戳。读取时通过索引表定位。这个设计的关键是索引表本身也要掉电保护我一般把索引表放在RAM里定期同步到Flash的固定位置同步频率根据日志产生速度调整。3.2 SPI NOR Flash的驱动实现STM32驱动W25Q系列可以用SPI外设或者QSPI外设。QSPI速度快四线模式下能到80MHz以上但引脚多布线要求高。SPI简单速度够用一般20到40MHz我大多数项目用SPI。驱动层要实现的函数包括读ID、读状态、写使能、扇区擦除、页编程、读数据。W25Q128的扇区是4KB页是256字节。写入前必须先擦除整个扇区这是NOR Flash的铁律。页编程只能把1写成0不能把0写成1所以覆盖写必须先擦后写。这个特性决定了日志系统不能原地更新只能追加写。下面是一个典型的扇区擦除和页编程实现#define W25Q_CMD_WRITE_ENABLE 0x06 #define W25Q_CMD_READ_STATUS 0x05 #define W25Q_CMD_PAGE_PROGRAM 0x02 #define W25Q_CMD_SECTOR_ERASE 0x20 #define W25Q_CMD_READ_DATA 0x03 void W25Q_WriteEnable(void) { uint8_t cmd W25Q_CMD_WRITE_ENABLE; HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(hspi1, cmd, 1, 100); HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_SET); } void W25Q_WaitBusy(void) { uint8_t cmd W25Q_CMD_READ_STATUS; uint8_t status; do { HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(hspi1, cmd, 1, 100); HAL_SPI_Receive(hspi1, status, 1, 100); HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_SET); } while (status 0x01); }提示SPI的CS引脚一定要用GPIO手动控制别用硬件NSS。硬件NSS在连续传输之间会自动拉高导致命令和数据被拆成两帧Flash识别不了。这个坑我踩过调了一下午才发现。3.3 日志系统的掉电保护设计日志系统最怕的是写到一半掉电导致索引和数据不一致。我的做法是每条日志带一个头头里包含魔数、长度、CRC和状态标志。写入流程是先写数据区再写索引区最后更新索引区的有效标志。掉电恢复时扫描索引区只加载有效标志完整的条目遇到不完整的条目就丢弃并回退写指针。为了减少掉电影响日志写入要尽量原子化。一条日志的大小控制在256字节以内正好一个页这样一次页编程就能写完不会跨页。如果日志超过256字节拆成多条每条独立带头和CRC。读取时按序号拼接。另外NOR Flash的擦除操作很慢4KB扇区擦除典型时间45ms大扇区更久。擦除期间如果掉电整个扇区数据全丢。所以日志区的擦除要提前做不能等到写满了才擦。我的策略是维护一个空闲扇区池后台任务在系统空闲时预擦除几个扇区备用写日志时直接从池里取避免实时擦除。实测下来这套日志系统在频繁掉电测试中表现很稳。我用继电器做掉电模拟每秒随机掉电一次连续跑了一周日志没有出现不可恢复的损坏。关键就是索引和数据的分离以及有效标志的最后写入。4. SD卡层大容量数据的存储与文件系统4.1 SD卡在工业场景的选型与坑SD卡在消费电子里很常见但工业场景用SD卡要格外小心。普通消费级卡用的是TLC甚至QLC闪存擦写寿命只有几百到几千次而且没有掉电保护写入过程中掉电很容易导致文件系统损坏。工业级SD卡用pSLC或者SLC闪存寿命长带掉电保护电容但价格是消费卡的几倍甚至十几倍。我选卡的经验是看两个指标一是TBW总写入字节数二是是否标注工业级或宽温。TBW低于100TB的卡别用在频繁写入的场景。宽温卡能在-40到85度工作消费卡一般只到70度工业现场夏天机柜内温度轻松超过70度消费卡会直接罢工。另一个坑是SD卡的文件系统。FAT32是通用性最好的但掉电容易损坏。exFAT支持大容量但授权和兼容性有问题。我的做法是用FAT32加掉电保护机制每次写入前先写日志文件记录本次操作写完数据后再清除日志。上电时检查日志文件如果有未完成的操作就回滚。这个机制配合工业级SD卡基本能保证文件系统不崩。4.2 SDIO接口的硬件设计与调试STM32的SDIO接口支持1位和4位模式4位模式速度快理论25MB/s以上但布线要求高。CLK、CMD、DAT0到DAT3六根线要等长阻抗控制50欧姆CLK线要包地。如果走线超过5厘米建议加缓冲芯片。电源要加去耦电容SD卡座附近放100nF和10uF各一个。调试SDIO最常见的问题是初始化失败。排查顺序是先量电源和时钟再查CMD线的上拉电阻一般10K到47K最后看初始化流程。STM32的HAL库SDIO初始化分几步卡上电、发送CMD0复位、CMD8查电压、ACMD41查OCR、CMD2取CID、CMD3取RCA、CMD9取CSD、CMD7选卡、ACMD6设总线宽度。任何一步超时都会失败。我遇到过一次初始化随机失败最后发现是SD卡座的金属外壳没接地引入了干扰。把外壳焊到地平面之后问题消失。还有一次是CLK线走线太长降到10MHz才能稳定工作。所以SDIO的时钟频率要根据实际布线调整别一上来就拉满。4.3 FatFs文件系统的移植与优化FatFs是嵌入式领域最常用的文件系统移植简单代码量小。移植时要提供几个底层函数disk_initialize、disk_status、disk_read、disk_write、disk_ioctl。这些函数对接SDIO驱动即可。关键配置在ffconf.h里_FS_TINY设为1省RAM_USE_LFN设为2支持长文件名但耗RAM_FS_REENTRANT设为1支持多线程。性能优化方面有几个点值得注意。第一扇区大小设为512字节和SD卡物理扇区一致避免读改写。第二启用多扇区读写disk_read和disk_write里用SDIO的多块传输模式速度能提升好几倍。第三文件写入用f_write批量写别一个字节一个字节写每次写至少一个扇区。第四定期调用f_sync把缓存刷到卡里但别太频繁否则速度掉得厉害。下面是一个批量写日志的示例用4KB缓冲写满一次刷一次#define LOG_BUF_SIZE 4096 static uint8_t logBuf[LOG_BUF_SIZE]; static uint32_t logBufPos 0; void Log_Append(uint8_t *data, uint32_t len) { if (logBufPos len LOG_BUF_SIZE) { UINT bw; f_write(logFile, logBuf, logBufPos, bw); f_sync(logFile); logBufPos 0; } memcpy(logBuf logBufPos, data, len); logBufPos len; }注意f_sync会触发实际的卡写入耗时可能几十毫秒。如果日志产生速度很快f_sync会成为瓶颈。我的做法是双缓冲一个缓冲在写卡另一个缓冲继续接收数据写完交换。这样能平滑掉写入延迟。4.4 SD卡数据完整性的保障手段SD卡存大容量数据完整性保障分几个层面。第一层是文件级CRC每个日志文件带一个CRC文件记录该文件的校验值读取时校验。第二层是记录级CRC每条记录带头和CRC防止文件内部损坏。第三层是文件系统级保护用日志机制防止FAT表损坏。我还习惯在SD卡根目录放一个状态文件记录当前写入的文件名、偏移量和时间戳。每次写入前更新状态文件写入后清除。上电时如果发现状态文件非空说明上次写入未完成根据记录的信息做恢复。这个机制简单但有效能处理大部分掉电场景。另外SD卡的热插拔要处理好。工业现场可能有人误拔卡如果文件系统正在写入拔卡会导致数据损坏。我的做法是检测卡检测引脚CD一旦检测到拔卡立即停止所有写入操作关闭文件并置位错误标志。重新插卡后重新初始化文件系统。这个逻辑要放在中断里响应要快。5. STM32与FPGA的存储协同设计5.1 双核架构下的数据流划分STM32和FPGA协同存储核心是数据流的划分。FPGA负责高速数据采集和预处理比如ADC采样、图像处理、编码器计数这些数据速率高STM32直接处理不过来。FPGA把处理后的数据通过FSMC、SPI或者自定义并行总线传给STM32STM32负责落盘。具体分工我一般这样定FPGA内部用Block RAM或者外挂DDR做乒乓缓冲采集一批数据比如1MB后触发中断通知STM32。STM32收到中断后通过FSMC把数据读出来写入NOR Flash或者SD卡。写入期间FPGA继续采集下一批到另一个缓冲实现无缝衔接。这个乒乓机制是关键能保证数据不丢。FSMC总线的配置要注意时序。STM32的FSMC支持NOR Flash、SRAM、NAND等模式和FPGA通信一般用SRAM模式。地址建立时间、数据保持时间要根据FPGA的时序要求调整。我一般先用保守值比如建立时间15个HCLK周期调通后再逐步压缩。FPGA那边要把总线接口做成异步SRAM的样子片选、读使能、写使能、地址、数据线都要接对。5.2 FPGA侧的数据缓存与DMA搬运FPGA侧的数据缓存小批量用Block RAM大批量用DDR。Block RAM容量有限一般几MB但速度快适合做乒乓缓冲。DDR容量大几百MB到几GB但需要DDR控制器设计复杂度高。如果数据量在几MB以内Block RAM够用超过的话要么外挂DDR要么降低采集速率。DMA搬运是提高效率的关键。STM32的DMA可以在FSMC和内存之间搬运数据不占CPU。配置DMA时注意源地址是FSMC的数据寄存器地址目的地址是内存缓冲传输长度是数据量传输宽度根据总线宽度选16位或32位。DMA传输完成中断里触发写Flash或SD卡的操作。FPGA那边也可以用DMA但一般叫DMA控制器或者描述符搬运。Xilinx和Intel的FPGA都有现成的DMA IP配置一下就能用。如果自己写状态机要处理好地址递增、传输计数和中断产生。我一般用Xilinx的AXI DMA配合AXI Stream接口效率很高。5.3 跨时钟域的数据同步STM32和FPGA的时钟域不同数据传递要做同步。如果走异步总线比如FSMC靠握手信号同步问题不大。如果走同步总线比如SPI要注意时钟极性和相位。SPI的CPOL和CPHA有四种组合STM32和FPGA必须配置一致否则数据错位。更麻烦的是中断和标志的同步。FPGA产生的中断信号是异步的STM32的中断控制器需要边沿触发所以FPGA那边要把中断信号做同步化处理用两级触发器打拍再输出给STM32。标志寄存器也要做同步STM32读标志时FPGA要保证标志稳定。我踩过的一个坑是FPGA的数据就绪标志在STM32读取期间变化导致读到半新半旧的数据。解决办法是加双缓冲标志FPGA写缓冲A时标志指向A写完后切换标志指向BSTM32读标志后读对应的缓冲。这样读写分离不会冲突。5.4 存储任务的优先级与调度STM32上跑RTOS的话存储任务要合理分配优先级。我的经验是EEPROM写入任务优先级最高数据关键且量小NOR Flash日志任务次之SD卡大文件写入任务优先级最低可以后台慢慢写。但要注意SD卡写入如果被长时间打断可能导致写入超时所以SD卡任务虽然优先级低但不能饿死要保证一定的执行时间片。中断和任务的配合也很重要。FPGA的数据就绪中断里只做一件事释放一个信号量或者发送一个消息给存储任务。实际的数据搬运和落盘在任务里做避免在中断里做耗时操作。如果数据量很大中断里可以启动DMADMA完成中断里再通知任务。提示存储任务之间共享总线比如SPI总线可能同时挂NOR Flash和SD卡要做好互斥。我一般用互斥量保护总线谁用谁申请用完释放。但互斥量不能嵌套否则死锁。如果确实需要嵌套用递归互斥量。6. 常见问题与排查技巧实录6.1 存储介质典型故障速查表故障现象可能原因排查方法解决方案EEPROM写入后读回错误I2C时序问题、上拉电阻不合适、写周期未等待用逻辑分析仪抓I2C波形检查ACK调整上拉电阻增加写周期延时NOR Flash擦除失败写使能未发送、扇区地址错误、芯片保护读状态寄存器检查WEL和WIP位确保每次擦写前发写使能检查地址对齐SD卡初始化失败电源不稳、上拉电阻缺失、时钟太快量电源纹波查CMD线电平降时钟加去耦电容补上拉电阻降频到400kHz初始化文件系统损坏写入中掉电、卡质量差、FAT表未同步用读卡器在PC上检查看能否修复换工业级卡加掉电保护定期f_sync数据写入速度慢扇区未对齐、单字节写入、总线频率低测实际写入速度看总线占用批量写入扇区对齐提高总线频率掉电后数据丢失缓存未刷、写入未完成、无掉电检测模拟掉电测试检查最后写入的数据加掉电检测电路关键数据立即刷盘6.2 掉电测试的实操方法掉电测试是验证存储可靠性的关键环节。我的做法是用一个可编程电源或者继电器控制设备电源的通断。测试模式有两种随机掉电和同步掉电。随机掉电是每隔随机时间断一次电模拟现场电网波动。同步掉电是在特定操作比如写Flash进行到一半时断电模拟最坏情况。测试时要记录每次掉电后的数据完整性。我一般写一个测试程序上电后检查所有存储介质的数据和预期值对比记录错误。连续跑几千次掉电循环统计错误率。如果错误率不为零就要分析是哪个环节的问题。实测经验EEPROM在写周期内掉电有概率导致整个字节损坏但双备份机制能恢复。NOR Flash在扇区擦除时掉电整个扇区数据丢失所以擦除前要确保数据已备份。SD卡在FAT表更新时掉电文件系统可能损坏日志机制能回滚。这些结论都是通过大量掉电测试得出的比看数据手册靠谱。6.3 存储寿命的估算与预警存储介质的寿命要提前估算别等坏了再换。EEPROM按写入次数算AT24C02是100万次如果每天写100次能用27年。NOR Flash按擦除次数算W25Q128是10万次如果每天擦除10个扇区能用27年。SD卡按TBW算工业级卡一般100TB以上如果每天写1GB能用270年。看起来都很充裕但实际使用中往往因为设计不当导致寿命骤减。我习惯在固件里加寿命计数器。EEPROM记录每个块的写入次数超过阈值比如80万次就告警。NOR Flash记录每个扇区的擦除次数超过8万次就标记为坏块不再使用。SD卡记录总写入量接近TBW的80%就提示更换。这些计数器存在EEPROM或者NOR Flash的固定位置掉电不丢。预警机制要提前做不能等坏了才报。我一般设两级预警一级是提醒比如写入次数到70%二级是告警到90%。提醒级别只记录日志告警级别要上报到上位机或者点亮指示灯。这样运维人员有时间提前更换避免现场停机。6.4 电磁干扰下的存储可靠性加固工业现场的电磁干扰是存储可靠性的隐形杀手。我遇到过好几次莫名其妙的数据错误最后查出来都是干扰导致的。加固措施分几个层面硬件上存储芯片的电源加磁珠和去耦电容信号线加TVS管PCB布局时存储区域远离功率器件。软件上所有写入操作带CRC校验读回验证失败重试。关键数据写三份读的时候投票。SPI和I2C总线在干扰下容易出错可以降低时钟频率、增加滤波电容、用屏蔽线。SDIO总线更容易受干扰因为线多且速度快建议加共模电感。如果现场干扰特别严重可以考虑用光耦隔离或者数字隔离器把存储部分和主控隔离开。还有一个技巧是看门狗配合存储。如果存储操作卡死看门狗会复位系统复位后检查存储状态做恢复。我一般把存储操作放在独立的任务里任务喂狗如果任务卡死看门狗触发复位。复位后上电自检会检查存储完整性发现异常就修复。6.5 调试工具与手段推荐调试存储问题光靠打印日志不够得用专业工具。逻辑分析仪是必备的抓I2C、SPI、SDIO的波形看时序对不对。我用的Saleae Logic Pro 16支持协议解码能直接看到I2C的地址、数据和ACK。示波器看电源纹波和信号完整性特别是SDIO的时钟和数据线。软件层面STM32的SWD调试能看寄存器和内存配合断点能定位到具体哪一行出错。如果问题在中断里用SWO输出调试信息不占用串口。FPGA那边用ILA集成逻辑分析仪抓内部信号Xilinx的Vivado和Intel的SignalTap都好用。还有一个笨办法但很有效把存储操作的关键步骤用GPIO翻转标记出来用逻辑分析仪抓GPIO和总线波形能直观看到每一步的耗时和顺序。这个方法不依赖任何调试器适合现场排查。6.6 现场返修案例复盘说一个真实的返修案例。客户反馈设备运行三个月后参数丢失设备无法启动。返修后检查发现EEPROM的A块CRC错误B块也错误。进一步检查发现客户现场电网波动频繁设备每天掉电几十次。每次掉电时如果正好在写EEPROM就会损坏数据。双备份机制虽然能恢复大部分情况但极端情况下两个块同时损坏。解决方案是加掉电检测电路。用一个比较器监测电源电压当电压降到阈值以下时触发中断STM32在中断里立即停止所有写入操作并把关键数据刷到EEPROM。同时加一个大电容保证掉电后STM32还能工作几十毫秒足够完成紧急写入。改造后同样工况下运行一年没有再出现参数丢失。这个案例的教训是掉电保护不能只靠软件硬件检测加软件配合才可靠。掉电检测的阈值要算好一般设在稳压器输出下限以上保证检测到掉电时系统还能正常工作一段时间。电容容量根据系统功耗和所需时间算比如系统功耗100mA需要50ms电容至少470uF。6.7 存储方案的扩展与升级路径这套分级存储方案不是一成不变的可以根据需求扩展。如果数据量更大可以把SD卡换成eMMC或者SSD接口从SDIO换成SDIO 4位或者PCIe。如果可靠性要求更高可以加RAID或者双卡冗余。如果速度要求更高可以用NVMe或者UFS。软件层面可以从FatFs升级到LittleFS或者SPIFFS后者对掉电更友好适合NOR Flash。如果跑Linux可以用UBIFS或者JFFS2。如果数据需要加密可以在写入前做AES加密密钥存在STM32的OTP区域或者安全芯片里。升级路径要根据实际需求选别为了升级而升级。我见过一个项目本来用EEPROM存参数就够了非要上文件系统结果复杂度大增bug一堆。存储方案的选择永远是在容量、速度、可靠性、成本、复杂度之间找平衡没有最好的只有最合适的。
返回列表