ARTICLE DETAIL

资讯详情

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

MRAM+MCU:工业数据记录中的非易失存储方案实战解析

MRAM+MCU:工业数据记录中的非易失存储方案实战解析 嵌入式行业里非易失存储一直是躲不开的话题。工业设备跑着跑着突然断电数据不能丢配置不能乱。常用的 EEPROM 擦写次数有限Flash 要整块擦除而在频繁记录数据的场景里这两种都让人头疼。我最近在一台工业数据采集终端上把 MR25H40CDF 这颗 4Mbit SPI MRAM 和 PIC18LF45K50 这颗 8 位 MCU 搭在一起用来存储和读取运行数据。整套方案做下来稳定性和速度都超出了预期。这篇就围绕这个组合把硬件连接、寄存器配置、读写流程和踩过的坑一次说清楚适合正在做工业数据记录、设备参数存储的嵌入式工程师参考。1. 存储选型MR25H40CDF 凭什么挤掉 Flash 和 EEPROM1.1 工业设备存数据先算寿命账做工业设备的人都知道存储器件选型不能只看“能存多少”。很多产品批量出货后真正的噩梦常常来自存储寿命。一块常规 SPI NOR Flash标称擦写次数大概在 10 万次到 100 万次之间而且必须先擦除再写。如果设备每秒钟记录一次温度、振动、电压这类工况数据一天就是 86400 次写入。按 100 万次寿命算撑不过半个月。EEPROM 虽然便宜、接口简单寿命通常也只有 100 万次左右同样撑不住高频写入。就算用外部铁电存储器 FRAM容量和成本也是问题。MRAM 的优势正好砸在这些痛点上。标称写入耐力达到 10 的 15 次方级别基本上可以当作“无限次写”来用。写之前不用擦除一个地址反复写也不会衰减。配合工业级温度范围和掉电保持能力非常适合做长期运行日志、关键参数备份和故障记录。MR25H40CDF 作为 Everspin 的 4Mbit SPI MRAM容量 512KB在嵌入式场景里正好卡在“需要数据记录但不至于用大容量 Flash”的位置上。1.2 MR25H40CDF 的关键参数和优势先列出我实际使用中比较关心的几个点。容量4Mbit也就是 512KByte。工业数据记录、设备运行参数、电表事件记录这个容量根本用不完还能做多份冗余。接口标准 SPI四线制SCK、SI、SO、CS外加 WP 和 HOLD。PIC18LF45K50 自带 MSSP 硬件 SPI不需要软件模拟占用引脚很少。供电3.3V和 PIC18LF45K50 同一个电压域不需要电平转换。写入速度SPI MRAM 写入是“即时写”指令带地址带数据CS 拉高就完成不需要像 Flash 那样等页擦除。我实际把 SPI 时钟配置到 4MHz 左右写入 256 字节数据耗时远远小于同等容量 Flash。数据保持MRAM 掉电后数据保持能力按年算手册给出的保持年限很充裕工业产品完全够用。封装后缀CDF 这类后缀一般对应封装形式、温度等级和包装方式。拿货的时候我习惯直接找代理核对数据手册避免买错工业级还是商业级。对比常用的存储介质MRAM 的特点一句话总结它把 SRAM 的写入速度和 Flash 的非易失性结合到了一起代价是价格比 Flash 高但在工业品里这钱花得值。1.3 PIC18LF45K50 和 MRAM 是搭子PIC18LF45K50 是 Microchip 的 8 位 MCU主频可以跑到 48MHz带 USB 接口、多个定时器、DMA还有 nanoWatt XLP 低功耗技术。我选它的原因是项目里正好需要一个 3.3V 供电、引脚不算太少的 MCU同时要方便现场用 USB 导出数据。PIC18LF45K50 的 MSSP 模块就是用来做 SPI 的硬件收发缓冲、时钟分频这些都有比完全用 GPIO 模拟 SPI 省心太多。和 MRAM 搭配时两边都是 3.3V 电平SPI 模式也兼容硬件上几乎不需要额外处理。更重要的是PIC18LF45K50 的 SPI 时钟可以分到比较低方便我在调试阶段用几 kHz 到几 MHz 的时钟测试 MRAM 的响应。等稳定后再把时钟升上去避免一上来就吃高频信号的亏。2. 硬件连接SPI 总线上的几个容易栽的细节2.1 引脚连接表我用的连接方式比较常规。CS 没有接到 MSSP 的硬件从选择引脚上而是用普通 GPIO 控制这样灵活性最好。下面是连接表。MR25H40CDF 引脚PIC18LF45K50 引脚电平要求SISDO1MOSI 数据输入SOSDI1MISO 数据输出SCKSCK1SPI 时钟CS任意 GPIO如 RB2低有效片选WP3.3V拉高允许状态寄存器写入HOLD3.3V拉高禁用 HOLD 暂停功能VDD3.3V供电VSSGND共地注意不同芯片的 MSSP 引脚定义可能不同比如 SDO1、SDI1 在封装上可能是换成其他编号所以画原理图之前一定要打开 PIC18LF45K50 的数据手册和封装图核对一遍。2.2 WP、HOLD、CS 的“防呆”处理这三根线看着简单处理不好能坑你一整天。WP 是写保护引脚低电平时禁止通过 WRSR 指令修改状态寄存器。如果 WP 悬空或者不小心被拉到低电平你会发现硬件连接看起来完全正确但状态寄存器写不进去某些读保护配置改不了。我在工业环境下干脆用一个 10k 电阻把 WP 上拉至 3.3V确保默认状态下不锁状态寄存器。HOLD 引脚的作用是暂停 SPI 通信。正常工作时要把它拉高。很多人默认 HOLD 悬空也能跑但在有强干扰的现场悬空引脚很容易被感应的噪声拉低导致通信到一半 MRAM “暂停”数据就错乱了。所以同样要上拉。CS 也要做上拉处理。MCU 上电瞬间GPIO 默认可能是高阻态如果 CS 没有外部上拉MRAM 可能被误选通收到 MCU 引脚电平稳定前的乱码。加一个 10k 上拉后CS 默认高电平只有 MCU 主动拉低时才选中器件。2.3 供电和 PCB 布局MRAM 虽然是存储芯片但它本质上是随机存取存储器结构翻转速度很快对电源噪声比普通 Flash 敏感一些。我在 MRAM 的 VDD 引脚旁边放了 0.1uF 陶瓷电容和 10uF 钽电容两个电容尽量贴近芯片引脚。如果板子上空间允许MCU 的电源也单独去耦。SPI 信号在低频时随便飞线都能跑但工业现场不是实验室。SCK、SI、SO、CS 这几根线如果走线太长串扰和信号边沿退化就会显现出来。我一般把 SPI 信号线走在一起尽量保持等长地和电源不要夹在中间。SCK 信号单独包地能有效减少对其他线的干扰。如果 MCU 和 MRAM 不在一块板上距离超过 10cm建议加 SPI 隔离或至少加缓冲器不要直接用长线拖到主板上。3. 初始化配置与读写流程3.1 指令集速查MR25H40CDF 的指令集和普通 SPI Flash 很像下面的表是我在固件里用到的几条关键指令。指令操作码说明WREN0x06写使能写状态寄存器前必须使用WRDI0x04写禁止RDSR0x05读状态寄存器WRSR0x01写状态寄存器READ0x03读数据WRITE0x02写数据RDID0x9F读设备 ID地址是 24 位对应 512KB 地址空间。因为 4Mbit 只用到 0x000000 到 0x07FFFF所以高字节的高位实际会被忽略。但发送地址时仍然要按 3 字节发送顺序是高位在前、低位在后。3.2 SPI 初始化手写还是用 MCC我个人建议直接用 MPLAB X 的 MCC 生成 SPI 初始化省事、出错少。关键点是把 MSSP1 配置成主模式选择 SPI Mode 0也就是空闲时钟为低、数据在第一个边沿采样。MRAM 手册支持的 SPI 模式一般包括 Mode 0 和 Mode 3Mode 0 最通用和 PIC 的 MSSP 配合也最顺。MCC 生成后初始化函数大概长这样void spi1Initialize(void) { // 使用 MSSP1主模式SPI Mode 0 // 时钟分频按实际主频调整 SSP1CON1 0x22; // SPI 使能主模式分频系数对应 64 分频 SSP1STAT 0x40; // 采样点设置主模式下数据在中间采样 TRISC 0xFB; // 设置 SCK 输出具体引脚按实际原理图调整 TRISB | 0x10; // 设置 SDI 输入 }上面是示意代码具体寄存器值受主频、引脚映射影响直接照抄不一定能跑。正确做法是在 MCC 里选择主频和 SPI 时钟让工具算出分频系数再检查生成的寄存器值。初始化完成之后我习惯先发送 RDSR 指令读状态寄存器。如果读到 0xFF 或者 0x00 以外的数值说明通信链路基本通了如果一直是 0xFF先查接线和 SPI 模式。3.3 读数据流程读取流程很简单核心是先拉低 CS发送 READ 指令接着发 3 字节地址然后连续读数据。读完后拉高 CS。实际代码里我用一个通用函数完成“发送一个字节并获得返回值”这样既能发送指令也能在接收模式下用空字节产生时钟。uint8_t MRAM_SendByte(uint8_t byte) { SSP1BUF byte; while (!SSP1STATbits.BF); return SSP1BUF; // 读取接收字节同时清除 BF 标志 } void MRAM_ReadBytes(uint32_t addr, uint8_t *buf, uint32_t len) { MRAM_CS_LOW(); MRAM_SendByte(0x03); // READ MRAM_SendByte((uint8_t)(addr 16)); MRAM_SendByte((uint8_t)(addr 8)); MRAM_SendByte((uint8_t)addr); for (uint32_t i 0; i len; i) { buf[i] MRAM_SendByte(0xFF); // 发哑字节收数据 } MRAM_CS_HIGH(); }注意 MSSP 的 BF 标志表示接收缓冲器已满其实也代表一个字节传输完成。发送每个字节前确保上一字节带来的接收数据已经被读走否则容易置 SSPOV 溢出标志通信就会乱掉。上面把发送和收数合并成一个函数就解决了这个问题。3.4 写数据流程写数据分两步走。第一步是发 WREN 写使能第二步是发 WRITE 指令。对 MRAM 本身来说它的存储单元写入不一定强制依赖 WREN但写状态寄存器之前必须 WREN。我为了保险写数据前也会发一次 WREN实测没有副作用反而能避免一些从 Flash 移植过来时的逻辑问题。void MRAM_WriteEnable(void) { MRAM_CS_LOW(); MRAM_SendByte(0x06); // WREN MRAM_CS_HIGH(); } void MRAM_WriteBytes(uint32_t addr, const uint8_t *buf, uint32_t len) { MRAM_WriteEnable(); MRAM_CS_LOW(); MRAM_SendByte(0x02); // WRITE MRAM_SendByte((uint8_t)(addr 16)); MRAM_SendByte((uint8_t)(addr 8)); MRAM_SendByte((uint8_t)addr); for (uint32_t i 0; i len; i) { MRAM_SendByte(buf[i]); } MRAM_CS_HIGH(); }这里要特别注意 CS 的时序。CS 必须先拉低再发 WREN发完立刻拉高。WREN 的 CS 高电平结束动作就是“锁存写使能”的那一刻如果提前拉高或者漏了不是高电平结束写使能可能不生效。WRITE 操作必须从 CS 拉低开始一直到所有数据发送完CS 才能拉高。中途 CS 意外弹起写入会立即终止前面的字节可能白写。写入长度方面MRAM 没有 Flash 那种 256 字节页限制理论上可以连续发多个字节直到 CS 拉高。但我习惯把一次写入长度控制在 512 字节以内方便和读回校验的缓冲区对应也符合实际应用的分包需求。3.5 校验和冗余存储工业数据最怕读到被破坏的内容。写寄存器、写配置参数的时候我通常不是单纯写入而是加一层保护。简单做法是在地址空间里划分几个区域比如主配置区、备份配置区、运行日志区。每个区域开头放几个字节的“魔数”比如 0xA5 0x5A后面跟着数据最后放 4 字节 CRC32。读取时先判断魔数对不对再算 CRC如果不对就切换到备份区。如果备份区也损坏才恢复出厂默认值。这样虽然多花了几百字节存储空间但能显著降低设备在强干扰环境下出现配置丢失的概率。MRAM 本身不容易丢数据但外部总线上的噪声可能导致写入错误数据加入 CRC 后至少能识别出来。4. 实战排查我踩过的坑和验证方法4.1 SPI 模式不对读回来全是 0xFF第一次调这块板子的时候我配置完 SPI调用 RDSR结果读回来的数据一直是 0xFF。查接线、查供电、查 CS 电平都没问题。后来用示波器抓 SCK 和数据线才发现 SCK 空闲电平是高还是低和 MRAM 的预期不一致。SPI 模式需要 MRAM 和 MCU 匹配。MRAM 支持 Mode 0 和 Mode 3但 PIC 的 MSSP 如果配置成 Mode 1 或 Mode 2数据采样边沿就会错开读取结果自然不对。解决办法是在 MCC 里直接把 SPI Mode 设成 Mode 0重新生成代码问题立刻消失。以后再遇到通信不工作我第一个动作就是用示波器看 SCK 空闲电平和 MOSI 数据变化时刻不要先盲目改分频或换芯片。4.2 写入无效先看 WP 和地址另一个常见问题是写数据后读回来还是旧值。有次我发现写状态寄存器不生效查了 WP 引脚发现原理图把它接到了 GND这就等于把状态寄存器写保护锁死了。后来改成上拉问题解决。还有个隐蔽的坑是地址溢出。MR25H40CDF 只有 512KB 空间如果用 24 位地址访问超过 0x07FFFF 的地方地址位会回绕到低地址造成“写到 A 地址却出现在 B 地址”的假象。我在写日志循环队列时对地址做了取模处理才避免这个问题。写入无效时请按这个顺序排查CS 时序是否完整、WREN 是否发出且 CS 高电平结束、WP 是否正确拉高、地址是否越界、电压是否稳定。不要一上来就觉得芯片坏了。4.3 上电掉电验证不能只测读写只调通读写命令还不算完工业设备必须做掉电验证。我的测试方法是用一个交流接触器控制工装电源让 MCU 在写入过程中随机断电循环几百次然后上电检查数据是否完整。因为 MRAM 写入是即时的只要 WRITE 指令完整发送完数据就落住了整体表现比 Flash 好很多。但要注意MCU 掉电瞬间如果电源跌落导致 SPI 信号抖动MRAM 收了一部分乱字节也会把错误数据写进地址。解决思路是加电源检测芯片当电压掉到阈值以下时MCU 第一时间拉高 CS 并进入复位切断正在进行的 SPI 事务。同时结合应用层 CRC把这种极端情况兜住。另外新出厂的 MRAM 芯片内部数据可能是随机的首次烧录前最好全片写一次 0x00 或固定模式避免把杂散数据当成有效记录。4.4 工业现场抗干扰的几个有效措施现场走线和实验室不同我带设备到车间里跑过一段发现偶尔会出现读到的数据跳变。后来做了几件事问题基本绝迹。第一SPI 线全部压在 PCB 内层不跨分割区SCK 优先级最高。第二MCU 和 MRAM 的电源分别加滤波MRAM 靠近电源入口处加磁珠。第三如果 MRAM 和主控距离接近我给 CS 加了一个 100 欧姆串联电阻降低边沿过冲。第四固件里所有读取操作都加了重试连续读两次结果一致才采用。还有一个容易被忽略的点如果板子上有电机、继电器这类干扰源务必在继电器线圈两端加 RC 吸收触点必要时加压敏电阻。不然干扰顺着电源和地线传到 SPI 总线芯片本身再稳也没用。最后说一点个人体会。MR25H40CDF 和 PIC18LF45K50 这个组合真正爽的地方不是某一个指标而是“省心”。MRAM 不用管理等擦除时间不用频繁搬家磨损均衡SPI 流程简单到几乎像操作 SRAMPIC18LF45K50 的 MSSP 又正好把这个流程接得非常顺。后来我再做类似的数据记录产品存储介质首选还是 MRAM只有当成本压力特别大时才会考虑退回去用高寿命 EEPROM 加磨损均衡。如果手里有现成的 PIC 平台强烈建议拿这套组合先做一个最小系统试试你会回来感谢那颗不用等写周期的 MRAM。
返回列表