ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

M95M04读取全FF?从SPI链路到协议时序的排查指南

M95M04读取全FF?从SPI链路到协议时序的排查指南 1. 现象确认你真的遇到问题了吗1.1 先把读取全FF和芯片本来就是FF区分开很多人第一次调M95M04把读回来的数据打印出来发现全是0xFF第一反应就是芯片坏了或者代码写错了。但SPI EEPROM有一个容易被忽略的基本事实全新出厂的芯片所有存储单元的内容就是0xFF。这不是故障这是正常的初始状态。所以遇到全FF第一步不是怀疑代码而是先问自己一个问题这块芯片之前有没有写入过有效数据如果是全新批次从没写过那读出来全FF完全正确。怎么验证呢很简单往一个非0xFF的地址写一个已知值比如0xA5然后重新读出来。如果能正确读回0xA5说明芯片和通信链路都是好的。如果写0xA5之后再读还是0xFF那才真正进入了排查流程。这里还要提醒一点M95M04的写操作不是发完WRITE指令就立刻完成的它需要等待内部写周期完成。判断方式就是轮询状态寄存器RDSR指令0x05里的WIP位。很多人第一次用写完马上读读到的是旧值就误以为写入失败其实只是还没写完。这个我在后面写操作验证那部分会展开。1.2 用RDSR快速验证SPI链路是否有反应在怀疑世界之前先做一个最省事的实验读状态寄存器。状态寄存器不是存储区域它是芯片内部的工作状态寄存器读它不需要地址指令也简单CS拉低发0x05然后持续产生时钟芯片就会把状态寄存器的值从MISO吐出来。如果SPI链路是通的读出来的状态寄存器值一般在0x00、0x02、0x04这些范围里。即使是全新芯片也应该是明确的状态值。如果你发完0x05之后MISO上回来的依然全是0xFF那基本可以锁定问题出在通信链路本身——芯片根本没有响应你的指令。这一步的价值在于它能把问题快速分成两类现象判断RDSR能读到正常状态值但READ读存储区全FF链路基本通问题在READ指令、地址或存储区本身RDSR也全是FF链路层或芯片供电/选通出了问题我调试过很多SPI器件这个区分方法帮我把排查范围缩小了一半以上。如果你在RDSR这一步就卡住了后面章节值得逐字看。1.3 记录现象单字节全FF还是随机地址全FF拿到全FF这个现象之后我建议你把怎么读的完整记录一下。是固定读一个地址还是从0x000000开始连续读是读到了全芯片的FF还是只有某些地址段是FF这些细节直接决定排查方向。比如说如果只有前几个地址返回FF后面能读到数据那可能是地址格式错了——地址的高位被忽略导致你实际访问的地址不对。如果所有地址都是FF那问题更偏向链路层或者芯片根本不在工作状态。还有一个小经验用示波器或者逻辑分析仪之前先在代码里加一个简单的功能——读RDSR并把结果打印出来。不要上来就分析整段读操作先把最基础的指令跑通。我在实际项目中从来没有跳过这一步它虽然简单但每次都能节省至少半小时的排查时间。2. 读操作时序的真正细节全FF在协议层意味着什么2.1 引脚定义里最容易踩的三个坑M95M04是SOIC-8封装8个引脚不算多但恰恰因为引脚少很多人不看数据手册直接接线然后就出事了。我说三个高频坑。第一个把1脚S和2脚Q接反。M95M04的1脚是片选CS数据手册上叫S2脚是数据输出Q对应MISO。很多其他SPI芯片的引脚排列不是这样如果你之前用过别的型号很容易套用旧的习惯结果就是CS信号没接到芯片上芯片从头到尾都没被选中MISO自然一直输出高阻态——你读到的就是全FF。第二个把5脚D和6脚C接反。5脚是数据输入D对应MOSI6脚是时钟C对应SCLK。这两个接反的后果很迷惑有时候能读出数据有时候读不到因为芯片把时钟和数据的角色对调了协议完全乱套。如果你反复调试都找不到原因用万用表把每一根线从头到尾量一遍重点看这几个引脚有没有接对。第三个7脚HOLD悬空。这个坑我后面专门用一整节来讲因为它太隐蔽了——很多人只关注CS、SCLK、MOSI、MISO这四根线WP和HOLD接不接觉得无所谓但HOLD悬空恰恰是读全FF的一个经典元凶。2.2 READ指令的字节序与24位地址M95M04的容量是4Mbit也就是512KB。这个容量决定了它不能用16位地址——16位地址最多访问64KB512KB至少需要19条地址线。因此M95M04的READ指令使用的是24位地址格式。完整的读操作时序是CS拉低然后依次发送一个字节的读指令0x03紧接着发送三个字节的地址先高位后低位地址之后继续产生时钟芯片就会把对应地址的数据从MISO线上送出来。整个过程CS要保持低电平读完最后一个字节之后再拉高。很多人在这里犯的错误是照搬小容量芯片的代码只发送两个字节的地址。结果就是地址对不上读到的地址完全不是你想要的。更麻烦的是如果你只发了两个字节地址芯片会把后面读数据阶段的前一个字节误当成第三个地址字节导致第一个有效数据被吞掉后面读取的位置整体偏移。这种问题不会表现为全FF但会出现读到的数据莫名其妙错位的现象。还有一点需要注意24位地址虽然有三字节但M95M04实际上只用到A16~A0512KB需要19位地址最高字节的bit7~bit3应该设置为0。如果你不小心把高位字节写成了0xFF芯片虽然会忽略某些位但某些兼容芯片的行为可能不完全一致这也是一个值得留意的点。2.3 收到FF在协议层面意味着什么从协议角度看SPI读取EEPROM时如果MISO线上持续收到0xFF只有几种可能。第一种芯片根本没驱动MISO线。EEPROM没有被CS选中或者芯片处于HOLD状态或者芯片供电异常此时MISO引脚是高阻态。而大多数电路板上MISO线会有一个上拉电阻有些是MCU内部上拉高阻态被上拉成高电平SPI外设采到的每一位都是1拼出来就是0xFF。第二种时钟采样沿不匹配。任何SPI设备都有一个时钟极性和相位要求M95M04支持SPI Mode 0CPOL0, CPHA0和Mode 3CPOL1, CPHA1。如果你配置成了Mode 1或Mode 2主控在错误的时钟边沿采样数据采到的可能全是1。这种情况在逻辑分析仪上看MISO上其实是有信号的只是你采样采不到正确的位置。第三种芯片实际上在正常工作但你读的存储区域内容本来就是FF。这一点我前面提到过出厂状态全FF或者是之前擦除过。想清楚这几种可能排查思路就清楚了先确认芯片有没有被选通再确认MISO线上有没有实际信号最后再核对采样沿是否正确。下面这章我会按顺序把每一步怎么查讲透。3. 从物理层到协议层四步排查链路详解3.1 第一步万用表把八根线全部过一遍排查SPI问题我从不让别人先改代码。第一件事永远是用万用表把硬件连接从头到尾过一遍。这不是浪费时间恰恰是最快的排查方式——很多灵异问题最后都证明只是杜邦线松了或者焊错了。你要量的东西包括VCC引脚的电压是不是在规格范围内M95M04支持1.8V~5.5V但要注意如果MCU是3.3V芯片供电也应该是3.3V5V供电的话IO电平匹配要另行确认VSS和系统地是不是同一电位SCS、DMOSI、CSCLK、QMISO四根线分别接到主控的哪个引脚每个引脚有没有接对WP和HOLD是不是都接在了高电平具体原因后面讲。这里有个细节用万用表导通档量杜邦线的时候一定要用手轻轻晃动线材两端看阻值有没有跳动。杜邦线接触不良是最常见的隐性故障之一它可能让你花费几小时排查但问题其实只是一根线虚接。如果万用表量完都正常下一步我会把CS、SCLK、MOSI、MISO这四根线在原理图或开发板丝印上重新核对一遍——特别是M95M04的引脚顺序1脚是S2脚是Q5脚是D6脚是C这点和很多其他厂牌EEPROM不完全一致。接线错位的问题靠看代码是看不出来的只能靠硬件核对。3.2 第二步逻辑分析仪直接抓波形别用猜的排查SPI问题时逻辑分析仪是性价比最高的工具。几十块钱的8通道逻辑分析仪就够用了配合Saleae Logic或者PulseView软件能够直接把CS、SCLK、MOSI、MISO四根线上的信号抓出来看。配置上要注意采样率至少设置到10MHz以上25MHz更保险否则波形细节可能抓不全。触发方式选择CS的下降沿因为一次SPI事务从CS拉低开始。抓完波形之后你会面临几种情况CS从始至终保持高电平说明主控代码里CS引脚根本没拉低或者是GPIO配置成了其他功能没有真正输出低电平。这个情况在软件里查先确认GPIO模式和初始电平。CS拉低了但没有时钟SPI外设没有被激活。检查SPI外设的使能、时钟使能以及是否有DMA配置错误导致传输根本没启动。有时钟但MOSI上没有指令MOSI引脚复用配置错误或者SPI发送缓冲区没写入数据。先确认MOSI对应的GPIO复用功能。四根线都有信号但MISO恒为高电平芯片没有响应。这时候重点检查芯片供电、HOLD引脚、WP引脚甚至是芯片本身有没有被焊接/接触不良。MISO上有翻转信号但软件解出来还是FF大概率是SPI Mode配置错误采样沿不对。我在实际调试中逻辑分析仪一接上问题基本就定位到具体某一层了。这里有个小技巧如果逻辑分析仪显示MISO有信号但协议解析器解出来全是0xFF可以手动看波形里MISO的电平变化——如果波形有低电平出现那说明芯片确实发了数据只是你的采样点不对问题出在SPI模式或者采样沿配置上。3.3 第三步核对SPI模式、速率和引脚复用逻辑分析仪排除了物理层问题之后就该仔细核对软件配置了。M95M04的数据手册明确支持SPI Mode 0和Mode 3如果你的配置是Mode 1或Mode 2读操作大概率会出现数据异常。这里快速解释一下SPI模式的四个组合Mode 0是时钟空闲为低、数据在第一个边沿上升沿采样Mode 1是时钟空闲为低、数据在第二个边沿下降沿采样Mode 2是时钟空闲为高、数据在第一个边沿下降沿采样Mode 3是时钟空闲为高、数据在第二个边沿上升沿采样。M95M04支持Mode 0和Mode 3也就是说它不在乎时钟空闲极性但要求数据在偶数边沿采样。如果配置错了你从逻辑分析仪上看MISO可能是有数据的但数据就是不对。这时候直接把SPI初始化里的CPOL和CPHA改成Mode 0或者Mode 3重新测试即可。速率也是一个容易被忽视的因素。M95M04的最大SPI时钟频率受工作电压影响5V供电时一般能做到10MHz左右3.3V时会低一些。但在调试阶段我强烈建议你把SPI时钟降到100kHz~1MHz。这个建议不是没道理的杜邦线、面包板、飞线这些连接方式在高速下会有信号完整性问题——振铃、反射、边沿变缓都会导致通信失败。先把速率降下来确认功能没问题再逐步提高频率测试。引脚复用方面特别是STM32这类MCU同一个引脚可能有多达十几个复用功能。如果GPIO复用配置成了UART或者其他功能SPI外设的信号就出不去。打开你的工程逐个核对SCLK、MOSI、MISO、CS四个引脚的GPIO初始化代码确认它们都正确分配给了SPI外设。3.4 第四步用写操作验证芯片是否可编程如果前面三步都查完了RDSR也能读到状态值但存储区读出来全是FF那就要做一次写操作来验证芯片到底能不能写入数据。这一步能把芯片坏和代码问题彻底分开。写操作的流程是先发WREN指令0x06把写使能锁存器置1然后发WRITE指令0x02接着发送24位地址最后发送要写入的数据最多128字节M95M04的页大小是128字节。写完需要通过轮询RDSR查看WIP位是否清零如果WIP为1说明芯片还在内部写周期必须等它写完再读。为了测试你可以先写一个单字节比如往地址0x000000写0xA5等WIP清零后再读0x000000看看是不是0xA5。如果写入后再读还是FF这时候再看几个点WP引脚是不是被拉低了WP拉低且状态寄存器BP位非0时写操作会被拒绝。测试时直接把WP接VCC最省事。有没有忘记发WRENWREN没发或者发送失败WRITE指令会被芯片忽略。写的是不是超过了页边界跨页写入时超过了128字节边界地址会回卷到页内开头覆盖掉同页之前的数据。通常走到这一步问题已经水落石出了——要么芯片物理损坏要么某个配置漏掉了。只要RDSR能读、写操作能生效全FF的问题就基本解决。4. 高频根因复盘我把实际踩过的坑都列在这里4.1 HOLD引脚悬空导致的灵异现象这是我认为最值得单独说的问题。M95M04的7脚是HOLD低电平有效作用是暂停芯片与主控之间的通信。手册上明确写了不用的时候必须接高电平或者由主控控制。但很多人包括我早期觉得这只是个辅助引脚悬空应该没事——结果芯片的实际表现就是偶尔正常偶尔全FF完全不可控。HOLD引脚悬空意味着它的电平是不确定的可能因为电路板漏电、空间电磁干扰、甚至手指靠近板子而随机跳变。一旦HOLD被拉低芯片会立即停止响应忽略D和C上的信号Q输出变成高阻态。这时候从主控看去就是读不出来数据反复读都是FF。这种问题的迷惑性在于它不是100%复现的。你可能刚上电的时候能读到数据动一下杜邦线或者过了几秒就全FF了。如果你遇到这种时好时坏的情况第一个要查的就是HOLD引脚。解决办法很简单把HOLD引脚直接接到VCC上。同理WP引脚也一样如果你不需要写保护功能就把WP也接到VCC。这两个引脚千万不要悬空。4.2 片选信号失效的版本管理问题CS引脚接对了代码也写了CS拉低但逻辑分析仪显示CS从来没低过——这听起来像硬件问题但我在实际项目中遇过一次诡异的版本管理问题代码在开发板上调好了移植到量产板上却全FF。最后发现是CS引脚在原理图上用的是PA4但固件里GPIO初始化写的是PA5。原理图、PCB、固件、文档四方各写各的各有各的版本问题就被埋进去了。调试这种问题最快的方式就是拿逻辑分析仪或者示波器探头点在CS引脚上直接在代码里强制拉低CS看电平有没有变化。如果MCU引脚输出正常那就是板子走线或焊接问题如果MCU引脚没有输出那就是代码里GPIO的编号、时钟使能、或者复用配置错了。还有一点某些MCU的SPI外设有硬件NSS功能。如果你把某个引脚的复用功能配置成了SPI_NSS而代码里又试图用普通GPIO拉低它两者可能互相冲突。建议要么完全使用硬件NSS要么完全使用软件GPIO模拟CS不要混着用。4.3 MISO电平浮动与上拉电阻的博弈前面提到过芯片不驱动MISO时MISO引脚是高阻态如果总线上有上拉电阻就会被拉高读到0xFF。这里有个值得展开的细节有些MCU的GPIO内部上拉电阻是可配置的如果你把MISO对应的GPIO配置成了内部上拉那在芯片没有响应时读到FF几乎是必然的。如果你把内部上拉关掉MISO浮空时读到什么取决于电路板布局和噪声可能是不稳定的随机值。那这是不是意味着内部上拉不能开不是。关键在于你要清楚MISO上有上拉电阻只是为了在总线空闲时给一个确定电平防止误触发。真正的问题是芯片没有驱动MISO你要做的是找到原因而不是纠结上拉电阻。不过有一种情况例外如果MISO线上连接了多个SPI设备且设备没有三态输出控制极罕见某些设备可能会在未选中时驱动总线导致电平打架。M95M04不会这样它的Q引脚在未选中时是高阻。所以排查思路要清晰MISO电平浮动只是表象根因在芯片没有响应。4.4 地址位宽不匹配两个字节地址的惯性思维如果你之前用过M95080、M95128这类小容量EEPROM它们的地址都是16位代码里发送的地址就是两个字节。换到M95M04如果还沿用两个字节地址读出来的内容是错的而且看起来非常奇怪——有些地址能读到数据有些地址读到的内容和你预期完全对不上。原因很直白M95M04需要三个字节地址你少发了一个字节芯片就会把读数据阶段的第一个字节当成地址导致后续数据输出整体错位。这种问题在代码层面很好修把地址发送部分从两个字节改成三个字节。但要注意发送顺序MSB在前先发最高字节。例如地址0x0000A5就应该依次发送0x00、0x00、0xA5三个字节。另外即使发了三个字节也要注意最高字节里没有用到的位要置0。比如0x123456这个地址对于M95M04来说超出了容量范围芯片的行为在数据手册上可能没有明确说明但正常使用中不要发送超出0x07FFFF的地址。4.5 全新芯片的出厂FF并非故障我见过有人拿着全新的M95M04测了一下读出全FF然后直接判定芯片是坏的。如果芯片在寿命周期内完全没写过就读全FF这不是故障。真正要辨别芯片没数据和芯片读不到数据最直接的办法就是写一个已知字节再读。测试代码我建议这样写初始化SPI之后先读RDSR确认链路正常再执行WREN写0xA5到0x000000等待WIP清零最后读0x000000。如果读回来是0xA5芯片就是好的。如果读回来还是0xFF再按前面的排查步骤走。5. 实际操作中的几点补充与一个小技巧写了这么多我再分享几个实际调试中的细节体会供你参考。5.1 关于电平匹配的补课M95M04是一个宽电压器件1.8V到5.5V都能工作。但如果你用的是5V供电的M95M04而MCU是3.3V的那MOSI、SCLK、CS这些信号从3.3V MCU输出到5V芯片输入高电平阈值一般能接受但MISO从5V芯片输出到3.3V MCU就可能超过3.3V的耐压值。这在正规设计里需要电平转换但在调试阶段很多人直接用分压电阻或者干脆硬接。如果你硬接了且MCU的MISO引脚内部有保护二极管可能会导致信号被钳位波形异常。稳妥的做法是调试时让芯片和MCU使用同一个电压域比如都3.3V先把功能跑通再说。5.2 一个百试百灵的定位技巧最后分享一个我用了很多年的小技巧在排查全FF问题时把SPI时钟频率直接降到最低可用的值比如100kHz然后用逻辑分析仪抓一次完整的READ操作波形把CS、SCLK、MOSI、MISO四根线一次看全。在低速下波形非常干净很容易看出问题所在如果CS没拉低看代码如果MOSI上没有完整指令看发送如果MISO恒高看芯片侧。这个方法听起来简单但它能强制你跳出自责代码的惯性从更全局的视角看问题。我靠这个方法解决过的SPI疑难杂症不下五个——不是因为我聪明而是因为低速波形下每个细节都看得清清楚楚。5.3 不要低估供电和去耦电容还有一个细节M95M04的供电引脚旁边一定要放一个0.1uF的去耦电容离VCC引脚越近越好。如果没有这个电容芯片在内部写周期尤其是在写入大量数据时会让电源产生明显的纹波可能导致逻辑电平误判表现为读操作偶尔正常偶尔全FF。调试时可以在芯片的VCC和VSS之间临时焊一个电容很多时候这个动作能让莫名其妙的问题直接消失。读取全FF这个问题本质上就是SPI通信链路中某个环节断了或者错位了。把问题一层层拆开从硬件连接到协议时序从模式配置到地址位宽每个环节都验证到位你定位到的速度会比你想象的快得多。
返回列表