博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
STM32 USB 枚举分析
阅读量:4086 次
发布时间:2019-05-25

本文共 6843 字,大约阅读时间需要 22 分钟。

STM32 USB枚举分析

芯片:STM32F407VE

编译器:KEIL5

作者:SY

日期:2017-7-19 08:14:14

STM32 USB枚举

用到比较重要的寄存器:OTG_HS 主机端口控制和状态寄存器 (OTG_HS_HPRT)

  • 系统复位

    • 等待USB连接,延时100ms
    • 主机对USB设备复位,主机检测到端口使能位置位,与设备建立连接
    • 主机再次对USB设备复位,复位结束,开始枚举过程。
    • 主机拥有8个通道,其中IN占用0通道,OUT占用1通道。打开INOUT管道
  • 获取设备描述符,只获取8个字节,为了得到通道0的最大包长度。将状态机调整到HOST_CTRL_XFER。同时备份当前全局状态,便于跳转到HOST_CTRL_XFER恢复状态。

    USBH_Get_DevDesc(pdev , phost, 8); -->USBH_GetDescriptor(); -->        phost->Control.setup.b.bRequest = USB_REQ_GET_DESCRIPTOR; //发送的请求      phost->Control.setup.b.wLength.w = length; //数据长度。如果为0,则在[控制传输]中忽略数据阶段        USBH_CtlReq(); -->                USBH_SubmitSetupRequest(); -->                    USBH_HandleControl(); -->                         CTRL_SETUP -> CTRL_SETUP_WAIT ->                         if (phost->Control.setup.b.wLength.w);                      then                            [CTRL_DATA_IN/CTRL_DATA_OUT]                      else                            [CTRL_STATUS_IN/CTRL_STATUS_OUT]                      fi
    • 发送SETUP令牌包,等待回复
    • 发送DATA1数据包,等待回复
    • 发送状态,回复从机

    流程走完后,获取到当前通道的最大包长度64,因此修改当前通道的最大包长度为64

  • 获取全部设备描述符,长度18字节

    typedef struct _DeviceDescriptor{uint8_t   bLength;uint8_t   bDescriptorType;uint16_t  bcdUSB;        /* USB Specification Number which device complies too */uint8_t   bDeviceClass;uint8_t   bDeviceSubClass; uint8_t   bDeviceProtocol;/* If equal to Zero, each interface specifies its own classcode if equal to 0xFF, the class code is vendor specified.Otherwise field is valid Class Code.*/uint8_t   bMaxPacketSize;uint16_t  idVendor;      /* Vendor ID (Assigned by USB Org) */uint16_t  idProduct;     /* Product ID (Assigned by Manufacturer) */uint16_t  bcdDevice;     /* Device Release Number */uint8_t   iManufacturer;  /* Index of Manufacturer String Descriptor */uint8_t   iProduct;       /* Index of Product String Descriptor */uint8_t   iSerialNumber;  /* Index of Serial Number String Descriptor */uint8_t   bNumConfigurations; /* Number of Possible Configurations */}USBH_DevDesc_TypeDef;
    • 可以看到第8个字节,正好是bMaxPacketSize最大包大小
    • 而且已经获取到设备的VIDPID
  • 设置地址

    #define USBH_DEVICE_ADDRESS                             1USBH_SetAddress(pdev, phost, USBH_DEVICE_ADDRESS) -->phost->Control.setup.b.wValue.w = (uint16_t)DeviceAddress;USBH_CtlReq(pdev, phost, 0 , 0 ); -->    USBH_HandleControl(); -->
    typedef union _USB_Setup{uint8_t d8[8];struct _SetupPkt_Struc{  uint8_t           bmRequestType;  uint8_t           bRequest;  uint16_t_uint8_t  wValue;  uint16_t_uint8_t  wIndex;  uint16_t_uint8_t  wLength;} b;} USB_Setup_TypeDef;
    • SETUP包一共包含8个字节
    + 将设备的地址设置为`1`,`SETUP`包包含设备地址字段+ 发送`SETUP`令牌包,等待回复+ 发送状态,回复从机
  • 获取配置描述符

    #define USB_CONFIGURATION_DESC_SIZE                        9USBH_Get_CfgDesc(pdev, phost, USB_CONFIGURATION_DESC_SIZE); -->USBH_GetDescriptor(); -->        USBH_ParseCfgDesc();
    typedef struct _ConfigurationDescriptor{uint8_t   bLength;uint8_t   bDescriptorType;uint16_t  wTotalLength;        /* Total Length of Data Returned */uint8_t   bNumInterfaces;       /* Number of Interfaces */uint8_t   bConfigurationValue;  /* Value to use as an argument to select this configuration*/uint8_t   iConfiguration;       /*Index of String Descriptor Describing this configuration */uint8_t   bmAttributes;         /* D7 Bus Powered , D6 Self Powered, D5 Remote Wakeup , D4..0 Reserved (0)*/uint8_t   bMaxPower;            /*Maximum Power Consumption */}USBH_CfgDesc_TypeDef;
    • 这9个字节为第一次获取配置描述符时,从机返回的数据。主要获取wTotalLength的值。实测wTotalLength=32
  • 获取配置描述符集合

    /* get FULL config descriptor (config, interface, endpoints) */USBH_Get_CfgDesc(pdev, phost, phost->device_prop.Cfg_Desc.wTotalLength); -->USBH_GetDescriptor(); -->        USBH_ParseCfgDesc();
    • 获取到的数据存储在数组中,数据结构如下:

      typedef  struct  _DescHeader { uint8_t  bLength;        uint8_t  bDescriptorType;} USBH_DescHeader_t;
    • 描述符类型bDescriptorType列表:

      /* Table 9-5. Descriptor Types of USB Specifications */#define  USB_DESC_TYPE_DEVICE                              1#define  USB_DESC_TYPE_CONFIGURATION                       2#define  USB_DESC_TYPE_STRING                              3#define  USB_DESC_TYPE_INTERFACE                           4#define  USB_DESC_TYPE_ENDPOINT                            5#define  USB_DESC_TYPE_DEVICE_QUALIFIER                    6#define  USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION           7#define  USB_DESC_TYPE_INTERFACE_POWER                     8#define  USB_DESC_TYPE_HID                                 0x21#define  USB_DESC_TYPE_HID_REPORT                          0x22
    • 解析数据:

      • 解析接口描述符
      typedef struct _InterfaceDescriptor{ uint8_t bLength; uint8_t bDescriptorType; uint8_t bInterfaceNumber; uint8_t bAlternateSetting;    /* Value used to select alternative setting */ uint8_t bNumEndpoints;        /* Number of Endpoints used for this interface */ uint8_t bInterfaceClass;      /* Class Code (Assigned by USB Org) */ uint8_t bInterfaceSubClass;   /* Subclass Code (Assigned by USB Org) */ uint8_t bInterfaceProtocol;   /* Protocol Code */ uint8_t iInterface;           /* Index of String Descriptor Describing this interface */}USBH_InterfaceDesc_TypeDef;

      获取到bNumEndpoints端点个数为2

      • 然后解析端点描述符
      typedef struct _EndpointDescriptor{ uint8_t   bLength; uint8_t   bDescriptorType; uint8_t   bEndpointAddress;   /* indicates what endpoint this descriptor is describing */ uint8_t   bmAttributes;       /* specifies the transfer type. */ uint16_t  wMaxPacketSize;    /* Maximum Packet Size this endpoint is capable of sending or receiving */   uint8_t   bInterval;          /* is used to specify the polling interval of certain transfers. */}USBH_EpDesc_TypeDef;
    • 通知用户,此时通过接口描述符可以知道设备是哪一种类:

    #define MSC_CLASS                             0x08 /* MSC */#define HID_CLASS                             0x03 /* HID */#define USB_AUDIO                             0x01 /* Audio */#define USB_CDCC                              0x02  /* Communications and CDC Control */#define USB_HID                               0x03  /* HID (Human Interface Device) */#define USB_PRINTER                           0x07  /* Printer */#define USB_MSC                               0x08  /* Mass Storage */#define USB_HUB                               0x09  /* Hub */#define USB_CDCD                              0x0A  /* CDC-Data */#define USB_SMARTCARD                         0x0B  /* Smart Card */#define USB_VIDEO                             0x0E  /* Video */#define USB_AVD                               0x10  /* Audio/Video Devices */
  • 获取生产厂家字符串描述符

    USBH_Get_StringDesc -->    USBH_GetDescriptor -->    USBH_ParseStringDesc -->
    • 值为3SYSTEM
  • 获取产品字符串描述符

    USBH_Get_StringDesc -->USBH_GetDescriptor -->        USBH_ParseStringDesc -->
    • 值为USB Flash Disk
  • 获取产品序列号

    USBH_Get_StringDesc -->USBH_GetDescriptor -->        USBH_ParseStringDesc -->
    • 值为000000000000FD70AC4E2030
  • 设置配置

    USBH_SetCfg -->USBH_CtlReq -->
    • 设置默认配置
  • 枚举完成!

总结

  • 枚举大致流程:
    • 设备复位
    • 获取设备描述符
    • 第一次获取8字节,一部分设备描述符
    • 第二次获取18字节,全部的设备描述符
    • 设置设备地址
    • 获取配置描述符
    • 获取配置描述符集合
    • 获取厂家字符串描述符
    • 获取产品字符串描述符
    • 获取产品序列号
    • 设置配置
    • 枚举完成

转载地址:http://qnzii.baihongyu.com/

你可能感兴趣的文章
VUe+webpack构建单页router应用(一)
查看>>
Vue+webpack构建单页router应用(二)
查看>>
从头开始讲Node.js——异步与事件驱动
查看>>
Node.js-模块和包
查看>>
Node.js核心模块
查看>>
express的应用
查看>>
NodeJS开发指南——mongoDB、Session
查看>>
Express: Can’t set headers after they are sent.
查看>>
2017年,这一次我们不聊技术
查看>>
实现接口创建线程
查看>>
Java对象序列化与反序列化(1)
查看>>
心灵小品(1)
查看>>
HTML5的表单验证实例
查看>>
JavaScript入门笔记:全选功能的实现
查看>>
程序设计方法概述:从面相对象到面向功能到面向对象
查看>>
数据库事务
查看>>
JavaScript基础1:JavaScript 错误 - Throw、Try 和 Catch
查看>>
SQL基础总结——20150730
查看>>
SQL join
查看>>
JavaScript实现页面无刷新让时间走动
查看>>