2. USB 握手协议:ACK / NACK / STALL 握手包详解
搞 USB 调试,我猜你最先碰到的就是握手包。说白了,握手就是设备告诉主机:「我收到了,再发」或者「我不行,别催了」。
当年我刚入门时,以为握手就是 ACK 和 NACK 来回切。结果第一次调 U 盘,死活报 STALL,吓得我以为是芯片烧了。后来才发现,是因为端点配置错了——方向没对齐。嗯,从那以后我再也不敢轻视这三兄弟了。
2.1 握手包长什么样?
握手包是 USB 事务中最短的包,只有 1 个字节(8 bit),格式固定:
PID (4 bit) + 校验/补码 (4 bit)
PID 由 USB 规范定义,每种握手有固定值:
| 握手类型 | PID(二进制) | PID(16进制) | 含义 |
|---|---|---|---|
| ACK | 0010 1101 | 0x2D | 数据正确,继续 |
| NAK | 1010 0101 | 0xA5 | 暂未就绪,重试 |
| STALL | 1110 0001 | 0xE1 | 致命错误,别来了 |
注意:PID 的低 4 位是原始值,高 4 位是低 4 位的取反。比如 ACK = 0010 取反得 1101,拼接成 0010 1101。这种设计为了物理层抗干扰。
2.2 三种握手的「性格」
每种握手其实代表了设备的不同「态度」。你可以把它们想象成三个角色:
ACK —— 老实人,一切正常
设备确认主机发来的数据正确,并且准备好接收下一个包。主机收到 ACK 后,会进入下一阶段事务。
我遇到过的坑:有一次抓了总线波形,看到连续 30 个 ACK,但设备就是没反应。后来才发现是 FIFO 满溢了——设备虽然发 ACK,但实际上把数据丢了。注意,ACK 只代表「收到并校验通过」,不代表「已处理」。这是新手最容易忽略的。
NAK —— 拖延症,先别催
设备说:「收到了,但我现在忙,没法处理,你过会儿重试。」主机看到 NAK 后不会报错,而是会轮询重试(重试次数视具体控制器而定)。
在批量传输端点中,NAK 是常态。你想想看,U 盘在写大文件时,大部分时间都在回 NAK。这其实是好现象——说明设备还活着,只是还没就绪。
我曾踩过的雷:某次测一个 USB 转串口模块,一直收到 NAK,以为坏掉了。结果查手册才知道,该模块的写端点一次只能处理 64 字节,我一次发 256 字节,它只能 NAK。后来切成分批发送就好了。
STALL —— 摆烂了,别再试
STALL 是 USB 协议里的「死口」。设备一旦回复 STALL,代表这个端点当前根本无法工作。通常原因:
- 端点不存在(配置描述符里没暴露)
- 端点方向错误(主机试图向 IN 端点写数据)
- 控制传输中不支持的标准请求
- 固件内部发生了不可恢复的错误
在批量传输中,STALL 不会自动清除。主机必须通过控制端点发送 ClearFeature(ENDPOINT_HALT) 才能让设备重新工作。忘记清 STALL 是很多复测自动化脚本写不稳的根本原因。
2.3 握手阶段在事务中的位置
一个典型的 USB 事务包含三个阶段:令牌 → 数据 → 握手。以批量输出(OUT)为例:
- 令牌阶段:主机发 OUT 令牌包,指定设备地址 + 端点号
- 数据阶段:主机发 DATA0/DATA1 数据包
- 握手阶段:设备回复 ACK/NAK/STALL
如果是批量输入(IN):
- 主机发 IN 令牌
- 设备发 DATA0/DATA1 数据
- 主机发 ACK(正确接收)或 NAK/STALL(不会发,主机只能回复 ACK)
注意:主机不会在数据阶段向设备回复 NAK/STALL,但主机可以通过不发送 ACK 来强制设备重发——这叫「Ping 协议」,在高速传输中会用到。
调试时抓波形,我习惯先看握手阶段。如果握手丢掉了,说明问题在 PHY 层或链路层;如果握手一直在,但功能不对,那多半是数据内容错了。
2.4 握手失败常见场景与注入思路
做复测时,我们经常需要「模拟握手失败」。怎么做?可以提前想好几种场景:
| 异常类型 | 注入方法 | 预期系统行为 |
|---|---|---|
| ACK 缺失 | 用逻辑分析仪或 FPGA 截断握手包 | 主机超时重试(3 次后可能重置端点) |
| NAK 风暴 | 让固件在批量端点连续回 NAK | 主机反复轮询,直至超时 |
| STALL 保持 | 固件对某个请求回 STALL 后不清除 | 主机后续事务全部失败,需上层驱动重枚举 |
| 握手 PID 错误 | 硬件上翻转 PID 校验位 | 主机 CRC 失败,丢弃包 |
我个人习惯在做自动化测试脚本时,先写一个「握手包捕获」的 hook。用 Python 调 libusb 的底层 API,把每次事务的握手状态记录下来。等跑完一轮,看哪个端点回 NAK 超过 10 次,基本就是瓶颈。
2.5 核心知识结构一览
下面这张图是我自己画的结构,帮你在脑子里串起来。
2.6 避坑指南
最后说几个我在实战中流过的血:
- 不要凭肉眼判断 NAK 次数:Host 控制器内部可能重试了很多次,你看到一次 NAK,但实际总线上跑了 5 次。用逻辑分析仪抓原始波形最准。
- STALL 后立刻重试是徒劳的:我曾经写了一个死循环,STALL 后立即重发同个请求,结果端口被锁死直到重新枚举。正确做法:先发 ClearFeature。
- 控制端点的 NAK 含义不同:控制传输的 NAK 不一定是忙,也可能是设备在等待 setup 阶段完成。我就被这个坑过,调了三天才发现是 setup 包没发全。
好了,第二章就先到这儿。三种握手的「性格」记住了就行,后面第三章我们会真的动手抓波形,看看它们怎么在总线上跳的。