news 2026/9/12 16:48:10

SPI EEPROM读回全FF?从硬件到软件一步步排查搞定

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SPI EEPROM读回全FF?从硬件到软件一步步排查搞定

如果调试SPI EEPROM时发现读出来的数据全是0xFF,恭喜,你踩进了嵌入式开发里最经典也最让人抓狂的一个坑。最近帮朋友排查一个M95M04的故障,现象就是标题这句话:“Only receiving FF out of the M95M04”。芯片是ST的4Mbit SPI EEPROM,读任何地址返回的都是0xFF,写进去的数据再读回来也还是0xFF,整个芯片像是失忆了一样。这篇把这个问题从现象、原理到排查步骤完整捋一遍,文末附问题速查表,做硬件和固件调试的朋友可以直接对照排查。

M95M04这种SPI EEPROM在工业设备里很常见,仪表校准参数、设备配置、日志存储都靠它。全FF意味着系统拿到的是空白数据,轻则配置丢失需要恢复出厂,重则设备直接判定硬件异常、拒绝启动。很多人第一反应是“芯片坏了”,但我实际见过的情况里,真坏的比例很低,大部分是硬件连接、SPI配置、写保护引脚处理这几类问题。所以别急着换芯片,按下面的思路一步步来。

1. 现象定性:全FF到底说明了什么

1.1 先区分两种“全FF”

同样是读到0xFF,背后原因可能完全不同,排查方向也南辕北辙。我习惯把它分成两种情况。

第一种,芯片从头到尾没有任何响应。你发指令、发地址,MISO上一点反应都没有,读出来全是0xFF。这种情况的根因基本在通信层——要么芯片没上电,要么MOSI/MISO/SCK/CS四根线里有问题,要么SPI模式完全不匹配。芯片就像一个没插电的收音机,你调频没有任何声音。

第二种,芯片有响应,但读出来的数据本身就是0xFF。这里要特别提醒:全新EEPROM出厂数据本来就是全FF,这在Flash和EEPROM领域是标准状态,不是故障。但如果你是写完数据之后再读,发现还是FF,那就要怀疑写操作根本没生效——写保护没解除、写时序不对、页写越界,都可能导致“写了个寂寞”。

所以拿到全FF先别慌,先问自己一个问题:这个芯片之前写过数据吗?如果确认写过,什么时候写的?写完之后有没有成功读回来过?这几个问题的答案能把排查方向缩小一半。

1.2 全FF在SPI协议层面的含义

SPI是同步串行协议,主机提供时钟,从机在时钟边沿输出数据。当从机不驱动MISO线时,这条线处于高阻态。如果主机端MISO内部有上拉电阻,或者板子上有外部上拉,那么高阻态被上拉到高电平,读到的就是0xFF。

这条逻辑很关键。全FF意味着SPI总线上每个bit都是1,也就是MISO一直保持高电平。虽然可能是芯片工作正常但数据区为空,但更常见的是芯片根本没参与总线对话。你可以把MISO想象成一条共享电话线,多个设备挂在上面,谁都不说话时线路是安静的(被上拉到高电平),只有被CS选中的设备才会在这条线上输出数据。你一直听到“嗡嗡”的静音噪声,说明你要找的那个设备根本没拿起话筒。

1.3 全FF问题的典型影响范围

这类问题在项目里的影响有多大,取决于芯片里存的是什么数据。

如果M95M04存的是设备唯一标识或出厂校准数据,全FF会让设备在开机自检阶段就判定数据非法,直接拒绝运行。如果存的是用户配置,可能表现为每次断电重启都恢复出厂设置。如果是OTA升级里的引导参数,芯片数据损坏甚至会导致设备变砖。所以在产线调试、样机验证阶段,全FF这种问题杀伤力很大,但好消息是根因通常不复杂,关键是别瞎猜,按电路和时序一层一层查。

2. M95M04基础:从芯片特性反推问题点

2.1 M95M04到底是什么

M95M04是ST(意法半导体)出品的SPI接口EEPROM,容量4Mbit,换算过来是512KB。这个容量在EEPROM里算比较大的,所以它内部需要2字节地址来寻址(512KB需要19根地址线的寻址范围,一个字节8位不够用)。

它的引脚不多,典型8脚封装。CS是片选,C是时钟(对应SCK),D是数据输入(对应MOSI),Q是数据输出(对应MISO),W是写保护,HOLD是保持。还有电源和地。有些朋友第一次用这芯片,把W和HOLD直接悬空,结果就是问题不断。

2.2 必须搞懂的关键指令

M95M04的指令系统不复杂,但几个核心指令必须背下来,排查问题时刻都要用到:

  • 0x06 WREN:写使能。任何写操作之前必须先发这个指令,这是EEPROM防误写的重要手段
  • 0x04 WRDI:写禁用
  • 0x05 RDSR:读状态寄存器
  • 0x01 WRSR:写状态寄存器
  • 0x03 READ:读数据,后面跟2字节地址
  • 0x02 WRITE:写数据,后面跟2字节地址加数据
  • 0xB9 深掉电指令,0xAB 唤醒指令

特别要注意,EEPROM的写操作比读操作麻烦得多。读操作随时可以做,不需要先发WREN。但写操作前必须先发0x06写使能,然后检查状态寄存器里的WEL位确认写使能成功,再发写指令。而且写完后不能立刻写下一笔,必须轮询WIP位,等内部写周期完成。很多人第一次用EEPROM,写完了立刻读,发现数据没更新,其实就是写周期还没结束。

2.3 地址长度这个经典坑

M95M04这种4Mbit的芯片,地址是2字节。而M95040(4Kbit)、M95160(16Kbit)这些老型号,地址只要1字节。如果你把之前1字节地址的例程直接搬到M95M04上,读出来的数据十有八九不对,而且很可能是全FF。

原因很简单:芯片等你发两个地址字节,你只发了一个,它把第一个数据字节当成了地址的高字节,后面所有数据都错位了,读到的自然不是你想访问的地址内容。再加上如果你读的是0x0000这种低位地址,高字节地址被误认为0x00时看起来还行,但一旦地址超过255,就全面错乱。

排查全FF问题前,先确认你的代码发的地址字节数对不对。正确写法是先发0x03,再发两个地址字节,比如读地址0x1234,就发送 0x03, 0x12, 0x34,然后开始读。

3. 硬件排查:从引脚到波形逐项确认

3.1 供电、接地与连接

硬件排查第一步不是看软件,而是确认芯片“活”着。用万用表量芯片电源引脚对地电压。M95M04工作电压范围常见的是1.8V到5.5V(具体看尾缀,有-D后缀的多支持1.8V以上),但有个细节:电压不同,最高时钟频率也不同。5V时能跑20MHz,3.3V时可能就只有16MHz甚至更低。如果供电只有3.3V,你却按20MHz配置SPI时钟,芯片跟不上,读出来的数据也有可能是乱的。

量电压的同时,顺便量一下CS、SCK、MOSI、MISO这四根线到主控引脚之间的通断。我之前遇到过一块板子,目测焊接没问题,但MISO过孔在PCB内层断裂,万用表蜂鸣档一量就现原形。还有一次是排线接触不良,SPI信号时通时断。

注意SPI从机的MISO在未选中时是高阻态,所以主机端MISO必须有上拉电阻。很多MCU的GPIO内部上拉默认是关闭的,如果你用的是硬件SPI且没有外部上拉电阻,MISO悬空时读到什么全靠运气,最常见的就是读到全FF或者全00。解决方法是加一个10kΩ外部上拉,或者在初始化GPIO时把内部上拉打开。

3.2 WP和HOLD引脚——全FF的隐形元凶

M95M04的W(WP)引脚是硬件写保护输入,低电平有效。这个引脚的电平状态直接决定写操作能不能生效。如果WP被拉低,芯片的写保护区域无法写入,但读操作不受影响。注意这里有个迷惑性:写保护时读操作完全正常,你能读ID、能读状态寄存器、能读数据区,只是写不进去。所以如果读出来全是FF,而且这些FF是“写不进去”的FF,先查WP。

HOLD引脚同样低电平有效。HOLD拉低时,芯片暂停通信,忽略SCK上的时钟信号,此时如果你正在读数据,MISO会停在当前电平,你读到的是重复的位,也可能表现为数据异常。HOLD上有一个内部上拉电阻,但如果你把它接到地,芯片就永远处于暂停状态,这时候SPI通信是完全不响应的,读出来自然全是FF。

实际项目里WP的正确接法有两种。一种是直接接VCC,永久关闭硬件写保护,靠软件指令保护数据;另一种是接MCU的GPIO,需要写的时候拉高,平时拉低保护。新手最容易犯的错是把WP直接接地,然后发现写不进任何数据。HOLD则是强烈建议接VCC或者用GPIO拉高,不要让它悬空。虽然HOLD内部有上拉,但悬空引脚在电磁干扰环境下电平可能抖动,危险隐患很大。

3.3 示波器看波形:一锤定音的实测方法

软件排查了半天还定位不到问题,别犹豫,上示波器。这是我实际排查SPI问题时最有效的手段,甚至可以说,学会用示波器看SPI波形,能解决80%的SPI通信故障。

先把示波器探头接在SCK上,触发方式设置成上升沿或者下降沿,然后运行读操作。先看时钟是否正常:SCK是否有连续脉冲?空闲电平是否正确?如果配置的CPOL=0,空闲电平应该是低;如果CPOL=1,空闲应该是高。接着看CS:发指令时CS是否拉低?拉低的时机是否正确?CS必须在第一个时钟沿之前拉低,并且在整个指令过程中保持低电平。

然后看MOSI上的指令波形,对照数据手册确认发送的0x03后面确实跟了两个地址字节。最后把探头移到MISO上,在读数据阶段,MISO上是否真的有电平变化?如果MISO一路平坦,高电平不动,那么芯片确实没有回应你;如果MISO有波形,但读出来的数据和预期不符,那就要查数据是不是在正确的时钟边沿被采样。

示波器还能帮你确认SPI时钟频率是否过高。如果波形显示SCK频率太高,边沿已经变形、幅度不足,芯片很可能就无法正确采样。具体判断标准看数据手册,但经验上建议先用1MHz这种低速排查问题,通信正常了再逐步提高频率。

4. 软件排查:SPI配置与指令序列

4.1 SPI模式必须匹配CPOL和CPHA

硬件排查没问题的话,问题大概率在软件配置上。SPI有四种模式,由CPOL(时钟极性)和CPHA(时钟相位)组合而来。M95M04的数据手册明确支持模式0(CPOL=0, CPHA=0)和模式3(CPOL=1, CPHA=1)。

这两个模式的区别是:模式0是空闲时钟为低电平,第一个边沿(上升沿)采样数据;模式3是空闲时钟为高电平,第二个边沿(通常是下降沿)采样。如果你把芯片配成了模式1或模式2,采样边沿和芯片输出数据的时机不匹配,读到的数据就可能是全FF或者乱七八糟。

我之前遇到过最隐蔽的情况:主控用的是STM32硬件SPI,配置时误设置了SPI_CPOL_Low和SPI_CPHA_2Edge,也就是把CPHA写错了,结果读M95M04全FF,读别的SPI设备却正常。因为不同的SPI从机对时序的要求差异很大,A设备能容忍的错误时序,B设备就是不行。所以排查时一定先看数据手册,确认芯片支持的模式,然后回头看MCU的SPI初始化代码。

4.2 先读RDID,别急着读数据区

排查SPI EEPROM问题时,我强烈建议先做一件事:读设备ID。这比直接读数据区的命中率高得多,因为读ID需要芯片完整地响应一次SPI通信,能验证时钟、CS、MOSI、MISO全链路是否正常。

M95M04数据手册里对应的指令,比较常见的是0x9F(JEDEC ID)或0x83,不同批次和封装略有差异。发送指令后,连续读几个字节,如果读回了有意义的ID,比如厂商字节是ST的ID(0x20),说明SPI通信链路基本没问题。如果连ID都读不出来,返回全FF,那就回到硬件排查,问题和数据区内容无关,就是芯片没回应你的SPI指令。

如果ID能读出来,但数据区全FF,问题范围就缩小了。这时候重点检查写保护和写入流程,因为能读ID说明通信是好的,读不出数据可能只是数据真的没写进去。

4.3 状态寄存器:EEPROM的体检报告

M95M04有个状态寄存器,读完它等于给芯片做了一次体检。读状态寄存器的指令是0x05,发送指令后直接读一个字节。

状态寄存器里几个bit含义不一样。bit0是WIP,写进行中标志,为1表示芯片内部正在执行写操作,此时不能发起新的写指令。bit1是WEL,写使能锁存位,为1表示刚才的WREN指令生效,可以进行写操作。bit2和bit3是BP0和BP1,块保护位,决定哪些地址区域被写保护。这几个位如果被设置成非预期状态,写入就会失败,读回来自然全是FF。

排查顺序是这样的:先读状态寄存器。如果WIP一直为1,说明芯片卡在写操作中,可能是之前的写指令没有正确结束。如果WEL为0,说明WREN没生效,写使能不成功就不用谈后续写入。如果BP位不为0,说明有一部分地址被保护了,写入那些地址会被忽略。

还有一种可能:有人曾经往状态寄存器里写了非零值,把BP位设上了,芯片就进入了块保护状态。这种情况在旧板子二次开发时尤其常见,代码里初始化时没写状态寄存器,但上一版固件可能已经设置过保护。解决办法是发0x01写状态寄存器,把BP位清零。

4.4 写操作的完整姿势

如果你发现自己确实是在写数据后读回全FF,大概率是写操作步骤没走全。EEPROM写操作的标准流程如下:

  1. 拉低CS
  2. 发送0x06(WREN)写使能指令
  3. 拉高CS,结束指令
  4. 拉低CS,发送0x02(WRITE),发送2字节地址,发送要写的数据
  5. 拉高CS,触发内部写周期
  6. 等待WIP位清零(轮询0x05读状态寄存器,直到bit0为0)
  7. 重新发送0x03读数据,验证

这里最容易犯错的是第3步。WREN指令必须在CS拉高之后才算完成,有些人在WREN之后不拉高CS,直接发WRITE指令,芯片不会接受。我在代码里见过不少这种错误,看起来逻辑没错,实际完全无效。

还有一个高频坑:写操作后没有等内部写周期完成。EEPROM写入一个字节,内部需要几毫秒(M95M04典型值是5ms左右)。如果写完立刻发读指令,芯片可能还在忙,读到的当然还是FF。正确做法是轮询WIP,WIP为0才说明写完。

页写也要注意边界。M95M04支持256字节页写,但页写不能跨页。如果你从地址0x00FF开始写两个字节,第二个字节会写到0x0100吗?不会,它会回绕到本页开头0x0000。这种跨页回绕是EEPROM的通用行为,很多人不知道,数据写出来和预期完全不符。

5. 实战排查记录:从全FF到正常读取

5.1 案例一:WP引脚悬空导致的写不进去

朋友的项目里,M95M04焊在板子上,MCU通过软件模拟SPI访问。现象是:能读出ID,数据区读出来全FF,写入后立刻读,还是FF。我问他WP引脚怎么接的,他说“没接,悬空的”。

这就是典型问题。WP引脚内部没有可靠的默认电平,悬空状态下受周围电路影响,可能处于不定状态。实测时用万用表量WP引脚电压,只有0.8V,低于高电平门槛,芯片实际上一直处于写保护状态。把WP用飞线接到VCC后,写入恢复正常,数据能正确读回。

这个案例说明:EEPROM的每个功能引脚都不能裸奔。WP接GND会写保护,悬空会遇到不定电平,最稳妥的做法是接VCC或者由MCU控制。

5.2 案例二:SPI模式配置错误

另一个案例更隐蔽。主控用的是国产MCU的硬件SPI,初始化的时候按照之前用一个SPI Flash的配置,CPOL=1, CPHA=0,也就是模式2。读M95M04返回全FF。

从波形上看,SCK空闲为高,数据在下降沿被采样,但M95M04期望的采样时刻是第二个边沿或者第一个边沿(取决于是模式0还是模式3),和当前配置完全不匹配。芯片输出数据的时机会和主机采样的时机错开,导致采到的全是1。把SPI配置改成模式0或者模式3后,问题立即消失。

这个案例的教训是:SPI设备不是一样的,换芯片必须重新确认数据手册。尤其国产MCU的SPI硬件模块在实现细节上百家争鸣,有些还支持“SPI模式自动检测”,用不好反而更复杂。

5.3 案例三:时钟频率过高导致数据错乱

还有一个案例是SPI时钟频率太高。主控的SPI外设时钟设置成了18MHz,M95M04在3.3V供电下最高只支持16MHz(具体看数据手册表格),超频运行的结果是:读ID偶尔正常,读数据全FF。

示波器上看SCK波形,时钟边沿有明显振铃,波形幅度在上升沿后没有稳定,芯片在这个边沿采样时采到的是不确定电平。把SPI分频系数改一下,降到8MHz,所有问题消失。

所以排查时如果波形紊乱、数据不稳定,不要一味怀疑芯片,先检查SCK是否在芯片支持的频率范围内。尤其注意不同电压下最大时钟频率不一样,这个参数容易看漏。

6. 常见问题速查表与调试建议

6.1 全FF排查速查表

我把实际调试中遇到过的情况整理成一张表,按“现象 → 原因 → 解决办法”排列。项目里遇到全FF问题,直接对照表格排查,比从零分析快得多。

现象可能原因排查/解决方法
读ID、读数据都返回全FF芯片没上电或供电异常万用表量VCC,确认电压在规格范围内
读ID、读数据都返回全FFSPI模式配置错误确认CPOL/CPHA匹配模式0或模式3
读ID、读数据都返回全FFMISO虚焊/断开量MISO通断,确认主控引脚与芯片Q脚连接
读ID、读数据都返回全FFHOLD引脚被拉低确认HOLD为高电平,不要接地
读ID、读数据都返回全FFCS片选时序错误示波器看CS时序,确认指令期间CS为低
ID能读,数据区全FF出厂空白全新芯片默认全FF,执行写操作后重读
ID能读,写入后读回全FFWP引脚写保护确认WP接VCC或由GPIO控制为高
ID能读,写入后读回全FFWREN未正确执行检查WREN后CS是否拉高再发起写指令
ID能读,写入后读回全FF写入后未等待WIP清零轮询状态寄存器bit0,为0后再读
ID能读,写入后读回全FFBP位设置保护读状态寄存器,写0x01清除BP位
ID能读,写入后读回全FF写地址越界/页回绕确认地址不超过容量,页写不跨页
读数据部分正确部分FF供电电压不足检查电源纹波,确认在标准范围内
读数据部分正确部分FF时钟频率过高降低SPI频率到芯片支持范围
读数据部分正确部分FF地址字节数不对4Mbit必须发2字节地址,不是1字节

6.2 几个值得长期保留的调试习惯

调试EEPROM这类SPI芯片,有几个习惯是长期积累下来的,对排查问题帮助巨大。

第一个习惯,单独写一个SPI回环测试函数。把MOSI和MISO短接,发一串数据,看是否能原样读回。如果回环测试都失败,说明MCU的SPI配置或引脚有问题,根本没到芯片那一层。这个办法能快速区分是主控问题还是芯片问题。

第二个习惯,读回来的数据打印成十六进制,不要只打印字符串。0xFF和"FF"在串口助手里看起来有区别,但当你调试大量数据时,十六进制格式更容易发现规律。我见过全FF被误认为空字符串的情况,耽误了不少时间。

第三个习惯,准备一个已知好用的样板。新项目里遇到SPI问题,如果手头有另一块确认能正常读写M95M04的板子,直接把芯片拆过去试,或者把好板子的初始化代码拿来对比。很多时候问题就在几行初始化配置的差异上。

第四个习惯,EEPROM调试时务必把读操作的代码和写操作的代码分开封装,用独立函数测试。不要写一个“写后读校验”的大函数一把梭,不然出了问题你分不清是写失败还是读失败。分开测,定位快得多。

6.3 最后再分享一个实用技巧

M95M04这类大容量EEPROM调试时,建议先只写一个字节、读一个字节验证通路的正确性。很多人一上来就写整个扇区、整页数据,然后发现全FF,根本不知道从哪查起。从最小操作开始,确认单字节读写正常了,再扩展到页写和连续读。这个思路不只是适用这个芯片,所有I2C/SPI存储芯片调试都通用。

另一个小技巧是初始化GPIO时,把CS、SCK、MOSI都先设置成确定的电平(通常是高),再初始化SPI外设。有些MCU的GPIO复用功能切换瞬间会有毛刺,导致EEPROM收到错误的片选信号,进入异常状态。先确认GPIO电平稳定,再打开SPI外设,可以避免这类偶发问题。

如果你按上面的步骤排查之后,发现全FF问题依然存在,试着用示波器抓一次完整的读写操作波形,发给我看也没用——我不在你的实验室,但你可以自己对照数据手册里的时序图,一个边沿一个边沿地核对。SPI调试就是这样,看似玄学的问题,最后都能落到某一条具体的信号线上。我也在博客里整理过几份常见SPI EEPROM的数据手册时序对比,手头有这类项目的话可以翻翻,不同芯片之间的差异往往就是故障的根源。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 18:42:50

OBS 插件开发实战:5 步写出实时屏幕标注滤镜

OBS 插件开发实战:5 步写出实时屏幕标注滤镜 【免费下载链接】obs-studio OBS Studio - Free and open source software for live streaming and screen recording 项目地址: https://gitcode.com/GitHub_Trending/ob/obs-studio 远程上课,你只想…

作者头像 李华
网站建设 2026/9/3 7:03:41

图像编辑模型实战:从原理到接入MAI-Image-2.6-Preview

最近在整理图像编辑模型选型时,看到 MAI-Image-2.6-Preview 登顶图像编辑榜的消息,很多同学在评论区问这个模型到底能做什么编辑、效果怎么验证、接入成本高不高。本文先不跟着榜单宣传走,而是从技术角度拆解图像编辑模型的基本原理、环境准备…

作者头像 李华
网站建设 2026/9/5 19:13:41

AI的“智慧傲慢”:流畅自信不等于可靠

这个标题翻译过来是——“AI带来的只是某种智慧的傲慢”。可能有点刺耳,但真正长期使用大模型、做过 AI 应用开发、把它放到生产线上去跑过的人,大概率会停下来想一想:我们是不是正在用“说话足够自信”,替代“理解足够可靠”&…

作者头像 李华
网站建设 2026/9/4 8:17:50

PDFium 集成深度解析:LiteParse 如何用 C 库提取文本

PDFium 集成深度解析:LiteParse 如何用 C 库提取文本 【免费下载链接】liteparse A fast, helpful, and open-source document parser 项目地址: https://gitcode.com/GitHub_Trending/li/liteparse LiteParse 是一款快速、开源的文档解析器,而它…

作者头像 李华