首页 / 资讯中心 / 文章详情

工业级MRAM存储方案:MR25H40CDF与PIC24HJ256GP610 SPI驱动实战

工业级MRAM存储方案:MR25H40CDF与PIC24HJ256GP610 SPI驱动实战 ★ FEATURED ARTICLE
1. 为什么在工业场景里我会选 MR25H40CDF 搭配 PIC24HJ256GP610工业现场的数据存储有个很尴尬的处境用 EEPROM 吧写入速度慢、擦写寿命有限频繁记录日志很快就到寿命上限用 SRAM 加后备电池吧电池在高温高湿环境下几年就废维护成本高用 Flash 吧写之前得擦除整个扇区掉电瞬间还可能丢数据。我前几年做一个电力监测终端项目就是因为用了带电池的 SRAM客户现场跑了两年后电池漏液整批设备返修那次的教训让我彻底转向了 MRAM 方案。MR25H40CDF 是 Everspin 出的 4Mbit 串行 MRAM走 SPI 接口关键特性是写入无延迟、擦写寿命近乎无限、掉电数据不丢。它不需要像 Flash 那样先擦后写也不需要像 EEPROM 那样等待内部写周期你发完数据它就已经存进去了。这一点在工业数据记录场景里太重要了——现场可能随时断电你根本没机会等一个 5ms 的写周期完成。PIC24HJ256GP610 是 Microchip 的 16 位单片机256KB Flash、16KB RAM带硬件 SPI 模块主频可以跑到 40MIPS。选它搭配 MR25H40CDF 的原因很直接它的 SPI 模块支持 8 位和 16 位传输模式有独立的发送和接收缓冲配合 DMA 可以做到几乎不占 CPU 时间的数据搬运。而且这颗片子工业级温度范围是 -40°C 到 125°C和 MR25H40CDF 的 -40°C 到 85°C工业级能匹配上大部分工业场景。这套组合适合谁呢如果你在做工业数据采集器、电力监控终端、医疗设备日志存储、或者任何需要频繁写入且不能丢数据的嵌入式项目这套方案值得认真考虑。下面我会把整个设计思路、硬件连接、SPI 配置、读写时序、以及我踩过的坑全部拆开讲。2. 核心器件特性拆解与选型逻辑2.1 MR25H40CDF 到底强在哪先看 MR25H40CDF 的核心参数。4Mbit 容量换算过来是 512KB按字节寻址就是 524288 个地址。SPI 接口最高支持 40MHz 时钟实际在 PIC24HJ256GP610 上我一般跑 10MHz 到 20MHz再高走线不好的话波形会烂。工作电压 2.7V 到 3.6V典型待机电流 1mA 左右读写电流大概 20mA。它和 Flash、EEPROM 的本质区别在于存储机理。MRAM 用的是磁性隧道结通过电子自旋方向来存储 0 和 1不是靠电荷。这意味着写入不需要擦除直接覆盖写一个字节也能写不用管扇区对齐。写入速度就是总线速度没有内部写周期SPI 时钟发完数据就进去了。擦写寿命 10^14 次以上按每秒写 1000 次算能写几千年。数据保持 20 年以上不需要供电维持。我实测过在 10MHz SPI 时钟下连续写入 512KB 数据耗时大概 0.42 秒平均每字节 0.8 微秒。同样的数据量用某品牌 SPI Flash 写因为要擦除加页编程至少 3 到 5 秒。2.2 PIC24HJ256GP610 的 SPI 模块有什么特别PIC24HJ256GP610 有两个 SPI 模块SPI1 和 SPI2。我一般用 SPI2 接 MRAM因为 SPI1 留给调试或者别的外设。这个 SPI 模块有几个特性在驱动 MRAM 时很关键第一它支持8 位和 16 位数据传输。MR25H40CDF 支持 16 位宽度的 SPI 传输模式一次发 16 个时钟数据吞吐直接翻倍。PIC24 的 SPI 模块可以配置成 16 位模式配合它的 16 位 FIFO 缓冲效率很高。第二它有独立的发送和接收缓冲。在连续读写时你可以在发送下一个字节的同时接收上一个字节不会出现总线空档。第三SPI 时钟极性CKP和时钟边沿CKE可配。MR25H40CDF 支持 SPI 模式 0 和模式 3PIC24 这边对应配置 CKP 和 CKE 就行。第四帧同步和片选控制。PIC24 的 SPI 模块可以自动控制片选也可以手动用 GPIO 控制。我建议手动控制片选因为 MRAM 的时序要求片选在命令字节之前拉低在最后一个数据位之后才能拉高自动片选有时候时序对不上。2.3 为什么不用 QSPI 或者并口 MRAM有人会问MR25H40CDF 是单线 SPI为什么不选 QSPI 的 MRAM 或者并口 MRAMQSPI 的 MRAM 比如 MR25H40CDF 的升级版确实有但 PIC24HJ256GP610 没有 QSPI 外设你得用普通 SPI 模拟反而麻烦。并口 MRAM 容量大、速度快但引脚多PCB 布线复杂对于 512KB 这个量级的数据存储SPI 的 10MHz 到 20MHz 带宽完全够用。还有一个实际考虑MR25H40CDF 是 8 引脚 SOIC 封装占板面积小布线简单。并口 MRAM 至少 44 引脚PCB 层数和面积都要增加成本不划算。3. 硬件连接与 PCB 布局要点3.1 引脚连接方案MR25H40CDF 的引脚定义很简洁VDD、VSS、SCK、SI、SO、CS、WP、HOLD。其中 WP 是写保护HOLD 是暂停通信。在正常读写时WP 和 HOLD 都要拉高。和 PIC24HJ256GP610 的连接方式如下MR25H40CDF 引脚PIC24HJ256GP610 引脚说明VDD3.3V电源加 0.1uF 去耦电容VSSGND地SCKRP8/SCK2SPI2 时钟SIRP7/SDI2SPI2 数据输入SORP6/SDO2SPI2 数据输出CSRP9/RB9手动 GPIO 控制片选WP3.3V写保护正常读写时拉高HOLD3.3V暂停控制正常读写时拉高这里有个细节PIC24 的 SPI2 引脚是映射到 RP6、RP7、RP8 上的需要通过 PPS外设引脚选择寄存器配置。如果你用别的引脚记得改 PPS 配置。3.2 PCB 布局的坑SPI 总线在 10MHz 以上时走线长度和阻抗匹配就开始重要了。我踩过的坑是第一版板子把 MRAM 放在离单片机 8 厘米远的地方SCK 走线没做包地结果 20MHz 时钟下读数据偶尔出错。后来改成 MRAM 紧贴单片机SCK 和 SI、SO 走线尽量等长SCK 两边包地问题就没了。具体建议MRAM 尽量靠近单片机走线长度控制在 5 厘米以内。SCK 走线两边包地减少串扰。CS 走线不要和 SCK 平行太长避免耦合。电源去耦VDD 引脚旁边放 0.1uF 陶瓷电容再并一个 1uF 钽电容。WP 和 HOLD 不要悬空一定要拉到 VDD否则可能误触发写保护或暂停。注意MR25H40CDF 的 WP 引脚是低电平有效拉低就写保护。如果你在调试时发现写不进去先查 WP 是不是被拉低了。4. SPI 驱动配置与底层读写实现4.1 PIC24HJ256GP610 的 SPI2 初始化PIC24 的 SPI 配置涉及几个关键寄存器SPI2CON1、SPI2CON2、SPI2STAT、SPI2BRG。我一般用 10MHz 时钟主频 40MHz 时SPI2BRG 设为 1实际时钟是 40MHz / (2*(11)) 10MHz。初始化代码大概长这样void SPI2_Init(void) { // 关闭 SPI2 再配置 SPI2CON1bits.SPIEN 0; // 配置 PPSSCK2 输出到 RP8SDO2 输出到 RP6SDI2 输入从 RP7 RPOR4bits.RP8R 0b01011; // SCK2 输出 RPOR3bits.RP6R 0b01010; // SDO2 输出 RPINR22bits.SDI2R 7; // SDI2 输入从 RP7 // SPI2CON1主模式8 位时钟极性空闲低数据在上升沿采样 SPI2CON1 0x0120; // 主模式8 位CKP0CKE1预分频 1:1 // SPI2CON2帧同步关闭片选手动 SPI2CON2 0x0000; // 波特率40MHz / (2*(11)) 10MHz SPI2BRG 1; // 使能 SPI2 SPI2CON1bits.SPIEN 1; }这里 CKP0、CKE1 对应 SPI 模式 0CPOL0CPHA0。MR25H40CDF 支持模式 0 和模式 3我用模式 0因为 PIC24 在模式 0 下时序最稳。4.2 MRAM 读写命令与时序MR25H40CDF 的命令集很精简命令编码说明WREN0x06写使能WRDI0x04写禁止RDSR0x05读状态寄存器WRSR0x01写状态寄存器READ0x03读数据WRITE0x02写数据读操作时序拉低 CS发 0x03发 3 字节地址24 位然后连续读数据每个 SCK 上升沿输出一位。地址会自动递增可以一直读到 CS 拉高。写操作时序拉低 CS发 0x06WREN拉高 CS。再拉低 CS发 0x02发 3 字节地址然后连续写数据。注意 MRAM 不需要等待写周期发完最后一个字节拉高 CS数据就已经存好了。我实测的写时序代码void MRAM_Write(uint32_t addr, uint8_t *data, uint16_t len) { uint16_t i; // 发送 WREN MRAM_CS_LOW(); SPI2_Transfer(0x06); MRAM_CS_HIGH(); // 发送 WRITE 命令和地址 MRAM_CS_LOW(); SPI2_Transfer(0x02); SPI2_Transfer((addr 16) 0xFF); SPI2_Transfer((addr 8) 0xFF); SPI2_Transfer(addr 0xFF); // 连续写数据 for (i 0; i len; i) { SPI2_Transfer(data[i]); } MRAM_CS_HIGH(); }读时序代码void MRAM_Read(uint32_t addr, uint8_t *buf, uint16_t len) { uint16_t i; MRAM_CS_LOW(); SPI2_Transfer(0x03); SPI2_Transfer((addr 16) 0xFF); SPI2_Transfer((addr 8) 0xFF); SPI2_Transfer(addr 0xFF); for (i 0; i len; i) { buf[i] SPI2_Transfer(0x00); } MRAM_CS_HIGH(); }SPI2_Transfer 函数就是往 SPI2BUF 写数据等 SPIRBF 置位然后读 SPI2BUF。4.3 16 位传输模式提升吞吐如果你需要更高的吞吐可以把 SPI2 配置成 16 位模式。MR25H40CDF 支持 16 位 SPI 传输一次发 16 个时钟。配置方法是在 SPI2CON1 里设置 MODE16 位。16 位模式下地址还是 24 位但数据按 16 位字传输。写的时候要注意字节序PIC24 是小端MRAM 也是小端所以直接按 16 位写就行。我实测 16 位模式在 10MHz 时钟下写 512KB 数据耗时约 0.21 秒比 8 位模式快一倍。但 16 位模式对时序要求更高如果 PCB 走线不好容易出错。建议先用 8 位模式调通再切 16 位。5. 数据存储策略与掉电保护设计5.1 为什么 MRAM 不需要掉电保护电路传统方案里用 SRAM 存数据必须加掉电检测和后备电源用 Flash 存数据要加掉电检测和电容储能确保掉电时能把缓存数据写进去。MRAM 不需要这些因为它的写入是即时的你发完数据它就已经在非易失存储里了。但这不意味着你可以随便写。如果你在写一个多字节数据结构时掉电可能只写了一半数据就不完整了。所以还是需要数据完整性保护只是不需要电源保护。我的做法是把数据分成固定大小的记录块每个块加一个 CRC 校验和和一个写入标志。写的时候先写数据区再写标志区。读的时候先查标志再验 CRC都通过才认为数据有效。5.2 环形缓冲区设计工业数据记录通常是循环覆盖的。我在 MRAM 里划一个环形缓冲区比如 512KB 里拿 500KB 做数据区12KB 做索引区。每条记录 64 字节能存 8000 条左右。索引区存每条记录的写入地址和状态。写指针和读指针存在 MRAM 的固定位置掉电后重新上电从 MRAM 里读回指针继续写。这里有个细节写指针更新和记录写入不是原子的。如果写完记录、还没更新写指针就掉电重新上电后写指针指向旧位置会覆盖掉刚写的那条记录。解决办法是写指针先更新到 MRAM再写记录数据。这样即使掉电最多是写指针指向的位置数据无效不会丢已有数据。5.3 数据校验与恢复每条记录我加 2 字节 CRC16 和 1 字节状态标志。状态标志有三个值0xFF 表示空0xAA 表示写入中0x55 表示有效。写入流程把状态标志写成 0xAA。写数据区和 CRC。把状态标志改成 0x55。读取流程读状态标志。如果是 0x55读数据区和 CRC校验通过则有效。如果是 0xAA说明写入中断数据无效跳过。如果是 0xFF说明是空记录停止读取。这套机制在我做的电力监测终端上跑了三年多现场断电无数次没有丢过一条有效数据。6. 常见问题与排查技巧实录6.1 读写失败排查速查表现象可能原因排查方法解决方法读出来全是 0xFFCS 没拉低或 SCK 没输出用示波器看 CS 和 SCK 波形检查 CS GPIO 配置检查 SPI 使能读出来全是 0x00SO 线没接好或 MISO 配置错查 SO 走线和 PPS 配置重新配置 SDI2 输入引脚写进去读出来不对WP 被拉低或时序不对查 WP 引脚电平看写时序WP 拉高调整 CKP/CKE偶尔出错时钟太快或走线太长降低 SPI 时钟试试降到 5MHz优化走线写不进去WREN 没发或 CS 时序错查 WREN 命令和 CS 波形确保 WREN 后 CS 拉高再拉低6.2 我踩过的三个坑第一个坑WP 引脚悬空。第一版板子 WP 没接悬空被干扰拉低写保护生效数据写不进去。后来把 WP 直接焊到 VDD问题解决。建议 WP 和 HOLD 都加 10K 上拉电阻不要悬空。第二个坑SPI 时钟太快。我一开始设了 20MHz读数据偶尔错。用示波器看 SCK 上升沿有振铃MRAM 在振铃期间采样出错。降到 10MHz 后稳定。如果你的板子走线好20MHz 也能跑但建议留余量。第三个坑CS 时序不对。PIC24 的 SPI 模块自动片选有时候在最后一个时钟还没结束时就把 CS 拉高了导致最后一个字节写不进去。改成手动 GPIO 控制 CS在 SPI2STAT 的 SPITBF 清零后再拉高 CS问题解决。6.3 调试技巧调试 SPI 设备示波器比逻辑分析仪更直观。我一般看四个信号CS、SCK、SI、SO。重点看 CS 拉低到第一个 SCK 上升沿的时间MR25H40CDF 要求至少 5ns一般都能满足。再看最后一个 SCK 下降沿到 CS 拉高的时间也要至少 5ns。如果没有示波器可以用软件方法先写一个已知模式到 MRAM再读回来对比。如果读回来不对先降 SPI 时钟到 1MHz如果 1MHz 能通说明是时序问题如果 1MHz 也不通说明是连接或配置问题。7. 性能实测与优化建议7.1 实测数据我在 10MHz SPI 时钟、8 位模式下实测操作数据量耗时平均速率连续写512KB0.42s1.22MB/s连续读512KB0.41s1.25MB/s单字节写1B2.1us476KB/s单字节读1B1.8us556KB/s16 位模式下连续写 512KB 耗时 0.21s速率 2.44MB/s。7.2 优化建议如果你需要更高的写入速度有几个方向第一提高 SPI 时钟。MR25H40CDF 支持 40MHzPIC24HJ256GP610 的 SPI 最高可以到 20MHz主频 40MHz 时。如果你把主频超到 80MHzSPI 可以到 40MHz但功耗和稳定性要权衡。第二用 DMA 搬运数据。PIC24HJ256GP610 有 DMA 控制器可以配置 SPI 发送和接收 DMACPU 只需要初始化数据搬运由 DMA 完成。这样写 512KB 数据 CPU 占用几乎为零。第三用 16 位模式。前面说了16 位模式吞吐翻倍但时序要求高。第四减少 CS 切换。连续写多个字节时不要每写一个字节就切换 CS而是一次 CS 周期内写完所有数据。MRAM 地址自动递增可以连续写整个芯片。7.3 功耗考虑MR25H40CDF 的待机电流约 1mA读写电流约 20mA。在电池供电的工业设备里如果频繁读写功耗不小。优化方法不读写时把 CS 拉高MRAM 进入待机如果长时间不读写可以考虑给 MRAM 断电但要注意断电后数据不丢重新上电后直接读就行。PIC24HJ256GP610 的 SPI 模块在空闲时可以关闭需要时再使能。这样整体功耗可以降到微安级。8. 这套方案还能怎么扩展如果你需要更大的存储容量可以并联多片 MR25H40CDF用不同的 CS 控制。PIC24HJ256GP610 的 GPIO 足够多挂 4 片就是 2MB挂 8 片就是 4MB。如果你需要更高的可靠性可以用两片 MRAM 做镜像同时写两份读的时候对比。MRAM 本身可靠性很高但做冗余设计在工业场景里是常规操作。如果你需要和上位机通信PIC24HJ256GP610 有 UART、CAN、USB 接口可以把 MRAM 里的数据通过 CAN 总线传到主控或者通过 UART 传到无线模块。我在电力监测项目里就是用 CAN 把数据传到主站MRAM 做本地缓存通信中断时数据不丢恢复后继续传。最后分享一个小技巧MR25H40CDF 的状态寄存器里有一位是写保护状态你可以在初始化时读一下状态寄存器确认 WP 引脚状态和写保护配置。如果读出来不对先查硬件再查软件。这个习惯帮我省了很多调试时间。
阅读完成 · 觉得有帮助?
咨询建站