ARTICLE DETAIL

资讯详情

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

MR25H40CDF+dsPIC33:工业电机数据记录的非易失存储方案

MR25H40CDF+dsPIC33:工业电机数据记录的非易失存储方案 去年在调一套 7.5kW 电机驱动器的运行参数记录板时我一直在存储方案上较劲。现场要求每 100ms 存一条三相电流、母线电压、IGBT 温度和故障码掉电又完全不可预期。最开始用 SPI NOR Flash 做日志结果覆盖写一个扇区就要先整块擦除日志区只有几个扇区跑不了几天就轮到擦旧数据擦除期间的阻塞直接让控制周期乱掉故障记录还会出现几秒的空洞。后来我把存储芯片换成 Everspin 的 MR25H40CDF4Mbit SPI MRAM主控继续用 Microchip 的 dsPIC33FJ256GP710A整套方案才算真正稳定下来。这篇文章就把这套 MRAM DSC 组合的选型逻辑、底层驱动、存储布局和现场踩坑记录完整整理一遍给正要选非易失存储或者在做数据记录板的朋友做个参考。1. 为什么工业现场我宁可加几块钱也要用 MR25H40CDF 这类 MRAM1.1 从一次现场数据丢失说起很多人一看 4Mbit 容量第一反应是这不就是个 SPI 存储器嘛EEPROM 和 NOR Flash 也能干。这话在办公室调板子的时候成立拿到工业现场就未必了。我最初在样机上用的是一款 2Mbit EEPROM寿命按 100 万次擦写算。按我们 10Hz 的写入频率100 万次只够写 10 万秒也就是大约 27 小时。一个连续运行一周的设备写到第三天就到寿命边缘后面再写就是赌运气了。这个账一算就很残酷高频周期记录型应用EEPROM 的寿命根本撑不住。换 NOR Flash 呢寿命更低通常 10 万次量级而且写之前必须擦除。日志以循环覆盖方式写每次写到扇区末尾都要先抹掉整个扇区再重新写入单次操作耗时从几百微秒跳到几十毫秒。你在控制中断里临时塞一个几十毫秒的 Flash 擦除操作现场主站立刻报通信超时。MR25H40CDF 的出现恰好把这两个痛点同时解决了。它是磁阻存储器底层用磁性隧道结保存数据不是靠电荷。电荷存储器件写多了会漏电、会氧化、会劣化而 MRAM 的读写机制基本不存在这种磨损问题数据手册上写循环次数通常是 10^12 量级。按 10Hz 写入频率算理论寿命约 3000 年对工业设备来说就是写到设备报废都写不坏。1.2 MRAM 到底解决了什么本质问题MRAM 最本质的特点是非易失和高速随机写入可以同时成立。SRAM 快但掉电丢EEPROM 掉电不丢但写起来慢、寿命短NOR Flash 容量大但要有擦除步骤。MRAM 把 SRAM 的随机读写能力和 EEPROM 的非易失特性合在一起写之前不需要擦除按字节改就行。这对工程的意义是你的存储逻辑可以完全按内存去设计而不必照顾块/扇区/擦除这些 Flash 的怪脾气。具体到我的板子上最直接的收益是环形日志区实现变简单了。写日志就是顺序写一条 32 字节记录指针走到区域末尾就回卷到开头直接覆盖最旧的一条。如果是 NOR Flash回卷等于先擦掉一块旧数据再写新数据这里还要处理擦了一半掉电的恢复逻辑代码复杂度完全不是一个量级。MRAM 不需要擦除回卷就是普通写掉电了也只是最新一条可能不是完整的前一条数据依旧完好。1.3 与 FRAM、EEPROM、NOR Flash 的横向对比我知道很多人会用 FRAM 做掉电保存。FRAM 也是好东西写入不需擦除、寿命高但密度普遍偏小做诊断日志这种需要几百 KB 连续空间的场景不太够。MRAM 的密度和 SPI 引脚兼容性让它更像能掉电保存的 SRAM。下面这张表是我实际选型时列过的对比项目MRAMMR25H40CDFFRAMEEPROMNOR Flash存储原理磁性隧道结铁电晶体浮栅电荷浮栅电荷典型擦写次数10^12 量级10^12 量级10^5 ~ 10^610^4 ~ 10^5写前是否需要擦除不需要不需要不需要必须按扇区擦除按字节随机写支持支持支持不支持块内更新要先读改写写 256B 典型耗时约 0.3ms 8MHz SPI类似 MRAM约 5ms 级写入前还要加擦除时间整块更慢常见容量1Mbit ~ 几十 Mbit小容量居多小容量大容量 8Mbit 起步结论是如果项目里只是存几个配置参数EEPROM 完全够用便宜又大碗。但如果要做高频运行日志、事件记录或者频繁掉电保存MRAM 属于那种单价看着心疼现场少跑一次就回本的器件。2. MR25H40CDF 芯片要点引脚、指令集不是普通 SPI Flash 那套玩法2.1 引脚定义与最小接线MR25H40CDF 是 3.3V 供电的 SPI 接口存储器容量 4Mbit按字节寻址是 512KB地址需要 3 字节。芯片引脚不多但有几个和普通 EEPROM 不太一样的接线时得格外注意。我按最小系统列一下引脚方向作用与处理建议/CS输入片选低有效。用 MCU 普通 GPIO 控制别用硬件自动片选SCK输入SPI 时钟最高 40MHz工业板我建议跑 8~20MHzSI输入数据输入接主控 SDOSO输出数据输出接主控 SDI/WP输入写保护。平时用 10kΩ 上拉到 VCC/HOLD输入暂停通信。不使用时必须上拉到 VCC不能悬空VCC/GND电源VCC 对地并 0.1uF电源入口再放 10uF 电解为什么我强调 /HOLD 不能悬空因为 /HOLD 拉低时芯片会暂停当前通信但片选仍然是有效状态。如果这个引脚悬空现场干扰一耦合上去芯片就可能在某一次读写的中间暂停主控等不到数据后面所有字节错位。这是我在第一版 PCB 上真实踩过的坑后面专门有一节细说。2.2 指令集、状态寄存器与页面限制MR25H40C 的指令集沿用了 SPI 存储器的通用框架但少了 Flash 那一堆块擦除指令用起来更像 EEPROM。常用指令就这几个指令命令码说明WREN0x06写使能写操作前必须执行WRDI0x04写禁止RDSR0x05读状态寄存器WRSR0x01写状态寄存器READ0x03读数据3 字节地址WRITE0x02写数据3 字节地址读写都是先拉低 /CS然后依次发送命令码、地址高 8 位、地址中 8 位、地址低 8 位之后才是数据字节。读操作里主控要持续发 0xFF 来产生时钟每收一个字节 MISO 上就吐一个地址对应的数据。写操作要注意页长限制MR25H40C 的页长是 256 字节单次 WRITE 命令建议不要把地址穿过页边界。我的驱动里做了一个简单的拆分函数遇到跨页地址就自动拆成多次页写这样无论数据在哪个地址调用层都不用关心边界问题。状态寄存器里面最低位是 WIP写进行中位。虽然 MRAM 写周期很短但为了稳妥页写完成后我还是会轮询一下 WIP 清零再返回。另外 WEL 位表示写使能锁存状态WREN 命令执行后这一位置 1写完成后会自动清零。这点和普通 SPI EEPROM 的习惯一致写之前别忘了发 WREN。2.3 /WP 和 /HOLD 的处理原则/WP 和 /HOLD 这两个脚我见过不少板子直接把焊盘空着。如果只做单主控、单从机的简单 SPI 链路空着理论上也能跑但工业现场我强烈建议都加上拉电阻。 /WP 默认状态下主要控制状态寄存器相关保护位不会把整个存储阵列锁死但要防止干扰导致它意外变低所以拉到 VCC 是标准做法。 /HOLD 前面说过了干扰等于通信暂停键悬空就是给自己埋雷。另一个容易犯错的地方是片选信号。dsPIC33 这类 MCU 的 SPI 外设可以配置硬件 SS 脚自动拉片选但当你板上还挂了 ADC、铁电或者其他 SPI 器件时自动 SS 很容易互相抢总线。我的原则是MRAM 的 /CS 永远用普通 GPIO 手动控制SPI 只负责 SCK、SI、SO 三根线。这样每条命令的开始和结束都清清楚楚逻辑分析仪抓波形也直观。3. dsPIC33FJ256GP710A 侧SPI 主模式初始化与可复用的读写驱动3.1 SPI 引脚映射和时钟计算dsPIC33FJ256GP710A 是 3.3V 供电的 DSC最高 40 MIPS片上 Flash 256KBRAM 30KB带两个 SPI 模块。它的 SPI 寄存器和 PIC24 这一代是同一套体系初始化逻辑可以平滑移植。我这里以 SPI1 为例具体引脚要看你的原理图封装映射代码里用宏定义隔离方便换板子。时钟选择上MR25H40CDF 标称最高 40MHz但我并不建议一上来就跑满。工业现场走线难免经过连接器信号完整性和干扰问题会随频率放大。我实际把 SCK 设在 8MHz驱动能力足够波形余量也大。SPI 波特率由 Fcy、主分频、次分频和 SPIBRG 共同决定。初始化时把主次分频都设为 1:1SPIBRG 设为 4在 40MHz 系统时钟下可以得到约 8MHz 的 SCK。具体寄存器编码各家手册写法不一致别死记配完用示波器实测一下 SCK 频率最靠谱。3.2 初始化与底层读写函数下面是 XC16 环境下的完整初始化代码和底层函数这套是我在项目里实际跑着的版本去掉了板级无关的细节#define MR25_CS_TRIS TRISCbits.TRISC3 #define MR25_CS_LAT LATCbits.LATC3 void mr25_cs_low(void) { MR25_CS_LAT 0; } void mr25_cs_high(void) { MR25_CS_LAT 1; } void spi1_init_master(void) { // 先关 SPI避免配置过程中产生毛刺 SPI1STATbits.SPIEN 0; SPI1CON1 0; SPI1CON1bits.MSTEN 1; // 主模式 SPI1CON1bits.MODE16 0; // 8 位模式 SPI1CON1bits.CKP 0; // 时钟空闲为低 SPI1CON1bits.CKE 1; // 配合 CKP0对应 SPI Mode 0 SPI1CON1bits.SMP 0; // 数据稳定后采样 SPI1CON1bits.PPRE 0b00; // 主分频 1:1具体编码见手册 SPI1CON1bits.SPRE 0b111; // 次分频 1:1 SPI1BRG 4; // 实测 SCK 约 8MHz SPI1STATbits.SPIEN 1; // 上电先把片选置高防止误触发写 MR25_CS_TRIS 0; mr25_cs_high(); } uint8_t mr25_spi_rw(uint8_t out) { SPI1BUF out; while (!SPI1STATbits.SPIRBF) { } return SPI1BUF; } void mr25_write_enable(void) { mr25_cs_low(); mr25_spi_rw(0x06); // WREN mr25_cs_high(); } uint8_t mr25_read_status(void) { uint8_t st; mr25_cs_low(); mr25_spi_rw(0x05); // RDSR st mr25_spi_rw(0xFF); mr25_cs_high(); return st; } void mr25_wait_busy(void) { while (mr25_read_status() 0x01) { } // 等 WIP 清零 } void mr25_page_write(uint32_t addr, const uint8_t *buf, uint16_t len) { uint16_t i; mr25_write_enable(); mr25_cs_low(); mr25_spi_rw(0x02); // WRITE mr25_spi_rw((uint8_t)(addr 16)); mr25_spi_rw((uint8_t)(addr 8)); mr25_spi_rw((uint8_t)(addr 0xFF)); for (i 0; i len; i) { mr25_spi_rw(buf[i]); } // 关键等移位寄存器把最后一位送出去再拉高 /CS while (SPI1STATbits.SPITBF) { } mr25_cs_high(); Nop(); Nop(); mr25_wait_busy(); } void mr25_read(uint32_t addr, uint8_t *buf, uint16_t len) { uint16_t i; mr25_cs_low(); mr25_spi_rw(0x03); // READ mr25_spi_rw((uint8_t)(addr 16)); mr25_spi_rw((uint8_t)(addr 8)); mr25_spi_rw((uint8_t)(addr 0xFF)); for (i 0; i len; i) { buf[i] mr25_spi_rw(0xFF); } mr25_cs_high(); } void mr25_write(uint32_t addr, const uint8_t *buf, uint16_t len) { // 跨页拆分页长 256B while (len 0) { uint16_t cnt 256 - (uint16_t)(addr 0xFF); if (cnt len) { cnt len; } mr25_page_write(addr, buf, cnt); addr cnt; buf cnt; len - cnt; } }3.3 驱动层的几个不能省的等待第一次调这个驱动的朋友最容易犯的错是写完最后一个字节就立刻拉高 /CS。SPI 的发送缓冲是 FIFO 结构SPI1BUF写入只代表数据进了移位寄存器不代表已经全部从 SO/SI 线上送完。如果紧接着拉高 /CS最后的字节会被直接截断看起来就像是随机丢了最后一个字节。所以我在页写结束前专门加了while (SPI1STATbits.SPITBF) { }等发送缓冲为空再释放片选。同理写完以后我还轮询了 WIP 位。虽然 MRAM 写很快但工业上写完就断电的场景太多轮询这一下成本极低收益是换掉电安全。另一个等待来自读操作。读数据过程中 MISO 上可能因为走线电容导致最后一个字节不稳定我的做法是读完常规数据后再多读一个字节丢弃掉相当于给驱动加点余量。对于 100ms 才存一条日志的应用这几个等待完全不影响性能但可靠性高一个档次。4. 512KB 空间的规划艺术参数区、日志环、版本区的三段式布局4.1 整体分区4Mbit 看着不大但分好了反而比大容量 Flash 更容易管理。我的分区方案是经典的参数 日志 版本三段式表格如下区域起始地址长度用途参数镜像 A0x00000016KB当前运行参数、标定系数参数镜像 B0x00400016KB参数镜像备份运行日志区0x008000480KB32 字节一条的循环记录版本/出厂区0x07C00016KB固件版本、出厂序列号、初始化标志不把整颗芯片都塞满日志是因为参数区和日志区的寿命模型不一样。参数区写入频率极低但要求绝对可靠出一次错误整个设备都要返修日志区写入频率极高允许覆盖旧数据但不能破坏参数区。物理分区隔离后代码逻辑可以做到互相不越界。4.2 参数区双镜像与 CRC 校验参数区我用了双镜像方案。每次修改参数不是直接覆盖当前区而是写到另一份镜像里然后更新头部版本号。启动时读取两个镜像哪个版本号新并且 CRC 正确就用哪个。这样即使写入过程中掉电最多坏掉正在写的那份另一份仍然是完整的。镜像头部建议放这么几个字段两个字节的魔术字、四个字节的 CRC32、两个字节的版本号、四个字节的写入时间戳。MCU 上电后先读魔术字不匹配直接判无效再算一遍 CRC不对也判无效两个都有效就取版本号大的。这相当于给参数区做了一个轻量级事务配合 MRAM 掉电不丢的特性现场几乎不会出现参数莫名其妙被清掉的情况。4.3 环形日志区MRAM 让覆盖写变简单日志区我固定用 32 字节一条记录包含 4 字节时间戳、4 字节序列号、8 字节三相电流、4 字节母线电压、2 字节 IGBT 温度、2 字节故障码、2 字节 CRC16外加保留字节凑齐 32 字节。为什么固定长度因为定位快读日志时直接按 32 字节步进扫描不需要解析变长字段。维护两个指针写指针指向下一条要写的位置读指针或日志起始地址存在 RAM 里同时每写满一圈在日志区头部记录一个回卷标志。当写指针到达区域末尾下一个地址回到区域开头直接覆盖最旧记录。在 NOR Flash 方案里这个回卷要处理擦除旧扇区、搬运有效记录等一大堆事情。换到 MR25H40CDF 上回卷就只是重置一个地址变量因为我不需要擦除任何块。这个差异在实际开发中省下来的工作量比芯片单价差要值钱得多。4.4 读取数据的时间线调试时经常要回答刚才那 10 分钟设备到底发生了什么这类问题。我的做法是维护一个record_seq序列号每写一条加一。上电后读取日志区的最后一条记录取出序列号之后按序列号递增顺序回放。如果某条记录 CRC16 错误就停下来打一个日志断裂点报警因为 MRAM 在极端掉电情况下最多只可能破坏正在写的那一条前面所有数据依然有效。不要在这个时候做跳过坏记录继续读的花活工业诊断宁可少一条数据也要明确告诉上位机数据从哪一条开始不可信。5. 现场实测踩过的坑每一项都真实发生过5.1 /HOLD 悬空造成的幽灵错位第一版 PCB 上MR25H40CDF 的 /HOLD 脚被我漏接了上拉电阻想着不用就悬空。结果设备在高频干扰测试的时候偶尔会读出一整帧错位的数据。一开始怀疑 SPI 时序逻辑分析仪抓了很久才发现在一次正常 READ 过程中 MISO 上突然连续几个时钟没有输出然后又恢复正常。查 /HOLD 的波形发现它被干扰拉低了一段正好对应数据暂停的时间。解决方法是 /HOLD 用 10kΩ 电阻上拉到 VCC另外 SCK 走线尽量远离 IGBT 驱动信号。这个坑提醒我所有输入性质的引脚工业板上都不能靠不用就悬空来省事。5.2 写完立刻掉电的边界情况MRAM 虽然写入快但不是完全没有写周期。我在做掉电测试时发现如果主控刚发完 WRITE 命令的地址字节现场就断电那一条记录可能是半截数据CRC16 等于随机值。所以我在上电初始化时加入了一个日志区完整性扫描从头扫到底发现第一条 CRC 错误的记录就把它标记为无效起点后续直接从此处继续写。因为是环形覆盖这个坏记录很快就会被后续数据顶掉不需要额外修复命令。另外在 dsPIC33FJ256GP710A 这一侧我开了 BOR 欠压复位并且把欠压阈值设在 2.5V 左右。真正掉电时主控先收到欠压中断我抓住这个窗口把关键参数用mr25_write写进参数镜像。MRAM 的优势在这里会放大整条写命令只需要地址加数据没有擦除等待几十微秒就能完成BOR 窗口完全够用。5.3 SPI 走线过长引发的采样错位第二版为了布局方便我把 MR25H40CDF 放到了离 dsPIC 大约 8cm 的地方中间还过了一组排针。结果在 20MHz SCK 下SO 数据线上出现了明显振铃读回来的数据偶发错位。降频到 8MHz 后仍然偶发最后不得不改板子把存储芯片挪到 MCU 旁边走线控制在 3cm 以内并在 SCK 和 SI 上各串了 22Ω 电阻。如果你们的板子结构已经定死、没法挪位置也至少要在 SCK 上串电阻并且优先保证 SCK 和 SO 两根线短SI 可以稍微长一点。5.4 购买与封装提醒MR25H40CDF 这类小容量 MRAM 目前渠道比较固定买的时候一定确认好后缀和包装形式。DFN 封装焊接难度比 SOIC 高手工焊的话先在焊盘上涂助焊剂用拖焊方式处理焊完用万用表量一下 /CS 和 VCC、GND 之间有没有连锡。我在实验室就见过一块板子因为 DFN 的 /CS 引脚连锡导致上电后芯片一直处于选中状态SCK 波形正常但所有指令全部无效。最后再分享一个调试习惯在 PCB 上靠近 MRAM 的位置留一组 6 脚测试点把 SCK、SI、SO、/CS、VCC、GND 引出来封装成 2.54mm 间距排针。现场一旦出现存储异常逻辑分析仪直接夹上去比任何仿真器都管用。工业现场的问题往往是偶发、不可复现的有了这个测试点抓到一次完整时序就等于拿到一半答案。这套 MR25H40CDF dsPIC33FJ256GP710A 的组合我现在已经用了三代产品最深的体会是存储方案的选择不能只看容量和单价要看写入频率下的寿命账、掉电场景下的可靠性账以及后续维护时调试手段的便利账把这本账算清楚了方案自然就定了。
返回列表