USB设备编程_0

USB 设备编程

本篇将详细描述如何通过在嵌入式设备上(以百问网提供的全场景工业互联设备管理系统解决方案中所使用的 STM32H5 系列开发板为例)实现一个 USB 虚拟串口(Virtual COM Port,VCP),从而让嵌入式系统能够通过 USB 接口与计算机或其他主机设备进行串行通信。

本篇的目标是在大概理解 USB 体系结构协议的基础上通过移植 USBX 并编写驱动程序来实现 虚拟串口 来进一步学习和理解 USB 在实际开发中的应用。

USBX 组件

推荐学习由百问网提供的全场景工业互联设备管理系统解决方案 中对 USBX 组件的详细讲解。

来到USBX官方主页的README可以看到该组件如下图所示的简要概述。

其中提到 USBX 是高性能的、具有较小资源占用的嵌入式 USB 软件堆栈,Eclipse 基金会背书项目,与 ThreadX RTOS 完全集成,可用于所有支持 Eclipse ThreadX RTOS 的处理器。使其成为需要与 USB 设备接口深度嵌入的应用程序的理想选择。

由于我们不用 ThreadxRTOS,而是使用的 FreeRTOS,所以我们需要把 USBX 这套软件堆栈从 ThreadxRTOS 中迁移出来,这种想法能否实现,具体要看 USBX 作为 ThreadxRTOS 的一部分是否与 ThreadxRTOS 内核高度耦合。这里先给答案,可以作为单独组件使用,不过要根据具体的开发考虑依赖关系

在构建 ThreadX 本身之外的任何东西(USBX)时,都必须考虑上面的依赖关系图。

这个会在具体的移植过程中逐步解决。

开始移植

USBX 作为 ThreadX 的一部分,已集成到半导体制造商的SDK和开发环境中。您可以使用意法半导体、恩智浦、瑞萨电子和Microchip选择工具进行开发。

我们直奔 STMicroelectronics

来到推荐主页可以看到主要是在讲 ThreadX RTOS 在 STM32 中的使用,其中有 STM32 Cube扩展包为STM32 H7系列微控制器在STM32 Cube环境中提供了Microsoft® Azure RTOS的完全集成。它集成了RTOS(ThreadX)、USB主机和设备(USBX)、文件系统(包括对NOR和NAND闪存的支持)以及网络(包括以太网和Wi-Fi®媒体(NetX Duo))。

我们使用的是H5系列的开发板,通常在下载界面都会有相关链接,我们可以点击 Download now

看到有Get from GitHub的链接。

在仓库中找到了我们需要的 Sample,并且还有多个Projects

我们去仓库中找一下是否有 H5 的 Sample,可惜没有找到,我们可以去 Github 中找有关的 Samples。

可以找到是有相关示例的,在 STM32CubeH5 MCU Firmware Package中,我们直接拉取仓库到自己指定的目录中,分支选择 main 即可。

git clone --recursive  --depth 1 --branch vx.x.x https://github.com/STMicroelectronics/STM32CubeH5.git

或者直接下载也行。

可以看到USBX的目录中主要结构如下

.
├── cmake                   # CMakeList files for building the project
├── common                  # Core USBX files
├── ports                   # Architecture and compiler specific files
├── samples                 # Sample codes
├── support                 # Misc platform configurations file used by USBX
├── LICENSE.txt             # License terms
├── LICENSE-HARDWARE.txt    # Licensed hardware from semiconductors
├── CONTRIBUTING.md         # Contribution guidance
└── SECURITY.md             # Repo security guidance

Middleware USBX Component中找到

STM32-USBX 组件是源 USBX 的 STM32 定制的分支。
USBX 是一个完整的 USB 主机/设备堆栈,专为嵌入式系统设计。
它提供了一套完整的USB设备和主机类,如 CDC-ACM、大容量存储、HID。
该组件的目标是通过 STM32 HAL/USB 驱动程序集成 STM32 USB 硬件 IP。

详细内容请参阅STM32-USBX Wiki

或者学习由百问网提供的全场景工业互联设备管理系统解决方案 中对 STM32-USBX 组件移植的详细过程讲解。

USBX堆栈主要有三层:

  • 下层是控制器层,确保与硬件USB外围设备接口。对于STM32 MCU,该层与HAL兼容。
  • 中间层确保USB堆栈处理以及低层和高层之间的接口要求。
  • 更高层包括不同的类,并确保与应用程序层的接口。

下图概述了USBX三层体系结构和主要组件。

由于我们的的单片机是作为 USB 设备,与 PC 或其他 USB 主机进行通信,所以我们在自己的工程目录下创建如下几个目录

其中各个目录分别参考 USBX 的三层体系结构和 H5 示例。

Note:

在移植之前我们需要先了解一下 USB 实现虚拟串口的一些简要概念

计算机上的串行通信程序可以像操作传统的串口设备一样,与嵌入式设备通过 USB 进行通信。通信通常是通过 CDC (Communications Device Class) 类的 USB 协议栈来实现的,USBX需要被配置为 USB 设备(Device)模式,并且要支持 CDC 类(通讯设备类)。CDC类定义了通过USB与计算机进行串行通信的协议。

CDC-ACM (Abstract Control Model):这是实现虚拟串口的常见标准,允许计算机通过 USB 和设备进行串行通信。

将刚才下载的 H5 示例文件中 usbx 目录(以下简称 示例)下的 common/core/inc/ 中的文件和 ports/generic/inc/ 中的文件拷贝到我们的工程中,如下图所示。

将示例下的common/core/src/中的如下文件全部拷贝到我们的工程中

ux_device_stack_*(设备堆栈文件)、ux_utility_*(组件文件)、ux_system_*(系统文件)、ux_trace_*(调试文件)

如下图所示

将示例下的common/usbx_device_classes/inc中的如下文件全部拷贝到我们的工程中,如下图所示。

以及示例下的common/usbx_device_classes/src中的如下文件全部拷贝到我们的工程中,如下图所示。

Note

只拷贝所有的 ux_device_class_cdc_acm_* 文件。

将示例下的common/usbx_stm32_device_controllers/中的如下文件全部拷贝到我们的工程中,如下图所示。

全部拷贝即可。

将示例下的Projects\NUCLEO-H503RB\Applications\USBX\Ux_Device_CDC_ACM\USBX\AppProjects\NUCLEO-H503RB\Applications\USBX\Ux_Device_CDC_ACM\USBX\Target 中的如下文件全部拷贝到我们的工程中,如下图所示。

Note

示例中提供的 APP 程序使用的是 Threadx 编译时会出现错误,因为我们使用的是 FreeRTOS,我们只是参考提供的示例程序,然后修改成 FreeRTOS 的应用程序。

配置Keil

现在我们需要将刚刚在工程中创建的目录添加到 Keil 中,并尝试编译解决潜在的问题。

在Keil中添加过头文件的路径和源文件,尝试编译后将会遇到如下图的第一个错误。

错误出现在 ux_port.h 中的第 79 行,提示我们没有找到 tx_api.h 这个文件。

这是一个预编译问题,我们需要添加 UX_STANDALONE 这个宏表示单独使用 ux 组件。

再次尝试编译后,将会遇到如下图第二个错误。

提示我们在汇编出的文件中链接时没有找到 _ux_system_host 这个符号。

我们需要添加 UX_DEVICE_SIDE_ONLY 这个宏表示只使用 USB 设备端。

添加这两个宏定义后,再次尝试编译后,将会遇到如下图所示第三个错误。

提示链接时没有找到 _ux_utility_time_get 这个符号,打开这个符号所在的文件。

发现当定义了 UX_STANDALONE 这个宏后,需要我们提供一个获取时间戳的函数_ux_utility_time_get

这个可以在之后编写应用程序时,编写 _ux_utility_time_get 这个函数来获取时间戳。

除去这个问题外,所有问题都解决了后面就是编写 USB 的应用程序了。