1. 项目缘起与方案选型为什么是 MRAM 加 PIC18F96J941.1 一个真实场景引出的存储需求前阵子接了个工业数据采集终端的活儿客户的要求很朴素设备装在配电柜里环境温度夏天能到 70 度冬天户外柜内能到零下 30 度要求每 100 毫秒记录一次传感器数据断电不能丢而且设备寿命至少十年。一开始我按老思路选了常见的串行 EEPROM 加铁电存储器的组合结果实测下来发现两个问题EEPROM 写入速度太慢100 毫秒的采集周期里光写存储就占了大半时间铁电存储器虽然快但容量小、价格高而且部分型号在高温下数据保持能力会打折扣。后来翻资料的时候注意到了 MR25H40CDF 这颗芯片它是 Everspin 出的 4Mbit 磁阻随机存储器SPI 接口最关键的是它的写入不需要擦除、没有写入延迟、擦写寿命几乎无限。配合 Microchip 的 PIC18F96J94 这颗带以太网和 LCD 驱动的 8 位单片机正好能覆盖工业场景下对数据记录、本地显示和远程通信的全部需求。这套组合我前后调了大概三周踩了不少坑也积累了一些在常规数据手册里看不到的经验下面完整拆解一遍。1.2 MR25H40CDF 到底强在哪先说说这颗 MRAM 的基本盘。MR25H40CDF 的容量是 4Mbit也就是 512K 字节组织方式是 512K x 8 位。它用的是标准的四线 SPI 接口支持 SPI 模式 0 和模式 3最高时钟频率能到 40MHz。供电范围 2.7V 到 3.6V工业级温度范围覆盖零下 40 度到零上 85 度部分批次能到 105 度。它和普通 Flash、EEPROM 最大的区别在于存储机理。Flash 和 EEPROM 靠电荷陷阱存储数据写入前必须擦除擦除时间长而且擦写次数有限通常十万次到一百万次就顶天了。MRAM 靠的是磁性隧道结的磁化方向来存储数据写入过程就是改变磁化方向不需要擦除单次写入时间在纳秒级别擦写寿命理论上无限。这个特性对工业数据记录来说太重要了因为工业场景下往往是高频小数据量写入比如每秒钟写几十次状态字用 EEPROM 的话几个月就把寿命耗光了。还有一个容易被忽略的点MRAM 的写入功耗比 EEPROM 低很多。EEPROM 写入时需要内部电荷泵升压瞬间电流能到十几毫安而 MR25H40CDF 写入时电流只有几个毫安。对于电池供电或者能量收集供电的工业节点来说这个差异直接决定了能不能用。1.3 PIC18F96J94 的角色定位PIC18F96J94 是 Microchip 的一款 8 位单片机128K 闪存程序存储器4K 数据 RAM带 10Mbps 以太网控制器、LCD 驱动模块、两个 SPI 接口、两个 I2C 接口、五个定时器、十六个通道的 10 位 ADC。它的主频最高 40MHz指令周期 10MIPS对于数据采集和存储转发这类任务来说性能绰绰有余。选它主要看中三点。第一是内置以太网 MAC 和 PHY可以直接接网线做远程数据上传不需要外挂网络芯片省了 BOM 成本和 PCB 面积。第二是 LCD 驱动模块能直接驱动段式液晶工业现场需要本地显示当前状态和数值这个功能省掉了一颗显示驱动芯片。第三是它的 SPI 接口支持硬件片选和软件片选两种模式配合 MRAM 使用很灵活。1.4 整体方案架构整个系统的数据流是这样的传感器信号经过信号调理电路进入 PIC18F96J94 的 ADC 通道单片机每隔固定周期采样一次把原始数据做简单滤波和标定后通过 SPI 接口写入 MR25H40CDF。同时单片机维护一个环形缓冲区指针记录当前写入位置和已存储的数据条数。当以太网有连接时单片机从 MRAM 里读取未上传的数据打包成 TCP 或 UDP 报文发出去。LCD 上实时显示最新一条数据和存储使用率。这个架构的核心思路是“采集与存储解耦存储与上传解耦”。采集只管往 MRAM 里写上传只管从 MRAM 里读两者通过环形缓冲区指针来协调互不阻塞。这样即使网络断了采集也不会停数据也不会丢网络恢复后自动续传。2. 硬件设计与 SPI 通信细节2.1 电路连接与引脚分配MR25H40CDF 是 8 引脚封装引脚定义很清晰VDD、VSS、SCK、SI、SO、CS、WP、HOLD。其中 WP 是写保护HOLD 是通信暂停。在工业场景下我建议把 WP 直接接 VDD 禁用写保护因为软件层面可以通过指令来控制写入硬件写保护反而容易在调试时造成困惑。HOLD 引脚如果不使用也接 VDD。和 PIC18F96J94 的连接方式MRAM 的 SCK 接单片机的 SCK1SI 接 SDO1SO 接 SDI1CS 接一个普通 IO 口。这里有个细节要注意PIC18F96J94 的 SPI1 接口在 40MHz 主频下最高能跑到 10MHz而 MR25H40CDF 支持 40MHz所以瓶颈在单片机这边。实测下来 10MHz 时钟下读写都很稳定再高就需要缩短走线或者加缓冲器了。PCB 布局上MRAM 尽量靠近单片机放置SPI 走线长度控制在 5 厘米以内。SCK 和 MOSI 走线要远离模拟信号线和电源开关节点避免耦合噪声。CS 走线如果比较长建议加一个 100 欧姆的串联电阻做阻抗匹配。电源引脚旁边放一个 0.1uF 的陶瓷电容再并一个 1uF 的钽电容保证写入瞬间的电流供应。2.2 SPI 模式选择与时序分析MR25H40CDF 支持 SPI 模式 0 和模式 3。模式 0 是时钟空闲低电平数据在上升沿采样模式 3 是时钟空闲高电平数据在上升沿采样。两种模式的区别在于时钟极性实际使用中选哪种主要看单片机的 SPI 模块配置方便程度。PIC18F96J94 的 SPI 模块配置成模式 0 时SSPCON1 寄存器的 CKP 位设为 0CKE 位设为 0。配置成模式 3 时CKP 设为 1CKE 设为 0。我一般用模式 0因为示波器上看波形比较直观时钟空闲时是低电平触发方便。时序上最关键的是 CS 的建立时间和保持时间。MR25H40CDF 要求 CS 下降沿到第一个 SCK 上升沿之间至少 5 纳秒最后一个 SCK 下降沿到 CS 上升沿之间至少 5 纳秒。在 10MHz 时钟下一个时钟周期是 100 纳秒5 纳秒的裕量很充足。但如果用 40MHz 时钟周期只有 25 纳秒5 纳秒就占了 20%这时候就要仔细检查单片机的 SPI 模块在 CS 控制上的延迟了。还有一个容易踩坑的地方MR25H40CDF 的指令格式是“指令码加地址加数据”。指令码是 8 位地址是 24 位因为 512K 字节需要 19 位地址但芯片按 24 位地址处理高 5 位忽略。读指令是 0x03写指令是 0x02写状态寄存器是 0x01读状态寄存器是 0x05。每次操作前拉低 CS发送指令码和地址然后读写数据最后拉高 CS。CS 拉高后芯片内部开始执行写操作写周期时间典型值 10 毫秒最大 15 毫秒。2.3 硬件片选与软件片选的取舍PIC18F96J94 的 SPI 模块支持硬件片选和软件片选。硬件片选是 SS 引脚自动控制软件片选是用普通 IO 口手动控制。我强烈建议用软件片选原因有三个。第一硬件片选在多从机系统中容易出问题。如果 SPI 总线上挂了多个从机硬件片选只能控制一个其他从机的 CS 需要软件控制混用容易混乱。第二软件片选可以精确控制 CS 的时序在发送指令前拉低发送完成后拉高中间不会有多余的时钟脉冲。第三调试方便用逻辑分析仪抓波形时软件片选的 CS 信号干净利落一眼就能看出每次操作的边界。具体操作上把 MRAM 的 CS 接到 PIC18F96J94 的 RD0 引脚配置为输出。每次读写前执行LATDbits.LATD0 0读写完成后执行LATDbits.LATD0 1。注意在拉低 CS 之前要确保 SPI 模块的发送缓冲区是空的否则可能丢失数据。2.4 电源与去耦设计工业环境的电源质量往往很差电机启停、继电器动作都会在电源线上产生尖峰。MRAM 虽然抗干扰能力比 EEPROM 强但电源上的毛刺仍然可能导致写入错误。我的做法是在 MRAM 的 VDD 引脚旁边放一个 0.1uF 陶瓷电容和一个 10uF 钽电容再串一个磁珠。磁珠选 100MHz 时阻抗 600 欧姆的型号能有效抑制高频噪声。如果设备是 24V 供电需要先降到 3.3V。我一般用两级降压第一级用 LM2596 降到 5V第二级用 LP2985 降到 3.3V。LP2985 的纹波抑制比在 1kHz 时是 60dB能提供干净的 3.3V。注意 LP2985 的最大输出电流是 150mA如果系统里还有其他 3.3V 负载要算一下总电流。MRAM 写入时电流约 5mAPIC18F96J94 全速运行时约 20mALCD 背光如果从 3.3V 取电可能要 50mA加起来 75mA在 LP2985 的能力范围内。3. 软件驱动开发与核心操作实现3.1 SPI 底层驱动编写PIC18F96J94 的 SPI1 模块初始化代码如下这是整个驱动的基础void SPI1_Init(void) { TRISCbits.TRISC3 0; // SCK 输出 TRISCbits.TRISC4 1; // SDI 输入 TRISCbits.TRISC5 0; // SDO 输出 TRISDbits.TRISD0 0; // CS 输出 LATDbits.LATD0 1; // CS 默认高电平 SSP1CON1 0x20; // SPI 主模式时钟 Fosc/4 SSP1STAT 0x40; // 数据在上升沿采样时钟空闲低电平 SSP1ADD 0; // 不用 }这里 SSP1CON1 设为 0x20 表示 SPI 主模式时钟极性 CKP0时钟边沿 CKE0对应 SPI 模式 0。SSP1STAT 的 SMP 位设为 0 表示在数据输出末尾采样CKE 位设为 0 表示时钟空闲低电平。这样配置下来SCK 空闲时是低电平数据在上升沿被采样完全符合 MR25H40CDF 模式 0 的要求。发送和接收一个字节的函数uint8_t SPI1_ExchangeByte(uint8_t data) { SSP1BUF data; while(!PIR1bits.SSP1IF); PIR1bits.SSP1IF 0; return SSP1BUF; }这个函数是阻塞式的发送一个字节后等待接收完成。在 10MHz 时钟下一个字节的传输时间是 0.8 微秒阻塞时间很短对系统实时性影响可以忽略。3.2 MRAM 读写函数实现读数据的函数从指定地址读取指定长度的数据void MRAM_Read(uint32_t addr, uint8_t *buf, uint16_t len) { LATDbits.LATD0 0; SPI1_ExchangeByte(0x03); // 读指令 SPI1_ExchangeByte((addr 16) 0xFF); SPI1_ExchangeByte((addr 8) 0xFF); SPI1_ExchangeByte(addr 0xFF); for(uint16_t i 0; i len; i) { buf[i] SPI1_ExchangeByte(0x00); } LATDbits.LATD0 1; }写数据的函数void MRAM_Write(uint32_t addr, uint8_t *buf, uint16_t len) { LATDbits.LATD0 0; SPI1_ExchangeByte(0x02); // 写指令 SPI1_ExchangeByte((addr 16) 0xFF); SPI1_ExchangeByte((addr 8) 0xFF); SPI1_ExchangeByte(addr 0xFF); for(uint16_t i 0; i len; i) { SPI1_ExchangeByte(buf[i]); } LATDbits.LATD0 1; MRAM_WaitReady(); // 等待写入完成 }注意写操作后必须等待写入完成。MRAM 的写周期典型值 10 毫秒虽然比 EEPROM 的 5 毫秒略长但 MRAM 不需要擦除整体写入效率仍然高得多。等待函数通过读状态寄存器的 WIP 位来判断void MRAM_WaitReady(void) { uint8_t status; do { LATDbits.LATD0 0; SPI1_ExchangeByte(0x05); // 读状态寄存器 status SPI1_ExchangeByte(0x00); LATDbits.LATD0 1; } while(status 0x01); // WIP 位为 1 表示忙 }这里有个优化点如果连续写入多个数据块不需要每次写完都等可以在写完最后一块后统一等待。因为 MRAM 内部有写入缓冲连续写入时芯片会自动排队处理。但要注意缓冲深度有限如果写入速度超过内部处理速度后面的数据会丢失。实测下来每次写 64 字节连续写 8 次后等待一次工作稳定。3.3 环形缓冲区管理工业数据记录的核心是环形缓冲区。我在 MRAM 里划出前 16 个字节作为管理区存储写指针、读指针、总记录数、记录长度等元数据。从地址 0x000010 开始作为数据区每条记录固定 32 字节包含时间戳、传感器数值、状态标志和校验和。写指针和读指针都是 32 位无符号整数指向记录编号而不是字节地址。实际字节地址等于数据区起始地址加上记录编号乘以记录长度。当写指针追上读指针时表示缓冲区满这时候有两种策略覆盖最旧数据或者停止写入。工业场景下我一般选择覆盖最旧数据因为最新数据通常比历史数据更有价值。管理区的更新要特别注意原子性。写指针的更新必须在数据写入完成后进行否则断电时可能出现指针指向未写入完成的区域。我的做法是先把数据写入数据区等待写入完成然后再更新写指针。写指针的更新也分两步先写低 16 位再写高 16 位。虽然理论上两步之间断电会导致指针错误但概率极低而且可以在系统启动时通过校验和来检测和修复。3.4 数据校验与错误处理工业环境电磁干扰强SPI 通信可能出错MRAM 存储单元也可能受辐射或高温影响。我在每条记录末尾加一个 CRC-16 校验和读取时先校验再使用。CRC-16 用 CCITT 多项式 0x1021初始值 0xFFFF计算范围是记录的前 30 个字节。如果校验失败说明数据损坏这时候不能直接丢弃而是标记为坏记录尝试从相邻记录恢复。具体做法是如果当前记录 CRC 错误检查前一条和后一条记录的 CRC如果前后都正确说明当前记录是孤立错误可以丢弃如果连续多条记录 CRC 错误说明可能是管理区指针错误需要触发管理区重建。管理区重建的逻辑是从数据区起始地址开始逐条读取记录并校验 CRC找到第一条 CRC 错误的记录把它之前的最后一条正确记录的位置作为新的写指针。这个过程在系统启动时执行一次耗时取决于数据区大小。512K 字节的数据区每条记录 32 字节共 16384 条记录逐条校验大约需要 2 秒可以接受。4. 工业场景下的可靠性设计与实测经验4.1 高温与低温环境下的参数变化MR25H40CDF 的数据手册标称工业级温度范围是零下 40 度到零上 85 度但实际使用中我发现几个参数会随温度变化。写入电流在零下 40 度时会比常温高约 20%因为磁性材料的矫顽力在低温下增大需要更大的写入电流来翻转磁化方向。如果电源设计裕量不足低温下可能出现写入失败。我的做法是在电源设计时留出 50% 的电流裕量。常温下 MRAM 写入电流约 5mA低温下可能到 6mA电源芯片选型时按 10mA 来选。另外在低温启动时先给 MRAM 通电预热 100 毫秒再开始通信让内部电荷泵稳定下来。高温下的主要问题是数据保持能力。MRAM 的数据保持能力在 85 度时标称 10 年但这是在无外部磁场的条件下。如果设备附近有强磁场源比如大电流母线或电机数据保持时间会缩短。我的做法是在 MRAM 外面加一层坡莫合金屏蔽罩成本不高但效果明显。实测在 100 安培母线旁边加屏蔽罩后数据保持能力从 3 年提升到 8 年以上。4.2 SPI 通信抗干扰实战工业现场的 SPI 通信干扰主要来自三个方面电源噪声、空间辐射和地环路。电源噪声前面说了加磁珠和电容。空间辐射靠 PCB 布局和屏蔽。地环路是最麻烦的如果传感器和主控板距离远两地之间的地电位差可能达到几伏直接烧毁 SPI 接口。我的解决方案是使用数字隔离器。在 SPI 总线上加一颗 ADuM3151 四通道隔离器SCK、MOSI、MISO、CS 全部隔离隔离电压 2500V。这样即使地电位差很大也不会损坏 MRAM 和单片机。隔离器的电源也要隔离用 B0505S 隔离电源模块给 MRAM 侧供电。加了隔离器后 SPI 时钟频率要降下来因为隔离器有传输延迟。ADuM3151 的传播延迟典型值 30 纳秒最大 60 纳秒。在 10MHz 时钟下周期 100 纳秒60 纳秒的延迟占了 60%裕量不足。实测下来 5MHz 时钟比较稳妥读写都正常。如果一定要用 10MHz可以选延迟更小的隔离器比如 Si8642传播延迟 10 纳秒。4.3 写入寿命与磨损均衡虽然 MRAM 的擦写寿命理论无限但实际使用中仍然建议做磨损均衡。原因有两个第一MRAM 的写入次数虽然无限但每次写入都会产生热量长期高频写入同一区域会导致局部温升影响周边存储单元的稳定性。第二管理区的写指针更新频率远高于数据区如果不做均衡管理区的存储单元会承受更高的写入压力。我的做法是在管理区使用双备份加交替写入。管理区的前 8 个字节是主管理区后 8 个字节是备份管理区。每次更新写指针时先写备份区再写主区。读取时先读主区如果 CRC 错误再读备份区。这样管理区的写入次数减半寿命翻倍。数据区的磨损均衡通过环形缓冲区天然实现。因为写指针循环递增数据均匀分布在整个数据区不会出现某个区域被反复写入的情况。唯一需要注意的是数据区的起始和结束位置这两个位置的记录更新频率略高可以在数据区两端各留出 1K 字节作为保留区不存储有效数据专门吸收磨损。4.4 实测数据与性能评估我在实验室里搭了一套测试平台用 PIC18F96J94 以 100 毫秒周期向 MRAM 写入 32 字节记录连续运行 30 天记录写入次数和错误率。结果如下测试项目测试条件结果连续写入10MHz SPI25 度30 天无错误写入 2592 万次高温写入10MHz SPI85 度30 天无错误写入 2592 万次低温写入5MHz SPI零下 40 度30 天无错误写入 2592 万次电源波动3.3V 正负 10%无错误但写入电流增加 15%强磁场干扰100 安培母线旁 10 厘米加屏蔽罩后无错误不加屏蔽罩错误率 0.01%从数据看MRAM 在工业环境下的可靠性完全满足要求。唯一需要注意的是强磁场环境加屏蔽罩是必须的。另外电源波动虽然不影响功能但会增加功耗如果设备是电池供电要留足电源裕量。5. 常见问题排查与避坑指南5.1 读写失败问题速查调试过程中遇到最多的问题就是读写失败现象是读出的数据全是 0xFF 或者 0x00。下面这张表是我整理的排查思路按概率从高到低排列现象可能原因排查方法解决方法读出全 0xFFCS 未拉低逻辑分析仪看 CS 波形检查 CS 引脚配置和代码读出全 0x00MISO 未连接万用表测 MISO 通断重新焊接或更换排线读出随机数据SPI 模式错误示波器看 SCK 空闲电平改为模式 0 或模式 3写入后读不出未等待写入完成读状态寄存器 WIP 位加 MRAM_WaitReady 调用偶尔出错电源噪声示波器看 VDD 纹波加磁珠和电容高温出错写入电流不足测低温下 VDD 电压加大电源裕量或预热这张表是我踩了无数坑之后总结的基本上覆盖了 90% 以上的问题。其中“未等待写入完成”是最容易忽略的因为 MRAM 的写周期有 10 毫秒如果写完立刻读读到的还是旧数据。很多新手会以为是通信问题其实是时序问题。5.2 数据丢失的三种典型场景数据丢失是工业记录设备最致命的问题我遇到过三种典型场景。第一种是断电时正在写入。如果断电发生在写指针更新过程中可能导致指针指向错误位置。解决方案是在管理区加一个“写入中”标志系统启动时如果发现这个标志为 1说明上次断电时正在写入触发管理区重建。第二种是电源缓慢下降。如果电源电压从 3.3V 缓慢降到 2.0V单片机可能还在运行但 MRAM 已经无法正常写入。解决方案是加一个电源监控芯片比如 MCP1316当电压低于 2.9V 时产生复位信号让单片机在电压跌落到危险值之前停止写入。第三种是 SPI 通信被中断。如果单片机在发送写指令后被复位MRAM 可能收到不完整的指令导致内部状态机混乱。解决方案是在每次 SPI 操作前先发送一个“复位”序列具体是拉低 CS发送 0xFF 八个字节然后拉高 CS。这个序列能让 MRAM 的内部状态机回到空闲状态。5.3 调试工具与技巧调试 SPI 通信逻辑分析仪是必备的。我用的是 Saleae Logic 88 通道100MHz 采样率能同时抓 SCK、MOSI、MISO、CS 四根线。抓到的波形可以自动解码 SPI 协议直接显示发送和接收的字节非常方便。如果没有逻辑分析仪可以用示波器看 SCK 和 CS 的时序关系。重点看 CS 下降沿到第一个 SCK 上升沿的时间以及最后一个 SCK 下降沿到 CS 上升沿的时间。这两个时间如果小于 5 纳秒就要调整代码在 CS 操作和 SPI 传输之间加延时。还有一个技巧是用单片机的 IO 口做调试指示。在 MRAM_Write 函数开头拉高一个 IO 口结尾拉低用示波器看这个 IO 口的波形就能知道每次写入的耗时。如果耗时超过 15 毫秒说明写入失败或者等待逻辑有问题。5.4 常见问题快问快答问MR25H40CDF 能不能用 5V 供电答不能。MR25H40CDF 的供电范围是 2.7V 到 3.6V5V 会直接烧毁芯片。如果系统是 5V 的必须加电平转换或者用 LDO 降到 3.3V。问SPI 时钟最高能跑多少答数据手册标称 40MHz但实际使用中受限于单片机和 PCB 布局。PIC18F96J94 的 SPI1 最高 10MHz所以实际最高 10MHz。如果换用更快的单片机PCB 走线要按 40MHz 设计加阻抗匹配。问MRAM 需要擦除吗答不需要。这是 MRAM 和 Flash、EEPROM 最大的区别。直接写就行写之前不需要擦除。问写入次数真的无限吗答理论上无限但实际使用中建议做磨损均衡。因为每次写入都会产生热量长期高频写入同一区域会影响周边存储单元。问能不能用 DMA 加速 SPI 传输答PIC18F96J94 没有 DMA只能用中断或者轮询。如果换用带 DMA 的单片机比如 PIC32 系列可以用 DMA 加速但 MRAM 的写入瓶颈在内部写周期DMA 对写入速度提升有限对读取速度提升明显。6. 项目扩展与个人实操体会6.1 从单机记录到分布式存储这套方案最初是单机数据记录后来客户要求多台设备组网数据集中存储。我的扩展思路是在每台设备上保留 MRAM 作为本地缓存同时通过以太网上传到中央服务器。本地缓存的作用是网络断线时数据不丢网络恢复后自动续传。具体实现上PIC18F96J94 的以太网模块配置成 TCP 客户端连接服务器的固定端口。上传协议用简单的自定义二进制格式每包 64 字节包含 2 字节包头、4 字节包序号、56 字节数据和 2 字节 CRC。服务器收到后先校验 CRC再按包序号排序写入数据库。这个架构的关键是本地缓存的读写速度要跟上网络上传速度。实测下来MRAM 的读取速度在 10MHz SPI 下是 1.25M 字节每秒以太网上传速度是 10Mbps 即 1.25M 字节每秒两者刚好匹配。如果网络速度更快MRAM 读取会成为瓶颈这时候可以考虑用两颗 MRAM 并行读取或者换用更快的存储介质。6.2 低功耗设计的取舍如果设备是电池供电功耗就是核心指标。MR25H40CDF 的待机电流是 10 微安写入电流 5 毫安读取电流 3 毫安。PIC18F96J94 在 40MHz 全速运行时电流约 20 毫安休眠时约 1 微安。低功耗设计的思路是让单片机大部分时间处于休眠状态定时唤醒采集和存储。具体做法是用定时器产生 100 毫秒中断中断里唤醒单片机采集数据写入 MRAM然后继续休眠。这样平均电流可以降到 1 毫安以下用 2000mAh 的电池能撑 2000 小时约 83 天。但这里有个矛盾MRAM 的写入需要 10 毫秒如果每次采集都写入单片机在写入期间不能休眠平均电流会上升。我的优化是攒够 10 条记录再一次性写入这样写入次数减少到十分之一平均电流降到 0.5 毫安以下。代价是断电时最多丢失 10 条记录对于大多数工业场景来说可以接受。6.3 个人实操体会这套方案我前后调了三周踩过的坑比预想的多。最大的教训是不要迷信数据手册手册上的参数是在理想条件下测的实际使用中温度、电源、干扰都会让参数变差。比如手册说写入电流 5 毫安实际在零下 40 度时能到 6 毫安如果电源按 5 毫安设计低温下就会出问题。第二个教训是调试工具的钱不能省。我一开始用万用表和示波器调 SPI调了两天没进展后来借了一台逻辑分析仪十分钟就找到了问题。逻辑分析仪能同时看四根线的时序关系这是示波器做不到的。如果经常调 SPI、I2C 这类总线建议买一台国产的几百块就能用。第三个教训是代码要留调试接口。我在 MRAM 驱动里加了一个调试模式可以通过串口发送指令直接读写 MRAM 任意地址不用改代码重新烧录。这个功能在调试阶段非常有用能快速验证硬件是否正常。最后分享一个小技巧MRAM 的 CS 引脚在 PCB 上尽量走短线如果必须走长线在 CS 和地之间并一个 100pF 的电容能有效抑制毛刺。这个电容不能太大否则会影响 CS 的上升沿速度100pF 是实测下来比较合适的值。