ARTICLE DETAIL

资讯详情

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

PIC18LF4515 驱动 MR25H40CDF MRAM 的工业级 SPI 存储方案

PIC18LF4515 驱动 MR25H40CDF MRAM 的工业级 SPI 存储方案 1. 项目缘起与方案选型1.1 为什么要在工业场景里折腾 MRAM做工业嵌入式这行十几年最头疼的事情之一就是数据存储。EEPROM 写一次要等好几毫秒Flash 擦除一个扇区动辄几百毫秒掉电瞬间数据就可能丢得干干净净。之前做过一个电力监测终端现场电网频繁闪断用 FRAM 成本压不下来用带电池的 SRAM 又要考虑电池寿命和环保问题客户三天两头投诉数据对不上。后来接触到 MRAM磁性随机存储器才算找到了一个折中的路子。MR25H40CDF 是 Everspin 出的 4Mbit SPI 接口 MRAM注意是 4Mbit 不是 4MByte换算下来是 512KByte 的容量。这个容量在工业数据记录场景里其实挺够用的——存个几千条带时间戳的传感器记录、设备配置参数、故障日志绰绰有余。它最大的卖点就是写入不需要擦除、没有写延迟、掉电数据不丢、读写寿命近乎无限。官方标称的数据保持时间是 20 年以上读写次数 10^14 级别这个量级基本上你设备报废了它还没坏。选它而不是选 FRAM 或者 NVSRAM核心原因有三个。第一是成本MRAM 单位容量价格比 FRAM 低不少比带电池的 SRAM 方案在长期维护上更省心。第二是接口简单标准 SPI四根线搞定PIC18LF4515 这种老牌 8 位机都能直接驱动不需要额外的总线转换。第三是工业温度范围MR25H40CDF 有 -40°C 到 85°C 的工业级版本焊在户外机柜里夏天暴晒冬天冰冻都不虚。1.2 PIC18LF4515 这颗老将为什么还能打PIC18LF4515 是 Microchip 的 8 位单片机44 引脚 TQFP 封装48KB Flash、3KB RAM、1KB EEPROM跑起来最高 40MHz。放在今天看参数确实不起眼但工业现场很多设备就是认这颗芯片——供货稳定、抗干扰强、开发工具链成熟、代码可移植性好。我手上好几个跑了七八年的老项目都是这颗片子现场从来没出过批量性问题。它自带一个 MSSP 模块可以配置成 SPI 主模式最高时钟频率是 Fosc/4。如果系统时钟跑 32MHzSPI 时钟就能到 8MHz驱动 MR25H40CDF 完全够用。MR25H40CDF 支持的最高 SPI 时钟是 40MHz所以瓶颈在单片机这边不在存储器这边。另外 PIC18LF4515 的宽电压范围2.0V 到 5.5V和 MRAM 的 2.7V 到 3.6V 工作电压能很好匹配直接 3.3V 供电就行不需要电平转换。注意PIC18LF4515 的 MSSP 模块在 SPI 主模式下SS片选引脚需要手动控制硬件不会自动拉低。这一点和 STM32 的硬件 NSS 不一样写代码的时候要特别注意。1.3 整体架构长什么样整个方案的核心链路很清晰PIC18LF4515 通过 SPI 总线连接 MR25H40CDF单片机作为 SPI 主机MRAM 作为从机。片选信号用普通 GPIO 控制SCK、SDI、SDO 三根线接到 MSSP 模块的对应引脚上。MRAM 的 WP写保护引脚和 HOLD保持引脚根据实际需求决定是否启用——如果不需要硬件写保护WP 直接拉高HOLD 不用的话也拉高。数据流是这样的传感器采集的数据先缓存在单片机 RAM 里攒够一批或者定时触发后通过 SPI 写入 MRAM 的指定地址。读取的时候反过来单片机发读命令加地址MRAM 把数据吐回来。因为 MRAM 没有写延迟写完立刻就能读不需要像 Flash 那样等待忙状态代码逻辑简单很多。这个架构的好处是极简。不需要文件系统不需要复杂的磨损均衡算法地址直接映射到数据块。对于工业设备这种数据结构固定、写入频率可控的场景裸地址读写反而是最可靠的做法。2. 硬件设计与 SPI 通信细节2.1 引脚连接与硬件设计要点先看接线。MR25H40CDF 是 8 引脚 SOIC 封装引脚定义如下1 脚是 CS片选低有效2 脚是 SO数据输出3 脚是 WP写保护低有效4 脚是 VSS地5 脚是 SI数据输入6 脚是 SCK时钟7 脚是 HOLD保持低有效8 脚是 VDD电源。和 PIC18LF4515 的连接方式CS 接到 RC2普通 GPIOSCK 接到 RC3SCK 功能SI 接到 RC5SDO 功能SO 接到 RC4SDI 功能。这里要注意 PIC 的命名习惯——SDO 是单片机输出数据对应从机的 SISDI 是单片机输入数据对应从机的 SO。很多人第一次接会搞反结果读出来全是 0xFF 或者 0x00。WP 和 HOLD 引脚的处理有讲究。如果系统不需要硬件写保护WP 直接上拉到 VDD。HOLD 如果不用也上拉到 VDD。但我在工业项目里一般会把 WP 接到一个 GPIO 上这样可以在固件升级或者关键数据写入时做双重保护——软件命令加硬件引脚双重保险防止程序跑飞误写。电源部分MR25H40CDF 的工作电流在读写时大约 10mA 左右待机时只有几十微安。PIC18LF4515 在 32MHz 下运行电流大概 15mA。整个系统 3.3V 供电用一颗 AMS1117-3.3 就够了。但工业现场电源纹波大建议在 MRAM 的 VDD 引脚旁边放一个 0.1uF 陶瓷电容加一个 10uF 钽电容离芯片越近越好。实操心得PCB 布线时SPI 的四根线尽量等长SCK 走线远离模拟信号线。如果 SPI 时钟超过 4MHz建议在 SCK 上串一个 22 欧姆的电阻能有效抑制过冲和振铃。我吃过这个亏8MHz 时钟下没串电阻通信误码率很高加了电阻之后稳如老狗。2.2 SPI 模式选择与时序分析MR25H40CDF 支持 SPI 模式 0CPOL0CPHA0和模式 3CPOL1CPHA1。这两种模式的区别在于时钟空闲状态和采样边沿。模式 0 下SCK 空闲为低电平数据在上升沿采样模式 3 下SCK 空闲为高电平数据在下降沿采样。PIC18LF4515 的 MSSP 模块支持这两种模式通过 SSPCON1 寄存器的 CKP 位和 SSPSTAT 寄存器的 CKE 位来配置。我一般选模式 0因为逻辑分析仪抓波形的时候看起来最直观上升沿采样空闲低电平一眼就能看出数据对不对。时序参数方面MR25H40CDF 要求 CS 拉低到 SCK 第一个边沿之间至少有 5ns 的建立时间SCK 最后一个边沿到 CS 拉高之间至少有 5ns 的保持时间。PIC18 在 32MHz 下指令周期是 125ns随便怎么操作都能满足。但如果你用汇编写极致优化的代码连续操作 CS 和 SCK 的时候要注意加几个 NOP。SPI 时钟频率的计算PIC18LF4515 的 MSSP 在主机模式下SCK 频率 Fosc / (4 * (SSPADD 1))。等等这是 I2C 的公式。SPI 主模式下SCK 频率是 Fosc/4、Fosc/16、Fosc/64 或者 Timer2 溢出率。具体看 SSPCON1 的 SSPM 位设置。如果系统时钟 32MHz选 Fosc/4 就是 8MHz选 Fosc/16 就是 2MHz。MRAM 支持 40MHz所以 8MHz 完全没问题。但实际项目中我建议不要一上来就跑最高速。先用 1MHz 调通基本读写确认硬件没问题再逐步提高时钟。我见过太多人直接上 8MHz结果读出来数据错位查了半天以为是芯片坏了其实是 PCB 走线太长导致信号完整性出了问题。2.3 命令集与地址映射MR25H40CDF 的命令集很精简常用的就四条WREN写使能0x06、WRDI写禁止0x04、READ读数据0x03、WRITE写数据0x02。另外还有 RDSR读状态寄存器0x05和 WRSR写状态寄存器0x01但状态寄存器主要用来配置写保护和块保护一般场景下用默认值就行。地址是 19 位宽因为 512KByte 需要 19 根地址线2^19 524288。发送地址的时候分三个字节第一个字节的高 3 位是无效的低 5 位是地址的 A18 到 A14第二个字节是 A13 到 A6第三个字节是 A5 到 A0。这个地址格式和 25 系列 SPI Flash 完全一样所以如果你之前用过 W25Q64 之类的 Flash代码改改就能用。读写操作的基本流程拉低 CS发送命令字节发送三个地址字节然后连续读写数据最后拉高 CS。读操作可以连续读任意长度地址会自动递增到最高地址后回卷到 0。写操作也一样但要注意写入之前必须先发 WREN 命令否则写操作会被忽略。这是很多新手容易漏掉的一步。注意WREN 命令之后CS 必须拉高再拉低才能开始写操作。也就是说 WREN 是一个独立的 SPI 事务不能和 WRITE 命令连在同一个 CS 低电平周期里。我当初就是在这里卡了半天逻辑分析仪上看波形明明都对但数据就是写不进去后来翻数据手册才发现这个细节。3. 固件实现与核心代码解析3.1 SPI 底层驱动封装先写最底层的 SPI 收发函数。PIC18LF4515 的 MSSP 模块用起来很直接SSPBUF 寄存器写数据启动发送同时接收数据也进 SSPBUF。判断发送完成看 SSPIF 标志位或者查 SSPSTAT 的 BF 位。// SPI 初始化主机模式时钟 Fosc/4模式 0 void SPI_Init(void) { TRISCbits.TRISC3 0; // SCK 输出 TRISCbits.TRISC5 0; // SDO 输出 TRISCbits.TRISC4 1; // SDI 输入 TRISCbits.TRISC2 0; // CS 输出 PORTCbits.RC2 1; // CS 默认拉高 SSPCON1 0x00; // 先复位 MSSP SSPSTAT 0x00; // 模式 0CKE0SMP0 SSPCON1 0x20; // SSPEN1SSPM0000Fosc/4 SSPADD 0; // SPI 模式下 SSPADD 不用 } // SPI 收发一个字节 uint8_t SPI_Transfer(uint8_t data) { SSPBUF data; while(!PIR1bits.SSPIF); // 等待发送完成 PIR1bits.SSPIF 0; // 清除标志 return SSPBUF; // 返回接收到的数据 }这段代码里有个细节SSPSTAT 0x00设置的是 CKE0 和 SMP0。CKE0 表示数据在时钟上升沿发送SMP0 表示在数据输出时间的中点采样。这两个位配合 SSPCON1 的 CKP0就是标准的 SPI 模式 0。SSPCON1 0x20是 SSPEN1 使能 MSSPSSPM0000 选择 Fosc/4 时钟。如果系统时钟 32MHzSPI 时钟就是 8MHz。想降速的话把 SSPM 改成 0001Fosc/16或者 0010Fosc/64。3.2 MRAM 读写函数实现有了底层 SPI 收发MRAM 的读写函数就很好写了。先定义命令码和片选操作#define MRAM_CMD_WREN 0x06 #define MRAM_CMD_WRDI 0x04 #define MRAM_CMD_READ 0x03 #define MRAM_CMD_WRITE 0x02 #define MRAM_CMD_RDSR 0x05 #define MRAM_CS_LOW() (PORTCbits.RC2 0) #define MRAM_CS_HIGH() (PORTCbits.RC2 1) // 写使能 void MRAM_WriteEnable(void) { MRAM_CS_LOW(); SPI_Transfer(MRAM_CMD_WREN); MRAM_CS_HIGH(); } // 写数据 void MRAM_Write(uint32_t addr, uint8_t *buf, uint16_t len) { MRAM_WriteEnable(); // 必须先发 WREN MRAM_CS_LOW(); SPI_Transfer(MRAM_CMD_WRITE); SPI_Transfer((uint8_t)((addr 16) 0x07)); // A18-A16 SPI_Transfer((uint8_t)((addr 8) 0xFF)); // A15-A8 SPI_Transfer((uint8_t)(addr 0xFF)); // A7-A0 for(uint16_t i 0; i len; i) { SPI_Transfer(buf[i]); } MRAM_CS_HIGH(); } // 读数据 void MRAM_Read(uint32_t addr, uint8_t *buf, uint16_t len) { MRAM_CS_LOW(); SPI_Transfer(MRAM_CMD_READ); SPI_Transfer((uint8_t)((addr 16) 0x07)); SPI_Transfer((uint8_t)((addr 8) 0xFF)); SPI_Transfer((uint8_t)(addr 0xFF)); for(uint16_t i 0; i len; i) { buf[i] SPI_Transfer(0xFF); // 发送哑数据接收有效数据 } MRAM_CS_HIGH(); }地址处理这里要注意MR25H40CDF 是 19 位地址所以第一个地址字节只需要低 3 位高 5 位是无关位。我写(addr 16) 0x07就是只取低 3 位确保不会把无效位发出去。虽然数据手册说无关位可以是任意值但养成好习惯总没错。读操作里发送0xFF作为哑数据是因为 SPI 是全双工主机必须提供时钟才能接收数据。发送什么值无所谓MRAM 会忽略 MOSI 上的数据只管把内部数据推到 MISO 上。3.3 数据存储结构设计裸地址读写虽然简单但如果没有规划用不了多久就会乱成一锅粥。我在工业项目里一般把 MRAM 的 512KByte 空间划分成几个固定区域区域名称起始地址大小用途系统配置区0x000004KB设备参数、校准系数、序列号运行日志区0x01000128KB循环记录运行状态和事件故障记录区0x2100064KB故障发生时的快照数据数据缓存区0x31000256KB传感器历史数据预留扩展区0x7100060KB后续功能扩展系统配置区用固定地址映射每个参数占固定偏移读写直接按偏移量操作。运行日志区和数据缓存区用循环队列的方式管理维护一个写指针写到区域末尾就回卷到起始地址。故障记录区用追加方式写满后停止记录或者覆盖最旧的数据看具体需求。循环队列的实现需要一个写指针变量这个变量本身也要掉电保存。我一般把它存在系统配置区的一个固定位置每次写入新数据之前先更新指针再写数据。因为 MRAM 没有写延迟这个顺序操作不会引入额外的时间开销。实操心得循环队列的写指针更新和数据写入之间如果发生掉电可能导致指针指向的位置没有有效数据。解决办法是在每个数据块头部加一个 2 字节的校验和或者魔数读取的时候先校验校验不过就跳过。这个开销很小但能避免读到脏数据。4. 工业场景下的可靠性设计与问题排查4.1 掉电保护与数据完整性工业现场最怕的就是掉电。虽然 MRAM 本身掉电不丢数据但单片机在掉电瞬间可能正在写数据写到一半电压就掉下去了结果就是半截数据。这个问题在 EEPROM 和 Flash 上更严重因为它们的写入过程更长掉电窗口更大。MRAM 的写入窗口很短但也不是零。我的做法是在硬件上加一个掉电检测电路。用一颗电压监控芯片比如 MAX809监测 3.3V 电源当电压低于 2.9V 时产生一个中断单片机在中断里立刻停止所有写操作把关键状态保存到 MRAM 的紧急区域。因为 MRAM 写入速度快从检测到掉电到完成保存通常只需要几十微秒足够在电源彻底跌落到 2.7V 之前完成。软件层面每个数据块加一个 4 字节的头部2 字节魔数比如 0xAA55、1 字节长度、1 字节校验和。读取的时候先检查魔数再校验长度和校验和全部通过才认为数据有效。如果校验失败说明这个块是掉电时写了一半的直接跳过读下一个块。typedef struct { uint16_t magic; // 0xAA55 uint8_t length; // 数据长度 uint8_t checksum; // 数据字节异或校验 uint8_t data[28]; // 实际数据 } DataBlock_t; // 总共 32 字节 bool MRAM_ReadBlock(uint32_t addr, DataBlock_t *block) { MRAM_Read(addr, (uint8_t*)block, sizeof(DataBlock_t)); if(block-magic ! 0xAA55) return false; uint8_t sum 0; for(uint8_t i 0; i block-length; i) { sum ^ block-data[i]; } return (sum block-checksum); }这个结构体设计成 32 字节正好是 2 的幂次地址计算方便也符合大多数工业数据记录的对齐习惯。28 字节的有效数据对于一条传感器记录来说够用了——4 字节时间戳、2 字节设备 ID、若干字节的传感器读数还能剩几个字节做预留。4.2 SPI 通信异常排查实录SPI 通信出问题排查思路要清晰。我一般按这个顺序来先看电源和地再看片选和时钟最后看数据线。现象一读出来全是 0xFF 或者 0x00。这种情况最常见的原因是片选没拉低或者 MISO 线没接好。用示波器看 CS 引脚确认在通信期间确实是低电平。如果 CS 正常再看 MISO 上有没有波形。如果 MISO 一直是高阻态检查 MRAM 的 SO 引脚有没有虚焊或者 HOLD 引脚是不是被拉低了——HOLD 低电平会让 SO 进入高阻态。现象二数据偶尔错位大部分时候正常。这是典型的信号完整性问题。SPI 时钟太快、走线太长、没有端接电阻都会导致采样错误。解决办法降低 SPI 时钟频率试试如果降频后正常了说明是时序问题。在 SCK 上串 22 到 100 欧姆的电阻在 MISO 上加 10pF 到 22pF 的对地电容能明显改善波形质量。现象三写进去的数据读出来不对。先确认 WREN 命令有没有发。用逻辑分析仪抓波形看写操作之前是不是有一个独立的 WREN 事务。如果没有那就是代码漏了。如果有 WREN 但数据还是不对检查地址字节的发送顺序——MRAM 是高位地址先发别搞反了。现象四通信一段时间后死机。检查 SPI 的等待循环有没有加超时。while(!PIR1bits.SSPIF);这种写法如果硬件故障导致标志位永远不置位程序就死在这里了。工业代码里一定要加超时计数uint16_t timeout 10000; SSPBUF data; while(!PIR1bits.SSPIF timeout--) { // 空循环 } if(timeout 0) { // 超时处理记录错误复位 SPI SPI_Init(); return 0xFF; }4.3 常见问题速查表问题现象可能原因排查方法解决方案读出全 0xFFCS 未拉低、MISO 断路、HOLD 被拉低示波器看 CS 和 MISO 波形检查片选代码、补焊 MISO、拉高 HOLD读出全 0x00MOSI 和 MISO 接反、MRAM 未供电测量 MRAM VDD 电压交换 MOSI/MISO、检查供电数据偶发错误SPI 时钟过快、走线过长降低时钟测试降频、串端接电阻、缩短走线写入无效缺少 WREN 命令、WP 引脚为低逻辑分析仪抓写时序补发 WREN、拉高 WP地址错乱地址字节顺序错误、地址超出范围核对数据手册地址格式按 A18-A16、A15-A8、A7-A0 顺序发送通信死锁等待标志位无超时检查 while 循环加超时计数和错误恢复数据保持异常电源纹波过大、去耦电容不足示波器看 VDD 纹波增加去耦电容、改善电源注意WP 引脚是低有效很多人看原理图的时候没注意直接接地了结果写保护一直生效怎么都写不进去。记住 WP 要拉高才能写。4.4 提升可靠性的几个实战技巧第一个技巧是双备份存储。关键配置参数存两份地址隔开。读取的时候两份都读出来对比一致就用不一致就用校验通过的那份并且把正确的那份复制到错误的那份地址上。这个逻辑很简单但能有效防止单点数据损坏。第二个技巧是写入后回读校验。每次写完一个数据块立刻读回来对比。MRAM 写入速度快回读校验增加的时间开销很小但能及时发现写入错误。如果回读不一致重写一次连续三次失败就记录故障。第三个技巧是SPI 总线加缓冲驱动。如果 MRAM 和单片机距离超过 10 厘米建议加一颗 74HC125 或者类似的总线缓冲器。工业现场电磁干扰大长走线容易引入噪声加缓冲器能显著提升通信稳定性。第四个技巧是定期自检。系统上电时对 MRAM 做一次全片或者抽样读写测试确认存储介质正常。运行过程中每隔一段时间比如 24 小时对关键区域做一次校验和检查发现异常及时告警。5. 性能实测与场景扩展5.1 读写速度实测数据我在实验室用逻辑分析仪实测了一组数据。PIC18LF4515 跑 32MHz 系统时钟SPI 时钟 8MHzMRAM 读写 32 字节数据块的时间如下操作类型数据长度耗时等效速率单块写入32 字节约 48 微秒约 667 KB/s单块读取32 字节约 44 微秒约 727 KB/s连续写入1KB约 1.1 毫秒约 909 KB/s连续读取1KB约 1.0 毫秒约 1000 KB/s连续读写比单块快是因为单块操作里 CS 拉高拉低和命令地址字节的开销占比大。如果数据块更大等效速率会更高。但工业场景下单次写入的数据量通常不大32 字节到 256 字节是常见范围所以实际有效速率在 600 到 900 KB/s 之间。这个速度对于工业数据记录来说绰绰有余。假设每秒钟采集 100 条记录每条 32 字节一秒钟才写 3.2KB占用 SPI 总线的时间不到 4 毫秒CPU 占用率极低。5.2 与 EEPROM 和 Flash 的对比为了直观说明 MRAM 的优势我整理了一个对比表特性MRAM (MR25H40CDF)EEPROM (24LC512)SPI Flash (W25Q64)写入前擦除不需要不需要必须擦除扇区写入延迟无5ms 典型值3ms 页编程 100ms 扇区擦除擦写寿命10^14 次10^6 次10^5 次数据保持20 年200 年20 年接口速度40MHz400kHz (I2C)80MHz容量512KB64KB8MB单位成本高中低掉电风险极低中高从表里能看出来MRAM 在写入延迟和擦写寿命上有压倒性优势代价是单位成本高、容量小。所以它适合频繁写入、数据量不大、可靠性要求高的场景。如果是要存大量历史数据、写入不频繁那 Flash 更划算。如果是小容量配置参数EEPROM 也能凑合。5.3 可扩展的应用场景这套方案不只适用于工业数据记录。我后来把它移植到了几个不同的项目里效果都不错。智能电表电表需要每隔几分钟记录一次电量数据而且现场经常停电。用 MRAM 存电量累积值和事件记录掉电不丢写入次数无限制比传统方案省心很多。医疗设备便携式监护仪需要记录患者的生命体征数据对数据完整性要求极高。MRAM 的无延迟写入特性确保在设备意外关机时数据不会丢失。汽车电子车载黑匣子需要记录碰撞前后的车辆状态。MRAM 的宽温特性和抗振动能力比机械硬盘和普通 Flash 更适合车载环境。工业 PLCPLC 的配方参数和运行日志用 MRAM 存储可以实现无磨损的频繁更新而且不需要超级电容或者电池来维持掉电保存。物联网边缘节点边缘计算设备需要缓存传感器数据等待网络恢复后上传。MRAM 的低功耗和快速写入适合电池供电的物联网节点。5.4 代码移植与平台适配这套代码虽然是为 PIC18LF4515 写的但 SPI 和 MRAM 的操作逻辑是通用的。移植到 STM32 或者 ESP32 上只需要改底层 SPI 收发函数和片选控制上层的数据结构和读写逻辑完全不用动。移植到 STM32 HAL 库的时候把SPI_Transfer换成HAL_SPI_TransmitReceive片选换成HAL_GPIO_WritePin。注意 STM32 的硬件 NSS 如果启用片选是自动控制的但 MRAM 的 WREN 命令需要独立的 CS 周期所以建议还是用软件片选手动控制 CS 引脚。移植到 ESP32 的话用 SPI Master 驱动配置好时钟极性和相位片选可以用任意 GPIO。ESP32 的 SPI 时钟可以跑到 40MHz能完全发挥 MRAM 的速度优势。实操心得跨平台移植的时候最容易出问题的地方是 SPI 模式配置。有的平台默认模式 0有的默认模式 3一定要根据 MRAM 的数据手册确认。另外片选的控制时序在不同平台上可能有细微差异移植后先用低速时钟调通再逐步提速。6. 写在最后的一些个人体会这个项目做下来最大的感受是选对存储器能省掉一半的代码复杂度。以前用 Flash 的时候要处理扇区擦除、页编程、忙等待、磨损均衡代码写了一大堆还经常出问题。换成 MRAM 之后写就是写读就是读没有擦除没有等待代码量少了三分之一可靠性反而更高了。当然 MRAM 也不是万能的。容量小、价格高是硬伤所以它适合做关键数据的存储不适合做大容量数据记录。我的做法是 MRAM 加 Flash 混搭——MRAM 存配置参数、故障快照、掉电保护数据Flash 存历史记录和日志文件。两者各司其职成本和可靠性都能兼顾。另外一点体会是工业项目的代码一定要加超时和校验。实验室里跑得好好的代码到了现场可能因为电磁干扰、电源波动、温度变化而出各种奇怪的问题。SPI 等待加超时、数据块加校验和、关键操作加回读验证这些看似多余的保护措施在关键时刻能救你一命。最后分享一个小技巧MR25H40CDF 的状态寄存器里有一个块保护位可以硬件锁定部分地址区域。如果你有一些绝对不能改的数据比如出厂校准参数可以用 WRSR 命令设置块保护把那段地址锁死。这样即使程序跑飞了也写不进去。解锁需要特定的时序相当于给关键数据加了一道硬件保险。
返回列表