
MISO线上出现20ns左右的窄脉冲而从机压根没有被置为发送Transmit模式——如果是第一次遇到你八成会怀疑是示波器触发起伏或者干脆以为是电磁干扰。我第一次在SPI总线调试中抓到这根细细的毛刺时也是先拍了张照留档然后怀疑自己是不是探头没接地。后来连续复现才发现它每次都出现在主机拉低CS、SCK开始翻转的那个时间窗口里跟从机的发送使能状态完全无关这才意识到问题不简单。这篇记录就以这个现象为入口把SPI主从通信里MISO输出机制、20ns脉冲的常见来源、定位方法和修复措施完整梳理一遍希望能让同样被这类窄毛刺折磨过的嵌入式开发者和FPGA逻辑工程师少走一些弯路。1. 现象复盘20ns脉冲在SPI总线里到底意味着什么1.1 先把现象量化20ns是多大的事20ns的脉冲在SPI调试里算是一个非常典型的窄毛刺信号。如果你跑的是低速SPI比如SCK只有1MHz时钟周期1us20ns只占周期的2%普通示波器上甚至不容易看清但如果跑的是10MHz甚至更高频率的SPI周期100ns或者50ns20ns就占了整个时钟周期的20%到40%这个毛刺已经完全可以被采样点抓到了。再从信号带宽的角度算一下一个上升、下降时间大约10ns的脉冲等效信号带宽约0.35/10ns35MHz。也就是说如果你的示波器带宽只有20MHz看到的波形幅度会明显偏小、脉宽被拉宽甚至干脆被滤成一小团噪声。反过来能用示波器清晰看到20ns的毛刺说明仪器带宽至少在100MHz以上这一点后面排查时还要用到。所以在讨论这个问题之前得先建立概念20ns对SPI来说已经不是可以忽略不计的微小噪声它已经进入了高速信号完整性的范畴。1.2 从机“未编程为发送”时MISO应该是高阻还是固定电平SPI是四线全双工协议主机通过MOSI向从机发数据从机通过MISO向主机回数据。问题是如果从机此刻根本没有要发送的数据MISO应该是什么状态很多人以为是输出低电平或者输出高电平其实都不对。在标准SPI总线上MISO通常由多个从机共用。为了避免多个从机同时驱动同一根线造成短路SPI从机的MISO必须通过片选CS/NSS来隔离只有当自己的CS被拉低、且从机确认自己要响应主机的这次事务时MISO的输出驱动器才被使能呈现推挽输出其余时间MISO必须处于高阻态Hi-Z。高阻态不是逻辑0也不是逻辑1而是引脚对总线而言就像“断开”。如果从机没有编程为发送模式MISO理应就是高阻。此时总线上如果有外部上拉电阻MISO会被拉到一个确定电平线上也不该出现任何脉冲。所以当你在MISO上抓到20ns的脉冲本质上说明从机在某个瞬间“违反”了这个高阻约定偷偷驱动了一下总线或者是外部干扰耦合到了MISO线上。这个基础概念非常重要因为后面所有排查方向的起点都是它毛刺到底是从机内部在驱动还是总线被外部信号耦合了。2. 根因分析20ns毛刺从哪里来2.1 从机输出使能逻辑的时序漏洞第一种可能是从机内部的三态门控制逻辑本身产生了毛刺。这种情况在FPGA模拟SPI从机时特别常见。举个简单的例子有人在HDL里写assign miso (cs_n 1b0 tx_en 1b1) ? tx_data : 1bz;这行代码看起来没什么问题但tx_en如果是由另一个时钟域产生的信号或者是一个未经过同步的组合逻辑信号当tx_en在SCK边沿附近发生变化时三态门的OE控制信号就可能出现极短的竞争冒险。在那一瞬间OE先变成了1miso引脚被瞬间拉起来然后OE再变回0引脚重新回到高阻于是就在MISO线上留下了一个20ns左右的窄脉冲。这类问题在FPGA从机项目里比较容易复现。定位时的特征也很明显毛刺总是在SCK边沿附近出现跟tx_en信号的翻转时刻强相关软件层面无论怎么改SPI配置都消不掉因为它根本不是SPI外设的行为而是数字逻辑输出使能信号没有做时钟同步造成的。解决思路也简单输出使能信号必须用SCK时钟域打拍同步或直接把三态控制放到寄存器输出级。如果FPGA驱动能力强毛刺很容易直接打到VCC或GND附近幅度非常大主机端必然收到错数据。MCU内部的SPI外设虽然没有FPGA那么自由但在低功耗、复位释放、外设尚未初始化但引脚已经被复用的情况下IO控制逻辑里的静态使能信号也可能短暂建立起来产生同样的瞬态驱动。这类问题往往和MCU引脚默认状态、SPI外设初始化顺序有关下面详细说。2.2 GPIO复用配置与初始化顺序的坑MCU平台上MISO毛刺最常见的原因其实是GPIO配置和SPI外