STM32-USB
+ -

STM32F407 USB设备模块数据结构及初始化入口函数USBD_Init

2022-06-14 1184 0

本人以STM32F404自带的读卡器SLAVE代码为来解说。

STM32F404支持OTG功能,其自带一个全速的USB功能。其USB初始化其实就是写相应的函数代码,这些函数代码却是通一个个的结构体整合起来成回调函数,这些函数是由我们自己写的。而STM32的库函数根据这些构体中的函数指针负责回调我们自己写的回调函数,实现USB功能。

STM32F407提供的全局结构USB_OTG_CORE_HANDLE用来表示USB模块的上下文。

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;

由于USB可以为OTG模式,为设备模式或主主机模式。这里我们只看主机模式的DCD_DEV。

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;

注意后面的三个类型成员变量USBD_Class_cb_TypeDef、USBD_Usr_cb_TypeDef和USBD_DEVICE,其分别代表设备各个状态时的用户回调,设备的初始化与断开和USB标准请求GetDescriptor回调。

USBD_Usr_cb_TypeDef

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_Class_cb_TypeDef

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;

USBD_DEVICE

typedef struct _Device_TypeDef
{
  uint8_t  *(*GetDeviceDescriptor)( uint8_t speed , uint16_t *length);  
  uint8_t  *(*GetLangIDStrDescriptor)( uint8_t speed , uint16_t *length); 
  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);   
} USBD_DEVICE, *pUSBD_DEVICE;

USB_SETUP_REQ

当然,接收到的USB标准请求使用数据结构USB_SETUP_REQ来表示。

typedef  struct  usb_setup_req {
    uint8_t   bmRequest;
    uint8_t   bRequest;
    uint16_t  wValue;
    uint16_t  wIndex;
    uint16_t  wLength;
} USB_SETUP_REQ;

USBD_Init

所以我们再来看USB的初始化函数。

void USBD_Init(USB_OTG_CORE_HANDLE *pdev,
               USB_OTG_CORE_ID_TypeDef coreID,
               USBD_DEVICE *pDevice,                  
               USBD_Class_cb_TypeDef *class_cb, 
               USBD_Usr_cb_TypeDef *usr_cb)
{
  /* Hardware Init */
  USB_OTG_BSP_Init(pdev);  

  USBD_DeInit(pdev);

  /*Register class and user callbacks */
  pdev->dev.class_cb = class_cb;
  pdev->dev.usr_cb = usr_cb;  
  pdev->dev.usr_device = pDevice;    

  /* set USB OTG core params */
  DCD_Init(pdev , coreID);

  /* Upon Init call usr callback */
  pdev->dev.usr_cb->Init();

  /* Enable Interrupts */
  USB_OTG_BSP_EnableInterrupt(pdev);
}

可以看到,第一个参数pdev是全局上下文,是我们自己定义的全局变量的指针,coreID是设备初始化的类型,后面三个对应设备初始化的三个回调函数集合。

typedef enum
{
  USB_OTG_HS_CORE_ID = 0,
  USB_OTG_FS_CORE_ID = 1
}USB_OTG_CORE_ID_TypeDef;

初始化函数为:

USBD_Init(&USB_OTG_dev,USB_OTG_FS_CORE_ID,&USR_desc,&USBD_MSC_cb,&USR_cb);

三个自己指定的回调函数结构体为:

USBD_DEVICE USR_desc =
{
  USBD_USR_DeviceDescriptor,
  USBD_USR_LangIDStrDescriptor, 
  USBD_USR_ManufacturerStrDescriptor,
  USBD_USR_ProductStrDescriptor,
  USBD_USR_SerialStrDescriptor,
  USBD_USR_ConfigStrDescriptor,
  USBD_USR_InterfaceStrDescriptor,
};

USBD_Class_cb_TypeDef  USBD_MSC_cb = 
{
  USBD_MSC_Init,
  USBD_MSC_DeInit,
  USBD_MSC_Setup,
  NULL, /*EP0_TxSent*/  
  NULL, /*EP0_RxReady*/
  USBD_MSC_DataIn,
  USBD_MSC_DataOut,
  NULL, /*SOF */ 
  NULL,  
  NULL,     
  USBD_MSC_GetCfgDesc,
#ifdef USB_OTG_HS_CORE  
  USBD_MSC_GetOtherCfgDesc,
#endif
};

USBD_Usr_cb_TypeDef USR_cb =
{
  USBD_USR_Init,
  USBD_USR_DeviceReset,
  USBD_USR_DeviceConfigured,
  USBD_USR_DeviceSuspended,
  USBD_USR_DeviceResumed,
  USBD_USR_DeviceConnected,
  USBD_USR_DeviceDisconnected,    
};
HID人机交互QQ群:564808376    UAC音频QQ群:218581009    UVC相机QQ群:331552032    BOT&UASP大容量存储QQ群:258159197    STC-USB单片机QQ群:315457461    USB技术交流QQ群2:580684376    USB技术交流QQ群:952873936   

0 篇笔记 写笔记

Windows系统HidD_GetPreparsedData数据结构PHIDP_PREPARSED_DATA研究
上天开了一个玩笑,研究了REACTOS的HidD_GetPreparsedData函数的数据结构(http://www.usbzh.com/article/detail-980.html ),竟然发现这和Windows体统的不兼容。所以这一节我们来研究一下Windows下的HidD_GetPrepa......
UVC摄像头VS_PROBE_CONTROL和VS_COMMIT_CONTROL对应的数据结构定义
UVC 视频流接口控制请求 http://www.usbzh.com/article/detail-45.html 需要使用一些数据字段进行通讯,如UVC1.0是26个字节的长度,UVC1.1是34字节的长度,UVC1.5是48字节的长度。这里我们定义一个通用长48字节结构体,对应VS_PROBE_......
HID报告描述符ITEM的数据结构及代码分析过程
HID报告描述符是数据流的形式,其中最小单位是项英文ITEM,根据定义分为4种。分别为GLOBA,LOCAK和MAIN。项分为长项和短项,这里我们只介绍短项。短项头的一字节定义为:typedef struct{ UCHAR Size:2; UCHAR Type:2; ......
HID报告描述符解析过程中的数据结构关系
Hid报告描述符的短项定义了MAIN,GLOBAL,LOCAL三种类型的项。其中MAIN项主要定义了三个类型,分别为集合(COLLECTION),输入报告(Input Report),输出报告(Output Report)和特性报告(Feature Report).在Windows系统的Pars......
ffmpeg常用库、术语、API、数据结构总结
本文的转载得到了零声教育的QQ同意。一、常用音视频术语和概念容器/文件(Conainer/File):指特定格式的多媒体文件,比如mp4、flv、mov等视频格式;媒体流(Stream):一个容器(如mp4文件)中可存在多个流,可以是视频流、音频流、字幕流。数据帧/数据包(Frame/Pac......
UAC1数据结构关系由f_audio_bind函数引出的struct f_uac1_opts和struct f_uac1之间的联系解读
前面看到了分别通过f_audio_alloc_inst和f_audio_alloc函数申请struct f_uac1_opts和struct f_uac1结构体,而我们在看UAC1源代码的时候,就需要这些结构体之间进行转换。首先我们先看struct f_uac1_opts和struct f_uac......
STM32F407 USB设备模块数据结构及初始化入口函数USBD_Init
本人以STM32F404自带的读卡器SLAVE代码为来解说。STM32F404支持OTG功能,其自带一个全速的USB功能。其USB初始化其实就是写相应的函数代码,这些函数代码却是通一个个的结构体整合起来成回调函数,这些函数是由我们自己写的。而STM32的库函数根据这些构体中的函数指针负责回调我们自......
USB键盘的数据结构
struct options { const char *opt; unsigned char val; };static struct options kmod[] = { {.opt = "--left-ctrl", .v......
UAC扬声器同步传输URB数据结构USBD_ISO_PACKET_DESCRIPTOR成员StartFrame
凡是USB的数据设备的数据传输,都是通过URB实现的。在Windows系统中,凡是同步传输,都是通过URB_ISOCH_TRANSFER实现的。当然,本站也提供了一个USB同步传输X64 URB数据在线分析工具:https://www.usbzh.com/tool/urb-iso.htmlURB_......
FFMEPG的图形格式定义及数据结构
FFMEPG的图形格式定义是一个枚举量:enum AVPixelFormat { AV_PIX_FMT_NONE = -1, AV_PIX_FMT_YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample p......
UAC虚拟麦克风同步传输数据结构与BUSHOUND抓包URB的对比
昨天晚上在家又在卷。。。在Windows系统下虚拟的UAC麦克风,这是一个自己很熟练的事情了,不过自己为了再次优化一些代码,也在疯狂的试探某些数据的底线在那里,所以卷的结果就是使用BUSHOUND抓了个包。UAC设备是USB的音视设备分类,所以我们看到的USB麦克风、扬声器(耳机)之类的,都符合UA......
USB驱动数据结构usb_device/usb_host_config/usb_interface/usb_host_interface/usb_host_endpoint
相对于USB规范中的USB相关描述符,Linux定义了几个相关的结构体。这几个结构体可在以下位置查看:https://elixir.bootlin.com/linux/v5.5-rc2/source/include/linux/usb.h以下介绍的USB结构体关系如下:struct usb_de......
关注公众号
  • HID人机交互
  • Linux&USB
  • UAC音频
  • TYPE-C
  • USB规范
  • USB大容量存储
  • USB百科
  • USB周边
  • UVC摄像头
  • Windows系统USB
  • 音视频博客
  • 取消
    感谢您的支持,我会继续努力的!
    扫码支持
    扫码打赏,你说多少就多少

    打开支付宝扫一扫,即可进行扫码打赏哦

    您的支持,是我们前进的动力!