USB协议基础——3
枚举
当USB设备的速度类型确定之后,USB通信的双方将会工作在相同的速度模式下,随后USB枚举才会开始。USB枚举的本质就是USB主机获取USB设备的参数信息并且对于可配置参数进行配置的过程。当枚举结束时,USB设备将会使用在枚举过程中USB主机所配置的参数进行工作,从而确保通信双方使用相同的参数。同时,需要指出的是,可配置的参数可以在后续的通信过程中进行修改。
设备状态
枚举完成之前,USB设备要经过一系列的状态变化,才能最终完成枚举。这些状态是连接状态(attached)、供电状态(powered)、默认状态(default)、地址状态(address)、配置状态(configured)、挂起状态(suspended)。当设备状态变为配置状态时,即可认为USB设备和USB主机间的枚举完成。
连接状态
USB设备需要的主机先建立物理上的连接。如果USB设备连接到主机,就处于连接状态。
供电状态
USB设备可以从USB的VBUS上获取电源,或者通过外部电源获取电源。通过外部电源供电的设备称为自供电(Self-powered)设备,通过VBUS供电的设备称为总线供电(Bus-powered)设备。对于自供电设备,在连接到主机之前,设备已经通电,但此时设备并不是USB协议定义的供电状态,只有VBUS有电之后,才进入供电状态。
默认状态
USB设备进入供电状态后,在被复位之前,不能响应总线上的任何事务(Transaction)。只有当USB设备被复位,处于默认状态后,才会响应主机发送过来的请求。
地址状态
在USB设备被复位后,且在USB主机给USB设备设置一个新的地址之前,所有的USB设备使用默认的0地址与主机通信。USB设备收到主机发送的设置地址SetAddress()请求之后,USB设备会得到一个唯一的地址。会保存这个地址。
指定了新的地址的USB设备在收到USB主机发出的复位信号后会进入默认状态,之前所指定的地址也将无效,USB设备需要USB主机重新分配地址。
配置状态
在USB设备的功能能够使用之前,USB设备和USB主机必须协商确定功能相关的配置项。USB主机通过获取描述符GetDescriptor()请求获得USB设备相关的描述符,通过设置接口SetInterface()和设置配置SetConfifuration()来设置设备的相关配置项。一旦相关功能参数被配置后,USB设备就能正常工作了。
正常工作的USB设备在收到USB主机发出的复位信号后进入默认状态,之前所指定的地址、所配置的接口(Interface)和配置项(Configuration)都将无效,需要由USB主机重新指定设备地址,获取描述符并配置相关配置项,才能使设备再次工作。
挂起状态
挂起/恢复时USB协议实现低功耗的一种机制,总体来说,除了设备的连接状态,在其他状态下,当USB总线持续3ms没有活动时,设备就会自动进入挂起状态。进入挂起状态后,USB设备要维持所有的内部状态,如软件的状态机,以及设备的地址和配置项等。
枚举流程
USB设备状态从初始的连接状态到最终的配置状态的变化过程就是整个枚举流程。在USB2.0协议中,USB设备状态的改变都是由USB主机发起的请求(Request)所触发的,而这些请求实际上就是一个个的控制传输(Control Transfer),如下表所示是一个枚举的流程。
获取设备描述符
枚举的第一步就是获取设备描述符,主机通过GetDescriptor(Device type)请求来获取设备的设备描述符。对于高速设备和低速设备,用于控制传输的端点0支持的最大包长度时确定的,分别是64字节和8字节。对于全速设备,端点0支持的最大包长度可能时8字节、16字节、32字节或者64字节。
有两种情况:
1 USB主机端指定的最大包长度 USB设备端点的最大包长度 USB设备描述符的长度。 主机要求设备返回64字节的设备描述符并默认USB设备端点0的最大包长度为64字节。如果设备端点0的最大包长度大于等于 标准设备描述符的长度(18字节),设备就可以一次性将18字节的设备描述符发送给主机。通信双方保持一致。
2 如果设备的端点0最大包长度(8字节)小于设备描述符的长度,那么此时设备要使用多个事务向主机发送一个完整的设备描述符,就会出现不同步的情况。
设置设备的地址
在下图中,在Transfer 1 中主机发送setAddress()请求来设置设备的地址,在本例中,SetAddress()请求的setup数据内包含主机为设备分配的新地址。设备收到地址后,进入地址状态,在该设备从主机上被断开或者复位之前,设备要一直使用该地址与主机通信。在本次传输中,USB主机和USB设备都仍然使用地址0进行通信。
设备收到SetAddress()请求后,必须要在50ms内处理该请求并完成该请求的状态阶段。在完成状态阶段后,可以有2ms的恢复时间。在该恢复时间内,USB主机不能使用其刚刚指定的地址与USB设备通信。在2ms后,设备必须使用该新地址与USB主机进行通信。
获取完整设备描述符
当设备的新地址设置完成后,USB主机将会使用新的地址与USB设备进行通信。如下图所示,在Transfer2 中,USB主机使用新地址9与USB设备进行通信,以获取完整的18个字节的USB设备描述符。
USB设备描述符的第18个字节表示该设备配置描述符的数目,当USB主机获取到完整的设备描述符后,USB主机就可以获取USB设备的配置描述符了。
获取配置描述符
USB设备的配置描述符的第3个和第4个字节表示USB设备的配置描述符长度,第9个字节代表该配置下USB设备的最大消耗电流值。所以USB主机会先获取配置描述符的前9个字节,以获取该配置描述符的总长度和最大消耗电流值。
其中windows 和ubuntu两种不同的方式。
获取字符串描述符
当USB主机遍历USB设备所有的配置描述符,确定有可用的配置后,主机通过GetDescriptor(String type)标准请求获取该设备的一些字符串格式的信息,如设备制造商、产品信息和序列号等。这些字符串格式的信息是用字符串描述符的形式提供的,而这些信息所对应的字符串描述符的索引描述符的索引是在USB设备的设备描述符中提供的。
获取限定描述符
如下图所示,在Transfer 6 中USB主机也会尝试去获取USB设备的限定描述符,以获取USB设备在其他速度模式下的信息。
USB设备不一定会支持限定描述符,在这种情况下,USB设备会恢复STALL表示设备不支持该描述符。这种控制传输的失败并不影响设备的正常枚举和使用。USB主机会再次获取USB设备的设备描述符(Transfer 7)、配置描述符(Transfer 8) 并进行后续的流程。
配置设备的配置描述符
USB主机获取USB设备的某个配置描述符后,会解析该配置描述符中所有的接口信息和端点信息,之后主机就可以发出SetConfiguration()请求来通知USB设备使用哪一个配置。即使USB设备只有一个配置描述符,这个SetConfiguration()请求也不能被省略。该命令中包含一个配置值,这个配置值是主机从设备的配置描述符中解析得来的。
USB设备收到SetConfiguration()请求后,会判断配置值是否合法。如果合法,设备就进入配置状态**。设备会根据配置值选择对应的配置描述符,进入初始化操作,如初始化该配置中所有接口中所有的端点。初始化完成后设备就具备与主机进行数据传输的能力,此时枚举阶段接收**。
在Transfer10中,USB主机使用SetConfigurantion()配置成功后,整个枚举流程结束。后续的USB通信将主要发生在配置描述符的接口/端点描述符所描述的端点上。
参考 微控制器USB的信号和协议实现