USB CDC ACM 串口调试:Line Coding、控制线状态与无数据
通过 SET_LINE_CODING、SET_CONTROL_LINE_STATE、Bulk 端点传输和固件行为排查 USB CDC ACM 虚拟串口设备不通的问题。
USB CDC ACM 设备被广泛用于虚拟串口、设备控制台、固件烧录工具、遥测通道、测试夹具和嵌入式诊断。从应用层看很简单:打开一个 COM 口或 /dev/ttyACM*,设个波特率,读写字节。但在底层,主机和设备还是要交换类特定 USB 请求和 Bulk 传输。
一台 CDC 设备枚举成功却不出数据的时候,抓包可以告诉你问题出在描述符布局、Line Coding、控制线状态、端点流量,还是固件缓冲上。
CDC ACM 有 Communication 和 Data 两个接口
一个标准的 CDC ACM 设备暴露一个 Communication Interface 和一个 Data Interface。主机在数据开始之前可能会先发一些类特定请求。
重要的证据:
- Communication Interface 描述符
- Data Interface 描述符
- CDC Functional Descriptor
- Notification Endpoint
- Bulk IN Endpoint
- Bulk OUT Endpoint
SET_LINE_CODINGGET_LINE_CODINGSET_CONTROL_LINE_STATE
如果这些请求根本没到,HOST 大概率没装上预期的 CDC 驱动。
波特率常常只是信号,不是真正的物理 UART
对很多 USB CDC 设备来说,波特率不再像 UART 那样有真正的物理意义。但主机还是会发 Line Coding。固件可以用它来配置桥接芯片、忽略它、或者校验它。
抓包要回答:
- 主机有没有发
SET_LINE_CODING? - 请求的波特率、校验位、停止位、数据位分别是多少?
- 固件有没有接受这个请求?
- 主机有没有通过
SET_CONTROL_LINE_STATE拉高 DTR 或 RTS? - 固件是不是在等 DTR 才往外发?
"串口没输出"的问题里,很大一部分其实是"固件在等 DTR,但主机从来没拉过",或者"应用打开了端口但没按预期配置"。
Bulk 端点才能证明数据真在走
初始化完成之后,CDC 数据通常走 Bulk 端点。如果主机的写操作出现在 Bulk OUT 上,但 Bulk IN 上看不到任何回包,那就是固件没在往外发。如果 Bulk IN 数据出来了但应用不显示,问题可能在主机应用那一侧。
要查的:
- Endpoint 方向
- 传输长度
- 反复 NAK / 超时的模式
- 实际的 payload 字节
- 传输状态
- 与 Line State 请求之间的先后顺序
这就是 USB 抓包为什么比终端截图更有用的原因。
Bus Scope 在这个场景里做什么
Bus Scope 应该帮固件团队把描述符、类请求、原始端点数据放在同一个会话里。对 CDC ACM 调试来说,它需要回答:
- 主机有没有装上 CDC?
- 它发的 Line Coding 是什么?
- DTR/RTS 状态有没有变化?
- Bulk OUT 有没有带命令?
- Bulk IN 有没有带响应?
- 问题是出在类串口流量开始之前,还是开始之后?
你搜 "USB CDC ACM 没数据"、"虚拟 COM 口没输出"、"SET_CONTROL_LINE_STATE DTR" 的时候,证据不只在终端里——它在 USB 的类请求和端点传输里。