USB原理之一连接建立
1.基础通信模型
一个点对点通信模型如下,有三个关键点,通信的双方AB,通信的通道以及数据传输。不同的通信介质,不同的传输协议具体传输实现的细节、要求以及适用的场景都有所区别。在无线通信领域,通信的介质是微波,常见的无线通信协议有bluetooth、zigbee、ant协议,还有局域网中的WLAN,以及基站用到的3G、4G、5G协议簇等等。而在有线通信中,UART、SPI、IIC等通信也都不外乎这个基础模型。在网络应用中,传输协议TCP、UDP在这个模型基础上有了区别,即TCP是面向连接,要管理维护连接,而UDP是无连接,也就是下图中的连线是存在的,但通信的双方并不关注而已。而当这个基础模型适用于USB通信的时候,每个要素都赋予了新的含义。首先来说通信的双方A和B。USB是一种主从结构,主机叫Host,从机叫Device,所以我们经常把从机叫做设备。USB数据通信只能发生在主机与从机之间(新的USB扩展规范USB OTG可以实现主机与主机之间通信,但实质也是通过设备作为媒介实现),所有的数据通信都由主机发起,而从机只能被动地应答。通常,通信的双方是电脑端与USB设备,因此,准确的说通信的双方是主机软件与设备上的端点。USB数据在主机软件与USB设备特定的端点间被传输。主机软件与USB设备特定的端点间的关联叫做pipes。一个USB设备可以有多个管道(pipes)。对于数据传输,USB规定了自己帧格式、对不同传输类型做了分类,后续原理篇一一介绍。
对于像串口类似的简单的通信,双方设备支持串口协议,仅需基本配置一致,物理上连线即可通信。对于USB通信,由于它涵盖的范围广,支持的设备多,通信速率快,适用场景丰富,因此从设备上电、标准请求、连接建立、设备枚举、数据通信都有其自身的概念和术语,下面各节将按照这个逻辑依次说明。
2.连接建立与枚举
USB架构中(前面已介绍), hub负责检测设备的连接和断开,利用其中断IN端点(Interrupt IN Endpoint)来向主机(Host)报告。在系统启动时,主机轮询它的根hub(Root Hub)的状态看是否有设备(包括子hub和子hub上的设备)连接。主机检测到D+与D-之间有电压差,就认为有新的设置接入。 一旦获悉有新设备连接上来,主机就会发送一系列的请求(Resqusts)给设备所挂载到的hub,再由hub建立起一条连接主机(Host)和设备(Device)之间的通信通道(pipe)。然后主机以控制传输(Control Transfer)的方式,通过端点0(Endpoint 0)对设备发送各种请求,设备收到主机发来的请求后回复相应的信息,进行枚举(Enumerate)操作。所有USB设备必须支持标准请求(StandardRequests),控制传输方式(Control Transfer)和端点0(Endpoint 0)。所谓枚举,就是从设备读取一些信息,知道设备是什么样的设备,如何进行通信,这样主机就可以根据这些信息来加载合适的驱动程序。调试USB设备,很重要的一点就是USB的枚举过程,只要枚举成功了,那么就已经成功大半了。 具体过程: 设备插入 1)用户插入USB(设备处于上电状态,端口不工作),Hub检测各个端口(能判断是什么设备)并用中断端点向host报告各个端口状态。 2)host发送request(Get_Port_Status)请求连接设备,hub回复设备速度类型信息。 3)host等待100ms,让电源稳定,发送复位请求(Set_Port_Feature)到设备(单对单),host不断查询设备复位状态(Get_Port_Status请求),hub持续10ms复位,当撤销后设备就处于默认/空闲状态(Default state),准备接收主机发来的请求。 4)主机发送Get Descriptor请求获取默认管道的最大包长度 ,再次复位,再次复位的目的是使设备进入一个确定的状态(不是规定的状态,是windows的行为)。 5)Host通过Set_Address请求向设备分配一个唯一的地址。在完成这次传输之后,设备进入地址状态(Address state),之后就启用新地址继续与主机通信。这个地址对于设备来说是终生制的,设备在,地址在;设备消失(被拔出,复位,系统重启),地址被收回。同一个设备当再次被枚举后得到的地址不一定是上次那个了。 枚举过程 6) 然后正式进入描述符的解析,主机发送 Get_Descriptor请求到新地址读取设备描述符,这次主机发送Get_Descriptor请求可算是诚心,它会认真解析设备描述符的内容。设备接到包后就开始解析包(其实就是你在固件程序里判断处理) ,然后按固定格式返回自己设备的设备描述符,这一步主要是主机知道你的USB设备的基础属性。设备描述符内信息包括端点0的最大包长度,设备所支持的配置(Configuration)个数,设备类型,VID(Vendor ID,由USB-IF分配), PID(Product ID,由厂商自己定制)等信息。之后主机发送Get_Descriptor请求,读取配置描述符(Configuration Descriptor),字符串等,逐一了解设备更详细的信息。 7)主机通过解析描述符后对设备有了足够的了解,选择一个最合适的驱动给设备。 然后tell the world(announce_device)说明设备已经找到了,最后调用设备模型提供的接口device_add将设备添加到 usb 总线的设备列表里,然后 usb总线会遍历驱动列表里的每个驱动,调用自己的 matc(usb_device_match) 函数看它们和你的设备或接口是否匹配,匹配的话调用device_bind_driver函数,现在就将控制权交到设备驱动了。(读完设备描述符,控制权交给驱动,设备进入配置状态)驱动(注意,这里是驱动,之后的事情都是有驱动来接管负责与设备的通信)。 8)根据前面设备回复的信息,发送Set_Configuration请求来正式确定选择设备的哪个配置(Configuration)作为工作配置(对于大多数设备来说,一般只有一个配置被定义)。至此,设备处于配置状态(Configured),当然,设备也应该使能它的各个接口(Interface)。
|