OOB 信号详解:COMINIT、COMWAKE、COMRESET 时序与检测

做 SATA bring-up,最难抓的是啥?我猜不少人会说是 OOB 信号。说白了,OOB(Out-of-Band)信号就是设备在链路初始化时,用特定的脉冲序列来“打招呼”的方式。它不靠数据线传输,而是靠差分信号线上的电平跳变来传递信息。

我个人习惯把 OOB 看作“三剑客”:COMRESET、COMINIT、COMWAKE。它们三个的时序和检测,几乎决定了链路能否建立。搞不清楚这个,光看着示波器上的毛刺,你根本不知道是设备没响应,还是 Host 发错了。

OOB 信号的“对话”流程

链路刚开始建立时,到底谁先开口?Host 还是 Device?答案是:看谁主动。来看看标准的握手顺序:

  1. COMRESET —— Host 端先发,强制复位 Device。这个信号一出现,Device 必须把自己初始化到 Gen1 速度。
  2. COMINIT —— Device 收到 COMRESET 后,需要回复这个信号,告诉 Host“我在线,准备好了”。
  3. COMWAKE —— 这是“唤醒”信号,由主动发起低速通信的一端发送,用来把链路从省电状态拉回来。

你想想看,这三个信号的时序如果任何一个出问题,比如脉冲宽度不够、间隔太长,接收端就会直接忽略掉。我记得有一次,一台 Device 总是 Link Reset 失败,查了三天,最后发现是 COMINIT 脉冲宽度差了那么 0.1ns。

COMRESET 详解

COMRESET 由 Host 发出,用来强制初始化链路。它的核心参数:

参数定义最小值最大值说明
COMRESET 脉冲宽度差分信号 D+/D- 同时拉高的持续时间320 ns—至少持续 320 ns
COMRESET 间隔两次脉冲之间差分信号复位的低电平时间160 ns—通常保持 160 ns
COMRESET 发送次数连续发送的脉冲个数615标准要求 6 个,Host 可能发更多
COMRESET 脉冲序列总时长从第一个脉冲开始到最后一个结束3.36 μs—6 个脉冲 + 5 个间隔

为什么脉冲宽度要这么长?其实是为了容错。SATA 链路工作在不同速度下,接收端需要一定时间来检测这个“长脉冲”。如果 Host 发的脉冲太短,Device 可能根本感知不到。

调试小技巧: 用示波器抓 COMRESET 时,我建议把时间基调到 100ns/div 左右。从差分对的正负端同时抓,看它们是不是同时拉高。如果差了一点点,那可能是 PCB 走线不等长导致的。

COMINIT 详解

COMINIT 是 Device 对 COMRESET 的回应。它的时序和 COMRESET 一模一样,只是方向不同。

参数定义最小值最大值说明
COMINIT 脉冲宽度Device 发送的每个脉冲宽度320 ns—与 COMRESET 一致
COMINIT 间隔脉冲间复位低电平时间160 ns—标准值
COMINIT 发送次数Device 发送的脉冲个数615通常也是 6 个
COMINIT 发出延迟Device 收到 COMRESET 后到发出 COMINIT 的时间10 μs30 μs必须在收到后立刻回复

等一下,有个容易踩的坑 —— Device 必须在收到 COMRESET 后的 10 μs 到 30 μs 内发出 COMINIT。如果你发现 Device 迟迟不回,很可能是它内部的 PHY 没准备好。我曾经遇到一个情况,芯片复位时序太长,导致 COMINIT 发出时已经超过了 30 μs,Host 直接认为 Device 丢失。

避坑指南: 检查 COMINIT 的发出延迟时,别忘了考虑 PHY 内部 PLL Lock 的时间。有些芯片需要先锁相才能产生 OOB 脉冲,这时候 10 μs 真的非常紧张。

COMWAKE 详解

COMWAKE 是“唤醒”信号,用来从省电状态(比如 Partial、Slumber)恢复。它的参数略有不同:

参数定义最小值最大值说明
COMWAKE 脉冲宽度每个脉冲宽度160 ns—注意:这比 COMRESET 的脉冲短一半
COMWAKE 间隔脉冲间低电平时间80 ns—对应短间隔
COMWAKE 发送次数脉冲个数615标准是 6 个
COMWAKE 检测阈值接收端判断为有效 COMWAKE 的脉冲数24有些芯片检测到 2 个脉冲就认为有效

这里我着重提一下检测阈值的差异。有些 Host 端芯片设计成检测到 2 个 COMWAKE 脉冲就认为是有效唤醒,有的是 3 个甚至 4 个。如果把 Device 和 Host 的阈值搞反了,你可能会发现链路唤醒后一直不稳定,时断时续。

OOB 信号的检测流程

检测 OOB 信号,本质上就是个“看脉冲”的过程。看脉冲的宽度、看脉冲的间隔、看脉冲的个数。Host 和 Device 内部都有一个状态机在跑,专门做这个检测。我给个简化的流程:

  1. 状态机起始: 空闲状态,等待 OOB 信号出现。
  2. 检测脉冲前沿: 当差分信号同时拉高,启动计时器。
  3. 检测脉冲后沿: 差分信号回到零,检查脉冲宽度是否在允许范围内。
  4. 检查间隔: 等待下一个脉冲,并检查间隔时间。
  5. 累积计数: 每检测到一个有效脉冲,计数器加 1。
  6. 符合阈值: 当连续检测到脉冲个数达到阈值(通常 2-4 个),判定为有效的 OOB 序列。

在实际调试中,我经常用 FPGA 内部的 ILA 或逻辑分析仪抓取这些状态机的状态。而且注意,检测不是一出现脉冲就判定,而是要等连续几个脉冲都符合条件。为什么?因为单脉冲可能被噪声干扰。我记得有一次,就是噪声干扰让状态机错误地认为收到了 COMINIT,结果链路直接挂死。

OOB 检测性能对比:硬件 vs 软件

检测方式优点缺点适用场景
硬件状态机检测速度快,纳秒级响应,不占用 CPU设计复杂,需要验证各种边界常规 SATA 控制器实现
软件轮询检测灵活性高,可以动态调整阈值速度慢,容易受 CPU 负载影响调试阶段、测试用 FPGA
混合方式硬件检测+软件配置需要对接配置接口大部分商业 IP 的做法

大部分商用 SATA IP 都用硬件状态机。但在 bring-up 初期,我建议你让软件参与进来,配置几个 threshold 寄存器,这样你就能灵活调整,快速判断是硬件还是时序问题。

核心知识体系一览

下面这张图总结了 OOB 信号的核心要素:三个关键序列、对应的脉冲参数,以及检测流程。我把它当作调试时的“导航图”。

OOB 信号核心知识体系 COMRESET Host → Device COMINIT Device → Host COMWAKE 双向唤醒 脉冲参数 • 脉冲宽:≥320 ns • 间隔:≥160 ns • 次数:6~15 个 脉冲参数 • 脉冲宽:≥320 ns • 延迟:10~30 μs • 次数:6~15 个 脉冲参数 • 脉冲宽:≥160 ns • 间隔:≥80 ns • 检测阈值:2~4 个 OOB 检测核心:脉冲宽度判定 + 间隔判定 + 连续计数 三个序列共享相同的检测判决逻辑

做 OOB bring-up,你不需要会背所有参数,但必须知道三个关键点:脉冲宽度、间隔、连续计数。每个序列在这三项上的数值各有不同,搞混了就会出问题。

训练建议: 找一块 SATA 测试板,尝试用逻辑分析仪抓取一次完整的 Link Reset 过程。你会看到一串脉冲,把它们的顺序和参数和上面的图对照一遍,很快就能上手了。