新闻  |   论坛  |   博客  |   在线研讨会
USB 之枚举过程概述
鱼鹰谈单片机 | 2021-01-24 11:44:19    阅读:1512   发布文章

上篇笔记我们大概了解了一下 USB 设备插入主机后经历了什么阶段,本篇笔记和接下来的笔记将详细介绍整个流程。

每一个USB插入后交互的数据都可能不同,比如 U 盘和 CDC 设备的数据交互肯定不同,但基本流程是一致的,所以鱼鹰将以 CDC 设备作为接下来的讲解目标介绍交互情况。USB 枚举,在有些资料中,认为是插入USB后,USB 设备分配到新的设备地址,就认为枚举结束,这可能是更准确的定义,但为了更好的说明,鱼鹰把插入后的整个交互过程都称为枚举,也就是设备能被主机正确识别,可以被上位机使用了。首先我们要了解,枚举的终极目标是什么?当然是让应用程序可以正常使用设备了。为了完成这个目标,当 USB 设备插入后,所有的设备都要经历枚举过程,这是为了让主机正确的了解 USB 设备信息,这样才能更好的驱动它。比如 CDC 设备有如下信息需要主机通过枚举获得(这个图由 CMSIS-DAP 复合设备简化而来,可能有些细节有误,具体参考实际设备的交互数据):7.png上面有 USB 设备的制造商字符串(这里是“Osprey”,代表鱼鹰是制造商,这是鱼鹰生产的 USB,当然了,因为没有购买USB产品ID,所以只能私下使用,不能量产),产品字符串是“OSPREY-CDC”,通过字符串表明这是一个CDC类型的设备,即可以使用虚拟串口(说白了,USB 里面的字符串就是给人看的,真正识别设备却不是靠这些字符串,毕竟字符串是可以被随意修改的)。USB 版本 1.1,即全速 12 Mbit/s,鱼鹰测试过 CDC 全速设备的性能,最优化的情况下STM32F103可以达到 1 MB/s 左右(接近理论值),即使鱼鹰提供的未经过优化的例程,也能达到 900KB/s左右,一般的串口设备肯定是能满足带宽要求的。设备类型选项代表了这是一个 CDC 设备,当然在数据中可不会明确告诉你这是一个 CDC 设备,而是靠一个数字代号2,这个代号是 USB 标准规定的,不管哪个主机,看到 2 就知道这个设备属于CDC类,这样主机就知道应该怎么驱动该设备了。我们可以看看还有哪些类:6.png可以看到这些数字代表了所有的USB设备,你设计的 USB 设备一定属于这里的某一类或多类的组合,多个类型组合的设备就被称之为复合设备,即上面的 EF。那我想设计一种专有的 USB 设备怎么办,FE和FF 就是自定义的设备,因为是自定义的设备,所以别家的驱动都无法驱动该设备,只能由该设备制造商提供的驱动程序驱动。但是像 CDC 、HID、Mass Storage(U 盘)等设备因为是 USB 协议已经规定好的,大家都知道该怎么去驱动它,所以一般的操作系统都会自带该驱动程序,这就是标准 USB 设备的好处,免驱。这里第二列代表了用法,是用在设备描述符,还是用在接口描述符,还是都可以。这里又有一个新名词,描述符。为了在不了解设备情况下可以正确交互数据,USB 规定了一种 USB 设备必须支持的传输类型,即控制传输,四大传输之一。其他传输类型可以不支持,唯独这个,如果设备不支持,抱歉,主机识别不了,哪里凉快哪里待着去吧。控制传输只是定义了如何交互数据(可以查看前面章节了解),但并没有确定交互的具体数据格式或内容。所以 USB 协议为了让主机在设备插入后可以交互所需的数据,定义了一种数据格式,即标准请求,所有USB 设备都必须支持标准请求。因为标准请求的存在,而所有的设备都会支持,所以USB主机可以通过标准请求来获取设备信息。而设备为了回应主机的标准请求,也定义了一种数据格式,称之为描述符。也就是说,主机发送标准请求给设备,设备以描述符的形式回应,通过控制传输,即可完成一次数据交互。我们可以看一看主机是如何通过标准请求获取设备描述符的:5.png主机发送建立事务中的DATA0 数据包就包含了标准请求,请求内容为获取设备描述符,而从机返回的数据包中含有设备描述符,描述了设备的基本信息(注意,黄色代表由主机发送的数据包,橘黄色代表从机发送的数据包,也就是说一次事务中必定会有双方参与)。因为是控制传输,所以有一个状态阶段(DATA1 数据包为空,即包中不携带任何数据),代表这次数据交互完成,可以进行下一次交互了。以上例子,将USB中的主机、从机、包、事务、传输类型、标准请求、描述符等重要概念全部糅合在一起,掌握了它,USB 就算是入门了,枚举过程也变得容易,看代码也能很快理解,建议结合前面的笔记多理解。接下来的笔记可以说基本上是围绕标准请求展开的,毕竟枚举过程就是主机发起一次次标准请求,而从机以对应的描述符进行回应。标准请求数据其实很少,只有 8 个字节,可谓 8 字真言了,所以理解好这 8 字,再理解了描述符,枚举过程也不是那么难。以下是标准请求的数据结构含义:4.png有如下请求代码:3.png上面的每个GET请求代码都有一个对应描述符,用于回复主机的,接下来的 CDC 设备会涉及到里面的大部分请求,到时候鱼鹰会对涉及到的请求内容进行更详细的介绍,现在的你有点基本概念就行。现在回到之前的话题,主机需要通过标准请求获取什么设备信息呢?当我们知道一个 USB 设备是 CDC 类时,其实这个设备的大体框架就已经出来了(ST官方有一篇入门资料可以看一看《USB CDC类入门培训》):2.png枚举过程就是要在这个框架里面填充具体的细节,或者说把 USB 设备里面的框架信息告诉主机,仅此而已(鱼鹰画的那张图,你会发现和上面这张是基本一致的)。我们可以看到 CDC 类涉及到两个接口,接口 0 是通用接口,这个接口一般对应了一个端点,设备用它来传输一些信息给主机;接口 1 是数据接口,专门用来传输数据的,而数据传输是双向的,端点是单向的,所以需要两个端点IN 和 OUT完成数据传输工作。CDC 类固定了这种 USB 设备的整体框架,即下面的橘色部分,但是 USB设备本身有一些信息需要提供给主机,比如 USB 版本号、端点 0 最大包长度、配置数量等信息。1.png所以,把这些信息全部组合起来,就是 USB 设备信息,也是枚举过程需要交互的信息。主机通过标准请求,将 USB 设备中保存的信息交互到主机当中,这样主机就知道该如何驱动 USB 设备了。上图我们可以了解到配置、接口、端点这些重要概念,这里简单说一下。一个 USB 设备可以有多种配置(上图只有一种配置),同一时刻只有一种配置有用,即时分复用。配置下包含了接口,接口又包含了端点,什么意思?看上图就知道了。配置1 包含了接口0、接口1,接口0 下有1个 IN 端点,接口1 有IN 和 OUT 两个端点。最左边的端点是默认端点,即传说中的端点 0(IN和 OUT两个端点),它不需要端点描述符去定义它,天生为枚举过程准备的端点,只要是 USB 设备,必定有这两个端点存在,传输类型必定是控制传输。别问为什么,问就是任性!当然有一点需要告诉主机,那就是这个端点的大小,毕竟每种设备的传输能力不同,不能把它定义死了。设备描述符里面就有这个信息,在这里是 64 字节,所以一次事务可以传输 64 字节数据。正因为端点0是如此的特殊,所有的枚举数据交互都要经过它才行,所以如果我们要分析枚举过程,手上又没有逻辑分析仪可以使用的话,通过截获这两个端点的数据就能完整的了解枚举过程。不过因为数据量太多,太快,115200串口打印可能影响枚举过程,所以可以采用 ITM 或者KEIL的事件记录器功能【终极调试利器,各种Link通吃!】(鱼鹰初期分析就用这个,但效果还是不好,容易丢数据(主要是内存小),通过分段截获才把完整的交互数据记录下来,可谓历经折磨,ITM 或许会好一些,而使用逻辑分析仪会方便许多)。今天的内容很多,需要各位道友慢慢消化,下一小节将介绍 CDC 设备枚举过程的具体过程,再下一节就是介绍代码结构,这个系列基本就算完结了,到时候记得撒花哈!

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客