多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

掉电不丢数据:MRAM在工业嵌入式存储中的设计实践

掉电不丢数据:MRAM在工业嵌入式存储中的设计实践 工业现场掉电这种事做嵌入式的人迟早都会碰到。伺服驱动器正在记录累计运行时间PLC 刚把最后一批工艺参数写进去突然控制柜跳闸——如果存储介质经不起频繁写入或者写入一半被打断下次上电数据就是花的。最近我在一个基于 CEC1302 的工业辅助控制板上做数据存储最终选了 Everspin 的 MR25H40CDF4Mbit SPI MRAM作为存储介质把运行日志、配置参数和告警记录都放进去。整个过程跑下来最直观的感受是MRAM 这种“磁存储器”在处理工业嵌入式应用里的存储和读取数据这件事上比 EEPROM 和 NOR Flash 省心太多。这篇记录就围绕这套组合讲讲在工业和嵌入式设计里怎么把数据可靠地存进去、读出来以及我在选型、驱动和现场调试中踩过的坑。1. 先弄清工业存储场景到底缺什么从 EEPROM/Flash 到 MRAM 的选型逻辑1.1 工业设备里最常见的存储矛盾既要频繁写又要掉电不丢工业设备需要存的数据掰开来看基本就三类。第一类是配置参数比如 PID 系数、通讯地址、校准值、量程上下限这类数据写得不频繁但一旦改了就必须永久记住。第二类是运行数据比如累计运行时长、电能累计、脉冲计数、最后故障码这类数据可能每秒甚至每毫秒都在更新系统掉电的瞬间还得把最新值留住。第三类是事件日志包括告警记录、开关机记录、操作记录一天少则几十条多则几百条常年累月写下去存储介质的寿命必须扛得住。如果只用 EEPROM写次数通常是 10 万到 100 万次。一个每秒写一次的仪表10 万次寿命只够撑不到 28 小时妥妥的硬伤。NOR Flash 比 EEPROM 容量大但按页按扇区操作写一页要先擦除擦除一次要几十毫秒甚至上百毫秒而且擦写寿命通常只有 1 万到 10 万次还得折腾磨损均衡算法。电池供电的 SRAM 确实读写都快但工业现场的电池老化、漏液、维护成本都是长期麻烦。以前很多项目用“大电容掉电检测 EEPROM 紧急写”来凑合掉电瞬间触发中断赶紧写几个字节电容越大成本越高写一半电压跌穿照样失败这是治标不治本的路子。MRAM 的出现正好把这些痛点一起按住了。它本身是非易失存储器掉电不丢写入速度接近 SRAM纳秒到微秒级写入寿命极高资料上常见“无限读写耐久度”的说法实际上高强度测试也能到 10^14 次量级最关键的是写数据不需要先擦除CPU 说写就写没有“编程等待时间”。1.2 把存储介质拉出来对比差距非常直观我习惯在选型时做一张表把介质特性摊开看。介质类型典型写入速度写寿命是否需要擦除掉电一致性容量友好度EEPROM毫秒级10万~100万次否写一半可能损坏小NOR Flash写快擦除慢1万~10万次是编程/擦除中掉电高风险中电池SRAM纳秒级无限否掉电即丢依赖电池中FRAM纳秒级高频写够用否较好但容量普遍偏小小MRAM纳秒~微秒级极高否原子写入掉电不丢中等FRAM 其实也很强耐写、无需擦除但容量普遍在几百 Kbit 级别价格偏高新项目的供货渠道也不如 MRAM 稳。MRAM 能做到 4Mbit 甚至更大的 SPI 接口产品对工业日志这类场景更合适。我这边最后选了 Everspin 的 MR25H40CDF核心原因就是它的容量、接口和温度范围都匹配需求而且 SPI 接口占引脚少和手头的主控搭起来特别顺。1.3 为什么是 MR25H40CDF 和 CEC1302 的组合MR25H40CDF 是一款 4Mbit 的 SPI 接口 MRAMDFN 小封装适合板级空间紧张的工业设备。CEC1302 则是一颗 MIPS32 内核的嵌入式控制器片内集成 Flash 和 SRAMSPI、I2C、UART、GPIO 这类外设齐全。它在这套系统里不是主 CPU而是承担“随时待命、掉电也不慌”的辅助角色工业主控制器上电前CEC1302 已经把上次的运行历史和关键参数从 MRAM 里读出来准备好主控制器跑起来之后CEC1302 负责持续采集数据和写日志当系统掉电CEC1302 检测到电压跌落把最后一批关键数据写进 MRAM然后从容复位。这个组合还有一个好处CEC1302 的 SPI 外设可以直接挂 MR25H40CDF引脚资源占用很少给传感器、小屏、协议转换留出了空间。对于工业仪器仪表、机柜监控板、小型 PLC 这类“主控旁边需要一个小管家”的场景这套组合非常典型。2. MR25H40CDF 的硬件底细与 SPI 命令体系2.1 写入原理不是存电荷而是摆磁向MRAM 和 Flash 的存储机制完全不同。Flash 的存储单元靠浮栅里的电荷表示 0 和 1电荷会慢慢泄漏写入要先把电荷擦掉再注入所以擦写慢、寿命有限。MRAM 的存储单元是磁隧道结两层磁性材料夹一层极薄的绝缘层其中一层的磁化方向是固定的参考层另一层是自由层。自由层的磁化方向和参考层平行时隧道结电阻低读出为 1反平行时电阻高读出为 0。写入过程就是产生一个电流磁场把自由层的磁化方向翻过来。因为翻转的是磁畴方向不是注入电荷所以这种翻转机制没有物理磨损寿命特别长。MR25H40 属于 toggle MRAM写入时会先判断当前状态再决定用哪条电流路径去翻转整个写入动作是原子完成的。这也是工业掉电场景最看重的一点写一个字节的瞬间断电结果要么是旧值要么是新值不存在 Flash/EEPROM 那种“充电到一半、读出来都不知道是什么”的中间态。2.2 管脚定义、供电电压与温度版本MR25H40CDF 是 8 脚 DFN 封装供电电压是 1.8VCDF 后缀对应工业温度等级适合工业控制柜、自动化设备这些温度环境不友好的场合。它的引脚不多但对硬件设计来说每个引脚都要处理明白。引脚名称功能硬件处理建议1CS#片选MCU GPIO 控制平时拉高2SCK串行时钟接主控 SPI SCK3SI数据输入接主控 MOSI4SO数据输出接主控 MISO5WP#写保护不用时必须上拉否则可能锁死写入6HOLD#暂停传输不用时必须上拉悬空可能误触发7VSS地就近接地8VDD电源1.8V加 0.1µF 1µF 去耦WP# 引脚是低电平有效的写保护输入它配合状态寄存器里的块保护位可以锁定某一区域禁止写入。如果设计上不需要硬件写保护就直接把这个脚上拉到 VDD。HOLD# 引脚一旦被拉低芯片会暂停 SPI 传输在强干扰的工业现场悬空状态下很容易被噪声打乱时序所以不用的场景必须同样上拉。这里有一个选型经验如果主控 IO 电平是 3.3V与 MR25H40CDF 的 1.8V 供电之间就差了一个电平域。要么选同系列的 3.3V 版本要么加电平转换电路千万别把 3.3V 直接怼到 1.8V 器件上。关于具体后缀对应的电压和温度范围不同批次数据手册可能微调选型时一定以最新规格书为准。2.3 核心命令集小但够用MR25H40CDF 的 SPI 指令集兼容 SPI NOR Flash 的风格用起来很顺手。实际项目里我反复用到的命令就这几条。命令字节码功能描述WREN0x06写使能置位状态寄存器 WEL 位WRDI0x04写禁止清除 WEL 位RDSR0x05读状态寄存器WRSR0x01写状态寄存器配置块保护READ0x03从指定地址读数据WRITE0x02从指定地址写数据SLEEP0xB9进入睡眠模式降低待机功耗WAKE0xAB从睡眠模式唤醒状态寄存器里主要有 WEL 写使能锁存位、BP0/BP1 块保护位。MRAM 虽然写入不需要擦除但指令体系还是保留了 WREN 流程所以写数据前发一次 WREN 是稳妥的写完后可以 RDSR 确认 WEL 已经自动清零。和 NOR Flash 最大的区别是WRITE 命令执行完CS 拉高的那一刻数据就已经稳定有效了不需要额外等待几十毫秒的编程时间。同时芯片没有页的概念只要地址不越界、CS 一直保持低电平就可以连续写任意长度的数据。2.4 操作流程WREN 到 WRITE 再到校验一套标准的写流程是这样。第一步 CS 拉低发 WRENCS 拉高完成写使能。第二步 CS 拉低发 WRITE 命令紧跟 24 位地址和待写数据全部发完后 CS 拉高。第三步做一次读回校验把刚写的地址读出来比对。第三步在正式产品里一定要有因为 MRAM 本身不会丢数据但总线干扰、软件地址算错这类问题还是存在的回读是最廉价的防线。读取流程更简单CS 拉低发 READ 命令加 24 位地址然后从 MISO 上连续读数据读完拉高 CS。这里要注意地址范围MR25H40CDF 容量 4Mbit也就是 512KB24 位地址里高 5 位必须为 0。如果软件没做边界检查连续写越过最大地址时地址会回卷覆盖到存储器开头的区域这个坑我在后面会详细说。3. CEC1302 侧连接与驱动移植从电平到寄存器3.1 CEC1302 在这套系统里的实际分工CEC1302 给我的印象是一颗“干活很稳”的低功耗嵌入式控制器。它有一颗 MIPS32 内核片内集成 Flash 和 SRAMSPI、I2C、UART、定时器、PWM、GPIO 这些外设基本齐全非常适合做工业设备里的辅助管理角色。在我的项目里CEC1302 负责三件事一是开机时从 MRAM 里读取上次保存的设备状态和参数二是运行期间周期性地采集外部信号、更新 MRAM 里的运行日志三是掉电瞬间接管现场把最后的故障字、累计值写进 MRAM。选它还有一个原因MIPS32 内核的 C 语言开发环境成熟驱动代码迁移容易。CEC1302 片上本身有 Flash 和 SRAM但工业日志这种经常改写的数据不能总往片上 Flash 里写否则会快速消耗片内 Flash 寿命。挂着外部 MRAM就相当于给这颗控制器配了一个“可以随便写、掉电不丢”的草稿本。3.2 电平怎么搭直连、转换还是换版本硬件连接首先要解决电平一致性问题。MR25H40CDF 是 1.8V 供电版本CEC1302 的 IO 电平要看具体板级设计。如果 CEC1302 的 IO 电源域也是 1.8VSPI 的四根线加 CS 可以直接连这是最简单的情况。如果 CEC1302 工作电压和 IO 是 3.3V我在现场给过三种解决思路各有取舍。第一种最省事把存储芯片换成 3.3V 供电的 MR25H40CDC。同系列不同后缀版本性能和命令完全一致但电压域匹配了不用加任何转换器件。开发前期我强烈建议这么干先把功能跑通后面再考虑低电压优化。第二种是加电平转换芯片比如 SN74AVC4T245 这类双向转换器适合那种“1.8V 版本已经定死不能换”的项目。第三种是 SPI 信号用电阻分压和钳位二极管凑合SCK、SI、CS 是主到从单向SO 是从到主单向方向固定理论可行但工业现场 EMC 环境复杂波形边缘不干净很容易出问题我不推荐在正式产品上这么省。电源方面MRAM 的 VDD 要加 0.1µF 高频去耦电容和 1µF 储能电容两个电容都要尽量靠近芯片电源引脚。布局上SPI 走线尽可能短且远离大电流开关器件MRAM 虽然是磁存储技术对一般磁场有抗扰度但贴近大电感、变压器、直流电机之类强磁场源仍然不是好事能避就避。3.3 CEC1302 SPI 初始化用 GPIO 管 CS 是有意的CEC1302 的 SPI 外设初始化需要设置引脚复用、主从模式、时钟极性和相位、位宽、波特率。我这边的方式是引脚复利用作 SPI 功能配置成主机模式8 位数据宽度MSB 先行时钟极性 CPOL0、相位 CPHA0也就是 SPI 模式 0。MR25H40CDF 同时支持 SPI 模式 0 和模式 3选模式 0 方便和大多数 MCU 默认配置保持一致。这里要特别说一个设计决定CS 线不要用 SPI 外设的硬件自动片选而是单独用一个普通 GPIO 来手动控制。原因很简单MRAM 的一条命令可能包含“命令字节 3 字节地址 任意长度数据”硬件自动 CS 常常在每次字节收发结束时就把片选释放了没办法完成一次连续的突发传输。GPIO 手动控制 CS 的好处是从拉低到拉高的整个时长完全由软件掌握批量读写命令可以一次成型不会因为片选被中途拉高而出错。性能上 GPIO 翻转的时序开销微乎其微可靠性收益却是实打实的。3.4 驱动层完整的读、写、状态函数我整理的驱动代码可以直接移植到 CEC1302 上底层的 SPI 收发函数和 GPIO 控制宏需要按自己的板级定义替换。核心逻辑如下。#define MRAM_SIZE (512U * 1024U) /* 4Mbit 512KByte */ #define MRAM_WREN 0x06 #define MRAM_WRDI 0x04 #define MRAM_RDSR 0x05 #define MRAM_WRSR 0x01 #define MRAM_READ 0x03 #define MRAM_WRITE 0x02 #define MRAM_SLEEP 0xB9 #define MRAM_WAKE 0xAB #define MRAM_CS_LOW() mram_cs_gpio_write(0) #define MRAM_CS_HIGH() mram_cs_gpio_write(1) extern void mram_cs_gpio_write(uint8_t level); extern uint8_t spi_tx_rx(uint8_t byte); /* CEC1302 SPI 收发函数 */ static void mram_write_enable(void) { MRAM_CS_LOW(); spi_tx_rx(MRAM_WREN); MRAM_CS_HIGH(); } static void mram_write_disable(void) { MRAM_CS_LOW(); spi_tx_rx(MRAM_WRDI); MRAM_CS_HIGH(); } uint8_t mram_read_status(void) { uint8_t status; MRAM_CS_LOW(); spi_tx_rx(MRAM_RDSR); status spi_tx_rx(0xFF); MRAM_CS_HIGH(); return status; } void mram_write_status(uint8_t value) { mram_write_enable(); MRAM_CS_LOW(); spi_tx_rx(MRAM_WRSR); spi_tx_rx(value); MRAM_CS_HIGH(); } /* 从 addr 开始读 len 字节调用前确保 addr len MRAM_SIZE */ void mram_read(uint32_t addr, uint8_t *buf, uint32_t len) { uint32_t i; MRAM_CS_LOW(); spi_tx_rx(MRAM_READ); spi_tx_rx((uint8_t)((addr 16) 0xFF)); spi_tx_rx((uint8_t)((addr 8) 0xFF)); spi_tx_rx((uint8_t)(addr 0xFF)); for (i 0; i len; i) { buf[i] spi_tx_rx(0xFF); } MRAM_CS_HIGH(); } /* 从 addr 开始写 len 字节调用前确保 addr len MRAM_SIZE */ void mram_write(uint32_t addr, const uint8_t *buf, uint32_t len) { uint32_t i; mram_write_enable(); MRAM_CS_LOW(); spi_tx_rx(MRAM_WRITE); spi_tx_rx((uint8_t)((addr 16) 0xFF)); spi_tx_rx((uint8_t)((addr 8) 0xFF)); spi_tx_rx((uint8_t)(addr 0xFF)); for (i 0; i len; i) { spi_tx_rx(buf[i]); } MRAM_CS_HIGH(); /* 可选轮询状态寄存器等 WEL 清零 */ } void mram_sleep(void) { MRAM_CS_LOW(); spi_tx_rx(MRAM_SLEEP); MRAM_CS_HIGH(); } void mram_wake(void) { MRAM_CS_LOW(); spi_tx_rx(MRAM_WAKE); MRAM_CS_HIGH(); /* 唤醒后建议加微小延时再操作详见第 5 章 */ } void mram_init(void) { mram_write_status(0x00); /* 清除块保护确认 WEL 正常 */ (void)mram_read_status(); }底层发一个字节的同时会收回一个字节所以读数据时发 0xFF 作为时钟输入。CEC1302 的 SPI 硬件一般自带移位寄存器spi_tx_rx实现起来很直接关键是确保每一字节之间 CS 不能拉高这样才能保证突发读写的地址连续性。4. 工业级读写封装CRC、事务日志与掉电一致性4.1 为什么裸驱动不够数据校验与完整性很多工程师拿到驱动函数就开始写业务代码读写都通了就觉得完事了。但在工业现场校验必不可少。原因有两层第一MRAM 本身数据保持能力很强但 SPI 走线在电机启停、变频器干扰下可能发生比特翻转第二软件层面的地址越界、并发访问冲突同样会造成数据错乱。裸驱动只能保证“存进去的字节能读出来”不能保证“数据在物理上永远正确”。我在应用层一律加 CRC 校验。参数区用 CRC32日志条目用 CRC16计算量小碰撞概率也足够低。CRC 不光是写在存储区末尾还要连同“魔数 版本号 数据长度”一起校验这样既能发现数据错误也能识别数据新旧和格式变化。升级固件以后参数区结构变了版本号不匹配就知道要做参数迁移而不是傻乎乎地把旧数据当新格式解析。4.2 参数区双槽冗余改一半也不怕配置参数属于“改了必须能保存、坏了必须能恢复”的高价值数据。我的做法是在 MRAM 里划出两个槽位每个槽位前面放一个头部结构后面放参数主体和 CRC。参数区 A 槽: [魔数][版本][槽号][参数数据][CRC32] 参数区 B 槽: [魔数][版本][槽号][参数数据][CRC32]读取原则是优先读 A 槽校验失败再读 B 槽两个都失败就走默认参数。写入原则是修改参数时先写非当前有效槽写完校验通过后再更新该槽的头信息。掉电发生在任何时候至少有一个槽是完整可用的。这套双槽机制在 EEPROM 时代很流行但那时候因为写次数限制频繁双槽切换会加速介质老化。MRAM 完全没有这个顾虑双槽随便切寿命根本不计较。4.3 日志区环形缓冲不需要擦除的设计如果用 Flash 做环形日志最痛苦的事情是“日志写满了要擦老页”擦除期间掉电可能连引导数据都弄坏。MRAM 让我彻底摆脱了这个包袱。日志区可以设计成原地覆盖的环形缓冲每一条日志记录写完后就更新头部的写指针旧日志被新日志自然覆盖没有擦除动作也没有“腾空页”的中间态。头块的设计是这样write_index记录下一条日志的写入偏移next_seq记录下一条日志的序号wrapped标记是否已经绕回覆盖过。每条日志条目自带序号、长度、CRC。写入时先把条目内容写到write_index指向的位置回读校验成功后再更新头块。如果掉电发生在“条目写完、头块未更新”之间扫描日志时通过序号不连续就能发现最后一条不完整直接跳过它不影响前面所有日志。这里 MRAM 的好处特别明显日志条目的更新可以一条指令直接覆盖不需要“先擦后写”加上写数据本身原子日志完整性逻辑简单了一大截。4.4 掉电保护与并发访问CEC1302 内部有电源监视功能外部也可以加电压检测芯片。掉电检测触发后软件要立即放弃非关键任务把最重要的几个字段故障码、累计值、当前状态压缩成一个小数据块写入 MRAM。因为 MRAM 写入快且原子这个紧急写过程可以在电压跌穿之前从容完成不用像 EEPROM 那样提心吊胆地等编程完成。如果系统里跑了 RTOSSPI 总线必须加互斥锁。这里有个容易忽略的细节整个“CS 拉低 发命令/地址/数据 CS 拉高”的过程要在同一把锁内完成。不然日志任务刚拉低 CS 发送地址参数任务也抢到 SPI 总线开始传数据两条命令的字节在线上会搅成一团。我在项目里直接用一个 RTOS mutex 把mram_write、mram_read包起来中断里不发长数据需要记录告警时只置标志位由高优先级任务去执行实际写入避免锁死在中断上下文。5. 现场踩坑记录HOLD/WP、睡眠唤醒、SPI 模式与地址越界5.1 悬空的 HOLD 和 WP 引脚让我白调了一下午第一次画板时我把 HOLD# 和 WP# 引脚空着了想着芯片默认电平应该没问题结果调试时出现一个非常诡异的现象正常读写几十次然后突然一次写操作没反应过一会儿又自己恢复了。拿示波器看 CS、SCK、MOSI 波形完全正常但 MRAM 就是不响应。排查到最后发现是 HOLD# 引脚悬空手指碰到板子边缘、线缆靠近封装焊盘时耦合进去的噪声把 HOLD# 拉低了SPI 传输被芯片内部暂停命令自然执行不完。后来两个引脚都加了 10kΩ 上拉到 VDD问题彻底消失。这块的经验是在工业环境里任何“不用”的接口引脚都不能简单悬空该上拉的上拉该下拉的下拉。另外注意块保护位。曾经出现过一次“写数据回读是 0xFF”的情况查了很久发现是旧代码把状态寄存器的块保护位设成了非零值MRAM 整个存储区被锁定WREN 以后写也写不进去。初始化函数里固定执行一次mram_write_status(0x00)能避免很多莫名其妙的写失败。5.2 SPI 模式两套都能用但别来回切MR25H40CDF 支持 SPI 模式 0 和模式 3这对设计者来说挺友好但也埋了一个小坑。CEC1302 的 SPI 模块在不同驱动版本里可能有不同的默认极性配置有人在模式 0 下调好驱动后面优化功耗时把 SPI 初始化函数重构了一遍顺手改成了模式 3但因为 MRAM 两种模式都支持功能上仍然能跑通反过来让现场问题更隐蔽——电压、时序、硬件都没问题就是某个引脚在采样边沿刚好读到了不稳定电平出现“偶尔读错一个字节”的怪毛病。我的建议是整个项目只锁定一种模式最好写在硬件设计文档里驱动初始化时从配置项读取禁止“顺手改”。模式不匹配一般不会烧芯片但会让调试时间翻倍。5.3 地址超过 512KB 的越界回卷MR25H40CDF 容量 4Mbit也就是 512KBSPI 命令里的地址是 24 位。芯片物理上只有低 19 位地址有效高 5 位写什么都无所谓但越过 0x7FFFF 继续写地址计数器已经溢出回到 0x00000 继续写。曾经我在日志模块里计算写入偏移时少写了一个边界判断日志写到末尾后没有停在原地而是绕回开头把参数区数据覆盖了还花了很长时间才意识到是因为“日志区和参数区挨着”。后来我在驱动层统一加了边界钳制所有读写前先判断目标长度是否越界越界就截断或者报错绝不放行底层硬件。对于日志区这种必须允许绕回的设计我在应用层专门处理回卷逻辑而不是把越界地址直接交给驱动。这个习惯救了很多次后续的现场问题。5.4 睡眠唤醒命令的时序坑低功耗设计时让 MRAM 进睡眠模式能省不少待机电流但唤醒流程有讲究。芯片收到 SLEEP 命令后会进入睡眠态此时除了 WAKE 命令其他命令一概不响应。WAKE 命令的执行方式是 CS 拉低发送 0xAB然后 CS 拉高之后需要等待一个恢复时间才能执行正常读写。很多第一次用的人会忽略这个等待时间唤醒后马上读状态寄存器读出来全是垃圾数据。我这里的做法是mram_wake()函数里在 CS 拉高后加一个至少 10µs 的延时再继续后续操作。同时把“上电初始化”和“从睡眠唤醒”做成两条独立路径避免业务代码里重复执行mram_init()导致状态错乱。另外要注意的是片上 Flash 编程或者调试器连接时别让无关的 SPI 时钟漏到 MRAM 的 SCK 上否则可能误触发命令把不该写的地址写了。5.5 上电时序别在电压爬升期间就开始访问工业设备上电瞬间电源电压有一个爬升过程。CEC1302 自己有上电复位但 MRAM 也有一个上电初始化时间在 VDD 还没稳定、内部逻辑没有就绪时就发起 SPI 访问可能返回错误状态甚至让芯片处于不确定模式。我一般在主控启动流程里等电源稳定指示灯亮起后先读取一次 MRAM 状态寄存器如果读到的值异常就等一小段再重试两次重试都失败才上报错误而不是把一次失败直接判定为硬件故障。同理掉电过程中也有一个危险窗口。掉电检测触发后软件只做最小的关键写入写完立刻停止所有 MRAM 访问。不要想着顺手再补一条日志、刷新一下统计值电压一旦跌破芯片最低工作电压写一半比不写更麻烦。得益于 MRAM 原子写特性就算真的在写入中间断电存储单元也不是“烂一半”的状态但我仍然会刻意把最关键的数据放在一个独立的小块里让紧急写操作最短、最可控。最后说一句实在话。MR25H40CDF 和 CEC1302 这对组合给我带来的价值不只是某条命令怎么写、某个引脚怎么拉而是让我重新审视了“存储”这件事。以前用 Flash 和 EEPROM 时为了防止磨损、防止擦写掉电软件层面积累了一堆补丁磨损均衡、固化备份、掉电抢救、异步擦除。换成 MRAM 之后环形日志不需要擦除参数区双槽随便切紧急写不用等编程窗口整个存储模块的代码量简化了接近一半。如果你也正在做需要频繁断电保存数据的工业板卡先花半天时间画清楚自己的数据模型再去算 Flash 和 MRAM 的账——在我的项目里这笔账的答案已经非常清楚了。
返回列表