USB-C 系列第 11 章:USB PD 消息是怎么在 CC 线上传输的?BMC 编码、SOP 和消息头入门

USB-C 入门系列|第 11 章 / 连载中

你正在阅读第 11 章:USB PD 消息、BMC 编码、SOP 和消息头。如果你是从搜索引擎直接进来的,可以先看总目录,也可以按上一篇、下一篇顺着读。

这篇是 USB-C 入门系列第 11 章,开始往底层钻一点。

前面几章我们一直在说 Source_CapabilitiesRequestAcceptPS_RDYVDM。这些词看起来像软件里的函数名,但它们最后都要变成电信号,从 USB-C 接口的 CC 线上发出去。充电器和设备不是坐下来开会,它们是在一根细细的 CC 线上“敲电报”。

这一章就讲这封“电报”长什么样:PD 消息为什么走 CC 线,BMC 编码大概在干什么,SOP、SOP’、SOP” 为什么要分开,Message Header 里有哪些字段,以及 Control Message、Data Message、Extended Message 怎么区分。

这篇会比前面更偏技术玩家。小白读到这里如果有点头晕,很正常,谁第一次看协议包不头晕?先抓住主线就够了:一个 PD Packet 大致由 Preamble + SOP* + Payload + CRC + EOP 组成,Payload 里面才是我们平时说的那些 PD 消息。

PD 消息为什么走 CC 线

USB-C 接口里有很多线。高速数据走高速线对,USB 2.0 走 D+/D-,供电走 VBUS 和 GND。那 PD 协议消息走哪里?

走 CC。

CC 全称 Configuration Channel。前面第 2 章讲过,CC 一开始负责识别插入、方向、Source/Sink 角色、电流能力这些基础信息。到了 USB PD,它又承担了更高级的通信任务:双方通过 CC 线交换 PD 消息,把供电档位、请求、确认、角色交换、VDM、EPR 等事情谈清楚。

这就很妙。USB-C 没有为了 PD 再额外塞一条“聊天专线”,而是把 CC 这根已经用于连接识别的线继续用起来。插头插进去后,先靠 Rp/Rd 判断谁供电谁取电,再用 CC 上的 PD 通信把更复杂的事情聊完。

粗略看,链路是这样:

电流表上看到的“协议协商”,背后就是这条 CC 线在忙活。看起来只是电压从 5V 跳到 9V、20V,实际中间已经发了好几轮包。别看线细,活儿不少。

BMC 编码是什么

BMC 是 Bi-phase Mark Coding,USB PD 用它在 CC 线上表达 0 和 1。

规范里说 BMC 属于 Manchester 编码的一种改法:0 有一次跳变,1 有两次跳变。你不用把波形画到纸上背下来,先记住它的目的:让接收端可以从信号跳变里恢复时钟和数据。

普通人看到一根线,脑子里可能会想:“高电平就是 1,低电平就是 0,不就完了?”协议工程里很少这么潇洒。因为接收端需要知道什么时候采样、哪里是一个 bit 的边界、噪声来了怎么办。BMC 通过规律性的跳变,给接收端提供了节奏。像两个人敲桌子传暗号,不光要敲“轻重”,还要敲出拍子,不然对方听半天只觉得你手痒。

在 USB PD 里,发送端会把除 Preamble 之外的数据做 4b/5b 编码,然后整个 Packet 通过 BMC 从 CC 线上发出去。接收端做反向动作:恢复时钟、识别 SOP、解码数据、检查 CRC,没问题才把消息交给上层协议。

可以把它压成一条流水线:

这里先别陷进 4b/5b 表格。你只要知道:PD 消息不会把文本“Request 20V”直接丢到线上,它会一层层变成协议字段、字节、编码符号、BMC 波形。看协议抓包的时候,你看到的是高层翻译后的结果;示波器看到的是底层波形。两边都是真的,只是站的楼层不同。

一个 PD Packet 长什么样

USB PD 规范里的 Packet 可以粗略拆成五段:

Preamble + SOP* + Payload + CRC + EOP

每一段有自己的活:

部分作用人话版
Preamble让接收端醒来并锁定节奏“喂喂喂,要开始说话了”
SOP*标记这包发给谁“这句话是给你,还是给线缆芯片”
Payload真正的消息内容RequestSource_Capabilities
CRC校验消息有没有坏“你听到的和我说的是同一份吗”
EOP标记包结束“这句话说完了”

Preamble 是一串交替的 0 和 1,规范里定义为 64-bit,开头是 0,结尾是 1。它不做 4b/5b 编码,直接用 BMC 发。这个设计很实用:接收端先靠它进入状态,后面的 SOP 和 Payload 才不至于一上来就被听漏。

SOP* 是 Start of Packet 的一组标记。星号不是通配符的浪漫写法,它表示 SOP、SOP’、SOP”、Debug SOP 这些都算一类。日常读协议时看到 SOP*,脑子里可以展开成“某一种包起始序列”。

Payload 是重点。它里面至少有 16-bit 的 Message Header。Control Message 只有 Header;Data Message 会在 Header 后面跟 1 到 7 个 32-bit Data Object;Extended Message 还会多一个 Extended Message Header 和更长的数据块。

CRC 是 32-bit 校验,用来判断消息有没有在传输中坏掉。接收端校验通过,才会把包往上交;校验失败,直接丢。协议世界挺现实,听不清就当没听见。

EOP 是 End of Packet,表示这包结束。没有 EOP,就像一句话没有句号,接收端心里也没底。

SOP、SOP’、SOP” 有什么区别

SOP 这一组最容易把人绕晕。名字看起来像打字时手抖多敲了几个撇号,其实每个都有对象。

名称主要对象常见用途
SOP端口伙伴,也就是充电器和设备之间供电协商、角色交换、普通 VDM
SOP’线缆一端的电子标识/有源组件读取 E-marker、线缆能力
SOP”线缆另一端的电子标识/有源组件更复杂线缆或双端识别场景
SOP’_Debug / SOP”_Debug调试用途普通用户基本不用管

前面第 7 章讲 E-marker 时,我们说 Source 可以通过 Discover Identity 读取线材信息。那时候就会碰到 SOP’ 或 SOP”。也就是说,PD 通信不是只能和“对面设备”说话,还能对线缆里的芯片说话。

这件事很关键。高功率、全功能线、有源线、EPR 线材,都不能只靠外观判断。协议需要问线材:你是谁,你支持多少电流,你是什么线,你有没有电子标识。问电脑或手机,用 SOP;问线材芯片,就要换 SOP’ 或 SOP”。

画成图会更清楚:

这里也能解释一个现象:有些电流表能读到线材 E-marker,有些只能看电压电流。能读 E-marker 的设备,背后要能发对应 SOP’ 消息并解析线材返回的 VDO。它不是“多显示几行字”这么轻巧,底层要真会问。

Message Header 里有什么

每条 PD 消息都从 16-bit Message Header 开始。它像快递单的最小版本:这包是什么类型,带几个数据对象,谁发的,用哪个规范版本,有没有扩展消息。

常见字段可以这样记:

字段大概作用
Extended判断是不是 Extended Message
Number of Data Objects后面跟几个 32-bit Data Object
MessageID消息编号,用来确认和去重
Power Role / Cable PlugSOP 时表示 Source/Sink,SOP’ 时表示线缆端
Specification RevisionPD 规范版本,比如 PD 3.x
Data Role / ReservedSOP 时表示 DFP/UFP
Message Type这条消息到底是哪一种

最常用的判断逻辑在这三个字段:

  • Extended = 0Number of Data Objects = 0:Control Message。
  • Extended = 0Number of Data Objects > 0:Data Message。
  • Extended = 1:Extended Message。

也就是说,协议栈先看 Header,就能知道后面该按哪张表解析。像看快递单,先看“文件”“包裹”“大件”,再决定用信封刀还是搬运车。比喻有点土,但真好用。

MessageID 也很重要。PD 里每发一条消息,都需要对方用 GoodCRC 确认收到了。GoodCRC 会带着收到那条消息的 MessageID 回来,发送方就知道“这次确认的是刚才那包”。如果消息重发、丢包、重复确认,MessageID 能帮协议栈别乱套。

Control Message、Data Message、Extended Message 怎么分

前面讲过 Header 的判断逻辑,这里展开看三类消息。

Control Message 很短,只有 Message Header 和 CRC。它不带 32-bit Data Object。常见的 GoodCRCAcceptRejectWaitPS_RDYSoft_Reset 都在这里。

Data Message 会在 Header 后面跟 1 到 7 个 32-bit Data Object。我们前面几章经常见到的 Source_CapabilitiesRequestSink_CapabilitiesVendor_Defined 都属于 Data Message。PDO、RDO、VDO 这些东西,落到包里就是 Data Object 的不同格式。

Extended Message 用在更长、更复杂的数据上。它会在普通 Message Header 后面再加一个 Extended Message Header,并支持 chunking 之类的机制。比如一些扩展能力、状态信息、厂商扩展信息,会走这类消息。

按“有没有数据对象”和“是不是扩展”整理一下:

类型Header 判断后面跟什么例子
Control MessageExtended=0,NDO=0没有 Data ObjectGoodCRC、Accept、PS_RDY
Data MessageExtended=0,NDO>01 到 7 个 32-bit Data ObjectSource_Capabilities、Request、VDM
Extended MessageExtended=1Extended Header + 数据块Status、Source_Capabilities_Extended

这也是为什么同样叫“PD 消息”,复杂度差很多。Accept 像一句“好”;Source_Capabilities 像菜单;Vendor_Defined 像拿出一份厂商专用表;Extended Message 则像附件。你说它们都叫消息,没错;你说它们一样长,那就要出事。

Source_Capabilities 到底怎么变成一包

拿前面讲过很多次的 Source_Capabilities 举例。

用户看到的是:充电器支持 5V、9V、15V、20V,甚至 PPS、EPR。

协议里看到的是:Source 发出一个 Data Message,Message Type 是 Source_Capabilities,后面跟着若干个 PDO。每个 PDO 是 32-bit,里面按字段写明电压、电流、PDO 类型、是否支持 EPR、是否支持 USB 通信等信息。

电线上的过程大概是:

这个图和第 4、5 章的快充协商是一回事,只是现在我们换了个视角。以前看的是“谁先说什么”;这一章看的是“这些话怎么变成包”。同一个故事,从楼上看是小区地图,从楼下看是每块砖。

这里顺便提醒一下:电流表里看到的 PDO 列表,是工具把 Data Object 解析成人能看懂的结果。真实传输时没有“20V 5A”这几个汉字,也没有漂亮表格,全是字段。工具替你翻译了,别把翻译稿当原文。

GoodCRC 为什么到处都是

抓 PD 协议时,你会发现 GoodCRC 特别忙。几乎每条有效消息后面,都要来一个 GoodCRC。

GoodCRC 的作用很朴素:我收到了,而且 CRC 校验通过。

它不是说“我同意你的请求”。同意请求是 Accept,准备好供电是 PS_RDY,拒绝是 Reject,让你等等是 Wait。GoodCRC 只负责确认“这包听清了”。这点很容易混。

比如 Sink 发了一个 Request

  • Source 回 GoodCRC:说明 Request 这包收到了。
  • Source 再回 Accept:说明这个请求被接受。
  • Sink 回 GoodCRC:说明 Accept 收到了。
  • Source 最后发 PS_RDY:说明电源状态准备好了。

如果只看到 GoodCRC,就兴奋地以为快充成功,那就像别人回你“收到”,你直接以为项目结案。职场血泪史告诉我们,这俩差得很远。

GoodCRC 还和 MessageID 配合。发送方看到对方用同一个 MessageID 回 GoodCRC,才知道确认的是刚才那条消息。如果没等到对应 GoodCRC,就可能重发或进入错误处理。协议栈就是靠这些小动作保持秩序。

BMC、SOP、Header 和上层协议怎么串起来

把前面内容合起来,一条 PD 消息大概这样穿过各层:

  • 策略层决定要发什么,比如 RequestAcceptVDM
  • 协议层构造 Message Header 和 Data Object。
  • 协议层选择 SOP、SOP’ 或 SOP”。
  • PHY 层计算 CRC,做 4b/5b 编码。
  • PHY 层加 Preamble、SOP*、EOP。
  • 整个 Packet 用 BMC 从 CC 线上发出去。
  • 接收端恢复时钟、解码、校验 CRC。
  • 校验通过后,上层才看到这条 PD 消息。

这条链路的每一层都可能出问题。线材差、噪声大、CC 接触不良,可能底层包就收不稳;协议版本不匹配,可能 Header 或消息类型处理不一样;设备策略保守,可能收到请求也不接受。快充排查很烦,原因就在这里:你看到的是一个“不快充”,背后可能是从物理层到策略层任何一层没谈拢。

这也解释了为什么普通电流表和专业协议分析仪差别很大。普通电流表主要告诉你电压、电流、PDO 列表;协议分析仪能把消息时序、SOP 类型、Header 字段、GoodCRC、错误重传都摊开。前者适合日常判断,后者适合把锅按层分清楚。

用电流表或协议分析仪能看到什么

普通 USB-C 电流表通常能看到:

  • 当前电压、电流、功率;
  • Source 提供的 PDO/PPS/EPR 档位;
  • 设备请求的大致档位;
  • 线材 E-marker 信息,取决于型号;
  • 某些 VDM 或 Alt Mode 信息,取决于型号。

更专业的 PD 协议分析仪能看到:

  • 每条 PD 消息的时间顺序;
  • SOP、SOP’、SOP” 区分;
  • Message Header 字段;
  • Data Object 原始值和解析结果;
  • GoodCRC、Accept、Reject、Wait、PS_RDY;
  • Soft Reset、Hard Reset、重试、错误恢复;
  • BMC 物理层相关状态,取决于设备能力。

买工具时别被“支持 PD 3.1”几个字冲昏头。你要看自己想解决什么问题。只是判断充电器能不能跑 100W、PPS 有没有触发,普通电流表就够用。要分析为什么某个扩展坞 VDM 不通过、为什么 EPR 进不去、为什么某条线 SOP’ 没回应,那就要更专业的工具。

常见误区

PD 消息是不是走 USB 数据线?

不是。USB PD 的核心协商消息走 CC 线。USB 2.0、USB 3.x、USB4 数据通道可以各忙各的。充电协商不依赖你电脑是否正在传文件。

GoodCRC 是不是代表请求成功?

不是。GoodCRC 只表示消息被正确接收。请求是否被接受,要看后面的 AcceptRejectWait 等响应。小学语文都知道“收到”和“同意”不是一个词,协议里也一样。

SOP’ 和 SOP” 是不是普通用户不用管?

日常买线不一定要背,但高功率线、E-marker、有源线、全功能线都会牵扯到它。你不用会手写 SOP’ 包,但知道“设备会通过不同 SOP 找线缆芯片说话”,排查时会清醒很多。

只看电压电流能不能判断协议问题?

只能判断一部分。电压电流是结果,不是完整过程。只跑 5V 可能是设备没请求,也可能是请求被拒,也可能是线材能力不够,也可能是协议包根本没收稳。电流表能帮你缩小范围,协议分析仪才能把过程拆细。

BMC 编码需要普通玩家掌握到波形级吗?

多数情况下不用。知道 PD 消息通过 CC 线、用 BMC 编码、Packet 有 Preamble/SOP/Payload/CRC/EOP,已经足够读懂很多协议文章。真要做硬件调试,再去看示波器、眼图、mask、接收容限那些硬菜。

写在最后

USB PD 看起来像“充电器告诉设备自己有几个档位,设备选一个”,这句话没错,但它只站在很高的楼层。往下看,每一句话都要被打包成 Message Header 和 Data Object,再放进 Packet,通过 Preamble、SOP*、CRC、EOP 包起来,最后用 BMC 在 CC 线上发出去。

理解这一层以后,前面很多名词会忽然连起来:PDO 是 Data Object,RDO 也是 Data Object,VDM 还是 Data Message;GoodCRC 只是确认收到,Accept 才是接受请求;SOP 是对端口伙伴说话,SOP’ / SOP” 是对线材芯片说话。原来不是一堆术语在开派对,它们确实各有位置。

下一章建议回到更实用的方向:USB-C 不能快充、充电慢、功率不稳定时怎么排查。第十一章讲的是“包怎么发”,第十二章就拿这些知识去拆现场问题。毕竟读协议不是为了显得很懂,是为了少被一根线折腾半小时。

系列相关阅读