每周分享】USB协议波形中的SOF包为何如此设计?令我疑惑不解

📅 2026/7/17 23:56:42 👁️ 阅读次数 📝 编程学习
每周分享】USB协议波形中的SOF包为何如此设计?令我疑惑不解

前几天使用逻辑分析仪并按如下配置抓取了USB键盘的USB通信波形:

差分信号线D+和D-,即为Data+和Data-;

USB通信速度为full sped全速模式;

在没有任何按键操作的时候,同时Wireshark工具也没有监控到USB键盘和电脑的通信报文的时候,我起初以为这个时候应该没有波形才对,可是事实证明我错了:逻辑分析仪上面却是抓到了周期约为1ms的波形数据(这个1ms而已可以称为总线空闲时间):

打开看了一下波形数据详情,格式上都一样,如下面所示标注为“SOF”字样的协议波形:

实际时间不是刚好1ms,而是集中在997us左右,差了3us,但这种误差已经超出了USB2.0规范对SOF包发送周期的误差范围限制,即允许误差是±0.05%(0.9995 ms 至1.0005 ms),那为什么这里会有3us左右的时间呢?其实我们可以计算一下SOF包的总线有效带宽时间(SOF包传输时间)1000us-997us=3us:

也可以来计算一下:

SOF包总共32个bit位,全速USB的时钟频率是12MHz,则SOF包的传输时间为:

(1/12)*32+ 250= 83.3333ns*32+250ns = 2916ns,近似3us,刺激吧?

我们从逻辑分析仪上导出时间数据,也可以看出每个数据点的耗时,可以精确到ns:

对于这种周期固定且波形格式一样的数据,就好像那种“心跳包”一样,比如wifi模块什么的都有这种机制,其主要目的是主机为了与设备保持连接状态,防止设备断连。

于是乎进一步研究了一下SOF:

SOF究竟是什么呢?USB协议用它来干啥的?

所谓的SOF,其实是一种数据包,在全速(Full Speed,12Mbps)USB通信时,主机为了保证同步和确定时间基准,会严格按照每1ms一次的频率发送这个SOF包,它标志着每一帧的开始,所以其全称其实就是Start Of Frame,即为帧起始包

另外,如果是在高速(High Speed,480Mbps)USB通信,那么我在逻辑分析仪上看到的SOF包的周期应该是125us;而对于低速(Low Speed,1.5Mbps)设备,是不接收SOF包的,它们依靠集线器产生的“Keep Alive”信号来维持状态。

当然我们这里所说的USB通信速率,主要是针对USB2.0标准来说的,对于USB3.0标准,当然更快。

那它有什么作用呢?

在USB协议通信中,SOF包的作用主要体现在下面三个方面:

1、标记帧起始与同步:

它是主机定义时间基准的关键信号,告诉所有设备“新的1毫秒周期开始了”,此时设备可以校准自身时钟,从而实现与主机的时序同步;鉴于此,MCU的USB时钟源尽量使用外部时钟,其精度比内部时钟要好一些;

2、防止设备休眠:

在总线上没有数据传输,也就是总线处于空闲状态时,这些周期性发送的SOF包就像“心跳”信号一样,能让设备继续保持工作状态,不会误以为被断开而进入低功耗模式;

3、支撑同步传输:

对于音频、视频等对实时性要求高的实时传输,设备会利用SOF包来确保数据流以稳定的速率发送,从而避免卡顿或不同步等现象。

现在我们对SOF包有个基本概念了,那接下来我们再一起来看看SOF包的帧格式,以及为什么要这么设计呢?

我们以下面这个波形为例,先来说说波形上相关符号的含义:

我们可以看出来:

SOF包主要包括4个字段(Packet fields):SYNC、PID、Frame、CRC5;其中SYNC的位规则和其他三个不一样,后三个是按照LSB在前读取的,SYNC则相反。

“USB singnalling:Symbols”对应的K和J是什么含义呢?

J 和 K 并非代表数字“0”或“1”,而是USB协议定义的两种差分信号状态,是USB通信中最基础的物理信号单元,通过D+和D-两条数据线的电压高低来共同表示,即:

对于全速/高速设备:

D+为高电平,D-为低电平:表示J状态;

D-为高电平,D+为低电平:表示K状态;

USB总线的空闲状态一般是被定义为J状态,如下图所示:

当主机要发送一个SOF包时,它会驱动总线从空闲的J状态切换到K状态。这个由J到K的跳变,就是数据包开始的明确信号:

当遇到数据0时,信号电平翻转(J变K,K变J);当遇到数据1时,信号电平保持不变(J保持J,K保持K),如下图这样:

SOP的含义:

Start OfPacket,标志数据包的开始;

EOP的含义:

End OfPacket,标志数据包的结束;

SE0的含义:

Single-EndedZero,D+和D-两条线同时为低电平;这个状态非常重要,用于表示数据包结束(EOP)、总线复位(Reset)以及设备断开连接;

另外,如果出现SE1,即D+和D-两条线同时为高电平,注意了,这是一个非法的总线状态,它的出现通常表示发生了错误。

说完波形上相关的符号所代表的含义后,接下来我们再逐个讲解SOF包的4个字段:

1、SYNC:

同步域,占8个bit位,是必不可少的前导码,其核心作用是实现接收端与发送端的时钟同步,并标记数据包的开始;

在USB的NRZI编码规则下,SYNC是一串固定的二进制序列,即低速和全速USB设备为00000001,高速USB设备为00000000000000000000000000000001(占32个bit位);

如果用K和J信号符号来解释的话,SYNC序列是一串特定的“KJ”交替信号 “KJKJKJKK”:

接收端通过锁定这个固定的翻转模式,可以校准自己的时钟,与主机发送的数据速率保持同步;

另外,需要注意的是,不止是SOF包有SYNC信号,,USB总线上的每一个数据包(如事务包、数据包等),都是以SYNC开头的,如下图所示这些通过USB专用的协议分析仪(lecroy USB advisor bus andprotocol analyzer)抓取的帧数据包:

或者我按键时产生的波形数据也会有SYNC:

当SYNC出现非00000001的其他值的时候,就表示出现了SYNC ERROR,就需要你分析原因了:

我的这个设备就出现了,但目前还没发现有什么影响?不过也在排查原因中……

2、PID:

包标识符,Packet ID,占8个bit位,SOF包的PID是固定的,为10100101(0XA5),其作用即为标识该数据包是一个SOF包;其中低4位是类型,高4位是低4位的校验码,按位取反所得,如下图所示:

发送时按照最低有效位LSB优先的顺序在总线上传输。

3、Frame:

帧编号,Frame Number,占11个bit位,表示当前是第多少个SOF包,即随SOF包递增加1,达到最大值后又重新开始递增;比如下面这两个连续的SOF包:

4、CRC5:

5位循环冗余校验码,主要是对帧编号进行校验,占5个bit位,其计算核心是一个初始值为全1(USB规范中的强制要求,与许多CRC算法从0开始不同)、输入数据低位在前、最后结果按位取反的CRC算法。

以上通过结合波形数据对USB协议波形的SOF包进行了拆解和分析,疑惑的我算是知道为何要如此设计了。

另外,当我按下USB键盘的按键时,会产生更多的波形数据,如下所示:

……

咋一看,里面有地址address信息,端点endpoint信息等,这个地址为38,其实就是我这个USB键盘当前的设备地址,这不就和Wireshark抓包的数据包对应上了嘛,至于USB协议的解析,后续有机会再写了,估计内容会比较多,需要些时间。

果真是:活到老,学到老,学无止境!


---------------------
作者:dffzh
链接:https://bbs.21ic.com/icview-3518683-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。