本帖最后由 sunsili 于 2024-4-10 14:45 编辑
深入理解USB2.0通信协议——解读USB报文的神秘语言
导言
上一节我们详细讨论了USB的比特级编解码,本章将以此为基础,进一步介绍USB字段及包的格式。USB包的构成是一个逐层的过程,信息首先以二进制串行数据的形式存在。这些串行数据按照特定规则被组织成字段(filed),字段(filed)是包(packet)的基本单元。多个字段(filed)按照一定的顺序组成一个包(packed),进一步地,多个包(packed)可以组成一个事务(transaction),事务(transaction)是USB通信中更大粒度的数据传输单元。最终,多个事务(transaction)组成一个传输(transfer),代表了一个完整的数据传输过程。本文主要讲解Packet,下一章将会探讨USB事务(transaction)的传输过程。
1 字段(filed)
所有包都有包开始(SOP)和结束(EOP)界定符。包(packet)与开始界定符(SOP)的分隔符是 SYNC 字段。输入电路使用SYNC来将输入数据与本地时钟对齐,SYNC 字段中的最后两位是一个标记,用于识别 SYNC 字段的结束,并通过推断识别 PID 的开始。字段(filed)是包(packet)的基本单元,每种包(packet)都有对应的字段。
包标识符字段(PID)
每个USB包的SYNC字段后紧跟一个PID PID由一个四位包类型字段和一个四位校验字段组成 PID指示包的类型,暗示了包的格式和应用的错误检测类型 四位校验字段确保PID的可靠解码,以确保正确解释包 PID的四位校验字段是通过对包类型字段进行补码生成的 如果四个PID校验位与它们各自的包识别符位不是补码关系,则发生PID错误 主机和所有功能必须对所有接收到的PID字段进行完整解码 如果接收到的PID的校验字段失败,或者解码为非定义的值,则假定其已损坏 包接收器将忽略整个包,包括损坏的PID 如果功能收到了一个它不支持的事务类型或方向的有效PID,则该功能不得回应,例如,仅支持输入的端点应忽略输出令牌 PID分为四个编码组:令牌、数据、握手和特殊 传输的前两位PID位(PID<0:1>)指示编码组
地址字段
地址字段有两部分组成:功能地址字段(ADDR)和端点字段(EP)。 如果包的地址字段与设备端点不匹配则必须忽略这个包。
「功能地址字段(ADDR Field)」
ADDR字段通过其地址指定功能,根据令牌PID的值,功能可能是包的源或目的。
ADDR<6:0>指定了128个地址 ADDR字段用于IN、SETUP和OUT令牌以及PING和SPLIT特殊令牌 每一个单独的功能(function)都会有一个ADDR值,这意味着可能会有多个端点(Endpoint)共享一个ADDR 复位和上电时,ADDR默认为零,必须在枚举过程中由主机进行分配
ADDR 0被保留作为默认地址,不能分配给其他用途
端点字段(Endpoint Field) 附加的4位端点字段(ENDP)允许在多端点(Endpoint)的功能(Function)中更灵活地进行寻址
除了端点地址0外,其他端点地址是根据功能(Function)的端点来定义的 端点字段定义了用于IN、SETUP和OUT令牌以及PING特殊令牌 所有功能必须支持端点地址为零的默认控制管道(Default Control Pipe) 低速设备每个功能最多支持3个端点:端点编号为零的控制管道以及另外两个端点 额外的两个端点可以作为: 1.两个控制管道 2.一个控制管道和一个中断端点 3.两个中断管道 全速和高速功能可以支持最多16个IN和OUT端点(16组端点)
帧号字段(Frame Number Field)
USB帧的概念是用于组织和标记数据传输的时间间隔,帧号就是用来标识这些帧的序号,一个帧内可以包含一个或多个包 在USB帧的包中,帧号字段位于帧的头部。帧的头部包含同步(SYNC)和定界符(SOP)以及其他必要的信息,帧号字段在这个头部中用于指示当前帧的序号 USB 2.0规范中,帧号字段是11位长。这意味着,帧号的范围在0到2047之间,当达到2047后会重新从0开始 每当USB总线上的一个新帧开始时,帧号字段会递增 帧号字段的主要用途是为USB系统提供一个时间基准,确保设备和主机能够按照同一时间轴进行数据传输。帧号也用于帮助处理时间敏感的USB应用,如音频和视频传输
数据字段(Data Field)数据字段的范围可以从 0 到 1024 字节
数据字段通常位于USB数据包的中间部分,紧随在帧的同步和定界部分以及可能的地址、端点和其他控制信息之后。具体的数据字段位置和长度取决于USB传输的类型和帧结构 数据字段承载了需要在USB设备之间传输的实际数据。这可以是应用程序数据、控制命令、中断数据等,取决于USB传输的类型。例如,在批量传输中,数据字段可能携带文件的内容;在控制传输中,数据字段可能包含控制请求和应答等 数据字段之后通常会包含错误检测和结束标记。错误检测用于验证数据的完整性,而结束标记则指示数据字段的结束,帮助接收端正确解析传输
CRC字段(CRC Field)
和以太网类似,USB包在末尾也会有校验字段CRC,其CRC的校验不包括PID字段,主要校验PID之后的地址、帧号、数据等字段。USB包的CRC有两种分别应用于两种不同的场合:
「令牌CRC(Token CRC)」 「数据CRC(Data CRC)」 G(X) = X16 + X15 + X2 + 1 数据CRC字段用于校验带有Data字段的数据包(Data Packet)
如果所有数据和CRC位都正确接收,则16位余数将为1000000000001101B
2 数据包(Packet)
USB(Universal Serial Bus)的数据传输基本单位是数据包(Packet)。USB数据包根据不同的令牌类型和传输阶段,有不同的格式和含义。常见的令牌类型包括IN、OUT、SETUP、SOF(Start of Frame)等。整个USB通信过程由一系列数据包组成,这些数据包通过同步和特定字段的解析,实现设备之间的可靠数据传输。
令牌包(Token Packets)令牌包由PID(IN、OUT、SETUP类型)、ADDR和ENDP字段组成。PING特殊令牌包也包含相同的字段。令牌的PID指定了数据包类型和相关的地址、端点信息 令牌类型分为IN、OUT、SETUP和PING。IN令牌表示从设备到主机的数据传输,OUT和SETUP令牌表示从主机到设备的数据传输,PING令牌表示握手传输。令牌中的地址和端点字段用于唯一标识相关的设备端点 令牌包包含一个五位CRC校验,用于覆盖地址和端点字段。这有助于接收方验证令牌包的完整性。不过,CRC不覆盖PID,PID有自己的校验字段。 令牌和SOF(Start of Frame)包在三个字节的数据字段后由EOP标志作为结束。如果一个包在三个字节后未以EOP结束,即使它解码为有效的令牌或SOF,也必须被视为无效并被接收方忽略。 令牌包应用 设备初始化:当USB设备插入计算机的端口时,主机会向设备发送OUT令牌包,指定设备的地址和初始化信息。设备收到令牌包后,可能会进行初始化过程。 数据读取:如果主机需要从USB设备读取数据,它会发送IN令牌包,指定设备地址和相关的端点。设备在收到令牌后,将准备好的数据放入数据包中发送给主机。 数据写入:当主机需要向USB设备写入数据时,它会发送OUT令牌包,指定设备地址和相关的端点。设备在接收到令牌后,等待主机发送数据包,并进行数据的写入操作。 设备控制:主机通过发送SETUP令牌包向USB设备发送控制信息,例如设备的配置、状态查询等。设备收到SETUP令牌后,执行相应的控制命令。 握手协议:使用PING令牌包进行握手协议。主机发送PING令牌,指定设备地址和端点,设备收到PING后,可以回复握手信号,表示是否准备好继续通信
帧起始包(Start-of-Frame Packets(SOF))
SOF包由主机定期发出,全速总线为每1.00毫秒±0.0005毫秒一次,高速总线为125微秒±0.0625微秒一次。它包含一个指示数据包类型的PID,后跟一个11位的帧编号字段。 SOF令牌是一个令牌-only事务(仅由令牌阶段组成的事务),以精确定时的间隔分发SOF标记和相应的帧编号,对应于每个帧的开始。所有高速和全速功能(包括集线器)都接收SOF包。SOF令牌不会导致任何接收函数生成返回数据包,因此无法保证SOF包传递到任何给定的功能。 SOF令牌主要用于在总线上定期分发帧号,帮助USB设备同步其操作。SOF事务中的令牌仅包含PID(Packet Identifier)和帧编号字段,没有数据传输或握手。 帧和微帧 全速(Full-Speed)帧时间: USB定义了每1毫秒一个周期的全速帧时间 通过每1ms发出一次的SOF令牌来指示全速帧的开始 高速(High-Speed)微帧: USB还定义了高速微帧,其帧时间为125微秒
与全速类似,SOF令牌用于指示每125µs一个周期的高速微帧的开始 SOF令牌生成: SOF令牌由主机控制器或集线器事务转换器(hub transaction translator)生成 在全速链路上,每1毫秒生成一次SOF令牌 在高速链路上,每过七个125µs周期后生成一次SOF令牌 高速设备对SOF的处理: 高速设备在每1ms周期内看到具有相同帧号的SOF令牌共八次(每125µs一次) 高速设备可以通过检测具有与之前的 SOF 不同的帧编号的 SOF 并将其视为第0个微帧来本地确定特定的微帧“编号”。接下来的 7 个具有相同帧号的 SOF 可被视为微帧 1 至 7。 SOF应用: 帧同步:SOF令牌每隔一定的时间周期性地发出,用于同步所有连接到USB总线的设备。USB设备根据SOF令牌的到达来确定当前帧的开始。这对于协调和同步USB总线上的各个设备的操作至关重要。 时间基准:SOF令牌中包含一个帧编号字段,用于标识当前帧。USB设备可以利用帧编号来测量时间,实现时间同步或执行与时间相关的操作。这对于需要准确时间基准的应用非常重要。 轮询设备:主机通过SOF令牌可以定期轮询连接的USB设备。设备可以在SOF令牌的基础上执行特定的操作,例如响应主机的查询或报告设备的状态。 管理USB总线带宽:SOF令牌的周期性发送确保了USB总线的带宽分配。USB设备可以根据SOF令牌的到达来进行数据传输或执行其他操作,以确保总线上的有效利用。
数据包(Data Packets)数据包由PID、包含零个或多个字节数据的数据字段以及CRC组成 有四种不同PID标识的数据包类型,分别是DATA0、DATA1、DATA2和MDATA DATA0和DATA1两种数据包PID用于支持数据切换同步(Data Toggle Synchronization) 所有四种数据PID在高带宽高速等时钟同步端点(USB 支持单独的高速中断或同步端点,这些端点需要高达 192 Mb/s 的数据速率)的数据PID排序中使用
三种数据PID(MDATA、DATA0、DATA1)用于分割事务(Split Transactions) 数据必须始终以整数字节数发送 数据CRC仅计算在数据包的数据字段上,不包括PID,而PID有自己的检查字段 低速设备允许的最大数据负载大小为8字节,全速设备允许的最大数据负载大小为1023字节,高速设备允许的最大数据负载大小为1024字节
SPLIT包(分割事务包)
在 USB 中,分割事务(Split Transaction)是一种特殊的通信机制,允许高速 USB 主机与全速/低速 USB 设备进行通信。这个过程涉及两个令牌:开始分割事务令牌(Start-Split Transaction Token)和完成分割事务令牌(Complete-Split Transaction Token)。这种机制使得高速主机能够与全速或低速设备进行通信,同时维持 USB 总线的高速性能。分割事务的应用场景通常涉及带有分层结构的 USB 架构,例如 USB hub 将高速总线转换为全速或低速总线。
「开始分割事务令牌(Start-Split Transaction Token)」 Hub addr 字段:包含支持此全/低速事务的指定全/低速设备的集线器的 USB 设备地址(与功能地址字段涵义相同(ADD)) SC字段(开始/完成):设置为零的 SPLIT 特殊令牌包指示这是一个开始分割事务(SSPLIT)。 Port字段:包含此全速/低速事务指定的目标集线器的端口号。 S字段(速度):指定此中断或控制事务的速度 , 0 – 全速 1 – 低速 E字段(结束):对于全速等时 OUT 起始分割,S1(起始)和 E(结束)字段指定高速数据有效负载如何对应全速数据包的数据
以下开始分割情况S字段必须设置为零: 批量(bulk)事务 IN/OUT 等时( isochronous )事务 IN 开始分割 以下开始分割情况E字段必须设置为零: 批量(bulk)/控制(control)事务 IN/OUT 中断(interrupt) IN/OUT 等时( isochronous )事务 IN
ET(Endpoint Type)字段:指定全速/低速事务的端点类型
当高速主机需要与全速或低速设备进行通信时,它发送开始分割事务令牌 开始分割事务令牌的发送表明主机希望与设备进行通信。 主机等待一段时间,以便设备准备好接收通信。 如果设备可以接收,它返回 NYET(Not Yet)握手,表示尚未完成分割事务。 在收到 NYET 握手后,主机知道设备已准备好接收数据。
「完成分割事务令牌(Complete-Split Transaction Token)」 SC 字段:设置为 1 ,指示这是一个完全分割事务 (CSPLIT) U 字段(保留/未使用):必须置为零 (0B) 完全分割令牌包的其他字段与开始分割令牌包具有相同的定义
完成分割事务令牌用于结束分割事务,确认数据已经成功传输给全速/低速设备。 主机发送数据给设备,使用全速或低速速率。 完成分割事务令牌用于通知 hub 或主机,数据已经传输完成。 如果数据传输成功,hub 或主机将返回 ACK 握手。 如果出现错误,可能返回 NAK 或 STALL 握手。
握手包(Handshake Packets)
握手包仅由一个PID组成 握手包用于报告数据事务的状态,可以返回指示成功接收数据、命令接受或拒绝、流量控制和停止条件的值 仅支持流量控制的事务类型可以返回握手 握手始终在事务的握手阶段返回,可以在数据阶段返回握手而不是返回数据 握手包在一个字节的数据字段后由EOP定界如果一个数据包在解码为握手包的情况下,在一个字节后没有以EOP结束,它必须被视为无效并被接收器忽略
握手包有四种类型以及一种特殊的握手包: ACK(确认) ACK表示数据包在数据字段上没有发生比特填充或CRC错误,且数据PID正确接收。 ACK可以在序列比特匹配且接收器可以接受数据时发出,也可以在序列比特不匹配且发送方和接收方必须重新同步时发出。 ACK仅适用于已传输数据且期望握手的事务。 HOST可以为IN事务返回ACK,而功能(Function)可以为OUT、SETUP或PING事务返回ACK。
场景:假设主机向 USB 设备的 OUT 端点发送数据,设备成功接收并处理数据。 示例:数据传输结束后,设备可以返回 ACK 作为响应。主机接收到 ACK 后,知道数据已被成功接收,可以继续下一步的通信。
「NAK(否定)」 NAK表示功能(Function)无法从主机接受数据(OUT)或功能没有要传输给主机的数据(IN)。 NAK只能由功能(Function)在IN事务的数据阶段或OUT或PING事务的握手阶段返回。 主机永远不会发出NAK。 用于流量控制,表示功能暂时无法传输或接收数据,但最终将能够在无需主机干预的情况下执行。
场景:假设一个 USB 设备在接收数据的过程中发现临时无法处理,可能是因为其缓冲区已满。 示例:在一个 OUT 事务中,当设备无法接受更多的数据时,它可以返回 NAK。主机收到 NAK 后,可能会尝试重新发送数据,直到设备准备好接收。
「STALL(停止)」 STALL由功能响应IN令牌或OUT数据阶段后,或响应PING事务后返回。 STALL表示功能无法传输或接收数据,或不支持控制管道请求。 在返回STALL后,除了默认端点之外的任何端点的功能状态未定义。 STALL分为两种情况:功能性STALL和协议性STALL。功能性STALL在端点的Halt功能被设置时发生,而协议性STALL是控制管道的特例。
场景:设备检测到数据出现错误或设备无法接受主机的请求,需要中止当前的数据传输。 示例:在一个控制事务中,主机向设备发送了一个请求,但设备当前无法响应,可以返回 STALL。这可能是因为设备不支持该请求,或者由于某种原因导致无法继续。主机接收到 STALL 后,可能采取相应的措施,例如中止或重新尝试传输。
「NYET(Not yet)」 NYET是仅适用于高速的握手,在PING协议的一部分或在分割事务未完成或集线器无法处理分割事务时返回。 在PING协议中,当主机发出PING事务并等待高速设备的响应时,设备可以返回NYET,NYET表示设备目前不能接受数据,但可能会在未来的某个时候能够。 在分割事务中,如果目标端点尚未准备好接收数据,集线器可以返回NYET,表示当前不能接受数据。 NYET信号可以用于流量控制,告知主机在目标端点准备好之前,暂时不要发送更多的数据。
场景:假设一个高速 USB 设备正在执行分割事务,其中包含一个低速或全速的子事务,而目标设备还没有完成数据传输。 示例:分割事务的低速或全速子事务尚未完成时,集线器可以返回 NYET。主机可以根据 NYET 信号来决定是否等待,以便在目标设备准备好接收数据时继续传输。
ERR(错误) 场景:假设一个高速 USB 集线器在执行分割事务时发生了错误,导致无法完成全速或低速事务。 示例:集线器可能返回 ERR,通知主机发生了错误。主机在接收 ERR 后,可能会采取适当的措施,如尝试重新发送数据或采取其他纠正措施。
|