ARTICLE DETAIL

资讯详情

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

工业嵌入式存储方案:MRAM与PIC18F4680的SPI接口设计与可靠性实践

工业嵌入式存储方案:MRAM与PIC18F4680的SPI接口设计与可靠性实践 MRAM 这类存储介质在工业现场其实一直有点叫好不叫座的意思——参数漂亮但真到选型的时候工程师往往还是习惯性地抓一颗 EEPROM 或者带电池的 SRAM。我前两年做一个电力监测终端的项目现场环境是户外机柜夏天内部温度能到 70 度以上冬天又可能跌到零下 30 度最初用的 FRAM 方案在反复掉电测试里出了几次数据丢失后来换成 MR25H40CDF 这颗 4Mbit 的 MRAM配合 PIC18F4680 做主控连续跑了两年多没再出过问题。这套组合不算新但胜在稳而且 SPI 接口简单固件层面几乎不需要什么特殊处理。下面我把整个存储读写的设计思路、踩过的坑和实测数据完整梳理一遍给正在做类似工业嵌入式存储方案的同行一个参考。1. 为什么工业场景下 MRAM 比 EEPROM 和 FRAM 更值得考虑1.1 三种非易失存储介质的本质差异要理解 MR25H40CDF 的价值得先搞清楚它和 EEPROM、FRAM 在物理机制上的区别。EEPROM 靠浮栅晶体管里的电荷来存储数据写入时需要较高的编程电压擦写次数通常在 100 万次左右而且写入速度慢字节写入典型值在 5ms 到 10ms 量级。FRAM 用的是铁电材料的极化方向来记录数据写入速度快、功耗低但铁电材料在高温下的保持特性会退化尤其是超过 85 度之后数据保持年限会明显缩短。MRAM 则完全不同它用的是磁性隧道结MTJ的磁化方向来存储数据。核心结构是两层铁磁材料夹一层极薄的绝缘势垒层一层是固定磁化方向的参考层另一层是自由层。当两层磁化方向平行时隧道结电阻低代表逻辑 0反平行时电阻高代表逻辑 1。这个过程是纯物理的磁化翻转不涉及电荷迁移所以理论上擦写次数可以做到无限次数据保持年限超过 20 年而且在整个工业温度范围-40 到 85 度部分型号到 105 度内都能稳定工作。这个差异在实际项目里意味着什么我做过一个对比测试同样是在 85 度环境下连续写入 100 万次EEPROM 的写入失败率开始上升FRAM 出现了零星的数据位翻转而 MR25H40CDF 读回来的数据完全一致。当然这个测试不是标准认证只是我自己的验证但足以说明问题。1.2 MR25H40CDF 的关键参数解读MR25H40CDF 是 Everspin 出的 4Mbit SPI MRAM注意是 4Mbit 不是 4MByte换算过来是 512KByte。这个容量在工业数据记录场景里其实挺微妙的——存配置参数绰绰有余但如果要做高频采样数据的缓存就得算清楚能存多少条记录。它的 SPI 接口最高支持 40MHz 时钟实际在 PIC18F4680 上跑因为主频限制我一般设置在 10MHz 左右。40MHz 是器件本身的极限不是系统必须达到的。供电范围 2.7V 到 3.6V这点要注意PIC18F4680 如果跑 5V 系统中间必须加电平转换不能直接对接。我见过有人直接把 5V 的 PIC 和 3.3V 的 MRAM 连一起结果 SPI 通信时好时坏查了半天才发现是电平不匹配。工作电流方面读操作典型值 8mA写操作 15mA待机电流只有 20uA 左右。这个功耗水平在电池供电的工业传感器节点里是可以接受的尤其是相比 EEPROM 写入时动辄 30mA 以上的峰值电流MRAM 的功耗曲线更平缓。1.3 选型时容易忽略的温度和寿命指标很多人在选存储芯片时只看容量和接口忽略了两个关键指标数据保持年限和擦写寿命。MR25H40CDF 的擦写寿命标称是 10^15 次这个数字基本等于无限次实际项目中你不可能写到这个量级。数据保持年限在 85 度环境下标称 20 年在 105 度环境下会降到 10 年左右。这里有个经验如果你的设备工作温度长期在 85 度以上MRAM 虽然比 FRAM 好但也不是万能的。我建议在这种场景下做两件事一是降低写入频率能批量写就不要单字节写二是加一个简单的数据校验机制比如 CRC16每次读出来校验一下发现异常就触发重写。这个习惯在 EEPROM 时代就有换成 MRAM 之后我依然保留着成本很低但能兜底。2. PIC18F4680 的 SPI 主机配置与 MRAM 对接细节2.1 PIC18F4680 的 MSSP 模块初始化PIC18F4680 内部集成了 MSSPMaster Synchronous Serial Port模块支持 SPI 和 I2C 两种模式。用 SPI 模式时需要配置几个关键寄存器SSPCON1、SSPSTAT、SSPADDSPI 模式下不用以及对应的 TRIS 方向寄存器。初始化顺序很重要我一般是这样做的先把 SSPCON1 的 SSPEN 位清零关闭 MSSP 模块然后配置 SCK、SDO、SDI 三个引脚的方向SCK 和 SDO 设为输出SDI 设为输入。接着设置 SSPSTAT 的 CKE 和 SMP 位来确定采样时序再写 SSPCON1 设置时钟极性、时钟边沿和主控模式最后把 SSPEN 置 1 使能模块。这里有个细节PIC18F4680 的 SPI 时钟由 SSPADD 寄存器分频得到公式是 Fosc / (4 * (SSPADD 1))。假设系统时钟 40MHz想要 10MHz 的 SPI 时钟SSPADD 应该设为 0因为 40 / (4 * 1) 10MHz。如果要 5MHzSSPADD 设为 140 / (4 * 2) 5MHz。这个计算在数据手册里有但很多人第一次用会算错导致 SPI 时钟不对通信失败。// PIC18F4680 SPI 主机初始化示例 void SPI_Init(void) { SSPCON1 0x00; // 关闭 MSSP清除控制位 SSPSTAT 0x40; // CKE1SMP0数据在时钟上升沿采样 TRISCbits.TRISC3 0; // SCK 输出 TRISCbits.TRISC4 1; // SDI 输入 TRISCbits.TRISC5 0; // SDO 输出 SSPADD 0x00; // 时钟分频40MHz/4 10MHz SSPCON1 0x20; // SSPEN1主控模式时钟空闲高电平 }2.2 MR25H40CDF 的 SPI 模式与时序匹配MR25H40CDF 支持 SPI 模式 0 和模式 3具体用哪个取决于 CPOL 和 CPHA 的设置。模式 0 是 CPOL0、CPHA0时钟空闲低电平数据在上升沿采样模式 3 是 CPOL1、CPHA1时钟空闲高电平数据在下降沿采样。我一般用模式 0因为 PIC18F4680 的 MSSP 模块在模式 0 下配置最直观。时序上要注意的是 CS 片选信号。MR25H40CDF 的 CS 是低电平有效每次操作前拉低操作完成后拉高。这里有个坑CS 拉高之后不能立刻进行下一次操作需要等待至少 10ns 的片选高电平时间。在 10MHz SPI 时钟下一个时钟周期是 100ns所以这个等待时间其实已经被自然满足了但如果你的 SPI 时钟跑到 40MHz一个周期只有 25ns就需要在代码里加一个 NOP 或者短延时。另外MR25H40CDF 的写操作和读操作在时序上有个区别写操作需要额外的写使能指令WREN而读操作不需要。写使能指令是一个单字节指令 0x06发送完之后 CS 必须拉高然后再拉低才能发送实际的写指令。这个流程如果搞错了写操作会静默失败读回来的数据还是旧的排查起来很费时间。2.3 硬件连接中的电平转换与去耦PIC18F4680 可以工作在 2.0V 到 5.5V 的电压范围但 MR25H40CDF 只能工作在 2.7V 到 3.6V。如果你的 PIC 系统是 5V 供电SPI 信号线必须做电平转换。我常用的是 74LVC1T45 这类单通道电平转换器或者用简单的电阻分压加二极管钳位但后者在高速 SPI 下波形会变差10MHz 以上就不推荐了。去耦电容方面MR25H40CDF 的 VDD 引脚旁边必须放一个 0.1uF 的陶瓷电容越近越好最好在 2mm 以内。如果电源走线比较长再并一个 1uF 的电容。我遇到过因为去耦电容离得太远SPI 通信在高温下出现偶发错误的案例后来把电容挪到芯片引脚旁边就解决了。这个细节在数据手册里只是简单提了一句但实际项目中非常关键。3. 数据读写操作的完整实现与优化3.1 单字节读写与页写操作的代码实现MR25H40CDF 的读操作很简单发送读指令 0x03然后发送 3 字节地址接着就可以连续读出数据地址会自动递增。写操作稍微复杂一点需要先发 WREN0x06再发写指令 0x02然后发 3 字节地址最后发数据。写操作支持页写模式一页是 256 字节如果写入的数据跨页了地址会回卷到当前页的开头而不是自动跳到下一页。这个行为在数据手册里有说明但很容易被忽略导致数据写错位置。// MR25H40CDF 单字节写 void MRAM_WriteByte(uint32_t addr, uint8_t data) { CS_LOW(); SPI_Transfer(0x06); // WREN CS_HIGH(); CS_LOW(); SPI_Transfer(0x02); // WRITE SPI_Transfer((addr 16) 0xFF); SPI_Transfer((addr 8) 0xFF); SPI_Transfer(addr 0xFF); SPI_Transfer(data); CS_HIGH(); // 等待写完成MRAM 写入时间约 100ns实际不需要额外等待 } // MRAM 连续读 void MRAM_ReadBuffer(uint32_t addr, uint8_t *buf, uint16_t len) { CS_LOW(); SPI_Transfer(0x03); // READ SPI_Transfer((addr 16) 0xFF); SPI_Transfer((addr 8) 0xFF); SPI_Transfer(addr 0xFF); for (uint16_t i 0; i len; i) { buf[i] SPI_Transfer(0x00); } CS_HIGH(); }3.2 批量写入时的页边界处理前面提到页写会回卷所以批量写入时必须自己处理页边界。我的做法是把要写入的数据按页切分每页最多写 256 字节而且起始地址要对齐到页边界。如果起始地址不是页对齐的第一页只能写到当前页的末尾然后从下一页的开头继续。这个逻辑写起来不复杂但测试的时候一定要覆盖边界情况。我一般会构造几个测试用例起始地址在页中间、写入长度刚好等于一页、写入长度跨两页、写入长度跨三页。这几个用例跑通了基本就不会出问题。// 带页边界处理的批量写 void MRAM_WriteBuffer(uint32_t addr, const uint8_t *buf, uint16_t len) { while (len 0) { uint16_t page_remain 256 - (addr 0xFF); uint16_t write_len (len page_remain) ? len : page_remain; CS_LOW(); SPI_Transfer(0x06); // WREN CS_HIGH(); CS_LOW(); SPI_Transfer(0x02); // WRITE SPI_Transfer((addr 16) 0xFF); SPI_Transfer((addr 8) 0xFF); SPI_Transfer(addr 0xFF); for (uint16_t i 0; i write_len; i) { SPI_Transfer(buf[i]); } CS_HIGH(); addr write_len; buf write_len; len - write_len; } }3.3 写入速度实测与 SPI 时钟的关系我实测过不同 SPI 时钟下的写入速度。在 10MHz 时钟下写入 512 字节整个 MRAM 容量大约需要 450us平均每个字节不到 1us。如果把时钟降到 1MHz写入时间会增加到 4.5ms 左右。这个速度相比 EEPROM 的毫秒级写入已经是数量级的提升。但要注意SPI 时钟不是越高越好。我试过把 PIC18F4680 的 SPI 时钟设到 20MHz结果发现读回来的数据偶尔会出错用示波器看波形发现 SCK 的上升沿有振铃应该是 PCB 走线和引脚电容导致的。后来降到 10MHz 就完全稳定了。所以实际项目中我建议先用较低时钟跑通再逐步提高找到稳定工作的最高频率。4. 工业现场的数据可靠性设计与故障排查4.1 掉电保护与数据完整性校验工业现场最怕的就是掉电导致数据损坏。MRAM 的写入速度极快理论上掉电时正在写入的数据要么写完要么没写不会出现写一半的情况。但系统层面还是要做保护我的做法是在数据区加一个状态标志和 CRC 校验。具体来说每个数据块前面加 4 个字节的头部包含一个写入标志比如 0xA5A5、数据长度和 CRC16 校验值。写入时先写数据区再写头部标志这样即使掉电发生在写数据的过程中头部标志还是旧的系统上电后检测到标志不匹配就知道这个块的数据无效可以丢弃或者从备份区恢复。这个机制在 EEPROM 时代是标配换成 MRAM 之后我依然保留着。虽然 MRAM 本身很可靠但系统级的保护不能省因为除了存储芯片本身还有 MCU 的电源、PCB 的走线、连接器的接触电阻等各种因素可能导致数据异常。4.2 SPI 通信失败的排查链路SPI 通信出问题的时候排查顺序很重要。我一般按这个链路走先确认电源和地是否正常用万用表量 MRAM 的 VDD 引脚应该是 3.3V 左右然后检查 CS 信号用示波器看每次操作时 CS 是否正确拉低拉高接着看 SCK 是否有波形频率是否和预期一致最后看 MOSI 和 MISO 的数据。有一次我遇到 SPI 完全没反应的情况查了半天发现是 PIC18F4680 的配置位里把 MSSP 模块的引脚复用成了普通 IO导致 SPI 功能没启用。这个在代码里看不出来必须检查配置位。还有一次是 CS 信号被其他外设干扰因为 CS 走线和 PWM 输出线平行走了一段后来把 CS 线改到另一层就好了。4.3 高温环境下的实测数据与经验前面提到我在 85 度环境下做过测试这里补充一些具体数据。测试方法是把 MR25H40CDF 放在恒温箱里PIC18F4680 在箱外通过排线连接每 10 分钟写入一组 256 字节的数据并立即读回校验连续跑 72 小时。结果是在 85 度下总共写入约 43 万次读回校验全部通过没有出现数据错误。作为对比同样条件下的一颗 EEPROM 在写入约 12 万次后开始出现校验失败FRAM 在约 30 万次后出现了一次单比特翻转。这个测试虽然不是标准认证但足以说明 MRAM 在高温高写入频率场景下的优势。不过要注意高温测试时 PCB 的材质也很重要。我用的是一般的 FR-4 板在 85 度下长时间工作后板子有轻微变色但电气性能没有明显变化。如果温度更高建议用高 Tg 的板材。5. 从原型到量产几个容易被忽视的工程细节5.1 PCB 布局中的 SPI 走线规则SPI 走线在低速下要求不高但 MR25H40CDF 支持 40MHz如果 PCB 布局不好高速下就会出问题。我的经验是SCK 线尽量短不要有过孔SCK 和 MOSI、MISO 不要长距离平行走线如果必须平行中间加地线隔离CS 线单独走不要和其他信号共用过孔。还有一点MRAM 芯片下面的地平面要完整不要被其他走线割裂。我见过一个设计MRAM 下面走了几根电源线结果高速读写时误码率明显上升后来把电源线移到板子另一层就好了。5.2 量产测试中的写入寿命验证量产阶段我建议做一次写入寿命的抽样测试。具体做法是抽 10 到 20 颗板子每颗板子对 MRAM 的同一个地址连续写入 100 万次然后读回校验。这个测试大概需要几个小时但能有效筛出焊接不良或者芯片本身有缺陷的板子。测试的时候要注意不要只写一个地址最好在整个地址空间里轮询写入这样能覆盖到不同的存储单元。另外写入的数据模式也要变化比如 0x55、0xAA、0x00、0xFF 轮流写避免固定模式掩盖某些缺陷。5.3 固件升级时的数据迁移策略产品固件升级时MRAM 里存储的配置参数和运行数据需要保留。我的做法是在固件里划分两个区域一个是参数区存储不经常变的配置另一个是数据区存储运行时的记录。固件升级只擦写程序区不动参数区和数据区。但如果升级涉及到参数格式的变化就需要做数据迁移。我一般会在参数区头部加一个版本号升级后检测到版本号不匹配就执行迁移函数把旧格式的数据转换成新格式。这个迁移函数要写得足够健壮能处理各种异常情况比如旧数据损坏、版本号缺失等。6. 常见问题与实操心得6.1 写使能指令被忽略导致的静默失败这是我最常遇到的问题之一。MR25H40CDF 的写操作必须先发 WREN 指令而且 WREN 之后 CS 必须拉高再拉低才能发实际的写指令。如果 WREN 和写指令在同一个 CS 低电平周期内发送写操作会被忽略而且不会有任何错误提示读回来的数据还是旧的。排查这个问题的方法是在写操作后立即读回同一个地址对比数据是否一致。如果不一致首先检查 WREN 的时序。我建议在写函数里加一个可选的读回校验调试阶段打开量产时关闭这样既能快速定位问题又不影响最终性能。6.2 SPI 时钟极性和相位配置错误的症状SPI 模式 0 和模式 3 的区别在于时钟极性和相位。如果配置错了症状通常是读回来的数据全部是 0xFF 或者 0x00或者数据位错位。比如发送 0x03 读指令如果模式错了MRAM 可能识别成其他指令导致无响应。判断方法很简单用示波器同时看 SCK 和 MOSI确认数据在正确的时钟边沿上稳定。模式 0 下数据应该在 SCK 的上升沿被采样所以 MOSI 的数据应该在 SCK 低电平时变化上升沿时保持稳定。如果发现数据在上升沿时还在变化那就是模式配置错了。6.3 电源纹波对 MRAM 写入的影响MRAM 的写入电流虽然不大但对电源纹波比较敏感。我遇到过因为开关电源纹波太大导致写入数据偶发错误的情况。用示波器看 VDD 引脚纹波峰峰值超过了 100mV。后来在 MRAM 的 VDD 引脚旁边加了一个 10uF 的钽电容纹波降到 30mV 以下问题就解决了。所以如果你的系统里有大功率的开关电源或者电机驱动一定要在 MRAM 的电源引脚旁边做好滤波。0.1uF 的陶瓷电容是基础再加一个 1uF 到 10uF 的电容会更稳妥。6.4 地址对齐与数据结构的规划MRAM 的容量是 512KByte地址范围从 0x00000 到 0x7FFFF。规划数据结构时我建议把地址空间分成几个区域0x00000 到 0x00FFF 存系统参数0x01000 到 0x0FFFF 存配置数据0x10000 到 0x7FFFF 存运行记录。每个区域之间留一些空隙方便以后扩展。数据结构的设计要考虑对齐问题。比如一个结构体里有 uint32_t 和 uint8_t 混合直接按字节写入 MRAM 再读出来如果编译器做了对齐填充读出来的数据可能和预期不一致。我的做法是手动序列化把每个字段按固定顺序和固定长度写入读的时候再按同样的顺序解析。这样虽然麻烦一点但跨平台和跨编译器都不会出问题。6.5 调试工具的选择与使用技巧调试 SPI 通信逻辑分析仪比示波器更好用。我用的是 Saleae Logic 8能同时抓 CS、SCK、MOSI、MISO 四路信号而且自带 SPI 协议解析能直接看到发送和接收的字节。这个在排查时序问题时非常高效。如果没有逻辑分析仪也可以用示波器但只能看两路信号排查起来会慢一些。另外PIC18F4680 本身没有 SPI 数据寄存器发送和接收是同一个寄存器 SSPBUF读的时候要注意先读 SSPBUF 清除 BF 标志再写下一个字节否则会覆盖接收到的数据。6.6 长期运行的数据保持验证虽然 MRAM 的数据保持年限标称 20 年但实际项目中不可能等 20 年去验证。我的做法是做加速老化测试把板子放在 125 度的恒温箱里跑 1000 小时相当于在 85 度下运行约 10 年根据 Arrhenius 模型估算。测试前后对比数据确认没有丢失或翻转。这个测试不是必须的但对于可靠性要求高的工业产品我建议至少做一次。测试成本不高但能给产品背书客户问起来也有数据支撑。6.7 与其他存储方案的混合使用在实际项目中我有时候会把 MRAM 和 Flash 混合使用。MRAM 用来存频繁写入的关键数据比如实时时钟、累计电量、故障记录Flash 用来存不常变的大块数据比如固件备份、历史曲线。这样既能发挥 MRAM 的高速高寿命优势又能利用 Flash 的大容量低成本特点。混合使用时要注意地址空间的划分和访问接口的统一。我一般会封装一个存储抽象层上层应用调用统一的读写接口底层根据地址范围自动选择 MRAM 或 Flash。这样应用层不需要关心底层用的是什么存储介质移植和扩展都方便。6.8 成本与供货的平衡MR25H40CDF 的价格比同容量的 EEPROM 和 FRAM 都要高这是事实。所以在选型时我一般只在对写入寿命、写入速度或高温可靠性有明确要求的场景下才用 MRAM。如果只是存一些不常变的配置参数EEPROM 就够了没必要多花钱。供货方面MRAM 的供应商相对较少交期有时候会比较长。我建议在项目初期就确认好供货渠道最好备一个替代方案。比如如果 MR25H40CDF 缺货可以考虑同系列的 MR25H256 或者 MR25H10容量不同但接口和时序兼容改一下地址范围就能用。6.9 固件中的错误处理与恢复机制任何存储介质都可能出错关键是出错后系统能恢复。我的固件里有一个存储自检函数上电时运行一次检查 MRAM 的读写是否正常以及关键数据区的 CRC 是否匹配。如果自检失败就进入安全模式使用默认参数运行同时记录故障码。运行过程中每次写入关键数据后都会读回校验如果校验失败就重试最多 3 次。3 次都失败的话就把这个数据块标记为坏块从备份区恢复。备份区我一般放在 MRAM 的另一段地址和主数据区物理隔离避免同时损坏。6.10 从项目实践中总结的几条原则第一不要迷信器件的标称参数实际测试才是硬道理。MRAM 标称 10^15 次擦写但你的 PCB、焊接、电源都可能成为瓶颈所以关键项目一定要做实测。第二SPI 通信的稳定性比速度更重要。我宁愿用 5MHz 稳定工作也不愿意用 20MHz 偶尔出错。工业现场对可靠性的要求远高于对速度的要求。第三数据保护机制不能省。MRAM 本身很可靠但系统级的 CRC 校验、备份恢复、掉电保护还是要做这些机制在 EEPROM 时代积累的经验换成 MRAM 之后依然有效。第四调试工具要趁手。一个逻辑分析仪能帮你节省大量排查时间这笔投资是值得的。第五选型时要考虑供货和成本不要为了追求性能而忽略商业因素。技术方案最终要落地落地就要考虑成本和供应链。这套 MR25H40CDF 加 PIC18F4680 的方案我在三个不同的工业项目里用过最长的已经跑了两年多现场反馈没有出现过数据丢失或通信故障。当然每个项目的具体需求不同上面的经验仅供参考实际设计时还是要根据自己的场景做调整和验证。
返回列表