☰
MRAM与PIC18LF46K22工业存储方案:SPI驱动与掉电保护实战
2026/10/5 1:03:58 网站建设 项目流程

1. 为什么 MRAM 在工业现场总比 Flash 先被想起

工业设备里存数据这件事,看起来简单,实际上是最容易在量产之后翻车的环节。我做过好几个数据采集终端和电机控制器项目,EEPROM 写次数不够、Flash 掉电丢数据、铁电存储器容量太小,这些问题几乎每隔一段时间就会冒出来一次。后来接触到 MR25H40CDF 这颗 MRAM,才算找到一个在工业场景里比较省心的方案。这篇文章就围绕 MR25H40CDF 和 PIC18LF46K22 这一对组合,把存储和读取数据的完整思路讲清楚,包括硬件连接、SPI 时序、驱动写法、掉电保护策略,以及我在实际调试中踩过的坑。

MR25H40CDF 是 Everspin 出的 4Mbit 磁阻随机存储器,也就是 MRAM。它的核心特点是不需要擦除就能直接写,写入次数理论上没有上限,数据保持时间超过 20 年,而且掉电不丢。这几点放在工业环境里非常关键。很多工业现场是高温、强振动、频繁断电的场合,传统 Flash 的擦写寿命和写入延迟在这种环境下会变成系统瓶颈。PIC18LF46K22 是 Microchip 的一款 8 位单片机,自带 MSSP 模块可以配置成 SPI 主模式,工作电压范围宽,低功耗表现也不错,和 MR25H40CDF 搭配起来刚好能覆盖大部分中小型工业控制器的需求。

这篇文章适合谁看?如果你正在做工业仪表、数据记录仪、电机驱动参数存储、或者任何需要频繁写入且不能丢数据的嵌入式项目,这套组合值得认真考虑。如果你只是做消费类产品、写入频率很低,那用普通 EEPROM 或者 Flash 就够了,没必要上 MRAM。下面我会从选型逻辑开始,一步步讲到能直接跑起来的代码。

1.1 MR25H40CDF 和常见存储介质的本质差异

要理解为什么选 MRAM,得先搞清楚它和 EEPROM、NOR Flash、FRAM 的区别。我用一张表把关键参数拉出来对比,这样选型的时候一目了然。

特性MR25H40CDF (MRAM)典型 EEPROMNOR FlashFRAM
容量4Mbit (512KB)通常 1Kb~1Mb1Mb~128Mb通常 4Kb~1Mb
写入方式无需擦除,直接覆盖无需擦除必须先擦除扇区无需擦除
擦写寿命近乎无限约 100 万次约 10 万次约 10^14 次
写入速度字节级,无等待字节级,有写周期页写入,有擦除延迟字节级,无等待
掉电保持20 年以上10 年以上10 年以上10 年以上
接口SPII2C/SPISPII2C/SPI
单位成本较高低低中高

从表里能看出来,MRAM 的优势集中在写入寿命和写入方式上。Flash 最让人头疼的就是擦除操作,一个扇区擦除动辄几十毫秒,期间如果掉电,整个扇区的数据可能就废了。MRAM 没有这个问题,它写一个字节就是一个字节,不需要先擦后写,也不存在擦除过程中掉电导致数据损坏的情况。这一点在工业现场特别重要,因为工业设备的断电往往是随机的,不是你能控制的。

FRAM 在写入特性上和 MRAM 很像,但容量普遍偏小,而且价格在同等容量下并不便宜。MR25H40CDF 提供 512KB 的容量,对于存储参数、日志、校准数据这些场景来说已经相当充裕了。所以如果你的项目需要频繁写入、容量需求在几百 KB 级别、又不想在掉电保护上花太多心思,MRAM 是一个很平衡的选择。

1.2 PIC18LF46K22 的 MSSP 模块能直接对接 MRAM

PIC18LF46K22 内部有一个 MSSP 模块,可以配置成 SPI 主模式或者 I2C 主从模式。我们这里用 SPI,因为 MR25H40CDF 只支持 SPI 接口。PIC18LF46K22 的 MSSP 在 SPI 主模式下支持时钟极性、时钟相位、时钟频率的配置,最高可以跑到系统时钟的四分之一。假设单片机跑 16MHz,SPI 时钟最高可以到 4MHz,而 MR25H40CDF 支持的最高 SPI 时钟是 40MHz,所以单片机的 SPI 速度反而是瓶颈,但这对于存储参数和日志来说完全够用。

这里有一个细节需要注意:PIC18LF46K22 的 MSSP 模块在 SPI 模式下,数据是 MSB 先出,而 MR25H40CDF 也是 MSB 先出,两者一致,不需要做位序反转。另外,MR25H40CDF 的 SPI 模式支持模式 0 和模式 3,也就是 CPOL=0/CPHA=0 或者 CPOL=1/CPHA=1。PIC18LF46K22 的 SSPCON1 寄存器里 CKP 位控制时钟极性,SSPSTAT 里的 CKE 位控制时钟相位,配置的时候要对应上。

我一般习惯用模式 0,也就是空闲时时钟为低电平,数据在时钟上升沿采样。这个模式在大多数 SPI 器件里都是默认支持的,调试起来也最直观。配置的时候把 CKP 设为 0,CKE 设为 0,就能得到模式 0 的时序。

2. 硬件连接里那些容易接错又不容易发现的点

硬件连接看起来就是几根线的事,但实际调试的时候,很多问题恰恰出在这些线上。我见过太多因为片选接错、电源去耦不到位、走线太长导致通信不稳定的案例。这一节把 MR25H40CDF 和 PIC18LF46K22 的硬件连接细节讲透,包括电源、片选、时钟、数据线的处理方式。

2.1 电源和去耦电容的摆放位置

MR25H40CDF 的工作电压是 2.7V 到 3.6V,PIC18LF46K22 的 LF 版本工作电压是 1.8V 到 3.6V,所以两者都可以用 3.3V 供电,系统电源设计比较简单。但这里有一个容易被忽略的点:MRAM 在写入瞬间的电流需求会比静态时大,虽然不像 Flash 擦除时那么夸张,但如果电源走线太细或者去耦电容离芯片太远,写入时电源电压可能会瞬间跌落,导致写入失败或者数据出错。

我的做法是在 MR25H40CDF 的 VDD 引脚旁边放一个 0.1uF 的陶瓷电容,距离引脚不超过 2mm,再在电源入口处放一个 1uF 到 10uF 的钽电容或者陶瓷电容做储能。这两个电容的作用不一样,0.1uF 负责滤高频噪声,大电容负责在写入瞬间提供电流缓冲。很多人在原理图上画了电容,但 PCB 布局的时候把电容放到离芯片很远的地方,这样高频滤波效果就大打折扣了。

另外,MR25H40CDF 的 WP 引脚是写保护引脚,低电平有效。如果你不需要硬件写保护,直接把这个引脚拉到 VDD 就行。我一般会在 WP 引脚和 VDD 之间加一个 10K 的上拉电阻,同时留一个测试点,方便以后如果需要写保护功能的时候可以改。HOLD 引脚也是低电平有效,用来暂停通信,如果不用的话同样拉到 VDD。

2.2 片选信号的硬件片选与软件片选选择

SPI 通信里片选信号的处理方式有两种:硬件片选和软件片选。硬件片选是指用单片机的 SPI 模块自动控制片选引脚,软件片选是指用普通 GPIO 手动拉低拉高。PIC18LF46K22 的 MSSP 模块在 SPI 主模式下,片选信号并不是自动控制的,需要软件去操作。所以在这个组合里,我们只能用软件片选的方式,也就是用一个普通 IO 口来控制 MR25H40CDF 的 CS 引脚。

这里有一个实操经验:片选引脚一定要在发送命令之前拉低,在命令和数据全部发送完成之后再拉高。中间不能有中断打断,否则片选信号可能会被意外拉高,导致通信中断。我在一个项目里就遇到过这个问题,SPI 发送函数被定时器中断打断,片选信号在中断里被其他代码操作了,结果 MRAM 写入的数据错位。后来在 SPI 读写函数里加了关中断的操作,问题就解决了。

片选信号的走线也要注意,尽量短,尽量远离时钟线。如果片选线和时钟线平行走线很长,时钟信号可能会耦合到片选线上,导致片选信号出现毛刺,MRAM 会误以为通信开始或结束。我在 PCB 布局的时候,片选线一般和时钟线保持至少 3 倍线宽的间距,如果空间允许的话,中间走一根地线做隔离。

2.3 SPI 时钟频率和走线长度的权衡

SPI 时钟频率越高,通信速度越快,但信号完整性问题也越容易出现。MR25H40CDF 支持最高 40MHz 的 SPI 时钟,PIC18LF46K22 在 16MHz 系统时钟下最高能输出 4MHz 的 SPI 时钟。4MHz 这个频率在普通 PCB 上走线长度在 10cm 以内基本没有问题,但如果走线超过 20cm,或者经过排线连接,就可能出现时钟和数据之间的时序偏差。

我在一个工业控制器项目里,MRAM 和单片机分别放在两块板子上,通过 20cm 的排线连接。一开始 SPI 跑 4MHz,读写都正常,但批量生产后有少量板子出现数据校验错误。后来用示波器看波形,发现时钟信号的上升沿在排线末端已经变得比较缓,数据建立时间不够。把 SPI 时钟降到 1MHz 之后,问题就消失了。所以如果你的 MRAM 和单片机不在同一块板子上,或者走线比较长,建议先把 SPI 时钟降到 1MHz 左右调试,等通信稳定之后再尝试提高频率。

另外,SPI 的时钟线、数据线、片选线最好都串联一个 22 欧姆到 33 欧姆的电阻,靠近单片机端放置。这个电阻的作用是抑制信号反射,改善信号完整性。很多人在低速 SPI 上不加这个电阻也没问题,但一旦频率上去或者走线变长,这个电阻就能明显改善波形质量。

3. MR25H40CDF 的指令集和读写时序拆解

MR25H40CDF 的指令集不复杂,常用的就是读、写、读状态寄存器、写状态寄存器这几条。但每条指令的时序细节需要搞清楚,尤其是写操作之后的等待时间,以及状态寄存器里各个位的含义。这一节把指令集和读写时序讲清楚,后面写驱动的时候就能直接对照。

3.1 常用指令和操作码对照

MR25H40CDF 的指令操作码是 8 位的,发送指令的时候片选拉低,然后通过 MOSI 发送操作码,接着发送地址或者数据。我把常用指令整理成一张表,方便写驱动的时候查阅。

指令名称操作码功能说明
WREN0x06写使能,写操作之前必须发送
WRDI0x04写禁止,写操作完成后可以发送
RDSR0x05读状态寄存器
WRSR0x01写状态寄存器
READ0x03读数据,后面跟 24 位地址
WRITE0x02写数据,后面跟 24 位地址

这里要注意的是,MR25H40CDF 的地址是 24 位的,因为 512KB 的容量需要 19 位地址线,但芯片设计成 24 位地址,高 5 位保留。发送地址的时候要按照高位在前的顺序发送三个字节。比如要访问地址 0x000100,就依次发送 0x00、0x01、0x00。

写操作之前必须先发送 WREN 指令,否则写操作会被忽略。这一点和 EEPROM 类似,但 MRAM 的 WREN 不需要额外的等待时间,发送完 WREN 之后可以直接发送 WRITE 指令。写操作完成之后,可以发送 WRDI 禁止写入,但这不是必须的,因为每次写操作之前都会重新发送 WREN。

3.2 状态寄存器里真正需要关注的位

MR25H40CDF 的状态寄存器有 8 位,但实际用到的只有几位。我见过有人把状态寄存器读出来之后不知道怎么看,这里把关键位解释一下。

位名称含义
0WIP写进行中,1 表示正在写,0 表示空闲
1WEL写使能锁存,1 表示已使能写
2BP0块保护位 0
3BP1块保护位 1
7SRWD状态寄存器写保护

WIP 位是最常用的,写操作之后可以轮询这一位,直到它变成 0,表示写入完成。不过 MRAM 的写入速度很快,通常几十纳秒就完成了,所以实际项目中我很少轮询 WIP,写完直接进行下一步操作,从来没有出现过问题。但如果你对可靠性要求极高,轮询一下也无妨。

WEL 位在发送 WREN 之后会变成 1,写操作完成之后会自动变成 0。如果你发送了 WREN 但 WEL 没有变成 1,说明 WREN 指令没有被正确接收,需要检查 SPI 通信是否正常。

BP0 和 BP1 是块保护位,用来设置哪些地址范围是写保护的。如果你不需要写保护,这两位保持默认的 0 就行。SRWD 位和 WP 引脚配合使用,用来硬件写保护状态寄存器。一般项目里用不到,保持默认即可。

3.3 读写操作的完整时序流程

读操作的时序比较简单:片选拉低,发送 READ 指令(0x03),发送 24 位地址,然后 MRAM 会在时钟的下降沿或者上升沿把数据输出到 MISO 线上,单片机在对应的边沿采样。读操作可以连续读多个字节,地址会自动递增,直到片选拉高。

写操作的时序稍微复杂一点:片选拉低,发送 WREN 指令(0x06),片选拉高。然后再片选拉低,发送 WRITE 指令(0x02),发送 24 位地址,然后发送要写入的数据。数据可以连续发送多个字节,地址自动递增。发送完成之后片选拉高,MRAM 开始内部写入。写入完成之后,WIP 位会从 1 变成 0。

这里有一个细节:WREN 指令和 WRITE 指令之间必须把片选拉高再拉低,不能连续发送。因为 MR25H40CDF 把 WREN 和 WRITE 当作两个独立的事务,片选拉高表示一个事务结束。如果你在发送 WREN 之后不拉高片选就直接发送 WRITE,MRAM 会把 WRITE 的操作码当作数据或者地址的一部分,导致写入错误。这个坑我在第一次用 MRAM 的时候就踩过,当时调了半天才发现是片选没有拉高。

4. 在 PIC18LF46K22 上写出能直接用的驱动

驱动这部分我会给出完整的代码框架,包括 SPI 初始化、字节读写、MRAM 读写函数。代码基于 Microchip XC8 编译器,用 MCC 生成的代码也可以,但我会把关键寄存器配置直接写出来,这样即使不用 MCC 也能看懂。

4.1 MSSP 初始化的寄存器配置逻辑

PIC18LF46K22 的 MSSP 模块初始化涉及几个寄存器:SSPCON1、SSPCON2、SSPCON3、SSPSTAT、SSPADD。在 SPI 主模式下,SSPADD 不用,SSPCON2 也不用。关键是 SSPCON1 和 SSPSTAT。

void SPI_Init(void) { // 配置 SPI 引脚 TRISCbits.TRISC3 = 0; // SCK 输出 TRISCbits.TRISC4 = 1; // SDI 输入 TRISCbits.TRISC5 = 0; // SDO 输出 TRISBbits.TRISB2 = 0; // CS 输出 // 关闭 MSSP 模块再配置 SSPCON1 = 0x00; SSPSTAT = 0x00; // SSPCON1: SPI 主模式, 时钟 = Fosc/16 // bit5:4 = 00 表示主模式 // bit3:0 = 0010 表示 Fosc/16 SSPCON1 = 0x20; // SSPSTAT: 模式 0 // bit7 SMP = 0, 在数据输出末尾采样 // bit6 CKE = 0, 时钟上升沿发送数据 SSPSTAT = 0x00; // 使能 MSSP SSPCON1bits.SSPEN = 1; // CS 默认拉高 CS_PIN = 1; }

这里 SSPCON1 的值 0x20 表示 SPI 主模式,时钟频率是 Fosc/16。如果系统时钟是 16MHz,SPI 时钟就是 1MHz。如果要更快的速度,可以把低四位改成 0000,对应 Fosc/4,也就是 4MHz。我一般先用 1MHz 调试,稳定之后再改。

SSPSTAT 设为 0x00 对应 SPI 模式 0,也就是 CPOL=0,CPHA=0。这个配置和 MR25H40CDF 的模式 0 对应。如果你要用模式 3,把 SSPSTAT 的 CKE 位设为 1,同时把 SSPCON1 的 CKP 位设为 1。

4.2 字节收发函数的实现和注意事项

SPI 的字节收发函数是驱动的基础,读和写都靠它。

unsigned char SPI_ExchangeByte(unsigned char data) { SSPBUF = data; while (!SSPSTATbits.BF); // 等待接收完成 return SSPBUF; }

这个函数看起来简单,但有几个地方需要注意。第一,SSPBUF 写入之后,BF 位会在接收完成之后置 1,读取 SSPBUF 会清除 BF 位。第二,如果 SPI 时钟太快,而单片机主频太低,可能会出现溢出。PIC18LF46K22 在 16MHz 下跑 4MHz SPI 是没问题的,但如果主频降到 4MHz,SPI 时钟最好也降到 1MHz 以下。

第三,这个函数在发送数据的同时也在接收数据,这是 SPI 全双工的特性。读 MRAM 的时候,我们发送一个空字节(0xFF)来产生时钟,同时接收 MRAM 返回的数据。写 MRAM 的时候,我们发送实际数据,接收到的字节忽略即可。

4.3 MRAM 读写的完整函数实现

有了字节收发函数,MRAM 的读写函数就很好写了。

void MRAM_WriteEnable(void) { CS_PIN = 0; SPI_ExchangeByte(0x06); // WREN CS_PIN = 1; } void MRAM_Write(uint32_t addr, unsigned char *buf, uint16_t len) { MRAM_WriteEnable(); CS_PIN = 0; SPI_ExchangeByte(0x02); // WRITE SPI_ExchangeByte((addr >> 16) & 0xFF); SPI_ExchangeByte((addr >> 8) & 0xFF); SPI_ExchangeByte(addr & 0xFF); for (uint16_t i = 0; i < len; i++) { SPI_ExchangeByte(buf[i]); } CS_PIN = 1; } void MRAM_Read(uint32_t addr, unsigned char *buf, uint16_t len) { CS_PIN = 0; SPI_ExchangeByte(0x03); // READ SPI_ExchangeByte((addr >> 16) & 0xFF); SPI_ExchangeByte((addr >> 8) & 0xFF); SPI_ExchangeByte(addr & 0xFF); for (uint16_t i = 0; i < len; i++) { buf[i] = SPI_ExchangeByte(0xFF); } CS_PIN = 1; }

写函数里,MRAM_WriteEnable 会先发送 WREN 指令,然后片选拉高。接着片选再拉低,发送 WRITE 指令和地址,然后发送数据。这个顺序不能乱。读函数里,发送 READ 指令和地址之后,连续发送 0xFF 来产生时钟,同时接收数据。

这里有一个优化点:如果连续写入多个字节,地址会自动递增,不需要每次重新发送地址。MR25H40CDF 支持页写入和连续写入,一次片选拉低可以写入任意长度的数据,只要不超过地址边界。但要注意,如果写入跨越了 512KB 的地址空间,地址会回绕到 0,这个在实际项目中要避免。

4.4 掉电保护策略和写入完整性校验

MRAM 本身掉电不丢数据,但写入过程中如果掉电,正在写入的那个字节可能会处于不确定状态。虽然 MRAM 的写入速度极快,掉电正好发生在写入瞬间的概率很低,但在工业环境里,这种小概率事件积累起来也会变成问题。

我的做法是在数据区加一个校验字段。比如我要存储一组参数,我会在参数后面加一个 CRC16 校验值。读取的时候先读参数,再读 CRC,计算参数的 CRC 和存储的 CRC 对比,如果一致就认为数据有效,不一致就使用默认参数。这样即使写入过程中掉电导致数据损坏,系统也能检测出来并恢复到安全状态。

另外,对于关键参数,我会存两份,一份在主区,一份在备份区。读取的时候先读主区,校验失败再读备份区。写入的时候先写备份区,再写主区。这样即使主区写入过程中掉电,备份区还是完整的。这个策略在 EEPROM 上很常见,在 MRAM 上同样适用,而且因为 MRAM 写入速度快,双份写入带来的额外时间开销几乎可以忽略。

5. 实际调试中遇到的几个典型问题和排查过程

这一节分享几个我在调试 MR25H40CDF 和 PIC18LF46K22 组合时遇到的问题,以及排查过程。这些问题在数据手册里不会写,但实际项目中很容易遇到。

5.1 读出来的数据全是 0xFF 或者 0x00

第一次调试的时候,读出来的数据全是 0xFF,说明 MISO 线一直是高电平。这种情况通常有几个原因:片选没有拉低、SPI 时钟没有输出、MISO 线接错、或者 MRAM 没有正常上电。

我的排查顺序是这样的:先用示波器看片选信号,确认读写的时候片选确实拉低了。然后看 SPI 时钟,确认时钟在发送数据的时候有波形。如果这两个都正常,再看 MISO 线,如果 MISO 一直是高电平,可能是 MRAM 的 MISO 引脚没有正确连接到单片机的 SDI 引脚,或者 MRAM 没有上电。如果 MISO 一直是低电平,可能是 MISO 线对地短路了。

还有一个可能的原因是 SPI 模式配置错误。如果单片机的 SPI 模式和 MRAM 不匹配,数据采样时刻不对,读出来的数据也会是乱的。这时候把示波器接在 MISO 和时钟上,看数据在时钟的哪个边沿变化,和 MRAM 数据手册上的时序图对比,就能发现问题。

5.2 写入之后读出来数据不一致

写入之后读出来数据不一致,这个问题比读不出来更隐蔽。我遇到过一次,写入 0x55,读出来是 0xAA,正好是位反转。后来发现是 SPI 的位序配置错了,MRAM 是 MSB 先出,而我的配置变成了 LSB 先出。PIC18LF46K22 的 MSSP 模块在 SPI 模式下固定是 MSB 先出,不存在位序配置的问题,但如果你用软件模拟 SPI,就需要注意位序。

还有一次是写入地址不对,导致数据写到了别的地址。MR25H40CDF 的地址是 24 位的,发送的时候要按高位在前。我一开始把地址当成 16 位发送,只发了两个字节,结果地址错位,数据写到了错误的位置。后来改成发送三个字节,问题就解决了。

5.3 高温环境下通信不稳定

工业环境温度范围宽,MR25H40CDF 的工业级版本支持 -40 到 85 度,PIC18LF46K22 的工业级版本也是 -40 到 85 度。但在高温下,SPI 信号的时序可能会发生变化,尤其是如果 PCB 走线比较长,高温下信号延迟增加,可能导致建立时间或保持时间不够。

我在一个项目里遇到过高温下读写失败的问题,常温下一切正常,放到 70 度环境里跑一段时间就出现校验错误。后来用示波器在高温下看波形,发现时钟信号的上升沿变缓了,数据建立时间不够。解决办法是把 SPI 时钟从 4MHz 降到 2MHz,同时在时钟线和数据线上串联了 33 欧姆的电阻。改完之后高温下连续跑了 48 小时,没有再出现错误。

5.4 片选信号被中断打断导致通信错乱

前面提到过片选信号被中断打断的问题,这里详细说一下排查过程。现象是偶尔出现写入数据错位,概率大概千分之一。一开始怀疑是 MRAM 本身的问题,换了几颗芯片还是一样。后来用逻辑分析仪抓 SPI 波形,发现出错的时候片选信号中间有一个很窄的高电平脉冲,导致 MRAM 以为一次事务结束了。

查代码发现,SPI 读写函数没有关中断,而定时器中断里有一个操作 GPIO 的代码,正好操作了片选引脚所在的端口。虽然中断里没有直接操作片选引脚,但读-修改-写端口的操作影响了片选引脚的状态。解决办法是在 SPI 读写函数里加上关中断和开中断的操作,或者把片选引脚单独放在一个端口上,中断里不操作那个端口。我选择了前者,在 SPI 读写函数里加了 GIE 位的保存和恢复,问题就解决了。

6. 把 MRAM 用好的几个进阶思路

基本读写跑通之后,还有一些进阶的用法可以让 MRAM 在系统里发挥更大的价值。这一节分享几个我在实际项目中用过的思路。

6.1 用 MRAM 做环形日志缓冲区

工业设备经常需要记录运行日志,比如温度、电压、故障码。传统做法是用 EEPROM 或者 Flash,但写入次数有限,日志写多了芯片就坏了。MRAM 没有写入次数限制,非常适合做环形日志缓冲区。

我的做法是在 MRAM 里划出一块区域作为日志区,用一个写指针记录当前写入位置。每次写日志的时候,把数据写到写指针位置,然后写指针递增。当写指针到达日志区末尾时,回绕到起始位置。这样日志区可以无限循环使用,不需要擦除,也不需要磨损均衡。读取日志的时候,从写指针往前读,就能读到最近的日志记录。

日志记录里我会加一个时间戳和一个 CRC 校验。时间戳可以用单片机的 RTC 或者定时器计数。CRC 用来校验每条日志的完整性,如果某条日志的 CRC 不对,说明写入过程中掉电了,这条日志就丢弃。

6.2 参数存储的双备份和版本管理

产品参数需要经常修改,而且修改之后不能丢。我用 MRAM 存参数的时候,会做双备份和版本管理。参数区分为 A 区和 B 区,每个区里存一份完整的参数,外加一个版本号和一个 CRC。写入的时候,先读当前版本号,加一,然后写到另一个区。读取的时候,比较两个区的版本号,取版本号大的那个区,如果版本号相同,取 CRC 正确的那个区。

这样做的好处是,即使写入过程中掉电,至少有一个区的数据是完整的。而且版本号可以防止读取到旧数据。版本号用 32 位,足够用很多年。CRC 用 CRC16 或者 CRC32,根据参数长度选择。

6.3 用 MRAM 缓存频繁变化的数据

有些数据变化非常频繁,比如电机的转速、位置、电流。这些数据如果每次都写 EEPROM,芯片很快就坏了。但如果完全不存,掉电之后又丢失了关键状态。用 MRAM 做缓存是一个折中方案。

我的做法是在 MRAM 里划出一块区域作为状态缓存区,每隔一定时间或者状态变化超过阈值的时候写入一次。写入频率可以比 EEPROM 高很多,因为 MRAM 没有寿命限制。掉电之后重新上电,从 MRAM 里读取上次的状态,系统可以快速恢复到掉电前的状态。这个思路在电机控制、机器人关节控制里特别有用。

6.4 SPI 总线上挂多个从设备的片选管理

一个系统里可能不止一颗 MRAM,还可能挂其他 SPI 设备,比如 ADC、DAC、显示屏。这时候片选管理就很重要。我的做法是每个 SPI 设备分配一个独立的片选引脚,在访问某个设备之前,先确保其他设备的片选都是高电平。可以在 SPI 读写函数里加一个片选管理函数,每次访问之前先拉高所有片选,再拉低目标片选。

如果片选引脚不够用,可以用译码器扩展,比如 74HC138 可以把 3 个 GPIO 扩展成 8 个片选。但译码器的输出会有延迟,SPI 时钟频率高的时候要注意时序。我一般会在片选拉低之后加几个 NOP 延时,等片选信号稳定之后再发送数据。

7. 一些关于选型和替代方案的实在话

MR25H40CDF 不是唯一的选择,市面上还有其他 MRAM 型号,也有 FRAM 和 NVSRAM 可以选。这一节说说我在不同场景下的选型思路,以及什么情况下不建议用 MRAM。

如果你的项目写入频率很低,比如一天写几次,那用 EEPROM 就够了,成本更低。如果写入频率中等,比如每分钟写几次,但容量需求不大,FRAM 也是一个选择,FRAM 的写入寿命也很长,而且功耗更低。如果容量需求大,比如要存几 MB 的数据,那 MRAM 的成本就上去了,这时候可以考虑用 Flash 加掉电检测电路,在掉电之前把数据写到 Flash 里。

MR25H40CDF 的定位是中等容量、高写入频率、高可靠性。它的 512KB 容量对于参数存储和日志记录来说刚好够用,SPI 接口简单,和 PIC18LF46K22 搭配起来硬件成本也不高。如果你在做工业仪表、数据采集、电机控制这类项目,这套组合值得一试。

替代型号方面,Everspin 的 MR25H256 是 256Kb 的,容量小一半,如果数据量不大可以选这个,成本更低。MR25H10 是 1Mb 的,容量更大。如果买不到 Everspin 的芯片,Cypress 的 FRAM 系列比如 FM25V05 也是 SPI 接口,容量 512Kb,写入特性类似,但容量小一些,可以作为备选。

最后说一个实际采购中的注意事项:MRAM 芯片的供货周期有时候会比较长,尤其是工业级温度范围的型号。我在一个项目里因为芯片缺货,不得不临时改用 FRAM,虽然软件上改动不大,但硬件引脚不兼容,还是重新做了一版 PCB。所以如果你选定了 MRAM,最好提前备货,或者在设计的时候留一个兼容 FRAM 的封装位置,这样缺货的时候可以快速切换。

我在实际使用中体会最深的一点是,MRAM 的价值不在于它有多快或者容量有多大,而在于它让嵌入式系统里的数据存储变得简单了。不需要擦除,不需要磨损均衡,不需要复杂的掉电保护电路,写就完了。这种简单性在工业项目里意味着更少的故障点和更短的开发周期。当然,简单是有代价的,MRAM 的单位成本比 Flash 高,但对于那些数据不能丢、写入又频繁的场景,这个代价是值得的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询