ARTICLE DETAIL

资讯详情

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

MRAM与PIC32MZ实战:工业嵌入式高频写入与掉电保护存储方案

MRAM与PIC32MZ实战:工业嵌入式高频写入与掉电保护存储方案 1. 为什么偏偏是 MRAM 加 PIC32MZ 这套组合做工业嵌入式这行十几年我见过太多项目在存储方案上翻车。EEPROM 擦写次数不够、Flash 掉电丢数据、FRAM 容量太小还贵得离谱这些问题在数据采集、参数保存、日志记录场景里反复出现。直到我开始用MR25H40CDF这颗 MRAM磁性随机存储器配合PIC32MZ2048EFH144这颗高性能 MCU才算真正把频繁写、掉电不丢、速度快这三个需求同时按住。先说清楚这套组合是什么、能干什么。MR25H40CDF 是 Everspin 出的 4Mbit512KBSPI 接口 MRAM注意是512K 字节不是 512K 位这个容量在参数存储和中小规模日志场景里非常够用。它的核心特性是写入不需要擦除、没有写延迟、擦写寿命理论上无限官方给的是 10^15 次以上、掉电数据保持 20 年以上。PIC32MZ2048EFH144 是 Microchip 的 MIPS M 级 MCU200MHz 主频2MB Flash、512KB RAM自带多个 SPI 外设其中 SPI2 到 SPI5 支持8/16/32 位帧格式这点后面会重点讲因为它直接决定了你读写 MRAM 的效率。这套方案解决的核心问题是在工业现场那种电磁环境复杂、供电不稳定、需要高频记录数据的场合如何做到数据既写得快又丢不了。适合谁看如果你正在做工业数据采集器、电力监测终端、医疗设备参数存储、车载黑匣子这类项目或者你只是单纯想搞明白 SPI 接口的 MRAM 到底怎么用、和普通 Flash 有什么区别这篇内容都能直接抄作业。我先把结论摆在这MRAM 不是用来替代大容量 NAND 存固件或文件的它是用来替代 EEPROM 和 FRAM 做高频小数据量持久化的。理解了这个定位后面的选型和代码才有意义。2. 方案选型背后的逻辑与整体设计思路2.1 为什么不用 EEPROM、Flash 和 FRAM很多人第一反应是存个参数用 EEPROM 不就行了。我拿实际数据说话。普通 I2C EEPROM 比如 24C512页写入周期典型 5ms擦写寿命 100 万次。假设你每秒记录一次数据一天 86400 次100 万次大概 11 天就写废了。就算你做磨损均衡512KB 的 EEPROM 分页轮换也就撑个几年而且 5ms 的写周期意味着你根本做不到高频写入。SPI NOR Flash 比如 W25Q64写入前必须擦除整个扇区通常 4KB擦除时间几十到几百毫秒擦写寿命 10 万次左右。它适合存固件、存不常改的文件但绝对不适合做高频数据记录。你在工业现场掉电的瞬间Flash 正在擦除那一整块数据就没了这是血泪教训。FRAM 比如 FM25V05读写快、寿命高但容量小通常 256Kbit 以内、价格贵而且很多 FRAM 是 I2C 接口速度上不去。MRAM 在容量、速度、寿命、价格之间找到了一个更好的平衡点4Mbit 的容量、SPI 40MHz 的接口速度、无限擦写寿命单价虽然比 Flash 贵但比同等容量 FRAM 便宜不少。2.2 MR25H40CDF 的关键特性拆解我把这颗芯片最影响设计的几个点列出来这些都是我实际调试时踩过或验证过的特性项参数对设计的影响容量512KB4Mbit够存参数中等规模日志不够存大文件接口SPI Mode 0/3最高 40MHz需要 MCU SPI 时钟配置正确写延迟0无内部写周期写完即可读不需要轮询忙状态擦写寿命10^15 次以上基本可以当 RAM 用不用做磨损均衡数据保持20 年 85°C工业级温度范围可用供电2.7V ~ 3.6V注意和 MCU 电平匹配封装8-SOIC / 8-DFNPCB 布局要考虑去耦电容这里有个特别容易被忽略的点MR25H40CDF 没有写延迟意味着你发完写命令和数据的最后一个时钟沿数据就已经落盘了。这和 EEPROM、Flash 完全不同你不需要发 RDSR 查忙、不需要等 tWR。这个特性在掉电保护场景里价值巨大——你检测到掉电立刻写一条关键数据写完就断电数据一定在。2.3 PIC32MZ2048EFH144 的 SPI 外设为什么合适PIC32MZ 的 SPI 外设不是普通的 SPI。它的 SPI2~SPI5 支持可配置的帧宽度可以设成 8 位、16 位、32 位。这意味着你读 MRAM 的时候可以一次事务读 32 位而不是一个字节一个字节地读。在 40MHz 时钟下8 位模式每字节要 8 个时钟加事务开销32 位模式一次搬 4 字节效率提升非常明显。另外 PIC32MZ 有DMA 通道可以把 SPI 接收和发送挂到 DMA 上CPU 不用管数据搬运。你要连续读 512KB 数据的时候DMA 方案能让 CPU 去干别的事这在实时性要求高的工业应用里很关键。还有一点PIC32MZ 的 SPI 支持FIFO 缓冲发送和接收各有独立的 FIFO深度可配。配合 DMA 使用可以做到几乎无间隙的连续传输。这些特性组合起来才让用 SPI 高速读写 MRAM这件事真正落地。2.4 整体架构设计我的典型设计是这样的PIC32MZ 作为主控SPI2 专门挂 MR25H40CDF片选用一个普通 GPIO 控制不用 SPI 外设自带的 SS原因后面讲。MRAM 的存储空间我习惯这样划分0x00000 ~ 0x00FFF4KB系统参数区存设备配置、校准系数、序列号0x01000 ~ 0x01FFF4KB参数备份区双备份防止写坏0x02000 ~ 0x7FFFF约 504KB循环日志区用环形缓冲方式记录运行数据这个划分不是拍脑袋定的。参数区留 4KB 是因为工业设备的配置参数通常几百字节到 2KB留足余量。双备份是因为虽然 MRAM 几乎不会写坏但逻辑错误、程序 bug 可能导致写错地址双备份加 CRC 校验能兜底。日志区用环形缓冲是因为日志是持续写入的环形结构天然适合写满自动覆盖最旧数据不需要复杂的文件系统。3. 硬件连接与 SPI 时序的关键细节3.1 引脚连接与电平匹配MR25H40CDF 是 8 脚封装引脚定义很标准CS、SO、SI、SCK、VDD、VSS、WP、HOLD。这里有两个坑我要重点说。第一个坑是WP 和 HOLD 引脚。很多人直接悬空或者接地结果发现写不进去或者读出来全是 0xFF。WP 是写保护低电平有效你要写数据必须拉高。HOLD 是暂停通信低电平有效正常通信必须拉高。我的做法是两个都通过 10K 电阻上拉到 VDD需要写保护的时候再用 GPIO 拉低 WP。如果你不需要硬件写保护直接上拉到 VDD 最省事。第二个坑是电平匹配。PIC32MZ 的 IO 电压取决于你给 VDDIO 供多少通常是 3.3V。MR25H40CDF 的工作电压是 2.7V~3.6V所以 3.3V 对 3.3V 可以直接连不需要电平转换。但如果你用的是 5V 系统那就必须加电平转换芯片否则会烧 MRAM。我见过有人拿 5V 的 PIC 直接怼 MRAM上电就冒烟。连接关系如下PIC32MZ MR25H40CDF SPI2_SCK (RB14) -- SCK SPI2_SDI (RB15) -- SO SPI2_SDO (RB13) -- SI GPIO (RB8) -- CS 3.3V -- VDD, WP, HOLD (通过上拉) GND -- VSS3.2 为什么片选要用普通 GPIO 而不是硬件 SSPIC32MZ 的 SPI 外设自带 SS 引脚但我强烈建议用普通 GPIO 手动控制片选。原因有三个。第一硬件 SS 的时序是 SPI 外设自动控制的在某些配置下SS 的建立和保持时间可能不满足 MRAM 的要求。MRAM 要求 CS 拉低后到第一个时钟沿之间有最小建立时间CS 拉高前最后一个时钟沿到 CS 拉高之间有最小保持时间。手动控制 GPIO 你能精确掌握这个时序。第二一个 SPI 总线上可能挂多个从设备硬件 SS 只能对应一个多设备就要软件管理片选不如统一用 GPIO 来得清晰。第三调试的时候手动控制片选你能用逻辑分析仪清楚地看到 CS 和 SCK 的关系排查问题方便得多。手动控制片选的代码逻辑很简单但要注意顺序先拉低 CS再发数据数据发完等最后一个时钟沿结束再拉高 CS。中间不能有额外的时钟。3.3 SPI 模式与时序参数计算MR25H40CDF 支持 SPI Mode 0CPOL0, CPHA0和 Mode 3CPOL1, CPHA1。我用的是 Mode 0因为这是最常用的模式逻辑分析仪解码也方便。Mode 0 的含义是时钟空闲时为低电平数据在时钟上升沿采样对于从设备来说是输出在下降沿变化对于主设备来说是输出。你配置 PIC32MZ 的 SPI 时要设 CKP0空闲低、CKE1下降沿变化上升沿采样。时钟频率的计算要小心。MRAM 最高支持 40MHz但你要看 PIC32MZ 的 SPI 时钟源。假设外设总线时钟 PBCLK2 是 100MHzSPI 波特率 PBCLK2 / (2 * (SPIxBRG 1))。要得到 40MHzSPIxBRG 100/(2*40) - 1 0.25不是整数。所以实际能配到的最接近值是 SPIxBRG0 时 50MHz超了SPIxBRG1 时 25MHz。25MHz 是安全的我实测 25MHz 下读写非常稳定。如果你非要 40MHz得调整 PBCLK2 的分频让总线时钟是 80MHz这样 SPIxBRG0 就是 40MHz。注意SPI 时钟频率不是越高越好。PCB 走线长、有干扰的时候高频会导致数据错误。工业现场我一般降到 10MHz~20MHz牺牲一点速度换稳定性这笔账划算。3.4 PCB 布局的实操经验MRAM 是 SPI 接口走线不多但有几个细节决定成败。去耦电容必须紧贴 VDD 引脚我一般用 100nF 加 1uF 并联100nF 最近。SCK 是高频信号走线要尽量短不要和模拟信号平行走。CS 走线如果长建议加一个下拉电阻防止上电瞬间浮空导致误触发。还有一点MRAM 是磁性存储虽然 Everspin 做了磁屏蔽但你在 PCB 上不要把它放在大电流走线或者电感、变压器旁边。我有个项目把 MRAM 放在 DC-DC 电感旁边结果偶尔出现数据位翻转后来挪开就好了。这个坑不踩一次是想不到的。4. 底层驱动实现与核心读写操作4.1 SPI 外设初始化配置先上代码这是 PIC32MZ 上 SPI2 的初始化我加了详细注释说明每个参数为什么这么设void MRAM_SPI_Init(void) { // 关闭 SPI2 以便配置 SPI2CONbits.ON 0; // 清除控制寄存器 SPI2CON 0; SPI2CONCLR 0; // CKP0: 空闲时钟低电平 (Mode 0) // CKE1: 下降沿变化数据上升沿采样 SPI2CONbits.CKP 0; SPI2CONbits.CKE 1; // MSTEN1: 主机模式 SPI2CONbits.MSTEN 1; // 8位模式 (MODE320, MODE160) SPI2CONbits.MODE32 0; SPI2CONbits.MODE16 0; // SMP0: 在数据输出末尾采样 (低速时用) // 25MHz 时建议 SMP0 SPI2CONbits.SMP 0; // 波特率: PBCLK2100MHz, 目标 25MHz // 100 / (2*(11)) 25MHz SPI2BRG 1; // 使能 SPI SPI2CONbits.ON 1; // 配置片选 GPIO 为输出 TRISBbits.TRISB8 0; LATBbits.LATB8 1; // 初始拉高 }这里 SMP 位值得说一下。SMP1 是在数据输出中间采样适合高速SMP0 是在末尾采样适合低速。25MHz 属于中速我实测 SMP0 更稳。如果你上到 40MHz可以试试 SMP1。4.2 单字节收发与片选控制SPI 的本质是交换发一个字节的同时收一个字节。MRAM 的命令阶段是只发不收数据阶段是发地址收数据。我封装了两个基础函数// 片选控制 static inline void MRAM_CS_Low(void) { LATBbits.LATB8 0; } static inline void MRAM_CS_High(void) { LATBbits.LATB8 1; } // 收发一个字节 uint8_t MRAM_SPI_Transfer(uint8_t txData) { // 等待发送缓冲空 while (SPI2STATbits.SPITBF); SPI2BUF txData; // 等待接收完成 while (!SPI2STATbits.SPIRBF); return (uint8_t)SPI2BUF; }注意SPI2STATbits.SPITBF是发送缓冲满标志SPIRBF是接收缓冲满标志。这两个标志的轮询顺序不能反先等发送能写再写再等接收有数据。我见过有人先等接收再发送结果死循环。4.3 MRAM 命令集与读写时序MR25H40CDF 的命令集很精简常用的就几条命令编码功能WREN0x06写使能WRDI0x04写禁止RDSR0x05读状态寄存器WRSR0x01写状态寄存器READ0x03读数据WRITE0x02写数据读操作的时序是拉低 CS - 发 0x03 - 发 24 位地址3 字节- 连续读数据 - 拉高 CS。写操作的时序是拉低 CS - 发 0x06WREN- 拉高 CS - 拉低 CS - 发 0x02 - 发 24 位地址 - 发数据 - 拉高 CS。注意写操作前必须先发 WREN而且 WREN 是一个独立的事务CS 要拉高再拉低。这是很多人第一次用会搞错的地方。4.4 页写与地址边界处理MR25H40CDF 支持页写一页是 256 字节。但这里有个陷阱如果你一次写入跨越了页边界地址会回卷到页首覆盖前面的数据。比如你从地址 0x00F0 开始写 32 字节写到 0x0100 的时候地址会回卷到 0x0000而不是继续到 0x0100。这是 Flash 和 MRAM 都有的特性必须处理。我的做法是写函数里做边界判断跨页就拆成两次写void MRAM_Write(uint32_t addr, uint8_t *buf, uint32_t len) { while (len 0) { // 计算当前页剩余空间 uint32_t pageRemain 256 - (addr 0xFF); uint32_t writeLen (len pageRemain) ? len : pageRemain; // 写使能 MRAM_CS_Low(); MRAM_SPI_Transfer(0x06); MRAM_CS_High(); // 写命令 地址 数据 MRAM_CS_Low(); MRAM_SPI_Transfer(0x02); MRAM_SPI_Transfer((addr 16) 0xFF); MRAM_SPI_Transfer((addr 8) 0xFF); MRAM_SPI_Transfer(addr 0xFF); for (uint32_t i 0; i writeLen; i) { MRAM_SPI_Transfer(buf[i]); } MRAM_CS_High(); addr writeLen; buf writeLen; len - writeLen; } }这个函数看起来简单但页边界处理是必须的。我早期偷懒没做结果日志数据偶尔错乱查了两天才定位到是跨页写导致的。4.5 用 32 位模式提升读取效率前面提到 PIC32MZ 的 SPI 支持 32 位帧。读大块数据的时候把 SPI 切成 32 位模式一次事务搬 4 字节效率提升明显。代码大概是这样void MRAM_Read_Fast(uint32_t addr, uint32_t *buf, uint32_t wordCount) { // 切换到 32 位模式 SPI2CONbits.ON 0; SPI2CONbits.MODE32 1; SPI2CONbits.MODE16 0; SPI2CONbits.ON 1; MRAM_CS_Low(); // 命令和地址还是用 8 位模式发 // 这里需要临时切回 8 位或者用字节操作 // ... 发送 0x03 和 24 位地址 ... // 然后切 32 位读数据 for (uint32_t i 0; i wordCount; i) { while (SPI2STATbits.SPITBF); SPI2BUF 0xFFFFFFFF; // 发哑数据 while (!SPI2STATbits.SPIRBF); buf[i] SPI2BUF; } MRAM_CS_High(); // 切回 8 位模式 SPI2CONbits.ON 0; SPI2CONbits.MODE32 0; SPI2CONbits.ON 1; }这里有个细节命令和地址阶段必须用 8 位模式因为 MRAM 的命令是 8 位、地址是 24 位不是 32 位对齐的。所以你要在发完地址后切换模式读完再切回来。切换模式要关 SPI 再开这个开销相对于读大块数据可以忽略。实测下来读 512KB 数据8 位模式大概 200ms32 位模式能降到 130ms 左右提升约 35%。如果你再上 DMA还能再快而且 CPU 占用率大幅下降。5. 数据可靠性与掉电保护实战5.1 CRC 校验与双备份策略MRAM 虽然可靠但软件 bug、地址算错、总线干扰都可能导致数据错误。我的做法是每个数据块都带 CRC16 校验参数区做双备份。数据结构大概这样typedef struct { uint32_t magic; // 0x4D52414D MRAM uint16_t version; uint16_t length; uint8_t data[240]; uint16_t crc; // 前面所有字节的 CRC16 } ParamBlock;写入的时候先写主区再写备份区。读取的时候先读主区CRC 对就用主区主区 CRC 错读备份区备份区也错加载默认参数。这个逻辑看起来冗余但在工业现场一次参数错误可能导致设备误动作代价远大于这点代码。5.2 掉电检测与紧急写入这是 MRAM 相比 Flash 最大的优势场景。我在电源输入端加一个电压检测电路当输入电压降到阈值以下时触发一个中断。中断里立刻把关键数据写入 MRAM因为 MRAM 没有写延迟写完就安全。具体做法是用一个比较器监测电源输出接到 PIC32MZ 的外部中断引脚。中断服务程序里void __ISR(_EXTERNAL_1_VECTOR, IPL7AUTO) PowerFailHandler(void) { // 清除中断标志 IFS0bits.INT1IF 0; // 立即保存关键数据到 MRAM // 此时电源靠电容维持通常有 10ms~50ms 窗口 MRAM_Write(CRITICAL_DATA_ADDR, (uint8_t*)g_criticalData, sizeof(g_criticalData)); // 标记掉电事件 g_powerFailFlag 1; }这里的关键是中断优先级要设到最高而且写函数要精简不能有阻塞操作。MRAM 写 256 字节在 25MHz 下大概几十微秒完全来得及。如果你用 Flash光擦除就要几十毫秒电容根本撑不住。5.3 环形日志缓冲的实现日志区我用环形缓冲写指针到达末尾自动回到开头。为了区分新旧数据每条日志带一个递增的序列号。读取的时候按序列号排序就能还原时间顺序。typedef struct { uint32_t seq; // 序列号 uint32_t timestamp; uint16_t type; uint8_t payload[16]; uint16_t crc; } LogEntry; // 共 32 字节512KB 的日志区去掉参数区大概能存 16000 条日志。每条 32 字节对齐到 32 字节边界读写都方便。写指针存在 MRAM 的一个固定位置每次写日志前先读指针写完更新指针。这里要注意指针更新和日志写入不是原子的掉电可能发生在中间。我的处理是先写日志数据再写指针。如果掉电发生在写指针之前那条日志下次会被覆盖但不会破坏已有数据。5.4 常见问题排查速查表我把这些年遇到的问题整理成表方便你对照排查现象可能原因排查方法解决方案读出来全是 0xFFCS 没拉低、WP 没拉高、SPI 模式错逻辑分析仪看波形检查 CS 和 WP确认 Mode 0写进去读出来不对跨页写、WREN 没发、时序不对单字节写测试加页边界处理确认 WREN偶尔数据位翻转电源干扰、走线太长、时钟太快降频测试降 SPI 时钟加去耦电容上电后数据丢失掉电时正在写、没有掉电保护模拟掉电测试加掉电检测和紧急写入SPI 通信完全无响应引脚接错、MRAM 没供电万用表测电压检查接线和供电读速度慢8 位模式、没用 DMA测传输时间切 32 位模式上 DMA提示调试 SPI 设备逻辑分析仪是必备工具。几十块钱的 8 通道逻辑分析仪就能解码 SPI能看到命令、地址、数据的每一个字节比盲猜快一百倍。6. 性能优化与进阶玩法6.1 DMA 传输配置PIC32MZ 的 SPI 可以挂 DMA这是提升大块数据传输效率的关键。配置 DMA 的步骤稍微复杂但值得。核心思路是SPI 发送触发 DMA 搬数据到 SPI2BUFSPI 接收触发 DMA 从 SPI2BUF 搬数据到内存。void MRAM_DMA_Read_Setup(uint32_t addr, uint8_t *dest, uint32_t len) { // 配置 DMA 通道 0 用于 SPI 接收 DCH0CONbits.CHEN 0; DCH0ECONbits.CHSIRQ _SPI2_RX_VECTOR; DCH0ECONbits.SIRQEN 1; DCH0SSA (uint32_t)SPI2BUF; // 源地址 DCH0DSA (uint32_t)dest; // 目的地址 DCH0SSIZ 1; DCH0DSIZ 1; DCH0CSIZ len; // 传输次数 DCH0CONbits.CHAEN 1; DCH0CONbits.CHEN 1; // 触发传输先发命令和地址然后启动 DMA // ... }DMA 配置的坑在于中断向量号和触发源的对应关系不同型号的 PIC32MZ 可能不一样一定要查数据手册。我见过有人照抄别人的代码结果 DMA 死活不触发就是因为向量号对不上。6.2 缓存与预取策略PIC32MZ 有指令和数据缓存但 SPI 外设访问的内存不走缓存。如果你频繁读同一块 MRAM 数据可以在 RAM 里做一层缓存。我的做法是参数区在启动时全部读入 RAM之后读参数直接读 RAM写参数才写 MRAM。这样既保证了掉电安全又避免了频繁 SPI 访问。日志区不适合缓存因为它是持续写入的。但读取历史日志的时候可以一次读一大块到 RAM然后在 RAM 里解析比一条一条读快得多。6.3 多设备共享 SPI 总线工业项目里一个 SPI 总线往往挂多个设备比如 MRAM、显示屏、传感器。共享总线的时候片选管理是核心。每个设备一个独立的 GPIO 片选任何时刻只能有一个片选拉低。我的做法是封装一个 SPI 总线锁访问设备前先获取锁访问完释放防止多任务环境下片选冲突。typedef struct { volatile uint8_t locked; } SPIBusLock; SPIBusLock g_spiBus {0}; void SPI_Bus_Acquire(void) { while (g_spiBus.locked); g_spiBus.locked 1; } void SPI_Bus_Release(void) { g_spiBus.locked 0; }如果你的系统跑 RTOS用互斥量更规范。裸机系统用这种简单的标志位就够了但要注意关中断保护防止竞态。6.4 温度与长期可靠性考量MRAM 的工作温度范围通常是 -40°C 到 85°C工业级。但数据保持能力随温度升高而下降官方标称 85°C 下保持 20 年。如果你的设备工作在更高温度比如 105°C保持时间会缩短具体要查数据手册的降额曲线。长期可靠性方面MRAM 没有擦写次数限制但要注意读干扰。虽然 MRAM 的读干扰远小于 Flash但极端频繁的读取理论上也可能影响数据。不过在实际项目中我还没遇到过读干扰导致的问题这个更多是理论上的考量。7. 我踩过的坑和给你的实操建议最后这部分我想分享几个文档里不会写、但实际项目中一定会遇到的坑。第一个坑是SPI 时钟相位配错。MRAM 支持 Mode 0 和 Mode 3但如果你配成了 Mode 1 或 Mode 2读出来就是错位的数据。判断方法很简单读设备 ID 或者状态寄存器如果读出来是 0xFF 或者乱码先检查 SPI 模式。我建议固定用 Mode 0因为大部分 SPI 设备都支持逻辑分析仪解码也默认 Mode 0。第二个坑是写操作忘记 WREN。MRAM 的写操作需要先发 WREN 命令而且 WREN 是独立事务CS 要拉高再拉低。我见过有人把 WREN 和 WRITE 放在同一个 CS 周期里结果写不进去。记住WREN 单独一个 CS 周期WRITE 另一个 CS 周期。第三个坑是地址字节序。MRAM 的地址是 24 位高字节在前。发地址的时候是 (addr16) 0xFF、(addr8) 0xFF、addr 0xFF。如果你搞反了写到了错误的地址可能覆盖了参数区后果很严重。我建议写一个地址发送函数统一处理不要每次手写。第四个坑是掉电检测阈值设太低。电源电容的储能有限如果你等到电压降到 2.7V 才检测可能只剩几毫秒来不及写完数据。我的经验是阈值设在正常工作电压的 90% 左右比如 3.3V 系统设在 3.0V这样有足够的窗口完成紧急写入。第五个坑是忽略 MRAM 的 WP 引脚。WP 低电平写保护如果你悬空它可能被干扰拉低导致写失败。一定要上拉到 VDD需要写保护的时候再用 GPIO 控制。这套 MRAM 加 PIC32MZ 的方案我在三个工业项目里用过最长的已经连续运行四年多日志区每天写入几万条至今没有出现过数据丢失。它的价值不在于技术多先进而在于把可靠性做到了极致同时代码和硬件都不复杂。如果你正在为数据存储的可靠性发愁不妨试试这个组合踩过我上面说的这些坑基本就能一次跑通。
返回列表