OOB 信号详解:COMINIT、COMWAKE、COMRESET 时序与检测
做 SATA bring-up,最难抓的是啥?我猜不少人会说是 OOB 信号。说白了,OOB(Out-of-Band)信号就是设备在链路初始化时,用特定的脉冲序列来“打招呼”的方式。它不靠数据线传输,而是靠差分信号线上的电平跳变来传递信息。
我个人习惯把 OOB 看作“三剑客”:COMRESET、COMINIT、COMWAKE。它们三个的时序和检测,几乎决定了链路能否建立。搞不清楚这个,光看着示波器上的毛刺,你根本不知道是设备没响应,还是 Host 发错了。
OOB 信号的“对话”流程
链路刚开始建立时,到底谁先开口?Host 还是 Device?答案是:看谁主动。来看看标准的握手顺序:
- COMRESET —— Host 端先发,强制复位 Device。这个信号一出现,Device 必须把自己初始化到 Gen1 速度。
- COMINIT —— Device 收到 COMRESET 后,需要回复这个信号,告诉 Host“我在线,准备好了”。
- COMWAKE —— 这是“唤醒”信号,由主动发起低速通信的一端发送,用来把链路从省电状态拉回来。
你想想看,这三个信号的时序如果任何一个出问题,比如脉冲宽度不够、间隔太长,接收端就会直接忽略掉。我记得有一次,一台 Device 总是 Link Reset 失败,查了三天,最后发现是 COMINIT 脉冲宽度差了那么 0.1ns。
COMRESET 详解
COMRESET 由 Host 发出,用来强制初始化链路。它的核心参数:
| 参数 | 定义 | 最小值 | 最大值 | 说明 |
|---|---|---|---|---|
| COMRESET 脉冲宽度 | 差分信号 D+/D- 同时拉高的持续时间 | 320 ns | — | 至少持续 320 ns |
| COMRESET 间隔 | 两次脉冲之间差分信号复位的低电平时间 | 160 ns | — | 通常保持 160 ns |
| COMRESET 发送次数 | 连续发送的脉冲个数 | 6 | 15 | 标准要求 6 个,Host 可能发更多 |
| COMRESET 脉冲序列总时长 | 从第一个脉冲开始到最后一个结束 | 3.36 μs | — | 6 个脉冲 + 5 个间隔 |
为什么脉冲宽度要这么长?其实是为了容错。SATA 链路工作在不同速度下,接收端需要一定时间来检测这个“长脉冲”。如果 Host 发的脉冲太短,Device 可能根本感知不到。
COMINIT 详解
COMINIT 是 Device 对 COMRESET 的回应。它的时序和 COMRESET 一模一样,只是方向不同。
| 参数 | 定义 | 最小值 | 最大值 | 说明 |
|---|---|---|---|---|
| COMINIT 脉冲宽度 | Device 发送的每个脉冲宽度 | 320 ns | — | 与 COMRESET 一致 |
| COMINIT 间隔 | 脉冲间复位低电平时间 | 160 ns | — | 标准值 |
| COMINIT 发送次数 | Device 发送的脉冲个数 | 6 | 15 | 通常也是 6 个 |
| COMINIT 发出延迟 | Device 收到 COMRESET 后到发出 COMINIT 的时间 | 10 μs | 30 μs | 必须在收到后立刻回复 |
等一下,有个容易踩的坑 —— Device 必须在收到 COMRESET 后的 10 μs 到 30 μs 内发出 COMINIT。如果你发现 Device 迟迟不回,很可能是它内部的 PHY 没准备好。我曾经遇到一个情况,芯片复位时序太长,导致 COMINIT 发出时已经超过了 30 μs,Host 直接认为 Device 丢失。
COMWAKE 详解
COMWAKE 是“唤醒”信号,用来从省电状态(比如 Partial、Slumber)恢复。它的参数略有不同:
| 参数 | 定义 | 最小值 | 最大值 | 说明 |
|---|---|---|---|---|
| COMWAKE 脉冲宽度 | 每个脉冲宽度 | 160 ns | — | 注意:这比 COMRESET 的脉冲短一半 |
| COMWAKE 间隔 | 脉冲间低电平时间 | 80 ns | — | 对应短间隔 |
| COMWAKE 发送次数 | 脉冲个数 | 6 | 15 | 标准是 6 个 |
| COMWAKE 检测阈值 | 接收端判断为有效 COMWAKE 的脉冲数 | 2 | 4 | 有些芯片检测到 2 个脉冲就认为有效 |
这里我着重提一下检测阈值的差异。有些 Host 端芯片设计成检测到 2 个 COMWAKE 脉冲就认为是有效唤醒,有的是 3 个甚至 4 个。如果把 Device 和 Host 的阈值搞反了,你可能会发现链路唤醒后一直不稳定,时断时续。
OOB 信号的检测流程
检测 OOB 信号,本质上就是个“看脉冲”的过程。看脉冲的宽度、看脉冲的间隔、看脉冲的个数。Host 和 Device 内部都有一个状态机在跑,专门做这个检测。我给个简化的流程:
- 状态机起始: 空闲状态,等待 OOB 信号出现。
- 检测脉冲前沿: 当差分信号同时拉高,启动计时器。
- 检测脉冲后沿: 差分信号回到零,检查脉冲宽度是否在允许范围内。
- 检查间隔: 等待下一个脉冲,并检查间隔时间。
- 累积计数: 每检测到一个有效脉冲,计数器加 1。
- 符合阈值: 当连续检测到脉冲个数达到阈值(通常 2-4 个),判定为有效的 OOB 序列。
在实际调试中,我经常用 FPGA 内部的 ILA 或逻辑分析仪抓取这些状态机的状态。而且注意,检测不是一出现脉冲就判定,而是要等连续几个脉冲都符合条件。为什么?因为单脉冲可能被噪声干扰。我记得有一次,就是噪声干扰让状态机错误地认为收到了 COMINIT,结果链路直接挂死。
OOB 检测性能对比:硬件 vs 软件
| 检测方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 硬件状态机检测 | 速度快,纳秒级响应,不占用 CPU | 设计复杂,需要验证各种边界 | 常规 SATA 控制器实现 |
| 软件轮询检测 | 灵活性高,可以动态调整阈值 | 速度慢,容易受 CPU 负载影响 | 调试阶段、测试用 FPGA |
| 混合方式 | 硬件检测+软件配置 | 需要对接配置接口 | 大部分商业 IP 的做法 |
大部分商用 SATA IP 都用硬件状态机。但在 bring-up 初期,我建议你让软件参与进来,配置几个 threshold 寄存器,这样你就能灵活调整,快速判断是硬件还是时序问题。
核心知识体系一览
下面这张图总结了 OOB 信号的核心要素:三个关键序列、对应的脉冲参数,以及检测流程。我把它当作调试时的“导航图”。
做 OOB bring-up,你不需要会背所有参数,但必须知道三个关键点:脉冲宽度、间隔、连续计数。每个序列在这三项上的数值各有不同,搞混了就会出问题。