ARTICLE DETAIL

资讯详情

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

工业级MRAM存储方案:PIC18F55K42驱动MR25H40CDF实战

工业级MRAM存储方案:PIC18F55K42驱动MR25H40CDF实战 1. 项目缘起与方案选型为什么是 MRAM 加 PIC181.1 一个真实场景引出的需求前阵子接了个工业数据采集终端的活儿设备装在配电柜里环境温度夏天能到 70 度冬天户外柜内能到零下 30 度。需求说起来简单每隔 100ms 采一组传感器数据累计运行时间、故障记录、校准参数这些关键信息必须掉电不丢而且设备寿命要求十年以上期间不允许换电池。一开始想用 FRAM贵得离谱想用 EEPROM写入寿命和速度都扛不住 100ms 一次的频率想用带电池的 SRAM电池在高温下两年就鼓包了。后来翻资料翻到 Everspin 的 MR25H40CDF4Mbit 的 SPI MRAM无限次擦写、掉电即存、不需要电池工作温度覆盖工业级甚至部分车规范围。主控选了 PIC18F55K42原因很简单这颗片子自带 SPI 外设、DMA、充足的中断资源和 5V 容忍 IO在工业现场抗干扰能力比 3.3V 单电源的 ARM 更让人放心而且 Microchip 的生态对长期供货有保障。这个组合实测下来非常稳所以把整个存储和读取的完整实现过程整理出来给做工业嵌入式存储的朋友一个可直接抄作业的参考。1.2 MR25H40CDF 到底是个什么东西MR25H40CDF 是 Everspin 出的 4Mbit512K x 8串行 MRAM。MRAM 的全称是磁性随机存储器它的存储单元是磁性隧道结MTJ靠电子自旋方向存储数据而不是靠电荷。这个物理原理决定了它几个非常关键的特性写入不需要擦除不像 Flash 和 EEPROM 要先擦后写MRAM 直接覆盖写字节级随机写入没有块的概念。写入寿命近乎无限官方标称 10^14 次以上实际上你按 100ms 写一次算十年也就 3×10^9 次连零头都不到。写入速度极快SPI 时钟最高 40MHz没有写入等待周期写一个字节和读一个字节时间一样。掉电数据保持数据靠磁性状态保持不需要供电官方标称 20 年数据保持。宽温工作工业级 -40 到 85 度部分型号到 105 度。对比一下常见非易失存储的差异选型时一目了然特性MR25H40CDF (MRAM)典型 SPI Flash (W25Q64)典型 SPI EEPROM (25LC256)容量512KB8MB32KB写入前擦除不需要必须按扇区擦不需要擦写寿命10^14 次10 万次100 万次写入速度与读同速慢有等待慢有等待字节级写入支持不支持支持掉电保持20 年20 年200 年单价高低中贵是真贵但工业场景里数据可靠性比几块钱的 BOM 成本重要得多。我踩过的坑是曾经用 Flash 存运行日志结果设备频繁掉电导致擦写次数迅速耗尽现场返修换芯片售后成本远超当初省下的那点物料钱。1.3 PIC18F55K42 的 SPI 资源盘点PIC18F55K42 是 Microchip 的 8 位增强型单片机主频 64MHz自带两个 MSSP 模块SPI/I2C 可配置还有独立的 DMA 控制器。用它驱动 MR25H40CDF 有几个天然优势硬件 SPI 速率可配通过 SSPxCON1 的 SSPxCON0 寄存器设置时钟极性、相位和分频最高能到 16MHzFosc/4。DMA 支持可以把 SPI 收发和内存搬运解耦CPU 不用死等特别适合连续读写大块数据。5V 容忍 IOMR25H40CDF 是 3.3V 供电但 PIC 的 IO 可以容忍 5V 输入电平匹配简单不需要额外电平转换芯片。充足的中断向量SPI 收发中断、DMA 完成中断、定时器中断可以各司其职实时性有保障。选 PIC18F55K42 而不是更便宜的 PIC18F45K42主要是看中了 55K42 的更大 RAM4KB和更多外设做数据缓冲和 DMA 描述符管理更从容。2. 硬件连接与底层时序把线接对是第一步2.1 引脚连接与 PCB 布局要点MR25H40CDF 是 8 引脚 DFN 或 SOIC 封装引脚定义如下引脚名称功能接 PIC18F55K421CS片选低有效RC0软件片选2SO数据输出MISORC4SDI3WP写保护低有效接 3.3V 或 IO 控制4VSS地GND5SI数据输入MOSIRC5SDO6SCK时钟RC3SCK7HOLD保持低有效接 3.3V8VDD电源3.3V这里有几个实操中容易翻车的点注意WP 和 HOLD 引脚不要悬空。我见过有人把 WP 悬空结果上电瞬间被干扰拉低芯片进入写保护状态怎么调都写不进去。稳妥做法是 WP 和 HOLD 都通过 10K 上拉到 3.3V如果不需要动态写保护WP 直接接 3.3V 也行。PCB 布局上SPI 走线尽量短SCK 和 MOSI 远离模拟信号线。MRAM 的电源引脚旁边必须放 0.1uF 陶瓷电容紧贴芯片再加一个 1uF 的钽电容做低频滤波。地平面要完整不要被其他信号割裂。如果设备工作在强电磁环境SCK 线上可以串一个 22 欧姆的电阻做阻尼抑制过冲。2.2 SPI 模式选择与时钟计算MR25H40CDF 支持 SPI 模式 0CPOL0CPHA0和模式 3CPOL1CPHA1。我一般用模式 0因为 PIC 的 MSSP 默认配置就是模式 0省事。时钟频率计算PIC18F55K42 的系统时钟 Fosc 设为 64MHzSPI 时钟源是 Fosc/4 16MHz再通过 SSPxCON1 的 SSPxADD 分频。如果 SSPxADD 0SPI 时钟就是 16MHz。MR25H40CDF 最高支持 40MHz所以 16MHz 完全没问题。但实际调试时我发现16MHz 在长走线或劣质排线上容易出错后来降到 8MHzSSPxADD 1就非常稳。工业现场建议留余量不要跑极限。2.3 底层读写时序的代码实现MR25H40CDF 的指令集很简洁核心就几条指令编码功能WREN0x06写使能WRDI0x04写禁止RDSR0x05读状态寄存器WRSR0x01写状态寄存器READ0x03读数据WRITE0x02写数据注意 MRAM 和 EEPROM 不同它没有页的概念WRITE 指令后面跟 24 位地址然后可以连续写任意多个字节地址自动递增直到 CS 拉高。这比 EEPROM 的页写方便太多不用算页边界。下面是基于 PIC18F55K42 的 SPI 底层驱动代码用 MCC 生成的 MSSP 初始化基础上手写#include xc.h #include mcc_generated_files/spi1.h #define MRAM_CS_LAT() (LATC0 0) #define MRAM_CS_HIGH() (LATC0 1) // 写使能 void MRAM_WriteEnable(void) { MRAM_CS_LAT(); SPI1_ExchangeByte(0x06); MRAM_CS_HIGH(); } // 读状态寄存器 uint8_t MRAM_ReadStatus(void) { uint8_t status; MRAM_CS_LAT(); SPI1_ExchangeByte(0x05); status SPI1_ExchangeByte(0x00); MRAM_CS_HIGH(); return status; } // 写一个字节到指定地址 void MRAM_WriteByte(uint32_t addr, uint8_t data) { MRAM_WriteEnable(); MRAM_CS_LAT(); SPI1_ExchangeByte(0x02); SPI1_ExchangeByte((uint8_t)(addr 16)); SPI1_ExchangeByte((uint8_t)(addr 8)); SPI1_ExchangeByte((uint8_t)(addr)); SPI1_ExchangeByte(data); MRAM_CS_HIGH(); } // 从指定地址读一个字节 uint8_t MRAM_ReadByte(uint32_t addr) { uint8_t data; MRAM_CS_LAT(); SPI1_ExchangeByte(0x03); SPI1_ExchangeByte((uint8_t)(addr 16)); SPI1_ExchangeByte((uint8_t)(addr 8)); SPI1_ExchangeByte((uint8_t)(addr)); data SPI1_ExchangeByte(0x00); MRAM_CS_HIGH(); return data; }这段代码里有个细节MRAM_WriteEnable 之后必须紧跟写操作中间不能插入其他 SPI 事务否则写使能会失效。我在调试时曾经在 WREN 和 WRITE 之间加了一句读状态的调试代码结果写不进去查了半天才发现是这个原因。3. 数据存储架构设计怎么组织 512KB 空间3.1 分区规划与地址映射512KB 看着不大但存运行日志、参数、故障记录绰绰有余。我的分区方案如下分区起始地址大小用途参数区0x000004KB校准参数、设备ID、配置运行统计区0x010004KB累计运行时间、启停次数故障记录区0x0200060KB循环记录最近 1000 条故障数据日志区0x11000448KB循环记录传感器数据备份区0x7F0004KB参数区镜像带校验参数区用双备份加 CRC 校验写入时先写备份区校验通过再写主区防止写过程中掉电导致参数损坏。这个思路借鉴了汽车电子里 NVM 的常见做法。3.2 循环日志的读写指针管理数据日志区用循环队列头指针和尾指针存在运行统计区里。每写一条记录头指针前进如果追上尾指针就覆盖最旧数据。关键点是头尾指针的更新必须原子化否则掉电时可能指针和数据不一致。我的做法是每条记录末尾带一个 16 位 CRC读取时先校验 CRC不通过就认为这条记录无效跳过。这样即使掉电导致某条记录写了一半也不会影响整体数据的可用性。typedef struct { uint32_t timestamp; uint16_t sensor1; uint16_t sensor2; uint8_t status; uint16_t crc; } LogRecord_t; #define LOG_RECORD_SIZE sizeof(LogRecord_t) #define LOG_AREA_START 0x11000 #define LOG_AREA_SIZE 0x6F000 #define LOG_MAX_RECORDS (LOG_AREA_SIZE / LOG_RECORD_SIZE)按这个结构每条记录 11 字节448KB 能存约 4 万条。100ms 一条的话能存约 66 分钟。如果嫌短可以降低采样频率或者压缩数据。实际项目中我把传感器数据做了差分压缩存储时间延长到了 8 小时。3.3 掉电保护与写入原子性MRAM 本身写入是原子的但多条数据的逻辑事务不是。比如更新参数时要同时改参数值和 CRC如果写完参数值掉电CRC 还是旧的下次上电校验就失败。解决方案是双缓冲加事务标志在参数区头部设一个 4 字节的事务标志区。写参数前先把标志写成 0xAA55AA55 表示“写入中”。写完参数和 CRC 后把标志改成 0x55AA55AA 表示“写入完成”。上电时检查标志如果是“写入中”说明上次写了一半自动回滚到备份区。这个机制实测能扛住任意时刻的掉电参数不会丢也不会错。4. 完整读写流程与 DMA 加速实战4.1 单字节读写与批量读写的取舍单字节读写适合参数更新这种低频操作代码简单不容易出错。但数据日志区如果一条一条写SPI 事务开销太大。假设一条记录 11 字节单字节写要 11 次 CS 拉低拉高每次都有指令和地址开销实际有效数据率很低。批量写就一次 CS 拉低发 WRITE 指令加起始地址然后连续发 N 个字节地址自动递增。MR25H40CDF 没有页边界限制一次可以写满整个芯片只要你能等。实测 16MHz SPI 下连续写 1KB 数据大约 520 微秒效率比单字节写高一个数量级。void MRAM_WriteBuffer(uint32_t addr, uint8_t *buf, uint16_t len) { MRAM_WriteEnable(); MRAM_CS_LAT(); SPI1_ExchangeByte(0x02); SPI1_ExchangeByte((uint8_t)(addr 16)); SPI1_ExchangeByte((uint8_t)(addr 8)); SPI1_ExchangeByte((uint8_t)(addr)); for (uint16_t i 0; i len; i) { SPI1_ExchangeByte(buf[i]); } MRAM_CS_HIGH(); }4.2 用 DMA 解放 CPUPIC18F55K42 的 DMA 控制器可以配置成 SPI 发送和接收。配置步骤设置 DMA 源地址为内存缓冲区目标地址为 SPI1TXB 寄存器。设置传输长度为要发送的字节数。触发源选择 SPI1TX 空中断或软件触发。启动 DMACPU 去处理其他任务DMA 完成后产生中断。接收方向类似源地址为 SPI1RXB目标地址为内存缓冲区。注意 SPI 是全双工发送的同时会接收如果只发不收接收数据丢弃即可但 DMA 接收通道要关掉或者指向一个 dummy 变量。DMA 配置的坑在于PIC 的 DMA 和外设中断优先级要协调好如果 SPI 中断优先级高于 DMA 完成中断可能出现数据还没搬完就进中断的情况。我的做法是把 DMA 完成中断设为高优先级SPI 中断设为低优先级实测稳定。4.3 实测性能数据用逻辑分析仪抓了一下实际波形整理成表格操作SPI 时钟数据量耗时有效速率单字节写16MHz1B5.2us192KB/s批量写16MHz1KB520us1.97MB/s批量读16MHz1KB515us1.99MB/sDMA 批量写16MHz4KB2.06ms1.99MB/sDMA 批量读16MHz4KB2.05ms2.0MB/s可以看到批量操作能把有效速率拉到接近 2MB/s对于 512KB 的芯片来说全片读写也就 0.25 秒左右。DMA 相比 CPU 轮询的优势不在速率而在于 CPU 占用率从 100% 降到接近 0可以同时处理传感器采集和通信任务。5. 常见问题与排查技巧实录5.1 读写失败问题速查表现象可能原因排查方法解决方案读出来全是 0xFFCS 没拉低或时序不对逻辑分析仪抓 CS 和 SCK检查 CS 引脚配置确认拉低时机写不进去WP 引脚被拉低万用表测 WP 电压WP 接 3.3V 或上拉数据偶尔出错SPI 时钟太快或走线太长降低时钟测试降速到 8MHz加阻尼电阻上电后参数丢失掉电时写入未完成检查事务标志实现双缓冲事务机制读出的数据错位地址字节序搞反对照手册检查地址发送顺序高字节在前24 位地址DMA 传输不完成触发源配置错误查 DMA 状态寄存器确认触发源和通道使能5.2 几个让我熬夜的坑第一个坑是 CS 时序。PIC 的 MSSP 在配置成 SPI 主模式时CS 引脚如果配置成 SSPxSS 功能硬件会自动控制。但我用的是普通 IO 做软件片选结果初始化时忘了把 RC0 设为输出导致 CS 一直是高阻态MRAM 根本不响应。后来养成习惯所有片选引脚初始化时先设输出高电平再配置 SPI。第二个坑是 SPI 模式不匹配。MR25H40CDF 支持模式 0 和模式 3我一开始用模式 0但 PIC 的 CKP 位设错了实际输出的是模式 1结果读出来的数据整体偏移一位。用逻辑分析仪对比 SCK 和 MOSI 的相位才找到问题。教训是SPI 调试一定要有逻辑分析仪光靠串口打印是查不出时序问题的。第三个坑是电源纹波。工业现场 24V 转 3.3V 的 DC-DC 纹波比较大MRAM 在写入瞬间电流突增导致电源跌落写入失败。后来在 3.3V 输出端加了 100uF 电解电容和 0.1uF 陶瓷电容组合问题解决。所以电源设计不能省尤其是 MRAM 这种写入电流比静态电流大不少的器件。5.3 提高可靠性的几个实操心得上电自检每次上电先读参数区 CRC不通过就从备份区恢复。再写一个测试模式到日志区末尾读回验证确认 SPI 通路正常。写入后回读关键参数写入后立即回读比对不一致就重写最多重试三次。MRAM 写入失败概率极低但工业环境什么都有可能。温度监控如果设备工作温度接近 MRAM 的极限建议加温度传感器超温时降低写入频率或报警。ESD 防护SPI 走线如果引出到接插件一定要加 TVS 管工业现场静电打坏 SPI 引脚的案例不少。6. 这个方案还能怎么扩展如果你也在做类似的工业存储项目这套 MRAM 加 PIC 的组合可以直接复用。后续如果想扩展有几个方向一是把 PIC18F55K42 换成带以太网或 CAN 的型号把存储数据直接上传到上位机。二是增加文件系统层把 MRAM 模拟成 FAT 格式方便 PC 端直接读取。三是用双 MRAM 做冗余主备同时写可靠性再上一个台阶。我个人在实际操作中的体会是MRAM 的价格虽然高但在工业场景里它省掉的电池、省掉的擦写管理逻辑、省掉的售后返修综合成本反而更低。选型时不要只看 BOM 单价要把全生命周期成本算进去。另外SPI 调试千万别省逻辑分析仪的钱一个几百块的分析仪能帮你省下几十个小时的调试时间。
返回列表