ARTICLE DETAIL

资讯详情

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

STM32F745ZG与MR25H40CDF工业级MRAM存储方案实战

STM32F745ZG与MR25H40CDF工业级MRAM存储方案实战 1. 为什么工业现场的数据存储需要重新审视MRAM做过工业设备的人大概都有过这种经历设备在客户现场跑了半年突然返回一批数据异常拆机检查发现EEPROM的某个扇区写坏了或者FRAM在高温环境下数据保持能力下降又或者铁电存储器在强磁场环境里直接罢工。这类问题在实验室里几乎复现不出来但到了现场就是实打实的故障。传统的非易失存储方案在工业场景下各有各的短板。EEPROM写入速度慢、擦写寿命有限频繁记录日志的场景下很容易提前报废NOR Flash虽然容量大、成本低但写入前必须擦除整个扇区而且擦写次数通常只有十万次量级对于需要秒级甚至毫秒级记录运行数据的设备来说寿命根本扛不住FRAM读写速度快、寿命也够但容量普遍偏小而且对磁场敏感在电机、变频器旁边工作容易出问题。MRAM磁性随机存取存储器的出现恰好补上了这个缺口。它的写入原理是基于磁性隧道结的电阻变化而不是电荷存储或铁电畴翻转所以天然具备几个关键特性写入速度接近SRAM、擦写寿命理论上无限、数据保持能力超过二十年、对辐射和磁场有很强的抗扰度。这些特性放在工业与嵌入式场景里几乎每一条都打在痛点上。我这次选用的MR25H40CDF是Everspin出品的一款4Mbit串行MRAM接口是标准的SPI工作电压3.3V最高SPI时钟可以跑到40MHz。主控用的是STM32F745ZGCortex-M7内核主频216MHz带硬件SPI外设在STM32系列里属于性能比较富裕的型号。两者搭配起来既能满足工业现场对数据可靠性的要求又不需要在软件层面做太多复杂的磨损均衡处理。这篇文章会从硬件连接到SPI时序配置从寄存器操作到实际读写测试把整个链路拆开讲清楚。如果你正在做工业数据记录、设备参数存储、或者需要高频写入的非易失存储方案这套组合值得认真考虑。2. MR25H40CDF的引脚定义与STM32F745ZG的硬件对接2.1 MR25H40CDF的引脚功能拆解MR25H40CDF用的是标准的8引脚SOIC封装引脚定义和常见的SPI Flash非常接近但有几个细节需要注意。引脚编号名称功能说明1CS片选低电平有效2SO数据输出MISO3WP写保护低电平有效4VSS地5SI数据输入MOSI6SCK时钟7HOLD保持低电平有效8VDD电源3.3VWP和HOLD这两个引脚在MRAM上的行为和Flash不太一样。MR25H40CDF的WP引脚只保护状态寄存器不保护存储阵列本身。也就是说即使WP拉低你仍然可以正常读写存储区只是不能修改状态寄存器里的块保护位。这一点和很多SPI Flash不同后者拉低WP会直接阻止对存储区的写入。HOLD引脚的作用是在SPI通信过程中暂停传输而不需要重新拉片选。在多主机或者需要插入高优先级中断的场景下比较有用。如果系统里只有一个SPI主机这个引脚可以直接上拉到VDD不用管它。2.2 与STM32F745ZG的SPI外设连接STM32F745ZG有多个SPI外设我选的是SPI2挂在APB1总线上。接线方式如下MR25H40CDF的SCK接STM32的PB13SPI2_SCKMR25H40CDF的SI接PB15SPI2_MOSIMR25H40CDF的SO接PB14SPI2_MISOMR25H40CDF的CS接PB12普通GPIO软件控制片选WP和HOLD都上拉到3.3V这里我特意没有用SPI2的硬件NSS引脚而是用普通GPIO来控制片选。原因后面会详细说简单讲就是硬件NSS在多字节连续传输时容易出现时序问题软件片选更可控。电源部分MR25H40CDF的VDD和VSS之间建议放一个0.1uF的陶瓷电容位置尽量靠近芯片引脚。如果SPI走线比较长还可以在SCK和MOSI上串22欧姆的电阻做阻抗匹配减少过冲和振铃。2.3 硬件设计中最容易忽略的三个细节第一个是电源去耦。MRAM的写入电流比读取电流大不少虽然MR25H40CDF的整体功耗不高但在高频写入时电源引脚上的瞬态电流会导致电压跌落。如果去耦电容放得太远或者容值不够写入操作可能随机失败。我的做法是在VDD引脚旁边放0.1uF和1uF各一个前者滤高频后者补低频。第二个是CS引脚的上下拉。STM32在复位期间GPIO处于高阻态如果CS没有上拉MRAM可能会被误触发。虽然概率不高但在工业现场任何一次误触发都可能导致数据错乱。我在CS上加了10k的上拉电阻确保复位期间CS保持高电平。第三个是SPI走线的等长问题。如果SCK和MOSI/MISO的走线长度差异太大在高频下会出现采样窗口偏移。40MHz的SPI时钟周期只有25ns走线延迟差超过几纳秒就可能出问题。PCB布局时尽量让这四根线走在一起长度差控制在5mm以内。3. SPI模式选择与STM32CubeMX中的关键配置3.1 MR25H40CDF支持的SPI模式MR25H40CDF支持SPI模式0和模式3也就是CPOL0/CPHA0和CPOL1/CPHA1。这两种模式的区别在于时钟空闲电平和数据采样边沿。模式0SCK空闲为低电平数据在SCK的上升沿采样在下降沿变化。 模式3SCK空闲为高电平数据在SCK的上升沿采样在下降沿变化。两种模式在功能上完全等价选哪个取决于主控的方便程度。STM32的SPI外设在模式0下配置最简单我一般优先选模式0。这里有个容易踩的坑有些SPI Flash在模式0下要求CS拉低之后、第一个时钟沿之前SCK必须保持低电平至少几个纳秒。MR25H40CDF的时序要求相对宽松但如果你在CS拉低之前SCK是高电平然后CS拉低后SCK才降到低电平这个下降沿可能被MRAM误认为是第一个时钟沿。解决办法是在配置SPI时先把SCK引脚配置为低电平输出再切换为SPI复用功能。3.2 STM32CubeMX中的SPI参数设置在CubeMX里配置SPI2关键参数如下ModeFull-Duplex MasterData Size8 BitsClock PolarityLowClock Phase1 EdgeNSSSoftwareBaud Rate Prescaler根据实际需求选择First BitMSB First波特率预分频器的选择需要算一下。STM32F745ZG的APB1时钟默认是54MHzSPI2挂在这条总线上。如果预分频设为2SPI时钟就是27MHz设为4就是13.5MHz。MR25H40CDF的最高SPI时钟是40MHz所以27MHz完全在规格范围内。但实际项目中我建议先从一个较低的速度开始调试比如6.75MHz预分频8等读写都稳定了再逐步提高。SPI速度受走线长度、负载电容、电源质量的影响很大实验室里能跑40MHz到了现场可能20MHz就不稳了。3.3 软件片选与硬件片选的取舍STM32的SPI外设支持硬件NSS和软件NSS两种片选方式。硬件NSS由外设自动控制看起来省事但在实际使用中有几个问题。第一硬件NSS在多字节连续传输时NSS信号在字节之间可能会短暂拉高而MR25H40CDF要求在整个命令序列期间CS保持低电平。这个短暂的高电平会被MRAM误判为命令结束。第二硬件NSS的时序受SPI外设状态机控制在某些错误条件下比如溢出NSS可能不会正确释放。第三软件片选可以在CS拉低和第一个时钟沿之间插入精确的延时满足MRAM的tSLCHCS低到第一个时钟沿时序要求。所以我的做法是CubeMX里NSS选Software然后手动指定一个GPIO作为片选引脚在代码里显式控制。这样虽然多写几行代码但换来了完全的时序控制权。// 片选控制宏定义 #define MRAM_CS_LOW() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET) #define MRAM_CS_HIGH() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET) // 带片选控制的SPI传输函数 void MRAM_Transfer(uint8_t *txBuf, uint8_t *rxBuf, uint16_t len) { MRAM_CS_LOW(); HAL_SPI_TransmitReceive(hspi2, txBuf, rxBuf, len, HAL_MAX_DELAY); MRAM_CS_HIGH(); }这段代码看起来简单但MRAM_CS_HIGH()之后的延时不能省。MR25H40CDF要求CS拉高之后至少保持几个纳秒才能开始下一次操作。HAL库的函数调用本身会消耗一些时间在大多数情况下够用但如果你的SPI速度很低可能需要手动加一个__NOP()。4. MR25H40CDF的命令集与读写操作实战4.1 核心命令码速查MR25H40CDF的命令集和标准SPI Flash非常相似但去掉了擦除相关的命令因为MRAM不需要擦除。命令名称命令码功能说明WREN0x06写使能WRDI0x04写禁止RDSR0x05读状态寄存器WRSR0x01写状态寄存器READ0x03读数据WRITE0x02写数据RDID0x9F读设备IDRDID命令返回的字节序列可以用来确认芯片是否正常工作。MR25H40CDF的RDID返回8个字节前几个字节是厂商ID和产品ID。具体值可以查数据手册但实际调试时只要读到的不是全0或全1基本就能说明SPI通信是通的。4.2 写操作的完整流程MRAM的写操作比Flash简单不需要擦除但需要先发WREN命令。完整流程如下拉低CS发送WREN命令0x06拉高CS拉低CS发送WRITE命令0x02发送3字节目标地址高位在前发送要写入的数据可以连续多个字节拉高CS注意第3步和第4步之间CS必须拉高再拉低这是WREN命令生效的必要条件。有些SPI设备允许WREN和WRITE在同一个CS周期内完成但MR25H40CDF不行。void MRAM_WriteEnable(void) { uint8_t cmd 0x06; MRAM_CS_LOW(); HAL_SPI_Transmit(hspi2, cmd, 1, HAL_MAX_DELAY); MRAM_CS_HIGH(); } void MRAM_Write(uint32_t addr, uint8_t *data, uint16_t len) { uint8_t cmd[4]; cmd[0] 0x02; cmd[1] (addr 16) 0xFF; cmd[2] (addr 8) 0xFF; cmd[3] addr 0xFF; MRAM_WriteEnable(); MRAM_CS_LOW(); HAL_SPI_Transmit(hspi2, cmd, 4, HAL_MAX_DELAY); HAL_SPI_Transmit(hspi2, data, len, HAL_MAX_DELAY); MRAM_CS_HIGH(); }写操作完成后建议读一次状态寄存器确认WEL位已经清零。如果WEL位仍然为1说明WREN命令没有正确执行后续的写操作会被忽略。4.3 读操作的实现与速度优化读操作更简单不需要WRENvoid MRAM_Read(uint32_t addr, uint8_t *buf, uint16_t len) { uint8_t cmd[4]; cmd[0] 0x03; cmd[1] (addr 16) 0xFF; cmd[2] (addr 8) 0xFF; cmd[3] addr 0xFF; MRAM_CS_LOW(); HAL_SPI_Transmit(hspi2, cmd, 4, HAL_MAX_DELAY); HAL_SPI_Receive(hspi2, buf, len, HAL_MAX_DELAY); MRAM_CS_HIGH(); }如果要进一步提高读速度可以用DMA。STM32F745ZG的SPI2支持DMA请求配置好DMA通道后读操作可以完全不占用CPU。对于需要连续读取大量数据的场景比如把MRAM当作数据缓冲区DMA能把CPU解放出来做其他事情。不过DMA也有代价配置复杂、调试麻烦、在小数据量下反而不如中断方式灵活。我的经验是单次读取超过256字节时用DMA小于这个值直接用阻塞式传输代码简单出问题也容易排查。4.4 状态寄存器的解读MR25H40CDF的状态寄存器只有几位有效bit0WEL写使能锁存执行WREN后置1写操作完成后自动清零bit1WEL写保护使能和WP引脚配合使用bit2-7保留读状态寄存器的代码uint8_t MRAM_ReadStatus(void) { uint8_t cmd 0x05; uint8_t status; MRAM_CS_LOW(); HAL_SPI_Transmit(hspi2, cmd, 1, HAL_MAX_DELAY); HAL_SPI_Receive(hspi2, status, 1, HAL_MAX_DELAY); MRAM_CS_HIGH(); return status; }在实际调试中我习惯在每次写操作后读一次状态寄存器确认WEL位已经清零。这个习惯帮我抓到过好几次SPI时序问题——WEL位没清零说明WREN命令没有被正确识别通常是CS时序或者时钟极性配置错了。5. 实测中遇到的时序问题与排查过程5.1 现象写入后读出的数据随机错误第一次跑通读写测试时我写入了256字节的递增数据然后读回来对比。结果发现大约每几十次写入就有一次读出的数据不对错误位置随机错误值也没有规律。这种随机错误最让人头疼因为它不像固定错误那样容易定位。我一开始怀疑是SPI速度太快把时钟从27MHz降到6.75MHz错误率下降了但没有完全消失。这说明问题不只是速度。5.2 排查第一步用逻辑分析仪抓SPI波形借了一台逻辑分析仪抓取CS、SCK、MOSI、MISO四根线的波形。对比正常写入和异常写入的波形后发现了一个规律所有出错的写入操作CS拉高之后到下一次CS拉低之间的间隔都特别短只有几十纳秒。而正常的操作间隔都在微秒级别。查MR25H40CDF的数据手册发现有一个参数叫tSHSLCS高电平最短时间典型值是10ns。几十纳秒理论上满足要求但数据手册还提到在写操作之后MRAM内部有一个写入周期虽然不需要像Flash那样等待几毫秒但仍然需要一定的时间来完成磁性隧道结的状态翻转。这个时间没有在数据手册里明确标出但实测下来如果CS拉高后立即进行下一次操作写入可能会失败。5.3 解决方案在CS拉高后插入延时在MRAM_CS_HIGH()之后加了一个短暂的延时#define MRAM_CS_HIGH_DELAY() do { \ MRAM_CS_HIGH(); \ for(volatile int i 0; i 10; i); \ } while(0)这个循环在216MHz的STM32F745ZG上大约产生几十纳秒的延时。加上之后连续写入100万次没有再出现数据错误。这个坑的教训是数据手册上的时序参数是最低要求实际使用中留一些余量总是好的。尤其是MRAM这种写入机制和Flash不同的器件不能想当然地认为不需要擦除就等于不需要等待。5.4 另一个坑WP引脚悬空导致的写入失败在另一块板子上WP引脚没有上拉直接悬空。结果发现写入操作时好时坏读状态寄存器发现WEL位有时候能置1有时候不能。WP引脚悬空时电平不确定可能被外部噪声耦合到低电平触发写保护。虽然MR25H40CDF的WP只保护状态寄存器但状态寄存器里的块保护位如果被意外修改可能会阻止对某些地址范围的写入。解决办法很简单WP和HOLD都通过10k电阻上拉到3.3V。这两个引脚在不需要使用时绝对不能悬空。6. 工业场景下的数据可靠性设计6.1 写入数据的校验机制MRAM本身的数据保持能力很强但在工业现场SPI通信过程可能受到电机、继电器、变频器等设备的电磁干扰。为了保证写入数据的正确性我在每个数据块后面加了一个CRC16校验值。写入时先计算数据的CRC16然后把数据和CRC一起写入MRAM。读取时先读出数据和CRC重新计算CRC并与存储的值对比。如果不一致说明数据在传输或存储过程中出了问题。typedef struct { uint32_t timestamp; float temperature; float pressure; uint16_t crc; } DataRecord; uint16_t CalculateCRC16(uint8_t *data, uint16_t len) { uint16_t crc 0xFFFF; for (uint16_t i 0; i len; i) { crc ^ data[i]; for (uint8_t j 0; j 8; j) { if (crc 0x0001) { crc (crc 1) ^ 0xA001; } else { crc 1; } } } return crc; }CRC16的计算会增加一些CPU开销但在216MHz的M7内核上计算几十字节的CRC只需要几微秒完全可以接受。6.2 双备份与地址轮转策略对于关键参数我采用了双备份加地址轮转的策略。把MRAM的存储区分成两个区域每个区域存储一份完整的数据。写入时先写区域A再写区域B。读取时先读区域A如果CRC校验通过就用A的数据如果A校验失败再读区域B。地址轮转是指每次写入时把数据写到上一次写入位置的下一个块。这样可以避免某个固定地址被反复写入。虽然MRAM的擦写寿命理论上无限但地址轮转可以进一步降低风险同时也能保留最近几次的历史数据。#define BLOCK_SIZE 64 #define BLOCK_COUNT 16 #define AREA_A_BASE 0x000000 #define AREA_B_BASE 0x010000 uint32_t current_block 0; void SaveData(DataRecord *record) { uint32_t addr_a AREA_A_BASE current_block * BLOCK_SIZE; uint32_t addr_b AREA_B_BASE current_block * BLOCK_SIZE; record-crc CalculateCRC16((uint8_t*)record, sizeof(DataRecord) - 2); MRAM_Write(addr_a, (uint8_t*)record, sizeof(DataRecord)); MRAM_Write(addr_b, (uint8_t*)record, sizeof(DataRecord)); current_block (current_block 1) % BLOCK_COUNT; }这个策略的代价是存储容量减半但换来了更高的可靠性。在工业场景下这个取舍是值得的。6.3 上电自检与坏块标记虽然MRAM的可靠性很高但为了万无一失我在系统上电时做一次自检。自检的内容是向每个块写入一个已知模式读回来对比如果某个块读写不一致就把它标记为坏块后续不再使用。坏块信息本身也需要存储我把它放在MRAM的最后一个块里。这个块在自检时先读取自检完成后再更新。#define BAD_BLOCK_MAP_ADDR 0x03FF00 void PowerOnSelfTest(void) { uint8_t test_pattern[16] {0xA5, 0x5A, 0xAA, 0x55, 0xF0, 0x0F, 0xFF, 0x00, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0}; uint8_t read_buf[16]; uint8_t bad_block_map 0; for (int block 0; block BLOCK_COUNT; block) { uint32_t addr AREA_A_BASE block * BLOCK_SIZE; MRAM_Write(addr, test_pattern, 16); MRAM_Read(addr, read_buf, 16); if (memcmp(test_pattern, read_buf, 16) ! 0) { bad_block_map | (1 block); } } MRAM_Write(BAD_BLOCK_MAP_ADDR, bad_block_map, 1); }这个自检过程在216MHz的STM32F745ZG上只需要几毫秒对系统启动时间几乎没有影响。7. 性能实测数据与选型对比7.1 读写速度实测在SPI时钟27MHz、软件片选、阻塞式传输的条件下实测数据如下操作类型数据量耗时等效速率单字节写入1字节约2.1us约0.48MB/s连续写入256字节约82us约3.1MB/s连续读取256字节约78us约3.3MB/s连续读取DMA1024字节约245us约4.2MB/s单字节写入的耗时主要花在WREN命令和CS控制上实际数据传输时间很短。连续写入时命令开销被摊薄速率明显提升。DMA读取的速率提升有限因为瓶颈在SPI时钟本身DMA只是解放了CPU。如果把SPI时钟提高到40MHz连续读写速率可以接近5MB/s。但在工业现场我一般不会跑满40MHz留一些余量给信号完整性和温度变化。7.2 与常见非易失存储方案的对比特性MR25H40CDF (MRAM)W25Q64 (NOR Flash)FM25V05 (FRAM)24C512 (EEPROM)容量4Mbit64Mbit512Kbit512Kbit接口SPISPISPII2C写入前擦除不需要需要不需要不需要擦写寿命无限10万次100万亿次100万次写入速度快慢快慢数据保持20年20年10年40年抗磁场强强弱强单价高低中低从表格可以看出MRAM的核心优势在于不需要擦除和无限寿命这两点。对于需要频繁记录数据的工业设备这两点直接决定了方案的可行性。NOR Flash虽然便宜但擦写寿命和擦除开销让它不适合高频写入场景。FRAM虽然写入快、寿命长但抗磁场能力弱在电机旁边工作有风险。EEPROM则受限于I2C接口的速度和有限的擦写次数。7.3 什么场景下值得用MRAMMRAM的价格比NOR Flash和EEPROM贵不少所以不是所有场景都适合。以下几种情况我建议优先考虑MRAM数据写入频率高比如每秒记录一次运行参数设备寿命内写入次数超过百万次写入实时性要求高不能等待Flash擦除的毫秒级延迟工作环境有强磁场或辐射FRAM和EEPROM可能不可靠系统掉电时需要立即保存关键数据MRAM的写入速度可以满足如果只是存储一些出厂参数、校准系数写入频率很低那用EEPROM或Flash就够了没必要多花钱上MRAM。8. 代码组织与项目集成建议8.1 驱动层的模块划分在实际项目中我把MRAM驱动分成三层硬件抽象层封装SPI收发和CS控制提供MRAM_Transfer()、MRAM_CS_LOW()、MRAM_CS_HIGH()等基础函数命令层实现WREN、READ、WRITE、RDSR等命令的封装应用层提供SaveData()、LoadData()、PowerOnSelfTest()等业务接口这样分层的好处是如果以后换用其他SPI MRAM型号只需要修改命令层应用层代码不用动。如果换用QSPI接口的MRAM也只需要重写硬件抽象层。8.2 中断安全与多任务访问如果MRAM驱动在RTOS环境下使用多个任务可能同时访问SPI总线。这时候需要加互斥锁防止一个任务的SPI传输被另一个任务打断。osMutexId_t mram_mutex; void MRAM_WriteSafe(uint32_t addr, uint8_t *data, uint16_t len) { osMutexAcquire(mram_mutex, osWaitForever); MRAM_Write(addr, data, len); osMutexRelease(mram_mutex); }如果不用RTOS而是在裸机环境下可以在SPI传输期间关中断防止中断服务程序打断SPI时序。但关中断的时间要尽量短否则会影响系统的实时性。8.3 掉电保护的处理工业设备经常遇到突然断电的情况。如果在写入过程中断电可能导致数据只写了一半。MRAM的写入速度很快单次写入通常在微秒级别完成所以断电导致写入不完整的概率很低。但为了保险可以在数据块头部加一个写入完成标志只有标志置位后才认为数据有效。typedef struct { uint32_t magic; // 0x5A5A5A5A表示数据有效 uint32_t timestamp; float temperature; float pressure; uint16_t crc; } DataRecord; void SaveDataSafe(DataRecord *record) { record-magic 0; record-crc CalculateCRC16((uint8_t*)record, sizeof(DataRecord) - 2); MRAM_Write(current_addr, (uint8_t*)record, sizeof(DataRecord)); record-magic 0x5A5A5A5A; MRAM_Write(current_addr, (uint8_t*)record, sizeof(DataRecord)); }先写入magic为0的数据再写入magic有效的数据。读取时检查magic如果不等于0x5A5A5A5A说明数据不完整丢弃即可。这个技巧在EEPROM和Flash上更常用因为它们的写入时间长断电风险高。MRAM虽然写入快但加上这个机制也不会有明显开销算是一层额外的保险。9. 几个容易被忽略的调试细节9.1 用RDID命令快速确认通信每次拿到新板子我第一件事就是发RDID命令读回设备ID。如果读回的是全0或全1说明SPI通信根本没通先检查接线和电源。如果读回的值和手册一致说明SPI基本正常可以继续往下调。RDID命令的好处是不依赖任何配置不需要WREN不需要考虑地址纯粹是读操作。它是验证SPI链路是否通畅的最快方法。9.2 示波器看CS和SCK的时序关系逻辑分析仪适合看协议内容示波器适合看信号质量。我习惯用示波器同时抓CS和SCK看CS拉低到第一个SCK上升沿之间的时间是否满足tSLCH要求看CS拉高到SCK停止之间的时间是否满足tSHCH要求。如果CS和SCK的时序不对即使SPI配置看起来没问题MRAM也可能不响应。这种问题在逻辑分析仪上不容易发现因为逻辑分析仪只显示高低电平不显示上升沿和下降沿的细节。9.3 温度对SPI时序的影响工业级MRAM的工作温度范围是-40到85摄氏度。在低温下芯片内部的驱动能力会下降SPI的最高可靠时钟频率也会降低。如果在常温下调通了40MHz到了零下20度可能就不稳了。我的做法是在高低温箱里做一次SPI时钟的余量测试。从40MHz开始逐步降低时钟找到在温度极限下仍然稳定的最高频率然后在这个频率上再降一档作为工作频率。比如高低温下30MHz稳定那常温工作就用27MHz。9.4 电源纹波对写入可靠性的影响MRAM的写入操作需要驱动磁性隧道结的电流这个电流虽然不大但对电源纹波比较敏感。如果电源纹波超过50mV写入失败的概率会明显上升。在调试时我用示波器交流耦合档测量VDD引脚上的纹波。如果纹波偏大先检查去耦电容是否放对位置再检查电源芯片的负载调整率。有时候换一个低ESR的钽电容或者加一个LC滤波就能把纹波压下来。这些细节在数据手册里不会写但实际项目中每一个都可能成为拦路虎。我踩过的最大的坑就是电源纹波导致的随机写入失败查了整整两天才定位到。
返回列表