打印
[应用相关]

标准外设版USB驱动库详解(架构+文件+函数+使用说明+示例...

[复制链接]
6126|21
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
nawu|  楼主 | 2021-9-1 13:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
关于驱动

  STM32 MCU有两种带USB功能的IP


针对不同的芯片有不同的独立版本驱动(主要是芯片不同,USB的是有区别的)。目前有如下几个:


  • STSW-STM32046: 主要是针对STM32F105/7, STM32F2 and STM32F4 USB on-the-go Host and device library,对应的说明文档为UM1021。下载地址为https://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32-standard-peripheral-library-expansion/stsw-stm32046.html,该版本的驱动最新版本为2.2.0。下文就是以该驱动为例。
  • STSW-STM32121: 主要是针对STM32F10x, STM32L1xx and STM32F3xx USB full speed device library,对应的说明文档为UM0424。下载地址为https://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32-standard-peripheral-library-expansion/stsw-stm32121.html,该版本的驱动最新版本为4.0.1。
  • STSW-STM32092: 主要是针对STM32F0x2xx USB FS device library,对应的说明为UM1717。下载地址为https://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32-standard-peripheral-library-expansion/stsw-stm32092.html,该版本驱动的最新版本为1.0.0。这里需要注意,该驱动是针对STM32F0x2xx的,但是可以非常方便的移植到STM32F0xx系列得MCU中,需要注意的是,需要根据具体芯片的时钟,修改驱动的usb_conf.h和usb_bsp.c。关于具体的移植可参考网友的该**USB库STM32F0x2移植到STM32F070笔记

以下**主要介绍STSW-STM32046。



使用特权

评论回复
沙发
nawu|  楼主 | 2021-9-1 13:37 | 只看该作者
驱动结构

  目前,独立版USB驱动并不是支持所有的STM3的芯片,且ST已经不再维护独立版的USB库(被Cube系列取代),具体见驱动源码即可。驱动源码的结构还是比较简单的,主要包含驱动库源码、使用示例、其他实用程序、发行说明文档四大部分。驱动目录结构如下图所示:

 重点在Libraries目录中。其中的USB OTG是USB Device和USB Host 的基础。在实际使用,USB OTG是USB Device和USB Host 的底层驱动。(在一开始学习时,还以为每部分都可以独立使用!!)。

  此外,从上图可看到这个USB库里还带了标准外设库源码。主要是因为之前还没有HAL库。而且ST在Cube系列中,重新实现了所有源码(包括USB驱动)即:HAL库。但是需要说明的是,以上USB库不仅仅可以和标准外设库连用,还可以和HAL库连用。

  本文主要说明USB驱动,同目录下的标准库驱动(其他博文中有详细说明)不再多说。其他部分在实际移植过程中可作为参考,例如各种示例程序等,也不详细介绍。USB驱动的整个驱动库的架构如下图:


使用特权

评论回复
板凳
nawu|  楼主 | 2021-9-1 13:38 | 只看该作者
USB OTG core

  USB OTG core,即:STM32芯片内嵌的USB OTG 控制器。 STM32F105/07xx器件内嵌了一个USB OTG FS内核,而STM32F2xx和STM32F4xx器件内嵌了一个USB OTG FS内核和一个HS内核。 见下图:


比较如下:


  USB芯片也分为Controller部分和PHY部分。Controller部分主要实现USB的协议和控制。内部逻辑主要有MAC层、CSR层和FIFO控制层,还有其他低功耗管理之类层次。MAC实现按USB协议进行数据包打包和解包,并把数据按照UTMI总线格式发送给PHY(USB3.0为PIPE)。CSR层进行寄存器控制,软件对USB芯片的控制就是通过CSR寄存器,这部分和CPU进行交互访问,主要作为Slave通过AXI或者AHB进行交互。FIFO控制层主要是和DDR进行数据交互,控制USB从DDR搬运数据的通道,主要作为Master通过AXI/AHB进行交互。PHY部分功能主要实现并转串的功能,把UTMI或者PIPE口的并行数据转换成串行数据,再通过差分数据线输出到芯片外部。

  一般来说,如果usb phy封装在芯片内,基本采用UTMI+的接口。不封装到芯片内的一般采用ULPI接口,这样可以降低pin的数量。

  关于STM32芯片内嵌的OTG FS控制器、OTG HS控制器、OTG FS PHY具体见芯片手册。



使用特权

评论回复
地板
nawu|  楼主 | 2021-9-1 13:39 | 只看该作者
USB OTG full speed core
  OTG_FS 是一款双角色设备(DRD) 控制器,同时支持从机功能和主机功能,完全符合USB 2.0 规范的On-The-Go 补充标准。此外,该控制器也可配置为“仅主机”模式或“仅从机”模式,完全符合USB 2.0 规范。在主机模式下,OTG_FS 支持全速(FS,12 Mb/s)和低速(LS,1.5 Mb/s)收发器,而从机模式下则仅支持全速(FS,12 Mb/s)收发器。OTG_FS 同时支持HNP 和SRP。主机模式下需要的唯一外部设备是提供VBUS的电荷泵。其硬件框图如下

  OTG_FS支持HNP(主机协商协议)和SRP(会话请求协议)。 唯一需要的外部设备是Host模式下VBUS电源的电荷泵。
OTG_FS 接口的通用特性如下:
  • 经USB-IF 认证,符合通用串行总线规范第2.0 版
  • 模块内嵌的PHY 还完全支持定义在标准规范OTG 补充第1.3 版中的OTG 协议
  • 支持A-B 器件识别(ID 线)
  • 支持主机协商协议(HNP) 和会话请求协议(SRP)
  • 允许主机关闭VBUS以在OTG 应用中节省电池电量
  • 支持通过内部比较器对VBUS电平采取监控
  • 支持主机到从机的角色动态切换
  • 可通过软件配置为以下角色:
  • 具有SRP 功能的USB FS 从机(B 器件)
  • 具有SRP 功能的USB FS/LS 主机(A 器件)
  • USB On-The-Go 全速双角色设备
  • 支持FS SOF 和LS Keep-alive 令牌
  • SOF 脉冲可通过PAD 输出
  • SOF 脉冲从内部连接到定时器2 (TIM2)
  • 可配置的帧周期
  • 可配置的帧结束中断
  • 具有省电功能,例如在USB 挂起期间停止系统、关闭数字模块时钟、对PHY 和DFIFO电源加以管理
  • 具有采用高级FIFO 控制的1.25 KB 专用RAM
  • 可将RAM 空间划分为不同FIFO,以便灵活有效地使用RAM
  • 每个FIFO 可存储多个数据包
  • 动态分配存储区
  • FIFO 大小可配置为非2 的幂次方值,以便连续使用存储单元
  • 一帧之内可以无需要应用程序干预,以达到最大USB 带宽


OTG_FS 接口在主机模式下具有以下主要特性和要求:

  • 通过外部电荷泵生成VBUS电压。
  • 多达8 个主机通道(管道):每个通道都可以动态实现重新配置,可支持任何类型的USB 传输。
  • 内置硬件调度器可:
  • 在周期性硬件队列中存储多达8 个中断加同步传输请求
  • 在非周期性硬件队列中存储多达8 个控制加批量传输请求
  • 管理一个共享RX FIFO、一个周期性TX FIFO 和一个非周期性TX FIFO,以有效使用USB 数据RAM。

OTG_FS 接口在从机模式下具有以下特性:

  • 1 个双向控制端点0
  • 3 个IN 端点(EP),可配置为支持批量传输、中断传输或同步传输
  • 3 个OUT 端点,可配置为支持批量传输、中断传输或同步传输
  • 管理一个共享Rx FIFO 和一个Tx-OUT FIFO,以高效使用USB 数据RAM
  • 管理多达4 个专用Tx-IN FIFO(分别用于每个使能的IN EP),降低应用程序负荷
  • 支持软断开功能。



使用特权

评论回复
5
nawu|  楼主 | 2021-9-1 13:42 | 只看该作者
USB OTG high speed core
  OTG_HS 是一个双角色设备(DRD) 控制器,同时支持从机和主机功能,并且完全符合USB 2.0 规范的On-The-Go 补充标准。此外,该控制器也可配置为仅主机或仅从机控制器,完全符合USB 2.0 规范。在主机模式中,OTG_HS 支持高速(HS,480 Mbits/s)、全速(FS、12 Mbits/s)和低速(LS,1.5 Mbits/s)传输,而在从机模式中,仅支持高速(HS,480 Mbits/s)和全速(FS、12 Mbits/s)传输。OTG_HS 还支持HNP 和SRP。OTG 模式下需要的唯一外部设备是提供VBUS 的电荷泵。


USB DMA 不支持内部Flash寻址

OTG_HS支持HNP(主机协商协议)和SRP(会话请求协议)。 所需的唯一外部设备是OTG模式下VBUS电源的电荷泵。

OTG_HS 接口的通用特性如下:

  • 经USB-IF 认证,符合通用串行总线规范2.0 版本
  • 支持3 个PHY 接口
  • 片上全速PHY
  • 连接外部全速PHY 的I2 C 接口
  • 连接外部高速PHY 的ULPI 接口
  • 支持主机协商协议(HNP) 和会话请求协议(SRP)
  • 在OTG 应用中允许主机关闭VBUS以节省功耗,而不需要外部组件
  • 允许使用内部比较器来监视VBUS电平
  • 支持主机和从机之间的动态角色切换
  • 可通过软件配置为以下角色:
  • 支持SRP 的USB HS/FS 从机(B 器件)
  • 支持SRP 的USB HS/FS/LS 主机(A 器件)
  • USB OTG FS 双角色设备
  • 支持HS/FS SOF 以及低速(LS)“Keep-alive”令牌并具有如下功能:
  • SOF 脉冲引脚输出功能
  • SOF 脉冲与定时器2 (TIM2) 的内部连接
  • 可配置的帧周期
  • 可配置的帧结束中断
  • 模块内嵌DMA,并可软件配置AHB 的突发传输类型
  • 具备省电功能,例如在USB 挂起期间停止系统时钟,关闭数字模块内部时钟域、PHY 和DFIFO 电源管理
  • 具有包含高级FIFO 管理的专用4K 字节数据RAM:
  • 可以将存储区配置为不同FIFO,以便灵活高效地使用RAM
  • 每个FIFO 可包含多个数据包
  • 动态地进行存储器分配
  • FIFO 大小可配置为2 的幂以外的值,以便连续使用存储区
  • 一帧之内可以无需要应用程序干预,以达到最大USB 带宽

主机模式下的OTG_HS 接口特征如下:

  • 需要外部电荷泵来生成VBUS
  • 具有多达12 个主机通道(管道),每个通道可动态地进行重新配置,可支持任何类型的USB 传输
  • 内置硬件调度器:
  • 在周期性硬件队列中存储多达8 个中断加同步传输请求
  • 在非周期性硬件队列中存储多达8 个控制加批量传输请求
  • 管理一个共享RX FIFO、一个周期性TX FIFO 和一个非周期性TX FIFO,以有效使用USB 数据RAM
  • 在主机模式下具备对SOF 帧周期进行动态调校的功能

OTG_HS 接口在从机模式下具有以下特性:

  • 具有1 个双向控制端点0
  • 具有5 个IN 端点(EP),可配置为支持批量、中断或同步传输
  • 具有5 个OUT 端点,可配置为支持批量、中断或同步传输
  • 管理一个共享Rx FIFO 和一个Tx-OUT FIFO,可高效使用USB 数据RAM
  • 管理多达6 个专用Tx-IN FIFO(每个IN 配置的EP 使用一个)以降低应用程序负载
  • 具备软断开功能



使用特权

评论回复
6
nawu|  楼主 | 2021-9-1 13:43 | 只看该作者
USB OTG low level driver files

  USB OTG驱动源码目录结构及代码架构如下图所示:






使用特权

评论回复
7
nawu|  楼主 | 2021-9-1 13:59 | 只看该作者
USB OTG low level driver 配置
  USB OTG low level driver 配置是通过一个名为usb_conf.h的配置文件进行配置的。在实际的移植过程中,可以复制源码中的usb_conf_template.h然后更名为usb_conf.h,然后编辑修改即可。具体可配置的项目见下表:


使用特权

评论回复
8
nawu|  楼主 | 2021-9-1 14:19 | 只看该作者
USB OTG low level driver 使用
  在USB OTG low level driver的使用中,配置选项均在usb_conf.h中。除此之外,对于某些变量的定义也有如下需要注意的事项。
The Rx and Tx FIFOs size and start address are set inside this function to use one more endpoints in addition to the control Endpoint (0). The user can change the FIFO settings by modifying the default values and changing the FIFO depth for each Tx FIFO in the usb_conf.h file.

Low level driver structures
该部分使用一个结构体USB_OTG_CORE_HANDLE来定义需要使用的变量、状态和缓冲区等。这个结构体也是用户在使用时需要重点关注的第一个结构体。具体如下:

typedef struct USB_OTG_handle
{
  USB_OTG_CORE_CFGS    cfg;
  USB_OTG_CORE_REGS    regs;
#ifdef USE_DEVICE_MODE
  DCD_DEV     dev;
#endif
#ifdef USE_HOST_MODE
  HCD_DEV     host;
#endif
#ifdef USE_OTG_MODE
  OTG_DEV     otg;
#endif
}
USB_OTG_CORE_HANDLE , *PUSB_OTG_CORE_HANDLE;


同时在使用DMA时,需要注意:

  • 目前,DMA仅在高速模式下使用。
  • 在使用DMA时,必须要保证所有需要处理DMA 收发Buf的结构体必须是四字节对齐的。所以,USB_OTG_handle(其封装了所有内部Buffer和变量)必须要四字节对齐。具体可使用如下代码:


#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
  #if defined ( __ICCARM__ ) /*!< IAR Compiler */
    #pragma data_alignment=4   
  #endif
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
__ALIGN_BEGIN USB_OTG_CORE_HANDLE USB_OTG_Core __ALIGN_END;


__ALIGN_BEGIN和__ALIGN_END为特殊的编译器宏值,具体见usb_conf_template.h的定义。


使用特权

评论回复
9
nawu|  楼主 | 2021-9-1 14:24 | 只看该作者
USB OTG low level driver中的Host层
  该部分主要是指usb_hcd.c/h和usb_hcd_int.c/h两个文件。在初始化主机驱动程序(HCD)之后,低级驱动程序为数据和URB状态监视保存多个结构和缓冲区。 主机通道结构保存在主机驱动程序中,并通过主机号索引从上层访问。USB Host 的定义结构:

typedef struct _HCD
{
  uint8_t                  Rx_Buffer [MAX_DATA_LENGTH];  /* 此缓冲区保存IN数据包,并可以从全局主机核心结构直接访问,如下所示:pdev-> host.Rx_Buffer。*/
  __IO uint32_t            ConnSts; /* 连接状态。 它可以直接或通过使用HCD_IsDeviceConnected()函数进行访问。 */
  __IO uint32_t            PortEnabled;  /* */
  __IO uint32_t            ErrCnt[USB_OTG_MAX_TX_FIFOS];  /* 在一次传输过程中保存通道上的错误数量。 */
  __IO uint32_t            XferCnt[USB_OTG_MAX_TX_FIFOS]; /* 保存已在Rx_Buffer中接收和可用的IN数据的数量。 它可以直接访问或使用GetXferCnt()函数访问。*/
  __IO HC_STATUS           HC_Status[USB_OTG_MAX_TX_FIFOS];  /* 由驱动程序内部使用。 可被上层访问。它保存一个通道上的当前传输的状态 */
  __IO URB_STATE           URB_State[USB_OTG_MAX_TX_FIFOS]; /* 该变量保持主机通道上的传输状态。*/
  USB_OTG_HC               hc [USB_OTG_MAX_TX_FIFOS];
  uint16_t                 channel [USB_OTG_MAX_TX_FIFOS]; /* 这个变量管理主机通道状态(使用或空闲)。 */
}
HCD_DEV , *USB_OTG_USBH_PDEV;


usb_hcd_int.c/h文件中使用如下结构来处理USB中断

typedef struct _USBH_HCD_INT
{
  uint8_t (* SOF) (USB_OTG_CORE_HANDLE *pdev);
  uint8_t (* DevConnected) (USB_OTG_CORE_HANDLE *pdev);
  uint8_t (* DevDisconnected) (USB_OTG_CORE_HANDLE *pdev);
  uint8_t (* DevPortEnabled) (USB_OTG_CORE_HANDLE *pdev);  
  uint8_t (* DevPortDisabled) (USB_OTG_CORE_HANDLE *pdev);
}USBH_HCD_INT_cb_TypeDef;

extern USBH_HCD_INT_cb_TypeDef *USBH_HCD_INT_fops;


在库层中,一旦定义了USBH_HCD_INT_cb_TypeDef结构,就应该将其分配给USBH_DCD_INT_fops指针。因为库内部实际使用变量USBD_HCD_INT_fops。
必须在中断中引用函数uint32_t USBH_OTG_ISR_Handler (USB_OTG_CORE_HANDLE *pdev)


使用特权

评论回复
10
nawu|  楼主 | 2021-9-1 14:51 | 只看该作者
USB OTG low level driver中的Device层
  该部分主要是指usb_dcd.c/h和usb_dcd_int.c/h两个文件。这两个文件主要是定义实现USB作为Device时的每个断点的收发缓冲器、起始地址等。USB Device的定义结构:

/* DCD_DEV结构包含用于实时保存与设备有关的所有信息,控制传输状态机以及端点信息和状态的所有变量和结构。
在此结构中,device_config保存当前的USB设备配置,device_state控制具有以下状态的状态机:
// EP0 State
#define USB_OTG_EP0_IDLE        0
#define USB_OTG_EP0_SETUP       1
#define USB_OTG_EP0_DATA_IN     2
#define USB_OTG_EP0_DATA_OUT    3
#define USB_OTG_EP0_STATUS_IN   4
#define USB_OTG_EP0_STATUS_OUT  5
#define USB_OTG_EP0_STALL       6
在这个结构中,device_status定义了连接,配置和电源状态:
// Device Status
#define USB_OTG_DEFAULT        0
#define USB_OTG_ADDRESSED      1
#define USB_OTG_CONFIGURED     2
*/
typedef struct _DCD
{
  uint8_t        device_config;
  uint8_t        device_state;
  uint8_t        device_status;
  uint8_t        device_old_status;
  uint8_t        device_address;
  uint8_t        connection_status;  
  uint8_t        test_mode;
  uint32_t       DevRemoteWakeup;
  USB_OTG_EP     in_ep   [USB_OTG_MAX_TX_FIFOS];
  USB_OTG_EP     out_ep  [USB_OTG_MAX_TX_FIFOS];
  uint8_t        setup_packet [8*3];
  USBD_Class_cb_TypeDef         *class_cb;
  USBD_Usr_cb_TypeDef           *usr_cb;
  USBD_DEVICE                   *usr_device;  
  uint8_t        *pConfig_descriptor;
}
DCD_DEV , *DCD_PDEV;


usb_dcd_int.c/h文件中使用如下结构来处理USB中断

typedef struct _USBD_DCD_INT
{
  uint8_t (* DataOutStage) (USB_OTG_CORE_HANDLE *pdev , uint8_t epnum);
  uint8_t (* DataInStage)  (USB_OTG_CORE_HANDLE *pdev , uint8_t epnum);
  uint8_t (* SetupStage) (USB_OTG_CORE_HANDLE *pdev);
  uint8_t (* SOF) (USB_OTG_CORE_HANDLE *pdev);
  uint8_t (* Reset) (USB_OTG_CORE_HANDLE *pdev);
  uint8_t (* Suspend) (USB_OTG_CORE_HANDLE *pdev);
  uint8_t (* Resume) (USB_OTG_CORE_HANDLE *pdev);
  uint8_t (* IsoINIncomplete) (USB_OTG_CORE_HANDLE *pdev);
  uint8_t (* IsoOUTIncomplete) (USB_OTG_CORE_HANDLE *pdev);  

  uint8_t (* DevConnected) (USB_OTG_CORE_HANDLE *pdev);
  uint8_t (* DevDisconnected) (USB_OTG_CORE_HANDLE *pdev);   

}USBD_DCD_INT_cb_TypeDef;


在库层中,一旦定义了USBD_DCD_INT_cb_TypeDef结构,就应该将其分配给USBD_DCD_INT_fops指针。因为库内部实际使用变量USBD_DCD_INT_fops。
必须在中断中引用函数uint32_t USBD_OTG_ISR_Handler (USB_OTG_CORE_HANDLE *pdev)


使用特权

评论回复
11
nawu|  楼主 | 2021-9-1 15:11 | 只看该作者
选择合适的USB physical 接口
  用户可以根据以上配置来选择自己的PHY。

  • 对于全速模式,会使用芯片内嵌的全速的PHY。只能工作在全速模式
  • 对于高速模式,用户可以选择两种PHY:
  • ULPI接口的外部高速PHY:此时,USB HS Core将以高速模式运行。 此时用户可以通过修改usb_core.c文件中OTG_HS_GUSBCFG寄存器的ULPIFSLS比特位来修改为全速模式。
  • 芯片内嵌的全速PHY:USB HS Core将以全速模式运行。尽管选择了高速。

作为 USB Host 时,如果接入了一个低速设备,则核心会自动降速。


USB host library
  USB Host库是基于支持Host模式、Device模式和OTG模式的通用USB OTG低级驱动程序的,其适用于高速,全速和低速(主机模式)。


  • 支持多数据包传输功能,可传输大量数据; 而不必将其分成最大数据包大小的传输。
  • 使用配置文件更改核心和库配置,而不更改库代码(只读)。
  • 32位对齐的数据结构在高速模式下处理基于DMA的传输。
  • 从用户级别支持多个USB OTG核心实例。
  • 围绕全局状态机构建。
  • 完全兼容实时操作系统(RTOS)。






使用特权

评论回复
12
nawu|  楼主 | 2021-9-1 15:12 | 只看该作者
USB host 源文件及函数

其源码目录结构及执行状态机如下图:



核心状态机过程由USBH_Process函数实现。 应该从应用程序主循环周期性地调用该函数。 USB主机库的初始化由USBH_init函数实现。 该函数应在初始化期间从用户应用程序调用。

HOST_IDLE: 在主机初始化之后,内核在这种状态下开始轮询USB设备连接。 当检测到设备断开连接事件时以及未发生错误时也会进入此状态。

HOST_ISSUE_CORE_RESET: 当连接一个设备以产生一个USB总线RESET时进入这个状态。

HOST_DEV_ATTACHED: 当一个设备连接时,核心进入这个状态。 当一个设备被检测到时,状态机转到HOST_ENUMERATION状态。

HOST_ENUMERATION: 在这种状态下,核心进行USB设备的基本枚举。 在枚举过程结束时,选择默认设备配置(配置0)。

HOST_USR_INPUT: 这是一个中间状态,它遵循枚举并包括等待用户输入以启动USB类操作。

HOST_CLASS_REQUEST: 从此状态开始,类驱动程序接管,并调用类请求状态机以处理所有初始类控制请求(例如:HID的Get_Report_Descriptor)。 完成所需的类请求后,内核将移至HOST_CLASS状态。

HOST_CLASS: 在这种状态下,类状态机被称为类相关操作(非控制和控制操作)。

HOST_CTRL_XFER: 每当需要控制转移时就会进入该状态。

HOST_ERROR_STATE: 只要有任何库状态机发生未恢复的错误,就会进入此状态。 在这种情况下,调用用户回调函数(例如,显示未恢复的错误消息)。 然后主机库被重新初始化。


函数调用关系如下:


在检测到设备后,主库继续进行设备的基本枚举。下图显示了设备枚举中涉及的不同步骤。


使用特权

评论回复
13
nawu|  楼主 | 2021-9-1 15:13 | 只看该作者
Core
 USB host Core由五大块组成:Core host core、USB enumeration、USB control transfer management、USB I/O requests、Channels management。 Core中各文件说明如下:
  • **usbh_core (.c, .h):**该文件包含处理所有USB通信和状态机的功能。
  • **usbh_stdreq(.c, .h) :**该文件实现设备枚举的标准请求。
  • USBH_Get_CfgDesc:获取配置描述符请求。
  • USBH_Get_DevDesc:获取设备描述符请求。
  • USBH_Get_StringDesc:获取字符串描述符请求。
  • USBH_GetDescriptor:通用获取描述符请求
  • USBH_SetCfg:设置配置请求。选择默认配置(配置0)
  • USBH_SetAddress:设置地址请求。将地址设置为1
  • USBH_ClrFeature:清除特征的请求
  • usbh_ioreq (.c, .h): 该文件处理USB事务的生成。
  • USBH_CtlSendSetup:发起一个设置事务。
  • USBH_CtlSendData:发起一个控制数据OUT阶段事务。
  • USBH_CtlReceiveData:发起一个控制数据IN阶段事务。
  • USBH_CtlReq:用于生成控制传输的高级功能(设置,数据,状态阶段)。
  • USBH_BulkSendData:发起 一个bulk OUT事务。
  • USBH_BulkReceiveData:发起一个 bulk IN事务。
  • USBH_InterruptSendData:发起一个 中断OUT事务。
  • USBH_InterruptReceiveData:发起一个 中断IN事务。
  • usbh_hcs (.c, .h) : 该文件处理主机通道分配和触发进程。
  • USBH_Open_Channel:打开并配置新的主机通道。
  • USBH_Modify_Channel:修改现有的主机通道。
  • USBH_Alloc_Channel:将主机通道分配给设备端点(创建USB)。
  • USBH_Free_Channel:释放一个主机通道
  • USBH_DeAllocate_AllChannel:释放所有主机通道(在非初始化阶段使用)
  • usbh_conf.h: 该文件包含设备接口编号,配置编号和最大数据包大小的配置。


在枚举结束时,USB核心调用特定的类驱动程序函数来管理所有与类相关的操作。结构如下:

typedef struct _USBH_Class_cb
{
  USBH_Status  (*Init) (USB_OTG_CORE_HANDLE *pdev , void *phost);
  void (*DeInit) (USB_OTG_CORE_HANDLE *pdev , void *phost);
  USBH_Status  (*Requests) (USB_OTG_CORE_HANDLE *pdev ,void *phost);
  USBH_Status  (*Machine) (USB_OTG_CORE_HANDLE *pdev, void *phost);
} USBH_Class_cb_TypeDef;


库用户API函数仅限于以下两个函数:

  • void USBH_Process (void): 该功能实现核心状态机进程。它应该从用户主循环周期性地调用。
  • USBH_Init: 应该调用这个函数来初始化USB主机硬件和库。




使用特权

评论回复
14
nawu|  楼主 | 2021-9-1 15:14 | 只看该作者
Class

 Class文件夹包含所有与类实现相关的文件,并符合这些类中构建的协议的规范。使用如下结构将类引入到USB驱动

 Class文件夹包含所有与类实现相关的文件,并符合这些类中构建的协议的规范。使用如下结构将类引入到USB驱动


typedef struct _USBH_USR_PROP

{

  void (*Init)(void);       /* HostLibInitialized */

  void (*DeInit)(void);       /* HostLibInitialized */  

  void (*DeviceAttached)(void);           /* DeviceAttached */

  void (*ResetDevice)(void);

  void (*DeviceDisconnected)(void);

  void (*OverCurrentDetected)(void);  

  void (*DeviceSpeedDetected)(uint8_t DeviceSpeed);          /* DeviceSpeed */

  void (*DeviceDescAvailable)(void *);    /* DeviceDescriptor is available */

  void (*DeviceAddressAssigned)(void);  /* Address is assigned to USB Device */

  void (*ConfigurationDescAvailable)(USBH_CfgDesc_TypeDef *,

                                     USBH_InterfaceDesc_TypeDef *,

                                     USBH_EpDesc_TypeDef *);

  /* Configuration Descriptor available */

  void (*ManufacturerString)(void *);     /* ManufacturerString*/

  void (*ProductString)(void *);          /* ProductString*/

  void (*SerialNumString)(void *);        /* SerialNubString*/

  void (*EnumerationDone)(void);           /* Enumeration finished */

  USBH_USR_Status (*UserInput)(void);

  int  (*UserApplication) (void);

  void (*DeviceNotSupported)(void); /* Device is not supported*/

  void (*UnrecoveredError)(void);

}

USBH_Usr_cb_TypeDef;



  • MSC: (Mass storage class)大容量存储类驱动程序用于支持通用USB闪存驱动程序,使用BOT“Bulk-Only Transport”协议和透明SCSI命令集。

驱动程序文件说明如下:

usbh_msc_core.c /.h: MSC核心状态机实现。

usbh_msc_bot.c /.h : BOT(Bulk-Only Transport)协议实现。

usbh_msc_scsi.c /.h : SCSI命令的实现。

usbh_msc_fatfs.c/.h: 用于与Fatfs文件系统进行文件访问操作接口的功能。*其就是Fatfs中diskio.c/.h的实现。

  • HID: (Human Interface Device)USB主机库v1.0中的HID类实现用于支持HID启动的鼠标和键盘设备。 使用中断IN传输接收HID报告。

usbh_hid_core.c /.h: 该模块实现了HID类核心状态机。

usbh_hid_mouse.c /.h: HID鼠标特定例程。

usbh_hid_keybd.c /.h: HID键盘特定例程。


  • CDC: (Communication Device Class) USB通信设备类是USB组织定义的一类专门给各种通信设备(电信通信设备和中速网络通信设备)使用的USB子类。



使用特权

评论回复
15
nawu|  楼主 | 2021-9-1 15:15 | 只看该作者
USB host library configuration
  USB Host 配置(针对Core部分)是通过一个名为usbh_conf.h的配置文件进行配置的。使用者可以复制源码中的usbh_conf_template.h然后更名为usbh_conf.h,然后编辑修改即可。

USB host library 使用方法

第一步: 整理需要的源代码:USB OTG源码、USB Host Core源码、USB Device Class 源码,Keil示例如下:


第二步: 在usb_bsp.c/h文件中,实现 USB 需要使用的底层硬件资源。具体函数见上文及源码文件的注释。

第三步: 根据需要修改usbd_usr.c/h文件。

第四步: 根据源代码进行各种配置


  • USB OTG 配置文件usb_conf.h。具体配置选项见上文及源码中的注释。
  • USB Host配置文件usbh_conf.h。具体配置选项见上文及源码中的注释。

第五步: 实现USB Host所使用的类的源文件。例如本文使用了USB Host的MSC类,所以上图中出现了fatfs相关文件。

第六步: 在自己芯片对应的stm32f4xx_it.c文件中添加USB中断处理函数。

第七步: 定义USB_OTG_CORE_HANDLE USB_OTG_Core及USBH_HOST USB_Host全局变量,然后调用如下函数初始化USB Host 即可


USBH_Init( &USB_OTG_Core,

    #ifdef USE_USB_OTG_FS  

        USB_OTG_FS_CORE_ID,

    #else

        USB_OTG_HS_CORE_ID,

    #endif

        &USB_Host,

        &USBH_MSC_cb, /* 该变量在所使用的类文件中定义/声明 */

        &USR_cb );        /* 该变量在usbd_usr.c/h文件中定义/声明 */



第八步: 在主程序中循环调用void USBH_Process (void)。该函数处理实现USB Host状态机。



USB device library

  • 支持多数据包传输功能,以便可以发送大量数据,而无需将其分割为最大数据包大小传输。
  • 在控制端点上支持最多三个背靠背传输(与OHCI控制器兼容)。
  • 使用配置文件更改核心和库配置,而不更改库代码(只读)。
  • 32位对齐的数据结构来处理高速模式下的基于DMA的传输。
  • 从用户级别支持多个USB OTG核心实例。



使用特权

评论回复
16
nawu|  楼主 | 2021-9-1 15:17 | 只看该作者
USB device 源文件及函数

源码文件结构及驱动架构如下图:


源码文件函数调用关系如下:


使用特权

评论回复
17
nawu|  楼主 | 2021-9-1 15:18 | 只看该作者
Core

  Core文件夹包含修订版2.0通用串行总线规范定义的USB设备库机器。其主要由***USB device core、USB requests、USB I/O requests***三部分组成。各文件及其内部函数的说明如下:

  • usbd_core (.c, .h): 该文件包含处理所有USB通信和状态机的功能。该文件中的主要函数如下:
  • void USBD_Init(USB_OTG_CORE_HANDLE *pdev, USB_OTG_CORE_ID_TypeDef coreID, USBD_Class_cb_TypeDef *class_cb, USBD_Usr_cb_TypeDef *usr_cb):初始化设备库并加载类驱动程序和用户回调。
  • USBD_Status USBD_DeInit(USB_OTG_CORE_HANDLE *pdev):反初始化设备库
  • uint8_t USBD_SetupStage(USB_OTG_CORE_HANDLE *pdev):处理USB规范的SETUP阶段
  • uint8_t USBD_DataOutStage(USB_OTG_CORE_HANDLE *pdev , uint8_t epnum):处理USB规范的Data Out阶段
  • uint8_t USBD_DataInStage(USB_OTG_CORE_HANDLE *pdev , uint8_t epnum):处理USB规范的Data In阶段
  • uint8_t USBD_Reset(USB_OTG_CORE_HANDLE *pdev):处理复位事件
  • uint8_t USBD_Resume(USB_OTG_CORE_HANDLE *pdev):处理Resume事件
  • uint8_t USBD_Suspend(USB_OTG_CORE_HANDLE *pdev):处理Suspend事件
  • uint8_t USBD_SOF(USB_OTG_CORE_HANDLE *pdev):处理SOF事件
  • USBD_Status USBD_SetCfg(USB_OTG_CORE_HANDLE *pdev, uint8_t cfgidx:配置设备并启动接口。
  • USBD_Status USBD_ClrCfg(USB_OTG_CORE_HANDLE *pdev, uint8_t cfgidx):清除当前配置参数
  • uint8_t USBD_IsoINIncomplete(USB_OTG_CORE_HANDLE *pdev):处理不完整的同步IN传输
  • uint8_t USBD_IsoOUTIncomplete(USB_OTG_CORE_HANDLE *pdev):处理不完整的同步OUT传输
  • uint8_t USBD_DevConnected(USB_OTG_CORE_HANDLE *pdev):处理设备连接事件
  • static uint8_t USBD_DevDisconnected(USB_OTG_CORE_HANDLE *pdev):处理设备断开事件
  • usbd_req( .c, .h): USB请求处理。该文件中的主要函数如下:
  • void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len):将ASCII字符串转换为Unicode字符串以格式化字符串描述符。
  • static uint8_t USBD_GetLen(uint8_t *buf):返回字符串的长度
  • USBD_Status USBD_StdDevReq(USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req):处理标准USB设备请求。
  • USBD_Status USBD_StdItfReq(USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req):处理标准USB接口请求。
  • USBD_Status USBD_StdEPReq(USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req):处理标准USB端点请求。
  • static void USBD_GetDescriptor(USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req):处理获取描述符的请求。
  • static void USBD_SetAddress(USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req):设置新的地址
  • static void USBD_SetConfig(USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req):处理设置设备参数的请求。
  • static void USBD_GetConfig(USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req):处理获取设备参数的请求。
  • static void USBD_GetStatus(USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req):处理获取设备状态的请求。
  • static void USBD_SetFeature(USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req):处理设置设备特性的请求。
  • static void USBD_ClrFeature(USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req):处理清除设备特性的请求。
  • void USBD_ParseSetupRequest( USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req):将请求缓冲区复制到SETUP结构中
  • void USBD_CtlError( USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req):处理控制管道上的USB错误。
  • usbd_ioreq (.c, .h) : 该文件为控制端点提供IO请求API。
  • USBD_Status USBD_CtlSendData( USB_OTG_CORE_HANDLE *pdev, uint8_t *pbuf, uint16_t len):在控制管道上发送数据
  • USBD_Status USBD_CtlContinueSendData(USB_OTG_CORE_HANDLE *pdev, uint8_t *pbuf, uint16_t len):继续在控制管道上发送数据。
  • USBD_Status USBD_CtlPrepareRx(USB_OTG_CORE_HANDLE *pdev, uint8_t *pbuf, uint16_t len):准备核心以在控制管道上接收数据。
  • USBD_Status USBD_CtlContinueRx(USB_OTG_CORE_HANDLE *pdev, uint8_t *pbuf, uint16_t len):继续在控制管道上接收数据。
  • USBD_Status USBD_CtlSendStatus(USB_OTG_CORE_HANDLE *pdev):在控制管道上发送一个零长度的数据包
  • USBD_Status USBD_CtlReceiveStatus(USB_OTG_CORE_HANDLE *pdev):在控制管道上接收一个零长度的数据包
  • usbd_conf.h: 该文件包含设备的配置: - 供应商ID,产品ID,字符串等

 在USB设备库初始化期间,Core部分通过选择相应的类回调结构来选择USB类。 在usbd_core.h文件中,类结构定义(详细说明见注释)如下:


typedef struct _Device_cb

{

  uint8_t  (*Init)         (void *pdev , uint8_t cfgidx);/* 当设备收到设置的配置请求时调用此回调; 在这个函数中,类接口使用的端点被打开。 */

  uint8_t  (*DeInit)       (void *pdev , uint8_t cfgidx);/* 当收到清除配置请求时调用此回调; 此函数关闭类接口使用的端点。*/

/* Control Endpoints 控制端点使用 以下几个 */

  uint8_t  (*Setup)        (void *pdev , USB_SETUP_REQ  *req);/* 调用此回调来处理特定的类设置请求 */

  uint8_t  (*EP0_TxSent)   (void *pdev );/*发送状态完成时调用此回调。*/

  uint8_t  (*EP0_RxReady)  (void *pdev );/*当接收状态结束时调用此回调。*/

  /* Class Specific Endpoints*/

  uint8_t  (*DataIn)       (void *pdev , uint8_t epnum);/*这个回调被调用来执行相对于非控制端点阶段的数据。*/

  uint8_t  (*DataOut)      (void *pdev , uint8_t epnum);/*调用此回调函数以执行相对于非控制端点的数据输出阶段。*/

  uint8_t  (*SOF)          (void *pdev);/*当收到SOF中断时调用此回调函数; 这个回调函数可以用来同步一些进程和帧开始。*/

  uint8_t  (*IsoINIncomplete)  (void *pdev);/*当最后一个同步IN传输未完成时调用此回调。*/

  uint8_t  (*IsoOUTIncomplete)  (void *pdev);/*当最后一个同步OUT传输未完成时调用此回调。*/


  uint8_t  *(*GetConfigDescriptor)( uint8_t speed , uint16_t *length);/*该回调返回USB配置描述符。*/

#ifdef USB_OTG_HS_CORE

  uint8_t  *(*GetOtherConfigDescriptor)( uint8_t speed , uint16_t *length);/*该回调在高速模式下返回使用的类的其他配置描述符*/

#endif


#ifdef USB_SUPPORT_USER_STRING_DESC

  uint8_t  *(*GetUsrStrDescriptor)( uint8_t speed ,uint8_t index,  uint16_t *length);/*这个回调函数返回用户定义的字符串描述符。*/

#endif

} USBD_Class_cb_TypeDef;




每个Class都会在自己的实现文件中用该结构定义一个全局变量(例如本文使用的为CDC,则会有USBD_Class_cb_TypeDef USBD_CDC_cb;),表示类自己本身,供Core部分加载。具体为通过USBD_Init函数加载类。

  该库提供用户回调结构,允许用户添加特殊代码来管理USB事件。 在usbd_core.h文件中,这个用户结构定义(具体介绍见注释)如下:


typedef struct _USBD_USR_PROP

{

  void (*Init)(void);/* 该设备库启动(完成初始化后)时调用该回调。 */

  void (*DeviceReset)(uint8_t speed);/*当设备检测到来自主机的重置事件时,会调用此回调。*/

  void (*DeviceConfigured)(void);/*当设备收到设置的配置请求时,会调用此回调。*/

  void (*DeviceSuspended)(void);/*当设备检测到来自主机的暂停事件时,会调用此回调。*/

  void (*DeviceResumed)(void);/*当设备检测到来自主机的恢复事件时,会调用此回调。*/

  void (*DeviceConnected)(void);/*当设备连接到主机时调用此回调。*/

  void (*DeviceDisconnected)(void);/*当设备与主机断开连接时调用此回调。*/

}

USBD_Usr_cb_TypeDef;




这部分需要用户自己来实现。用法与上面的设备类的结构一个样!同样通过USBD_Init函数加载。在驱动内部,会在合适的位置调用用户回调的各函数。

  该库提供描述符回调结构,以允许用户在应用程序运行时管理设备和字符串描述符。 在usbd_core.h文件中,这个描述符结构定义如下:


typedef struct _Device_TypeDef

{

  uint8_t  *(*GetDeviceDescriptor)( uint8_t speed , uint16_t *length);/* 返回设备描述符 */

  uint8_t  *(*GetLangIDStrDescriptor)( uint8_t speed , uint16_t *length);/* 返回返回语言ID字符串描述符*/

  uint8_t  *(*GetManufacturerStrDescriptor)( uint8_t speed , uint16_t *length);/* 返回制造商字符串描述符 */

  uint8_t  *(*GetProductStrDescriptor)( uint8_t speed , uint16_t *length);/* 返回产品描述符 */

  uint8_t  *(*GetSerialStrDescriptor)( uint8_t speed , uint16_t *length); /* 返回序列号字符串描述符。 */

  uint8_t  *(*GetConfigurationStrDescriptor)( uint8_t speed , uint16_t *length);/* 返回配置描述符 */

  uint8_t  *(*GetInterfaceStrDescriptor)( uint8_t speed , uint16_t *length);/* 返回接口描述符 */


#if (USBD_LPM_ENABLED == 1)

  uint8_t  *(*GetBOSDescriptor)( uint8_t speed , uint16_t *length);

#endif   

} USBD_DEVICE, *pUSBD_DEVICE;




  在驱动源码的示例中,可以找到一个名为usbd_desc.c的文件,该文件即为用户实现的各种USB Device的描述符。这样,驱动在工作时,即会返回用户定义的各种描述符了。


通过上面的结构可以看到,其中提供的接口并不包含USB2.0规范定义的全部描述符,例如:端点描述符。主要是其不能由用户自定义!



使用特权

评论回复
18
nawu|  楼主 | 2021-9-1 15:20 | 只看该作者
Class

Class文件夹包含所有与类实现有关的文件。它符合这些类中构建的协议的规范。驱动在结构上使用如下定义的结构来将类引入到USB库中


typedef struct _Device_cb

{

  uint8_t  (*Init)         (void *pdev , uint8_t cfgidx);

  uint8_t  (*DeInit)       (void *pdev , uint8_t cfgidx);

/* Control Endpoints*/

  uint8_t  (*Setup)        (void *pdev , USB_SETUP_REQ  *req);  

  uint8_t  (*EP0_TxSent)   (void *pdev );   

  uint8_t  (*EP0_RxReady)  (void *pdev );  

  /* Class Specific Endpoints*/

  uint8_t  (*DataIn)       (void *pdev , uint8_t epnum);   

  uint8_t  (*DataOut)      (void *pdev , uint8_t epnum);

  uint8_t  (*SOF)          (void *pdev);

  uint8_t  (*IsoINIncomplete)  (void *pdev);

  uint8_t  (*IsoOUTIncomplete)  (void *pdev);   


  uint8_t  *(*GetConfigDescriptor)( uint8_t speed , uint16_t *length);

#ifdef USB_OTG_HS_CORE

  uint8_t  *(*GetOtherConfigDescriptor)( uint8_t speed , uint16_t *length);   

#endif


#ifdef USB_SUPPORT_USER_STRING_DESC

  uint8_t  *(*GetUsrStrDescriptor)( uint8_t speed ,uint8_t index,  uint16_t *length);   

#endif  

  

} USBD_Class_cb_TypeDef;



每个类中,各函数最终封装为以上的结构变量。由于类比较多,下面只针对用的到几个类做详细介绍。其他详细说明请参见ST手册。

HID: 该模块按照2001年6月27日的“人机接口设备(HID)版本1.11的设备类定义”管理MSC类V1.11。该驱动程序实现了规范的以下几个方面:引导接口子类、鼠标协议、用法页面:通用桌面、用法:操纵杆、收集:应用程序。

**usbd_hid (.c, .h):**该文件包含HID类回调(驱动程序)和与此类相关的配置描述符。


**MSC:**该模块按照“通用串行总线海量存储类(MSC)批量传输(BOT)1.0版1999年9月31日”管理MSC类V1.0。该驱动程序实现了规范的以下几个方面:Bulk-only传输协议、子类:SCSI透明命令集(参考SCSI主命令 - 3)。

**usbd_msc( .c, .h):**该文件包含MSC类回调(驱动程序)和与此类相关的配置描述符。

usbd_bot (.c, .h): 该文件处理批量传输协议。

usbd_scsi (.c, .h): 该文件处理SCSI命令。

**usbd_info (.c,.h):**该文件包含大容量存储设备的重要查询页面和感应数据。

usbd_mem.h: 该文件包含来自SCSI层的被调用函数的函数原型,以访问物理介质。


DFU:(Device firmware upgrade )DFU内核按照“设备固件升级版本1.1 2004年8月5日的设备类规范”管理DFU类V1.1。这个核心实现了规范的以下几个方面:设备描述符管理、配置描述符管理、枚举为DFU设备(仅在DFU模式下)、请求管理(支持ST DFU子协议,与DFU协议兼容)、内存请求管理(下载/上传/擦除/分离/ GetState / GetStatus)、DFU状态机实现。

usbd_dfu_core(.c,.h): 该文件包含DFU类回调(驱动程序)和与此类相关的配置描述符。

**usbd_flash_if(.c,.h):**该文件包含与内部闪存接口相关的DFU类回调。

**usbd_otp_if (.c,.h):**该文件包含与OTP存储器相关的接口的DFU类回调。

**usbd_template_if(.c,.h):**该文件提供了一个驱动程序模板,允许您实现更多的内存接口。在移植时,用户需要自行修改该文件。


**Audio:**此驱动程序管理音频类1.0遵循“USB设备类定义的音频设备V1.0 Mar.18,98”。没用过,不做过多说明

**usbd_audio_core(.c,.h):**该文件包含AUDIO类回调(驱动程序)和与此类相关的配置描述符。

**usbd_audio_out_if(.c,.h):**此文件包含低层音频输出驱动程序(从USB主机输出到扬声器)。


CDC:(Communication device class )此驱动程序管理2007年11月16日的“通信设备通用串行总线类别定义修订版1.2”,以及2007年2月9日的“通用串行总线通信类子类规范PSTN设备修订版1.2”的子协议规范。


**usbd_cdc_core(.c,.h):**该文件包含CDC类回调(驱动程序)和与该类相关的配置描述符。主要函数如下:


static uint8_t usbd_cdc_Init(void *pdev, uint8_t cfgidx):初始化CDC接口。

static uint8_t usbd_cdc_DeInit(void *pdev, uint8_t cfgidx):反初始化CDC接口。

static uint8_t usbd_cdc_Setup(void *pdev, USB_SETUP_REQ *req):处理CDC控制请求。

static uint8_t usbd_cdc_EP0_RxReady(void *pdev):处理CDC控制请求数据。

static uint8_t usbd_cdc_DataIn(void *pdev, uint8_t epnum):处理CDC IN数据阶段。

static uint8_t usbd_cdc_DataOut(void *pdev, uint8_t epnum):处理CDC OUT数据阶段。

static uint8_t usbd_cdc_SOF(void *pdev):处理SOF事件(数据缓冲区更新和同步)

static void Handle_USBAsynchXfer(void *pdev):处理IN数据缓冲区包装。

**usbd_cdc_if_template (.c,.h):**该文件提供了一个驱动程序模板,它允许您为CDC终端实现低层功能。在移植时,用户需要自行修改该文件。例如:示例程序的usbd_cdc_vcp.c/h文件就是基于此的。 底层硬件接口通过各自的驱动程序结构进行管理:


typedef struct _CDC_IF_PROP

{

uint16_t (*pIf_Init)     (void);   

uint16_t (*pIf_DeInit)   (void);   

uint16_t (*pIf_Ctrl)     (uint32_t Cmd, uint8_t* Buf, uint32_t Len);

uint16_t (*pIf_DataTx)   (void);     //  !!! 注意:源码中该函数与手册中的说明的不同(手册中的例子该函数时有参数的)

uint16_t (*pIf_DataRx)   (uint8_t* Buf, uint32_t Len);

}

CDC_IF_Prop_TypeDef;



  每个硬件接口驱动程序都应提供CDC_IF_Prop_TypeDef类型的结构指针。如果给定内存接口不支持某项功能,则相对字段将设置为NULL值。该文件中的主要函数如下:

- uint16_t pIf_Init (void): 初始化低层CDC接口。

- uint16_t pIf_DeInit (void): 反初始化低层CDC接口。

- uint16_t pIf_Ctrl (uint32_t Cmd,uint8_t* Buf, uint32_t Len): 处理CDC控制请求解析和执行。

- uint16_t pIf_DataTx (void): 处理从低层终端到USB主机的CDC数据传输(IN传输)。

- uint16_t pIf_DataRx (uint8_t* Buf,uint32_t Len): 处理来自USB主机的CDC数据接收到低层终端(OUT传输)。


  为了加速IN传输的数据管理,低层驱动程序(usbd_cdc_xxx_if.c / .h)应该使用从CDC核心导出的两个全局变量:


extern uint8_t APP_Rx_Buffer []:将CDC收到的数据写入此缓冲区。 这些数据将通过CDC核心功能中的USB IN端点发送。

extern uint32_t APP_Rx_ptr_in:将此指针递增或在将接收到的数据写入缓冲区APP_Rx_Buffer时将其返回以开始地址。

  该驱动程序提供结构指针:extern CDC_IF_Prop_TypeDef APP_FOPS;其中APP_FOPS应该在usbd_conf.h文件中定义为低层接口结构指针。



使用特权

评论回复
19
nawu|  楼主 | 2021-9-1 15:22 | 只看该作者
如何使用CDC

  该驱动程序使用硬件驱动程序的抽象层(即USART控制接口…)。 这个抽象是通过一个较低层(即usbd_cdc_vcp.c)执行的,您可以根据您的应用程序可用的硬件进行修改。


这部分驱动中,还有一种回环模式。即将受到的数据返还回原通信口,这种方式比较简单。还有一种是收到数据时转发到别的通信口,这就需要在usbd_cdc_vcp.c实现相关代码,包括需要的通信口。否则,该文件实现非常简单,具体见示例源码。


**第一步:**通过文件usbd_conf.h配置以下宏值:


        #define CDC_DATA_MAX_PACKET_SIZE                64   /* 端点IN和OUT数据包大小 实际驱动内部会将 CDC_DATA_IN_PACKET_SIZE 和 CDC_DATA_OUT_PACKET_SIZE 定义为 CDC_DATA_MAX_PACKET_SIZE */

        #define CDC_CMD_PACKET_SZE                                8    /* 控制端点包大小 */

        #define CDC_IN_FRAME_INTERVAL                        5    /* IN包之间的时间间隔 */

        #define APP_RX_DATA_SIZE                                2048 /* 用于IN数据传输的临时循环缓冲区的大小。Total size of IN buffer: APP_RX_DATA_SIZE*8/MAX_BAUDARATE*1000 应该要大于 CDC_IN_FRAME_INTERVAL */



第二步: 在启动时调用函数usbd_cdc_Init()以配置所有必需的固件和硬件组件(应用程序特定的硬件配置函数也由此函数调用)。 硬件组件由较低层接口(即usbd_cdc_vcp_if.c)管理,并且可以由用户根据应用程序需要进行修改。


该函数会由驱动层自动调用。


第三步: CDC IN和OUT数据传输由两个函数管理:


每次有数据(或一定数量的数据)可用于从硬件终端发送到USB主机时,***应由用户应用程序调用APP_DataTx(即VCP_dataTx)***。

每次从USB主机发送一个缓冲区时,CDC内核都会调用APP_DataRx(即VCP_dataRx),并且应该将其发送到硬件终端。 只有当缓冲区中的所有数据都被发送时,该函数才会退出(CDC内核会阻止所有即将到来的OUT数据包,直到该函数完成前一个数据包的处理)。

第四步: CDC控制请求应该由功能APP_Ctrl(即VCP_Ctrl)处理。 每次从主机收到请求时都会调用此函数,并且所有相关数据(如果有)都可用。 该函数应解析请求并执行所需的操作。

第五步: 要关闭通信,请调用函数usbd_cdc_DeInit()。 这将关闭使用的端点并调用较低层的去初始化函数。


已知局限性

  将此驱动程序与OTG HS内核一起使用时,启用DMA模式(在usb_conf.h文件中定义USB_OTG_HS_INTERNAL_DMA_ENABLED)会导致数据仅以4个字节的倍数发送。 这是由于USB DMA不允许从非字对齐地址发送数据。 对于这个特定的应用程序,建议不要启用此选项,除非需要。



使用特权

评论回复
20
nawu|  楼主 | 2021-9-1 15:23 | 只看该作者
USB device library process
  应用程序层只需调用一个函数(USBD_Init)来初始化USB低级驱动程序,USB设备库,硬件(BSP)然后启动库。该应用程序还使用通用USB ISR以及当在usb_conf.h文件中定义了 USB_OTG_HS_DEDICATED_EP1_ENABLED时还会使用特定EP1子例程。

  此外,USBD_Init函数需要用户回调结构来通知用户层不同的库状态和消息以及类回调结构来启动类接口。
  USB低级驱动程序可以通过USBD_DCD_INT_cb结构链接到USB设备库。 该结构确保了USB设备库和低级驱动程序之间的完全独立性; 使低级驱动程序可以被任何其他设备库使用。


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

72

主题

3307

帖子

3

粉丝