USB 2.0 详解(四)—— 协议层(中)

USB 协议层

8.5 事务的包序列(Packet Sequences of Transaction)

8.5.2 Bulk事务

Bulk事务类型的特点是能够通过错误检测和重试机制保证主机与设备之间的数据可靠传输。Bulk事务采用三相事务,包括Token包、数据包和握手包,如图8-30所示。在某些流控制和停止条件下,数据阶段可能被握手替代,从而形成一个两相事务,此时不会传输数据。PING和NYET包只能在高速设备中使用。

当主机准备接收bulk数据时,它发送一个IN Token包。设备端点响应返回数据包,或者如果无法返回数据,则发送NAK或STALL握手。NAK表示设备暂时无法返回数据,STALL表示端点已永久停止,需要USB系统软件干预。如果主机接收到有效的数据包,它会发送ACK握手。如果主机在接收数据时检测到错误,它不会向设备返回任何握手包。

当主机准备发送bulk数据时,首先会发送OUT Token包,随后发送数据包(或PING特殊Token包,见8.5.1节)。如果设备正确接收数据,它将返回以下三种(或包括NYET,总共四种,适用于高速设备)握手之一:

  • ACK:表示数据包没有错误,并通知主机可以发送下一个数据包。
  • NAK:表示数据没有错误,但主机应重新发送数据,因为设备处于临时状态,无法接收数据(例如,缓冲区满)。
  • STALL:如果端点已停止,返回STALL以表示主机不应重试发送数据,因为设备发生了错误。

如果数据包接收时发生了CRC或位填充错误,则不会返回任何握手。

图8-31和图8-32显示了主机和设备的状态机,分别用于bulk、控制和中断OUT全速/低速事务。图8-27、8-28和8-29显示了高速事务的状态机。图8-33和图8-34显示了主机和设备的状态机,分别用于bulk、控制和中断IN事务。


USB协议中,Bulk事务用于在主机与设备之间传输大量的数据,特点是保证可靠的错误检测和重试机制。Bulk事务有三个阶段:Token包、数据包和握手包。其流程如下:

  1. 接收数据

    • 主机发出IN Token包,设备回应数据包或NAK、STALL握手。
    • 如果数据正确,主机会回应ACK握手;如果有错误,不回应握手。
  2. 发送数据

    • 主机发出OUT Token包,接着发送数据包(或者是PING包)。
    • 设备响应ACK(数据正确)、NAK(设备临时不可接收数据,如缓冲区满)、或STALL(设备端点停止,出现错误)。
  3. 错误处理

    • 如果接收到的包有CRC错误或位填充错误,主机不会返回任何握手,设备需要重发数据。
  4. 高速设备

    • 高速设备使用额外的握手包(如NYET包)来优化流量控制和错误管理。

Bulk事务适用于大容量数据传输,如打印机、磁盘存储、摄像头等设备。由于其允许较大的数据包传输,并且具有较强的错误检测和恢复机制,因此它非常适合传输需要高可靠性的批量数据。

  1. 数据传输流程

    • 在Bulk事务中,数据传输分为三个阶段。首先是Token包,它用于标识数据传输的类型(IN或OUT)。数据包阶段是实际的数据传输阶段,如果数据包没有错误,主机会发送ACK握手,通知设备可以继续传输数据。如果数据传输有问题,主机会使用NAK或STALL包控制数据流。
  2. 错误恢复

    • 通过重试机制,USB协议确保数据的可靠传输。如果设备无法接收数据(例如内存不足或其他硬件限制),它会发送NAK,提示主机稍后重试。如果端点完全停止,则返回STALL,要求USB系统介入修复问题。
  3. 高效的高速设备

    • 高速设备引入了额外的机制(如NYET包)来优化数据流和提高效率。NYET包用于在某些条件下表明设备已经准备好接收数据,但无法立即处理,类似NAK,但它具有不同的时间处理机制。

Figure 8-30

Detailed description of Bulk Transaction Format

图 8-30 展示了 USB Bulk事务的执行流程,其中包括数据传输的主要阶段和每种情况下可能的结果。


  1. 整体结构

    • 三大主要阶段:图中以Token(令牌)、Data(数据)和Handshake(握手)为基础描述Bulk事务的完整流程。
      • Token:主机发送的包,用于指示数据传输的方向(IN/OUT)或设备状态检查(PING,High-speed OUT only)。
      • Data:实际传输的数据,设备与主机之间交换。
      • Handshake:确认或反馈数据传输的状态,如ACK、NAK、STALL等。

    图中的灰色方块表示“主机行为(Host behavior)”,白色方块表示“设备行为(Device behavior)”。

  2. Token阶段

    • IN:主机请求从设备读取数据。

      • 设备响应
        1. 返回数据包(DATA0/DATA1)。
        2. 返回NAK:表示设备暂时无法提供数据(例如缓冲区为空)。
        3. 返回STALL:表示设备端点被永久停止,需要主机干预。
      • 主机的后续处理
        • 若接收到有效数据包,则发送ACK握手。
        • 若接收错误数据(如CRC错误),不发送握手,设备需重新发送数据。
    • OUT:主机发送数据给设备。

      • 设备响应
        1. 返回ACK:确认数据包接收成功,可以发送下一个数据包。
        2. 返回NAK:数据包接收成功,但暂时无法处理(例如缓冲区满)。
        3. 返回STALL:表示端点停止,设备出现不可恢复的错误。
        4. 高速设备可能返回NYET(Not Yet):指示设备还未准备好接收下一个事务。
      • 主机的后续处理
        • 若收到ACK,主机可以继续发送数据。
        • 若收到NAK或NYET,主机需要等待或重试。
        • 若收到STALL,主机停止事务并报告错误。
    • PING(仅高速设备):主机检查设备是否可以接收下一个数据包。

      • 设备响应
        • 返回ACK表示设备准备好接收。
        • 返回NAK表示设备暂时无法接收。
        • 返回STALL表示设备端点停止。
  3. 数据传输阶段

    • 数据包为DATA0或DATA1,采用数据切换机制(Data Toggle)来标记包的顺序,防止重复接收或丢失数据。
    • 若数据接收无误,设备发送ACK握手。
    • 若接收出错(例如CRC错误或位填充错误),设备不返回任何握手,数据包需要重传。
  4. 握手阶段

    • ACK:数据成功传输。
    • NAK:设备暂时不可接收或未准备好。
    • STALL:端点停止,需主机干预。
    • NYET:高速设备专用,指示设备还未准备好接收下一个数据包。
  5. 状态机细节

    • 图中右下角的“Idle”状态表示事务的结束或设备等待下一事务。
    • 不同的状态路径表明:
      • 数据成功时的流程:Token → Data → ACK → Idle。
      • 数据错误时的流程:Token → Data → (Error,无握手) → Idle。
      • 设备繁忙或停止的流程:Token → NAK/STALL → Idle。

这张图通过不同的路径清晰地展示了Bulk事务在主机和设备之间的交互流程。它强调了以下几点:

  1. Bulk事务采用三阶段机制(Token → Data → Handshake)。
  2. 通过握手包(如ACK、NAK、STALL、NYET)实现可靠的错误检测和恢复。
  3. 高速设备中加入了PING和NYET机制以优化流量控制。

Figure 8-31

Detailed escriptions of Bulk/Control/Interrupt OUT Transaction Host State Machine

图8-31展示了USB协议中Bulk/Control/Interrupt OUT事务的主机状态机(Host State Machine)。


  1. 图的总体结构

    • 这是一个状态机图,显示了主机如何处理Bulk、Control和Interrupt类型的OUT事务。
    • 状态机主要分为以下三个阶段:
      1. Do_token:发送Token包。
      2. Do_data:发送数据包(Data Packet)。
      3. Wait_resp:等待设备的响应包。

    此外,还有一个错误状态 BCI_error 和各种分支条件。

  2. 状态解析

    (1) Do_token(发送Token包)

    • 主机在此阶段根据事务的类型发送相应的Token包:

    • 如果不是控制事务(control transaction)的设置(setup)阶段(not HC_cmd.setup),发送 OUT Token 包:

      Issue_packet(HSD1, tokenOUT);
      
    • 如果是控制事务的设置阶段,发送 SETUP Token 包:

      Issue_packet(HSD1, tokensetup);
      
    • 从状态 Do_token 流转到 Do_data,表示Token包已发送成功。

    (2) Do_data(发送数据包)

    • 主机在此阶段发送实际的数据包(Data Packet):

    • 包括 DATA0 或 DATA1,表示数据传输的同步标志。

      Issue_packet(HSD1, datax);
      
    • 一旦数据包发送完毕,状态进入 Wait_resp

    (3) Wait_resp(等待响应包)

    • 主机等待设备返回的响应包。这些响应可能是:
    • ACK:数据传输成功。
    • NAK:设备暂时无法接收数据。
    • STALL:端点已停止。
    • 其他异常情况或超时。

    等待的具体条件:

    Wait_for_packet(HSU2, ITG);
    

    HSU2 表示从设备接收的包,ITG 表示用于超时的计时器。

    (4) 分支条件

    • ACK

    • 如果设备返回ACK,说明数据包已成功接收:

      RespondHC(Do_next_cmd);
      
    • 主机可以继续处理下一个数据包或结束事务。

    • NAK

    • 如果设备返回NAK,说明设备暂时无法接收数据(例如缓冲区已满):

      RespondHC(Do_same_cmd);
      
    • 主机会等待一段时间后重试当前命令。

    • STALL

    • 如果设备返回STALL,说明端点停止,需要主机软件干预:

      RespondHC(Do_halt);
      
    • 主机会停止当前事务并报告错误。

    • 其他异常或超时

      • 如果响应不是上述三种情况或等待超时:
      RespondHC(Do_halt);
      
      • 主机会停止当前事务。
    • 错误计数机制

      • 每次事务失败(非ACK)时,错误计数器增加。
      • 如果错误计数器小于3,主机尝试重新发送当前命令:
      RespondHC(Do_same_cmd);
      
      • 如果错误计数器达到或超过3,主机停止事务:
      RespondHC(Do_halt);
      

    (5) BCI_error(错误状态)

    • IncError:表示主机检测到错误,错误计数器递增。
    • 如果进入该状态,状态机会根据错误计数器的值决定是重试事务还是终止事务。
  3. 重要逻辑分支

    • 条件判断(分支节点)

      • 图中有一个关键的条件分支:

        (HSU2.PID /= STALL and HSU2.PID /= NAK and HSU2.PID /= ACK) or HSU2.timeout
        

        解释:

        • 如果设备返回的包既不是ACK、NAK,也不是STALL,或者超时未返回任何包,进入错误处理状态。
    • 错误计数逻辑

      • ErrorCount < 3:重试事务。
      • ErrorCount >= 3:终止事务。
  4. 适用范围**

    • 事务类型:此状态机适用于Bulk、Control、Interrupt的OUT事务。
    • 注意事项
      • 图中明确标注了“Not allowed for control setup transaction”,说明控制事务的设置阶段不使用此状态机。

Figure 8-32

Detailed description of Bulk/Control/Interrupt OUT Transaction Device State Machine

图 8-32 展示了设备在处理USB Bulk/Control/Interrupt OUT事务时的状态机,描述了设备如何接收主机发送的OUT数据包并进行相应的处理,包括校验、存储以及反馈。


  1. 整体结构

    状态机包含三个主要阶段:

    1. Dev_wait_Odata:等待主机发送OUT数据包。
    2. Dchkpkt2:检查收到的数据包。
    3. Dopkt:处理数据包,返回ACK/NAK/STALL等响应。

    图中不同条件和分支决定了设备如何处理数据包,以及在何种情况下返回不同的握手响应。

  2. 各个状态的详细解析

    (1) Dev_wait_Odata(等待OUT数据包)

    • 设备处于等待主机发送数据包的状态。
    • 条件:
    • Wait_for_packet(HSU2, ITG):表示设备等待从主机接收到有效数据包 HSU2(即主机传输的数据包)。
    • 如果接收到数据包(Packet_ready(HSU2)),状态机进入 Dchkpkt2 状态,开始检查数据包。

    (2) Dchkpkt2(检查数据包)

    • 设备对接收到的数据包进行检查,包括:
    1. Token类型检查

      • 检查 token.PID 是否为 tokenOUTtokenSETUP
      • 检查 HSD2.PID 是否为有效数据包(DATAx,其中DATA0DATA1)。
    2. CRC校验

      • 检查数据包是否有错误(HSD2.CRC16 = ok)。
    3. 端点状态检查

      • 检查设备端点是否有足够的空间接收数据(device.ep(token.endpt).space_avail)。
      • 检查端点的 toggle 标志(同步数据切换位)。

      结果分支

      1. 数据校验通过并有足够空间
        • 转入 Dopkt 状态处理数据。
      2. 数据校验不通过或端点空间不足
        • 返回相应的握手包(NAK或STALL)。

    (3) Dopkt(处理数据包)
    在此状态,设备处理已通过校验的数据包,并返回握手响应:

    1. ACK(确认接收成功):

      • 条件:

        • HSD2.x 与设备端点的 toggle 同步;
        • CRC校验正确(HSD2.CRC16 = ok);
        • 设备端点有足够空间(device.ep(token.endpt).space_avail)。
      • 动作:

        Dev_accept_data;
        Issue_packet(HSU1, ACK);
        
    2. NAK(暂时无法接收):

      • 条件:

        • 数据同步;
        • CRC校验正确;
        • 端点空间不足。
      • 动作:

        Issue_packet(HSU1, NAK);
        
    3. STALL(端点出错):

      • 条件:

        • 如果端点出错(device.ep(token.endpt).ep_trouble)。
      • 动作:

        Issue_packet(HSU1, STALL);
        
    4. 超时或其他错误

      • 条件:
        • 数据包超时未接收到;
        • CRC错误(HSD2.CRC16 = bad);
        • 数据包PID无效。
      • 动作:
        • 状态流向错误处理。
  3. 关键条件分支**

    图中的条件分支控制着设备如何决定下一步操作:

    1. 数据包校验和同步检查

      HSD2.x = device.ep(token.endpt).toggle and HSD2.CRC16 = ok
      
      • 说明数据包的 toggle 位必须与设备端点一致,且CRC校验正确。
    2. 端点空间检查

      device.ep(token.endpt).space_avail
      
      • 如果端点空间不足,设备返回 NAK 握手,表示暂时无法接收数据。
    3. 错误处理

      (HSD2.PID = datax and HSD2.CRC16 = bad) or HSD2.timeout
      
      • 如果CRC错误或超时未接收到数据包,设备进入错误处理路径。
  4. 状态机的运行逻辑总结

    1. 数据包接收

      • 设备等待主机发送OUT数据包。
      • 检查数据包是否有效,包括PID、CRC和端点状态。
    2. 数据包处理

      • 若数据包通过所有校验且端点空间充足,设备接受数据并返回ACK。
      • 若校验失败或端点空间不足,返回NAK或STALL。
    3. 错误处理

      • 在超时或严重错误情况下,进入错误处理路径,可能需要主机重新启动事务。
  5. 应用场景

    这张状态机图适用于:

    • Bulk事务:如大容量文件传输。
    • Control事务:如设备的设置和控制命令。
    • Interrupt事务:如键盘输入或鼠标移动事件。

有了以上两个案例的详细分析,读者可以尝试分析

Figure 8-33. Bulk/Control/Interrupt IN Transaction Host State Machine

Figure 8-34. Bulk/Control/Interrupt IN Transaction Device State Machine


图 8-35 展示了在批量(Bulk)读取和写入中序列位和数据 PID 的使用方式。通过数据序列切换位(Data Sequence Toggle Bits)和 DATA0/DATA1 的 PID 来实现数据包同步。批量端点的切换序列在端点经历任何配置事件时被初始化为 DATA0(配置事件在第 9.1.1.5 和 9.4.5 节中解释)。端点的数据切换不会因为短包传输或 IRP(I/O 请求包)的完成直接初始化

主机在总线传输的第一次事务中总是初始化为 DATA0 PID,随后第二次事务会使用 DATA1 PID,接下来的数据传输将依次交替使用 DATA0 和 DATA1 PID,直到该批量传输完成。数据包的发送方在收到 ACK 后切换其序列位,而接收方在接收到有效数据包且接受该数据包时也会切换其序列位(参见 8.6 节)。


  1. 数据包同步机制

    • 批量传输依赖于DATA0 和 DATA1 PID 来确保数据包的顺序正确。
    • 数据序列切换位用于同步发送方和接收方的状态。
  2. 切换规则

    • 主机在配置事件发生后,总会从 DATA0 开始。
    • 数据传输以 DATA0 和 DATA1 交替方式进行。
  3. 初始化条件

    • 数据切换位在配置事件后被初始化为 DATA0。
    • 短包或 IRP 的完成不会导致数据切换位初始化。
  4. 切换逻辑

    • 发送方:在收到 ACK(确认包)后,切换序列位。
    • 接收方:在接收到无误的数据包并接受后切换序列位。

数据在传输中可能会因为噪声等因素而丢失。使用切换位的主要目的是确保数据即使在重试情况下,也不会被重复接收或发送。

  • 如果接收方因数据丢失而没有切换序列位,发送方可以通过序列位的对比得知需要重试传输。
  • 同步机制让双方始终知道对方的状态,确保数据一致性。

例如,当主机向 U 盘写入文件时:

  • 主机首先发送 DATA0 数据包。
  • U 盘收到后返回 ACK 并切换为 DATA1。
  • 主机随后发送 DATA1 数据包,依此类推。
  • 如果中途传输失败(如干扰导致接收方未返回 ACK),主机会重发当前数据包(保持原有的 DATA0 或 DATA1 状态)。

  • 短包传输:若数据包长度小于端点最大包大小,传输不会影响切换位的初始化。
  • IRP 完成:即使某个传输请求完成,数据切换位也不会被重置。

8.5.3 控制传输

控制传输至少包含两个事务阶段:设置阶段(Setup)和状态阶段(Status)。控制传输可以选择性地在设置阶段和状态阶段之间包含一个数据阶段(Data)。
在设置阶段,使用SETUP事务向功能端点传输信息。SETUP事务的格式类似于OUT事务,但使用SETUP而不是OUT PID。图8-36展示了SETUP事务的格式。SETUP事务的数据字段总是使用DATA0 PID。接收SETUP事务的功能必须接受SETUP数据并返回ACK;如果数据被破坏,必须丢弃数据并不进行握手。


控制传输(Control Transfers)是USB通信中的一种常见数据传输模式,通常包括三个阶段:

  1. 设置阶段(Setup):在这个阶段,主机通过SETUP事务向设备发送控制请求。这些请求包括设备地址、命令类型等信息。SETUP事务使用SETUP PID,并且数据字段的PID是DATA0。
  2. 数据阶段(Data):此阶段是可选的,只有在需要传输数据时才会存在。例如,向设备发送或从设备接收数据。如果存在数据阶段,传输的数据会在SETUP和状态阶段之间进行。
  3. 状态阶段(Status):这是控制传输的最后阶段,主机或设备会根据操作成功与否返回相应的ACK或NAK信号。如果数据出现损坏,传输的设备会丢弃数据并不会进行握手。

  1. SETUP事务:SETUP事务是控制传输的起始部分,专门用于传输控制命令。它的格式与OUT事务类似,使用SETUP PID标识,这意味着它用于指示发送命令和数据。SETUP事务的一个关键特点是数据字段使用DATA0 PID,它是一种特殊的标志,表明数据包是有效的。

  2. 设备对SETUP的响应:当设备接收到SETUP事务时,它需要解析其中的数据并做出相应的反应。设备必须确认它正确接收了SETUP数据,并发送ACK(确认)信号。如果数据损坏,设备会丢弃这些数据,并且不会进行后续的握手或操作。

  3. 数据传输(如果有):如果控制传输需要数据阶段,则SETUP阶段后会进入数据阶段,数据会被传输。这一阶段通常涉及双向数据传输,主机向设备发送数据,或设备向主机发送数据。

  4. 状态阶段:控制传输的最后阶段,主要用于确认数据是否成功传输。如果操作成功,主机或设备会通过ACK信号进行确认。如果数据在任何阶段损坏或出现错误,可能会导致操作失败,并通过错误处理机制重新传输。

控制传输通常用于发送USB请求,如设备的初始化、状态查询、配置选择等操作,是USB协议中非常基础且重要的部分。


Figure 8-36

Detailed description of Control SETUP Transaction

图8-36描述了 控制传输的SETUP事务流程,从主机(Host)向功能端点(Function)发送命令并完成握手确认的过程。

  • 灰色表示主机发送数据(Host)。

  • 白色表示设备接收数据并发送响应(Function)。

  • 如果设备发现数据损坏,会进入错误状态(Error),丢弃损坏的数据。主机会在超时后重新发送SETUP事务。

  • 传输开始于“Idle”(空闲)状态。

  • 传输完成后,双方进入“Idle”状态,等待下一次事务。


  1. Token(令牌阶段)

    • SETUP令牌:主机发送一个SETUP令牌来通知设备,接下来会发送一个设置(Setup)数据包。
    • 这个阶段的目的是初始化一个控制传输,并告诉设备即将到来的数据包含控制命令。
  2. Data(数据阶段)

    • DATA0数据包:主机发送包含命令信息的数据包(DATA0)。

      • 这是控制传输中的核心部分,包含设置请求的详细信息,比如请求类型(标准/类/厂商)、目标设备/接口的地址、请求编号等。
      • 注意:SETUP事务的数据字段总是使用DATA0 PID,表示数据序列号为0。
    • 设备响应数据包:设备接收到DATA0后会检查数据的完整性。

      • 如果数据完整且正确,设备会在下一阶段做出ACK(确认响应)。
      • 如果数据损坏(例如CRC校验失败),设备会丢弃数据并进入“Error”(错误)状态,不会发送ACK。
  3. Handshake(握手阶段)

    • ACK(确认响应):如果设备成功接收到并解析了DATA0数据包,它会发送ACK(Acknowledgment,确认)信号给主机,表示数据被正确接收。
    • 错误处理:如果设备没有收到正确的数据包(例如数据丢失或损坏),则不会发送ACK,主机会根据USB协议重新尝试发送SETUP事务。

控制传输中的数据阶段(如果存在)由一个或多个IN或OUT事务组成,遵循与批量传输相同的协议规则。数据阶段中的所有事务必须具有相同的方向(即,所有IN或所有OUT)。数据阶段要发送的数量及其方向是在设置阶段期间指定的。如果数据量超过了预先协商的最大数据包大小,则数据将在多个事务(IN或OUT)中发送,每个事务携带最大数据包大小。剩余的数据将在最后一个事务中作为残差发送。

控制传输的状态阶段是序列中的最后一个事务。状态阶段事务遵循与批量传输相同的协议序列。对于高速度设备,状态阶段还包括PING协议。状态阶段由数据流方向的变化来标识,并且总是使用DATA1 PID。例如,如果数据阶段由OUT事务组成,则状态阶段为单个IN事务。如果控制序列没有数据阶段,那么它只包含一个设置阶段,后跟一个由IN事务组成的状态阶段。

图8-37显示了控制读写序列中的事务顺序、数据序列位值和数据PID类型。序列位显示在括号中。


  1. 数据阶段(Data Stage)

    • 控制传输的“数据阶段”由多个IN或OUT事务组成。所有这些事务的方向必须一致(要么全是IN,要么全是OUT)。
    • 数据阶段的数据量和方向在“设置阶段”已经确定。
    • 如果需要发送的数据超过最大包大小,那么数据会被分割成多个事务,每个事务都使用最大包大小,直到所有数据发送完毕。剩余的数据将在最后一个事务中发送,作为“残差”数据。
  2. 状态阶段(Status Stage)

    • 状态阶段是控制传输的最后一个事务。它也遵循类似批量传输的协议规则。
    • 对于高速度设备,状态阶段还涉及到PING协议,用于确认数据传输的完成。
    • 状态阶段的方向与数据阶段相反,通常如果数据阶段是OUT事务,则状态阶段是一个IN事务。
    • 如果没有数据阶段(即仅有设置阶段),则状态阶段只有一个IN事务。
  3. 协议特点

    • 数据阶段和状态阶段遵循严格的事务序列和协议规则,确保数据传输的一致性和可靠性。
    • 控制传输中的状态阶段始终包括方向的反转,以及数据包标识符(PID)类型的使用(如DATA1)。

当一个控制端点(Control Endpoint)在控制传输(Control Transfer)的数据阶段(Data Stage)或状态阶段(Status Stage)发送了一个STALL握手(STALL Handshake)时,在该端点收到一个SETUP PID之前,必须在所有后续访问中返回STALL握手。如果该端点接收到一个后续的SETUP PID,则不需要再返回STALL握手。

对于默认端点(Default Endpoint),如果SETUP事务(Transaction)返回了ACK握手,主机将认为该端点已自动从导致STALL的条件中恢复,且该端点必须正常运行。


  1. STALL握手的定义

    • STALL是USB协议中的一种握手信号,表示设备当前无法处理主机的请求,可能是因为发生了错误或者设备不支持某些特定的操作。
  2. 控制传输(Control Transfer)的流程

    • 控制传输包括三个阶段:设置阶段(Setup Stage)、数据阶段(Data Stage)和状态阶段(Status Stage)。
    • 在数据或状态阶段,如果控制端点无法处理请求,会返回一个STALL信号。
  3. STALL的行为规定

    • 一旦控制端点在数据或状态阶段发送了STALL握手,它在收到下一个SETUP PID之前,必须始终返回STALL。这意味着端点处于“不可用”状态,直到主机通过发送新的SETUP PID重新初始化端点。
  4. 默认端点的特殊情况

    • 默认端点是设备中一个标准的控制端点(通常是端点0)。
    • 如果在SETUP事务中,设备返回了ACK握手(表示成功接收并理解了SETUP包),主机会认为设备已从STALL状态中恢复,且端点必须恢复正常功能。
  5. 主机的期望与设备的响应

    • 主机在收到ACK后,认为设备已解决了STALL的原因。因此,设备需要在ACK握手后继续按照协议正常工作。
    • 如果设备未能恢复正常,可能会导致主机与设备之间的通信失败。

Figure 8-37

图 8-37 描述了USB控制传输(Control Transfer)的三种常见序列:控制写(Control Write)控制读(Control Read)无数据控制(No-data Control)


  1. Control Write (控制写)

    控制写用于主机向设备发送数据,流程如下:

    1. Setup Stage(设置阶段):

      • 主机发送一个 SETUP 包,使用 PID SETUP (0)。该包包含请求信息,如目标端点、数据长度等。
      • 数据的 PID 是 DATA0
    2. Data Stage(数据阶段):

      • 主机发送多个 OUT 包(向设备发送数据)。
      • 这些包交替使用 DATA0DATA1,这是一种简单的数据包编号切换机制,用于检测数据包是否正确传输。
      • OUT (1)OUT (0) 表示主机正在发送数据。
    3. Status Stage(状态阶段):

      • 设备向主机发送一个 IN 包,确认数据接收情况。
      • IN (1)DATA1 表示设备在状态阶段返回确认包。
  2. Control Read (控制读)

    控制读用于主机从设备读取数据,流程如下:

    1. Setup Stage(设置阶段):

      • 主机发送一个 SETUP 包,使用 PID SETUP (0),同样用于发送请求信息。
      • 数据的 PID 是 DATA0
    2. Data Stage(数据阶段):

      • 设备发送多个 IN 包(向主机返回数据)。
      • 这些包交替使用 DATA0DATA1,表示数据包编号切换。
      • IN (1)IN (0) 表示设备正在发送数据。
    3. Status Stage(状态阶段):

      • 主机向设备发送一个 OUT 包,表示数据已接收。
      • OUT (1)DATA1 表示主机在状态阶段确认接收完成。
  3. No-data Control (无数据控制)

    无数据控制用于主机向设备发送没有数据阶段的简单命令,流程如下:

    1. Setup Stage(设置阶段):

      • 主机发送一个 SETUP 包,使用 PID SETUP (0),用于发送请求信息。
      • 数据的 PID 是 DATA0
    2. Status Stage(状态阶段):

      • 设备向主机发送一个 IN 包,表示命令已执行完成。
      • IN (1)DATA1 表示设备确认执行完成。

  1. 控制传输的阶段划分

    • 所有控制传输都包含 Setup StageStatus Stage,而只有控制写和控制读包含 Data Stage
    • 数据阶段的存在取决于传输的类型(写、读或无数据)。
  2. 数据包编号(DATA0/DATA1)

    • 在数据阶段,DATA0DATA1 交替使用,确保传输的可靠性。
  3. 方向标识(IN/OUT)

    • IN 表示从设备向主机发送数据。
    • OUT 表示从主机向设备发送数据。
  4. 无数据传输的特殊性

    • 无数据控制传输没有数据阶段,只有设置阶段和状态阶段。

8.5.3.1 状态报告结果

状态阶段向主机报告前一个设置阶段和数据阶段的结果。可能的返回结果有三种:

  • 命令序列成功完成。
  • 命令序列未能完成。
  • 设备仍在忙于完成命令。

状态报告始终是在功能设备到主机的方向进行的。表8-7总结了每种情况需要的响应类型。控制写传输在状态阶段的事务数据阶段返回状态信息;控制读传输在状态阶段的握手阶段返回状态信息,前提是主机在前一个数据阶段发送了零长度数据包。

对于控制读取,主机必须发送一个OUT令牌或者(在高速设备上)PING特殊令牌到控制管道以启动状态阶段。在这个阶段,主机只能发送零长度的数据包,但设备可以接受任何长度的数据包作为有效的状态查询。管道的握手响应该数据包,指示当前的状态。NAK表示设备仍在处理命令,主机应继续状态阶段。ACK表示设备已完成命令并准备好接收新命令。STALL表示设备由于错误无法完成命令。

对于控制写入,主机发送一个IN令牌到控制管道以启动状态阶段。设备以握手或零长度数据包响应,指示当前的状态。NAK表示设备仍在处理命令,主机应继续状态阶段;返回零长度数据包表示命令已正常完成;STALL表示设备无法完成命令。设备期望主机在状态阶段回应ACK数据包。如果设备没有收到ACK,它将保持在状态阶段,并会继续返回零长度数据包,直到主机继续发送IN令牌。

如果在数据阶段中,命令管道发送的数据量超出了在设置阶段中指示的数量(参见8.5.3.2节),设备应返回STALL。如果在数据阶段中,控制管道返回STALL,则该控制传输不会有状态阶段。


在USB 2.0的传输过程中,状态阶段用于报告先前的命令序列的处理结果。状态报告的方向是从设备到主机,且根据命令的执行情况,主机会收到不同的响应。常见的响应类型包括:

  1. ACK:表示设备已成功完成命令。
  2. NAK:表示设备仍在处理命令,需要主机继续等待。
  3. STALL:表示设备遇到错误,无法完成命令。

此外,在控制传输中,主机需要根据不同的情况发送不同的令牌(如OUT、IN令牌或PING令牌)来启动状态阶段,并根据设备的响应来了解命令的处理结果。如果数据传输超出预期范围,设备会返回STALL,表示错误或无法处理。


在USB协议中,传输的每个阶段都非常重要,特别是状态阶段,它确保了数据传输的可靠性与正确性。主机和设备之间通过控制传输来进行通信,其中包括三个阶段:设置阶段、数据阶段和状态阶段。

状态阶段的主要作用是向主机报告设备对先前命令的处理结果。这个过程通过USB管道进行,具体的状态响应(ACK、NAK、STALL)根据设备的工作状态和命令的执行情况进行反馈。

  1. 控制读取操作:当主机发起控制读取时,设备在状态阶段通过握手来报告处理状态。主机会发送OUT令牌或PING令牌,设备则通过NAK(表示命令未完成)、ACK(表示命令已完成)或STALL(表示命令错误)来做出回应。

  2. 控制写操作:控制写操作则是通过IN令牌来触发状态阶段,设备同样通过零长度数据包或握手来报告命令处理的结果。

  3. 错误处理:当命令传输的长度不符合预期时(比如数据阶段请求了比设置阶段更多的数据),设备会返回STALL,表明遇到错误,无法继续执行命令。


8.5.3.2 可变长度数据阶段

控制管道可能具有一个可变长度的数据阶段,在该阶段中,主机请求的数据量超过了指定数据结构中包含的数据量。当所有数据结构都返回给主机时,设备应通过返回一个短于管道的最大数据包大小(MaxPacketSize)的数据包来表示数据阶段的结束。如果数据结构恰好是管道的 wMaxPacketSize 的整数倍,设备将返回一个零长度数据包来指示数据阶段的结束。


USB协议中数据传输过程中的一种情况,具体是在控制管道(Control Pipe)进行数据传输时,如果主机请求的数据量大于数据结构的实际大小,那么设备将按实际数据的大小返回数据。当设备传输完指定的所有数据后,通过返回一个数据包来表示数据阶段的结束。如果返回的数据包大小恰好与管道的最大包大小 (wMaxPacketSize) 相等,设备需要返回一个零长度数据包以标志数据阶段的结束。


在USB协议中,控制管道(Control Pipe)用于发送和接收命令和数据,通常在设备和主机之间进行配置请求、命令传输和数据传输。在数据阶段,主机和设备之间会交换数据。

对于可变长度的数据阶段,主机请求的数据量可能超过了设备中实际存储的该数据结构的大小。为了正确表示数据传输的结束,USB协议规定了两种情况来结束数据阶段:

  1. 数据包小于最大包大小:当设备返回的数据结构比请求的大小小,并且没有更多数据需要传输时,设备会返回一个短于 MaxPacketSize 的数据包来表示数据传输已经结束。这意味着数据阶段已结束,主机可以继续处理后续的操作。

  2. 数据包等于最大包大小时返回零长度包:如果传输的数据量恰好是管道的最大数据包大小的整数倍(即 wMaxPacketSize),设备将返回一个零长度数据包(Zero-length packet)作为结束标志。这种方式是USB协议中一个特殊的机制,用于在数据量刚好为整数倍时明确告诉主机数据阶段已经结束。

8.5.3.3 最后一个数据传输的错误处理

如果一个IN事务的ACK握手被破坏,功能设备和主机会暂时对事务是否成功产生不一致的理解。如果此事务后跟随另一个IN事务,切换重试机制会检测到这种不一致并从错误中恢复。如果该ACK是数据阶段的最后一个IN事务的ACK,则不能使用切换重试机制,必须使用另一种方案。

成功接收了最后一个IN数据的主机会发送ACK。随后,主机会发出OUT标记,启动传输的状态阶段。如果功能设备没有收到结束数据阶段的ACK,功能设备会将状态阶段的开始解释为主机成功接收了数据。控制写操作不会出现这种歧义。如果OUT事务的ACK握手被破坏,主机不会进入状态阶段,而是重试最后的数据传输。重试策略的详细分析见第8.6.4节。


USB协议中处理最后一个数据事务的错误,特别是ACK握手损坏时的行为。

  • IN事务的错误处理:如果ACK握手被破坏,主机和功能设备会暂时对事务的成功与否产生分歧。后续的IN事务可以通过切换重试机制来检测这种不一致并进行恢复。如果ACK损坏的是数据阶段的最后一个IN,切换重试机制将无法解决问题,这时需要使用其他方法。

  • 状态阶段的开始:主机在接收到最后一个IN的数据后会发送ACK,并启动OUT标记,开始状态阶段。如果功能设备没有收到ACK,它会将状态阶段的开始视为主机已成功接收数据。

  • OUT事务的错误处理:如果OUT事务的ACK握手被破坏,主机不会进入状态阶段,而是重试数据传输。这种情况不会像IN事务那样产生歧义。


在USB协议中,事务通过握手(例如ACK、NAK等)来确认数据是否成功传输。在IN事务中,主机通过发送ACK来确认接收到功能设备的数据。如果ACK遭到破坏,主机和设备可能会在数据是否成功接收上产生分歧。正常情况下,如果是数据阶段的

8.5.3.4 控制管道返回的STALL握手

控制管道具有在控制传输过程中因功能问题而返回STALL握手的独特能力。如果设备无法完成命令,它将在控制传输的数据阶段和/或状态阶段返回STALL。与功能性STALL不同,协议STALL并不表示设备存在错误。协议STALL状态将持续到收到下一个SETUP事务为止,并且在此之前,设备将会对任何IN或OUT事务返回STALL。一般来说,协议STALL表示设备无法理解请求或其参数,从而提供了一种扩展USB请求的机制。

控制管道也可以支持功能性STALL,但不推荐这样做。这是一个退化的情况,因为控制管道上的功能性STALL表明它失去了与主机通信的能力。如果控制管道支持功能性STALL,则它必须具备一个Halt特性,主机可以设置或清除该特性。第9章详细介绍了控制管道上的Halt特性的特殊处理情况。设计良好的设备将会将所有功能和Halt特性与非控制端点关联起来,而控制管道应当保留用于处理USB请求。


  1. 协议STALL (Protocol STALL):当设备无法理解控制传输请求或其参数时,控制管道返回协议STALL。这表示设备无法处理当前的请求,但并不代表设备本身存在故障。协议STALL会持续,直到收到下一个SETUP事务。

  2. 功能STALL (Functional STALL):控制管道也可以支持功能STALL,这表示设备遇到实际的故障或问题,无法继续与主机通信。功能STALL表明控制管道失去了与主机的正常通信能力。如果设备支持功能STALL,它必须支持Halt特性,允许主机设置或清除这一状态。

  3. 不推荐在控制管道上使用功能STALL:由于功能STALL会导致设备失去与主机的通信,因此不推荐在控制管道上使用功能STALL。设计良好的设备通常将功能和Halt特性与非控制端点关联,而将控制管道保留给USB请求的处理。


  • 协议STALL的作用:协议STALL是一种非错误性的“停顿”状态,它表明设备无法理解当前的USB请求。这通常用于扩展或增强USB协议的能力。例如,设备可能不支持某些请求或参数,这时返回协议STALL可以有效地告知主机设备无法处理当前的请求,而不需要产生错误信号。

  • 功能STALL的风险:功能STALL意味着设备遇到了一些实际的故障,无法继续正常工作。如果控制管道返回功能STALL,设备可能已经失去了与主机的通信能力。为了应对这种情况,设备应支持Halt特性,这样主机就可以尝试清除这一状态并恢复正常通信。

  • 设计原则:为了提高USB设备的稳定性和可维护性,控制管道不应支持功能STALL。控制管道应该专门用于处理标准的USB请求,而非用于设备故障处理。因此,设备设计时应将功能STALL和Halt特性关联到非控制端点,从而避免干扰控制管道的正常功能。


8.5.4 中断传输

中断传输可以是IN传输或OUT传输。在收到IN令牌后,一个设备可以返回数据、NAK(未接收确认)或STALL(停止信号)。如果端点没有新的中断信息可返回(即没有待处理的中断),设备将在数据阶段返回一个NAK握手。如果中断端点的Halt功能被设置,设备将返回一个STALL握手。如果有中断信息待处理,设备将返回一个数据包作为中断信息。在主机收到数据包后,如果数据没有错误,主机会返回一个ACK(确认)握手;如果数据包有错误,主机将不返回握手信号。

图8-38展示了中断传输格式。

对于高速和高带宽中断端点,章节5.9.1中提供了更多信息。这些端点在一个微帧内使用多个传输,每个传输遵循图8-38所示的传输格式。

当一个端点使用中断传输机制传输实际的中断数据时,必须遵循数据切换协议(data toggle protocol)。这样可以确保设备知道数据已经被主机接收,并且事件条件可以被清除。这种“保证”事件交付的机制意味着设备只需在中断数据被主机接收之前发送一次数据,而无需每次轮询时都发送中断数据,直到USB系统软件清除中断条件。当使用切换模式时,中断端点会在任何配置事件下初始化为DATA0 PID,并表现得与图8-35所示的批量传输相同。


中断传输是一种常见的USB数据传输机制,特别适用于需要定期但低带宽传输的场景,如键盘、鼠标等设备的事件通知。中断传输有几个关键特点:

  1. IN和OUT传输

    • IN传输:设备将数据发送给主机。
    • OUT传输:主机向设备发送数据,虽然文中主要讨论的是IN传输。
  2. 响应方式

    • NAK:如果没有新数据可供返回,设备将返回NAK握手信号,表示当前没有中断信息。
    • STALL:如果中断端点处于Halt状态,设备将返回STALL,表示该端点被暂停。
    • 数据包:如果有待处理的中断信息,设备将返回一个数据包作为响应。
  3. 确认机制

    • 主机接收到数据包后,如果数据无误,将返回ACK确认握手。如果数据包有误,主机不会返回任何握手信号。
  4. 多事务传输

    • 高速和高带宽的中断端点可能需要多个传输才能完成一个操作,这通常发生在微帧内。每个传输遵循与普通中断传输相同的格式。
  5. 数据切换协议

    • 中断传输遵循数据切换协议(data toggle protocol),即数据包的发送和确认会交替进行,确保数据已成功接收,并且可以清除事件标志。这避免了设备重复发送相同的中断数据,直到确认数据被主机接收并且事件标志被清除。
  6. 数据初始化

    • 当中断端点启用数据切换模式时,它会初始化为DATA0 PID。这时,端点的行为类似于批量传输,使用标准的传输格式。

Figure 8-38

Figure 8-38. Interrupt Transaction Format

描述了USB中断传输的具体流程,包括不同阶段和可能的握手信号以及数据传递方式。

  1. Token(令牌阶段)

    • 图的顶部显示了两种中断传输的令牌类型:INOUT
      • IN令牌:表示主机请求从设备中读取数据。
      • OUT令牌:表示主机将数据写入设备。
    • 在Token阶段,主机发送令牌,以指示要进行的操作。
  2. Data(数据阶段)

    • 如果设备有数据需要发送或接收,则会进入数据阶段。
    • DATA0/DATA1
      • 数据包的类型(DATA0或DATA1)根据数据切换位(Data Toggle)协议交替发送。
      • 这种切换机制确保数据传输的可靠性,避免了重复发送的情况。
    • 如果没有数据需要发送:
      • NAK(Negative Acknowledgment,未接收确认):表示设备当前无法提供数据(IN)或无法接收数据(OUT)。
      • STALL:表示设备端点发生错误,可能需要恢复操作。
  3. Handshake(握手阶段)

    • 在数据阶段结束后,主机会进入握手阶段以确认数据传输是否成功。
      • ACK(Acknowledgment,确认):表示数据包已正确接收。
      • NAK:表示主机无法接收数据(例如数据忙或无效)。
      • STALL:表示设备发生错误,无法继续操作。
    • 如果数据阶段出现错误(例如数据包损坏或CRC校验失败),将直接返回Error路径。
  4. Idle(空闲状态)

    • 如果设备没有可用数据、处于NAK或STALL状态,或数据传输完成后,系统返回到空闲状态,等待下一次中断事务开始。

  • IN 传输(从设备到主机)

    • 主机发送IN令牌。
    • 设备:
      • 如果有数据可供传输,发送DATA0或DATA1包。
      • 如果无数据可供传输,发送NAK。
      • 如果发生错误或设备被停止,发送STALL。
    • 主机收到数据后:
      • 如果数据正确,发送ACK。
      • 如果数据损坏,不发送任何握手信号,直接进入错误处理。
  • OUT 传输(从主机到设备)

    • 主机发送OUT令牌。
    • 主机随后发送数据包(DATA0或DATA1)。
    • 设备:
      • 如果数据正确接收,返回ACK。
      • 如果无法接收,返回NAK。
      • 如果设备端点停止或出错,返回STALL。

8.5.5 Isochronous Transactions

同步事务具有一个令牌(token)和数据阶段(data phase),但没有握手阶段(handshake phase),如下图8-39所示。主机会发送IN或OUT标记,然后进入数据阶段,在此阶段中,设备(对于IN)或主机(对于OUT)传输数据。同步事务不支持握手阶段或重试功能。

  • 重要提示

    • 全速设备或主机控制器:应该能够接受数据包中的DATA0DATA1 PID(包标识符)。但是,它只能在数据包中发送DATA0 PID。
    • 高速主机控制器:必须能够接受并发送DATA0、DATA1、DATA2MDATA PID。
    • 高速设备(最多每微帧一次事务):只能在数据包中发送DATA0 PID。
    • 具有高带宽端点的高速设备(例如,每微帧多于1次事务的设备):必须能够接受和/或发送DATA0、DATA1、DATA2MDATA PID。
  • 关于同步事务的PID和传输

    • 全速同步事务不支持切换序列(toggle sequencing)。
    • 高速同步事务(每微帧只有一次事务)不支持切换序列。
    • 高带宽、高速同步事务支持数据PID序列(有关更多详细信息,请参见第5.9.1节)。

图8-40和图8-41展示了主机和设备的状态机,分别用于同步OUT事务;图8-42和图8-43展示了主机和设备的状态机,分别用于同步IN事务。


同步事务(Isochronous Transactions)主要用于需要实时传输的应用场景,如音频、视频流等。不同于其他类型的USB事务,同步事务的关键特点是:

  1. 没有握手阶段:握手阶段通常用于确认数据是否成功接收并需要重新传输,但同步事务不需要这种确认机制,因为它们关注的是数据的实时性和流畅性,而非精确的可靠性。

  2. 数据传输的可靠性:同步事务不支持重试。即如果数据传输失败,它不会进行重试操作,而是简单地丢弃该数据包并继续传输后续数据。

  3. PID类型和带宽要求

    • 全速和高速设备在同步事务中使用不同的PID。全速设备只能发送DATA0,而高速设备则可以支持更多的PID(如DATA0、DATA1、DATA2、MDATA),其中MDATA用于高带宽的事务。
    • 高速设备根据其带宽和事务频率的不同,支持的数据PID也不同。高带宽设备(每微帧有多个事务)能够支持更灵活的数据PID序列。
  4. 切换序列:对于全速和某些高速设备,同步事务中不使用切换序列。这意味着数据包的传输没有基于前一个包的状态来决定下一个包的传输方式。而在高带宽的高速同步事务中,数据包的传输则会依据PID的序列来管理。