ARTICLE DETAIL

资讯详情

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

MRAM与PIC18F97J94实现高可靠工业数据存储方案

MRAM与PIC18F97J94实现高可靠工业数据存储方案 1. 项目缘起与方案选型为什么是 MRAM 加 PIC18F97J94工业现场的数据记录有个很尴尬的处境用 EEPROM 吧写入速度慢、擦写寿命也就百万次级别遇到高频采集场景没几个月就写废了用 SRAM 加后备电池吧电池在高温高湿环境下两三年就鼓包漏液维护成本高得离谱用 Flash 吧写之前得擦整个扇区掉电瞬间还容易丢数据。我前几年做过一个电力监测终端客户要求每 100ms 记录一次三相电流电压一天就是 86 万次写入用 EEPROM 方案算下来寿命撑不过半年后来换成铁电存储器才勉强扛住但铁电容量小、价格也不便宜。这次要聊的MR25H40CDF就是来解决这类痛点的。它是 Everspin 出的 4Mbit 串行 MRAM磁性随机存储器SPI 接口关键特性很硬核写入没有延迟不像 Flash 需要等待擦除和编程周期擦写寿命理论上无限官方标称 10^14 次以上数据保持能力在工业温度范围内超过 20 年而且不需要电池。这三点加起来基本就是工业数据记录的理想存储介质。主控这边选PIC18F97J94是 Microchip 的 8 位 PIC18 系列带 96KB Flash、4KB RAM集成了 4 个 SPI 模块工作温度范围 -40°C 到 85°C工业级外设资源对于这种数据记录场景绰绰有余。有人可能会问都什么年代了还用 8 位机我的看法是工业记录仪这种场景对算力要求不高但对稳定性和长期供货的要求极高PIC18 系列在工业领域铺货时间长、工具链成熟、抗干扰能力强选它是有工程理性的不是守旧。这套组合的核心价值在于用 SPI 总线把 MRAM 挂到 PIC18 上实现高速、高可靠、长寿命的数据存储和读取。适合做工业数据记录仪、智能电表、车载黑匣子、医疗设备日志、POS 机交易记录这类需要频繁写入且不能丢数据的嵌入式项目。下面我把整个设计思路、硬件连接、SPI 驱动、读写时序、常见坑点全部拆开讲一遍。2. 核心器件解析与硬件设计要点2.1 MR25H40CDF 的关键参数与内部结构先把这颗芯片的规格理清楚不然后面写驱动容易踩坑。MR25H40CDF 的容量是 4Mbit也就是 512KB组织方式是 512K × 8 位。SPI 接口支持模式 0 和模式 3最高时钟频率 40MHz不过实际用的时候要看主控能不能跑到这个速度。供电范围 2.7V 到 3.6V典型工作电流在 40MHz 下大约 15mA待机电流只有几微安。内部结构上MRAM 的存储单元是磁性隧道结MTJ通过磁化方向来存储 0 和 1这跟 Flash 靠电荷存储的物理机制完全不同。带来的直接好处是写入时不需要先擦除直接覆盖写就行写入能量低速度快没有写等待周期读写次数没有实际限制。我实测过连续写入 100 万次读取数据完全正常没有任何位翻转。引脚方面MR25H40CDF 是 8 脚 SOIC 封装引脚定义如下引脚编号名称功能说明1CS片选低电平有效2SO数据输出MISO3WP写保护低电平有效4VSS地5SI数据输入MOSI6SCK时钟7HOLD保持低电平有效8VDD电源这里有个细节要注意WP 和 HOLD 引脚如果不使用必须上拉到 VDD不能悬空。我见过有人把 HOLD 悬空导致通信偶尔失败查了半天以为是时序问题结果是引脚状态不确定。2.2 PIC18F97J94 的 SPI 模块配置PIC18F97J94 有 4 个 SPI 模块我用的是 SPI1对应引脚是 RC3SCK、RC4SDI、RC5SDO片选用 RB0 普通 IO 来控制。这里选择软件片选而不是硬件片选原因是硬件片选在某些情况下会在字节边界自动释放而 MRAM 的读写命令需要 CS 在整个命令序列期间保持低电平软件控制更灵活。SPI 模式选择上MR25H40CDF 支持模式 0CPOL0CPHA0和模式 3CPOL1CPHA1。我选模式 0因为这是最常用的配置示波器抓波形也方便对照。时钟频率方面PIC18F97J94 在 64MHz 系统时钟下SPI 分频可以做到 Fosc/4也就是 16MHz。虽然 MRAM 支持 40MHz但 16MHz 已经足够满足大部分工业记录场景的需求而且信号完整性更容易保证。配置寄存器关键位设置如下// SPI1 配置为模式 0时钟 Fosc/4 SSP1CON1 0x20; // SSPEN1, CKP0, SSPM0000 (Fosc/4) SSP1STAT 0x40; // CKE0 (模式0) // 片选引脚配置 TRISBbits.TRISB0 0; // RB0 输出 LATBbits.LATB0 1; // 初始拉高2.3 硬件连接与 PCB 布局注意事项接线本身不复杂SPI 四根线加电源地但 PCB 布局有几个坑得提前说。第一SCK 走线尽量短如果超过 10cm 建议加串联电阻22Ω 到 33Ω做阻抗匹配否则高速下波形振铃会导致误码。第二MRAM 的电源引脚旁边必须放 0.1μF 陶瓷电容越近越好我一般放在 2mm 以内。第三如果 MRAM 和主控不在同一块板上排线要用地线隔离 SCK 和 MOSI减少串扰。还有一个容易被忽略的点MRAM 的 WP 引脚如果直接接地芯片就永远处于写保护状态只能读不能写。我建议用主控的一个 IO 来控制 WP这样可以在固件升级或关键数据保护时动态使能写保护灵活性更高。3. SPI 驱动层实现与读写时序拆解3.1 底层字节收发函数SPI 驱动的基础是字节收发函数PIC18F97J94 的 SPI 模块用起来很直接写 SSP1BUF 然后等 BF 标志位就行。但这里有个细节读的时候要先写一个 dummy 字节通常是 0xFF来产生时钟然后读 SSP1BUF。我见过有人在读的时候不写 dummy结果时钟没出来读到的全是 0。uint8_t SPI1_ExchangeByte(uint8_t data) { SSP1BUF data; while (!PIR1bits.SSP1IF); // 等待传输完成 PIR1bits.SSP1IF 0; return SSP1BUF; }这个函数看起来简单但实际用的时候要注意如果 SPI 时钟太快而主频太低等待循环可能来不及建议在初始化时确认 SPI 时钟不超过 Fosc/4。另外SSP1IF 标志位在读取 SSP1BUF 后会自动清除但为了保险我习惯手动清一次。3.2 MRAM 命令集与读写操作MR25H40CDF 的命令集很精简常用的就几条命令名称命令码功能说明WREN0x06写使能WRDI0x04写禁止RDSR0x05读状态寄存器WRSR0x01写状态寄存器READ0x03读数据WRITE0x02写数据写操作流程是拉低 CS → 发送 WREN0x06→ 拉高 CS → 拉低 CS → 发送 WRITE0x02→ 发送 3 字节地址 → 发送数据 → 拉高 CS。注意 WREN 和 WRITE 之间必须拉高 CS 再拉低这是 MRAM 的协议要求跟有些 Flash 不一样。我一开始没注意这个细节WREN 和 WRITE 连在一起发结果写不进去查了一下午才发现问题。读操作简单一些拉低 CS → 发送 READ0x03→ 发送 3 字节地址 → 读取数据 → 拉高 CS。读操作不需要 WREN也不需要中间拉高 CS。地址是 24 位的因为 512KB 需要 19 位地址用 3 字节传输刚好覆盖。地址的高位字节在前这是 SPI 存储器的通用惯例。3.3 页写与连续写策略MR25H40CDF 支持连续写没有页边界限制这点比 Flash 友好太多。Flash 通常有 256 字节页限制跨页写会回卷覆盖MRAM 完全没这个问题可以从任意地址开始连续写任意长度。但实际用的时候我还是建议按页对齐写原因是第一方便计算和校验第二如果写入过程中掉电页对齐的数据更容易做恢复。我一般把页大小定义为 256 字节写的时候先算好起始页和结束页分页写入。每页写完读回来校验一次确认无误再写下一页。这样虽然慢一点但可靠性高很多。实测下来16MHz SPI 时钟下写 256 字节大约需要 130μs加上校验时间也就 200μs 左右对于 100ms 的记录周期来说完全够用。4. 数据存储架构与掉电保护设计4.1 环形缓冲区设计工业记录场景通常是循环覆盖最老的数据被新数据覆盖。我在 MRAM 里划了三个区域数据区、索引区、配置区。数据区占大部分空间用环形缓冲区管理索引区记录当前写指针和读指针配置区存设备参数和校准数据。环形缓冲区的实现关键是写指针的原子更新。每次写完一条记录更新写指针然后再写数据。如果掉电发生在写数据过程中写指针没更新下次上电会覆盖这条不完整的记录不会影响已有数据。这个顺序不能反先更新指针再写数据的话掉电会导致指针指向一条无效记录。4.2 掉电检测与数据完整性PIC18F97J94 有内置的掉电检测模块HLVD可以设置触发电压。我一般设到 2.9V 触发因为 MRAM 最低工作电压是 2.7V留 0.2V 余量。掉电中断触发后立即停止写入操作把当前写指针和状态标志写入索引区然后进入低功耗模式等待电源完全掉电。这里有个经验掉电中断里不要做太多事情中断服务程序越短越好。我见过有人在掉电中断里做数据校验和保存结果中断还没执行完电就掉没了数据反而写坏了。正确做法是中断里只置一个标志位主循环检测到标志后快速保存关键状态其他事情等上电再说。4.3 数据校验与纠错MRAM 本身可靠性很高但工业环境电磁干扰大SPI 传输过程中还是可能出错。我在每条记录后面加 2 字节 CRC16 校验读取时先校验再使用。如果 CRC 不匹配标记该记录为无效跳过继续读下一条。这样即使偶尔有一条记录损坏也不会影响整体数据的可用性。CRC16 我用的是 CCITT 多项式0x1021查表法实现速度很快。每条记录 32 字节数据加 2 字节 CRC总共 34 字节按 256 字节页对齐的话一页能存 7 条记录剩 18 字节填充。填充字节写 0xFF方便识别。5. 实操调试与常见问题排查5.1 调试工具与波形分析调试 SPI 通信示波器是必备的。我一般用四通道示波器同时抓 CS、SCK、MOSI、MISO 四根线触发设在 CS 下降沿。重点看几个地方CS 拉低到第一个 SCK 边沿的时间是否足够MRAM 要求至少 5ns一般都能满足SCK 空闲电平是否正确模式 0 是低电平MISO 数据在 SCK 上升沿是否稳定。如果没有示波器逻辑分析仪也行但要注意采样率至少是 SCK 频率的 4 倍以上否则抓不到细节。我用的是一款 100MHz 采样率的逻辑分析仪抓 16MHz SPI 勉强够用能看到数据变化但边沿细节不太清楚。条件允许的话还是上示波器。5.2 常见问题速查表现象可能原因排查方法解决方法读不到数据全 0 或全 FFCS 未正确拉低示波器看 CS 波形检查片选 IO 配置写入后读回数据错误WREN 和 WRITE 之间未拉高 CS逻辑分析仪看命令序列按协议要求插入 CS 高电平偶尔通信失败HOLD 或 WP 引脚悬空万用表测引脚电压上拉到 VDD高速下误码率高SCK 走线太长或未匹配示波器看 SCK 波形缩短走线或加串联电阻掉电后数据丢失掉电检测阈值设置不当测掉电时 VDD 下降曲线调整 HLVD 阈值留足余量写入速度慢SPI 时钟分频太大测 SCK 实际频率调整分频比提高时钟5.3 实操心得与避坑技巧第一个坑MRAM 的写使能是自动复位的。每次写操作前都要发 WREN写完自动清除。我一开始以为发一次 WREN 可以连续写多次结果第二次写就失败了。后来看数据手册才发现WREN 在每次 WRITE 命令执行后自动复位必须重新发送。第二个坑地址对齐问题。虽然 MRAM 支持任意地址读写但如果你用 DMA 或者某些优化编译器可能会要求地址对齐。我建议数据区起始地址按 4 字节对齐这样用 32 位变量直接映射访问时不会出问题。第三个坑SPI 模式配置错误。MR25H40CDF 支持模式 0 和模式 3但有些主控的 SPI 模式 0 和模式 3 在实际波形上差异很小容易混淆。我建议先用模式 0 调通如果不行再试模式 3。判断方法很简单模式 0 下 SCK 空闲为低模式 3 下 SCK 空闲为高。第四个坑电源去耦不足。MRAM 在写入瞬间电流会有波动如果去耦电容不够VDD 会瞬间跌落导致写入失败。我一般在 MRAM 电源引脚旁边放 0.1μF 和 10μF 两个电容0.1μF 滤高频10μF 储能。6. 性能实测与场景扩展6.1 读写速度实测数据我在 16MHz SPI 时钟下做了实测结果如下操作类型数据量耗时备注单字节写1 字节约 5μs含 WREN 和地址页写256 字节约 130μs连续写无页边界单字节读1 字节约 3μs含地址连续读256 字节约 128μs无额外开销写加校验256 字节约 200μs含读回校验这个速度对于 100ms 记录周期来说绰绰有余即使 10ms 周期也能轻松应对。如果换成 40MHz SPI 时钟速度还能再提升一倍多但需要主控支持。6.2 工业场景扩展应用这套方案不只适用于数据记录仪还可以扩展到很多场景。比如智能电表里用来存电量数据和事件记录车载黑匣子里存行驶数据和故障码医疗设备里存患者参数和操作日志。核心优势都是一样的高频写入不丢数据掉电不丢数据长期使用不换电池。如果数据量更大可以多片 MRAM 级联用不同的 CS 引脚选择。PIC18F97J94 有 4 个 SPI 模块理论上可以挂 4 组 MRAM每组再通过片选扩展容量可以做到几 MB。对于大部分工业记录场景512KB 到 2MB 的容量已经足够存几个月的数据了。6.3 后续优化方向如果让我继续优化这套方案我会从三个方向入手。第一把 SPI 时钟提到 40MHz需要换用支持高速 SPI 的主控或者用 FPGA 做 SPI 控制器。第二加文件系统把 MRAM 模拟成 FATFS 磁盘方便用 PC 读取数据。第三加无线传输模块把记录的数据定期上传到云端实现远程监控。不过这些都是锦上添花核心的 MRAM 加 PIC18 方案已经足够稳定可靠。我在实际项目中用这套方案跑了两年多没有出现过数据丢失或写入失败的情况工业现场的电磁干扰、温度变化、电源波动都扛住了。对于需要高可靠数据存储的嵌入式项目这个组合值得认真考虑。
返回列表