第 3 章 - USBX 设备堆栈的功能组件

本章从功能角度介绍了高性能 USBX 嵌入式 USB 设备堆栈。

执行概述

设备的 USBX 由多个组件组成。

  • 初始化
  • 应用程序接口调用
  • 设备类
  • USB 设备堆栈
  • 设备控制器
  • VBUS 管理器

下图展示了 USBX 设备堆栈。

USBX Device Stack

初始化

若要激活 USBX,必须调用函数 ux_system_initialize。 此函数会初始化 USBX 的内存资源。

若要激活 USBX 设备功能,必须调用函数 ux_device_stack_initialize。 此函数反过来会对 USBX 设备堆栈使用的所有资源(如 ThreadX 线程、互斥和信号灯)进行初始化。

应该通过应用程序初始化来激活 USB 设备控制器和一个或多个 USB 类。 与 USB 主机端相反,设备端每次只能运行一个 USB 控制器驱动程序。 当类已注册到堆栈并且设备控制器初始化函数已被调用时,总线将处于活动状态,堆栈会响应总线重置和主机枚举命令。

应用程序接口调用

USBX 中有两个级别的 API。

  • USB 设备堆栈 API
  • USB 设备类 API

通常,USBX 应用程序不必调用任何 USB 设备堆栈 API。 大多数应用程序将只访问 USB 类 API。

USB 设备堆栈 API

设备堆栈 API 负责注册 USBX 设备组件(例如类和设备框架)。

USB 设备类 API

类 API 严格特定于每个 USB 类。 USB 类的大多数常见 API 提供了诸如打开/关闭设备以及从设备读取和向设备写入之类的服务。 这些 API 在本质上类似于主机端。

设备框架

USB 设备端负责设备框架的定义。 设备框架分为三个类别,如以下部分所述。

设备框架的组件的定义

设备框架的每个组件的定义与设备和设备使用的资源的性质有关。 下面是主要类别。

  • 设备描述符
  • 配置描述符
  • 接口描述符
  • 终结点描述符

USBX 支持高速和全速的设备组件定义(对低速的处理方式与全速相同)。 这允许设备在连接到高速或全速主机时以不同的方式运行。 典型区别在于每个终结点的大小和设备消耗的电量。

设备组件的定义采用遵循 USB 规范的字节字符串形式。 定义是连续的,框架在内存中的呈现顺序将与枚举期间返回到主机的顺序相同。

下面是高速 USB 闪存磁盘的设备框架示例。

#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60
UCHAR device_framework_high_speed[] = {
    /* Device descriptor */
    0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01,

    /* Device qualifier descriptor */
    0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00,

    /* Configuration descriptor */
    0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, 0x32,

    /* Interface descriptor */
    0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, 0x00,

    /* Endpoint descriptor (Bulk Out) */
    0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00,

    /* Endpoint descriptor (Bulk In) */
    0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00
};

设备框架的字符串的定义

字符串在设备中是可选的。 它们的用途是通过 Unicode 字符串让 USB 主机知道设备的制造商、产品名称和修订号。

主字符串是设备描述符中嵌入的索引。 其他字符串索引可以嵌入到各个接口中。

假设上面的设备框架在设备描述符中嵌入了三个字符串索引,则字符串框架定义可能类似于下面的示例代码。

/* String Device Framework:
    Byte 0 and 1: Word containing the language ID: 0x0904 for US
    Byte 2 : Byte containing the index of the descriptor
    Byte 3 : Byte containing the length of the descriptor string
*/

#define STRING_FRAMEWORK_LENGTH 38
UCHAR string_framework[] = {
    /* Manufacturer string descriptor: Index 1 */
    0x09, 0x04, 0x01, 0x0c,
    0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x20, 0x4c,
    0x6f, 0x67, 0x69, 0x63,

    /* Product string descriptor: Index 2 */
    0x09, 0x04, 0x02, 0x0c,
    0x4D, 0x4C, 0x36, 0x39, 0x36, 0x35, 0x30, 0x30,
    0x20, 0x53, 0x44, 0x4B,

    /* Serial Number string descriptor: Index 3 */
    0x09, 0x04, 0x03, 0x04,
    0x30, 0x30, 0x30, 0x31
};

如果必须为每种速度使用不同的字符串,则必须使用不同的索引,因为索引与速度无关。

字符串的编码基于 UNICODE。 有关 UNICODE 编码标准的详细信息,请参阅以下出版物:

Unicode 标准,全球字符编码版本 1 第 1 卷和第 2 卷,Unicode 联合会,Addison-Wesley Publishing Company,Reading MA。

设备针对每个字符串支持的语言的定义

USBX 能够支持多种语言,但英语是默认语言。 字符串描述符的每种语言的定义采用语言定义数组形式,定义如下。

#define LANGUAGE_ID_FRAMEWORK_LENGTH 2
UCHAR language_id_framework[] = {
    /* English. */
    0x09, 0x04
};

若要支持更多语言,只需在默认英语代码之后添加语言代码双字节定义。 Microsoft 已在文档中定义了语言代码。

针对 Windows 95 和 Windows NT 开发国际软件:Nadine Kano,Microsoft Press,Redmond WA

VBUS 管理器

在大多数 USB 设备设计中,VBUS 不属于 USB 设备核心,而是连接到用于监视线路信号的外部 GPIO。

因此,VBUS 必须与设备控制器驱动程序分开管理。

由应用程序向设备控制器提供 VBUS IO 的地址。 在设备控制器初始化之前,必须对 VBUS 进行初始化。

根据监视 VBUS 的平台规范,可以在 VBUS IO 初始化后让控制器驱动程序处理 VBUS 信号。如果这不可能,则应用程序必须提供用于处理 VBUS 的代码。

如果应用程序希望自行处理 VBUS,则它唯一的要求是在检测到设备已被提取时调用函数 ux_device_stack_disconnect。 在插入设备时无需通知控制器,因为当检测到总线复位断言/解除断言信号时,控制器会被唤醒。