历史上的今天
返回首页

历史上的今天

今天是:2025年03月11日(星期二)

正在发生

2019年03月11日 | STM32 UVC学习笔记1

2019-03-11 来源:eefocus

主机环境:Windows 7 SP1


开发环境:MDK5.18


目标板:STM32F103C8T6


开发库:STM32F1Cube库和STM32_USB_Device_Library


距离之前的STM32 USB学习又过去了N个月,想起最初想学习USB的初衷就是学习一下UVC协议,了解一下图像的传输,在逛STM32社区的时候有看到一句话:以前使用单片机必须熟悉I2C、SPI、UART等通信协议,但现在也必须熟悉USB通信协议了,因为目前主流的设备几乎都是USB接口的,在USB接口上又可以实现I2C、SPI、UART等协议,USB不可谓不强大。废话就到这吧。


经过之前的USB学习,基本上了解了STM32的USB外设,因此开始了USB接口之上的UVC的学习,中间可以说是一波三折,其中芯片还烧坏了一次,又买的新的芯片焊上去的,历史的经验告诉我们,学习一个新的东西,总不是一帆风顺的,UVC全程为USB Video Class--USB视频设备类,用于实现在USB接口上传输视频的功能,目前的UVC规范版本是1.5,可以从USB官网下载,其清单如下:



其中我们需要熟悉的是UVC 1.5 Class Specification文档,USB_Video_Example 1.5文档以及USB_Video_Payload_XX_1.5(一种)文档,由于是初学者因此这里我看的是USB_Video_Payload_MJPEG_1.5文档,也建议大家先学习该文档,毕竟新东西要从简单的开始学起。USB_Video_Example_1.5文档给出了使用MJPEG负载的示例,我们敲代码时可以用到其中的描述符。


UVC规范中说明了一个UVC设备需要实现一个VC(Video Control)接口和若干个VS(Video Streaming)接口,其中VC接口用于控制设备的功能,而VS接口用于传输视频数据流。在最简单的情况下,有一个VC接口和一个VS接口,这就是接下来我们需要实现的。在未熟悉UVC规范的情况下我们也可以把代码框架搭建起来,STM32_USB_Device_Library库是一个很方便扩展的库,因为它把内核和设备类区分出来了,我们要想实现UVC就要新建一个设备类文件夹,刚好UVC和UAC有那么一点类似之处,我们可以把AUDIO中的文件拷贝一份到UVC文件夹下并修改文件名,这样我们就有了usbd_uvc以及usbd_uvc_if文件了,至于usbd_conf,usbd_desc文件只要把之前的VCP例程中的文件稍作修改就可以使用了,这样我们的UVC代码框架就算完成了,在代码实现中就要参看Example文档一步步来完善就可以了,由于是首次学习,UVC的代码框架并不是很好,因此usbd_uvc_if文件其实是没有用到的,在以后再修改吧。因为在实现中,我们只需要把视频流数据发往USB主机即可,没有什么其他的功能要实现,当然在以后有更多功能要求时类接口文件就需要好好实现了,其中usbd_uvc_if.h文件内容如下:



/**

  ******************************************************************************

  * @file    USB_Device/UVC_Standalone/Inc/usbd_uvc_if.h

  * @author  MCD Application Team

  * @version V1.2.0

  * @date    19-June-2015

  * @brief   Header for usbd_uvc_if.c file.

  ******************************************************************************

  * @attention

  *

  *

© COPYRIGHT(c) 2015 STMicroelectronics

  *

  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");

  * You may not use this file except in compliance with the License.

  * You may obtain a copy of the License at:

  *

  *        http://www.st.com/software_license_agreement_liberty_v2

  *

  * Unless required by applicable law or agreed to in writing, software 

  * distributed under the License is distributed on an "AS IS" BASIS, 

  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

  * See the License for the specific language governing permissions and

  * limitations under the License.

  *

  ******************************************************************************

  */ 

 

/* Define to prevent recursive inclusion -------------------------------------*/

#ifndef __USBD_UVC_IF_H

#define __USBD_UVC_IF_H

 

/* Includes ------------------------------------------------------------------*/

#include "usbd_uvc.h"

 

/* Exported types ------------------------------------------------------------*/

/* Exported constants --------------------------------------------------------*/

 

extern USBD_UVC_ItfTypeDef  USBD_UVC_fops;

 

/* Exported macro ------------------------------------------------------------*/

/* Exported functions ------------------------------------------------------- */

 

#endif /* __USBD_UVC_IF_H */

 

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

可以看到文件基本上是空的,而usbd_uvc_if.c文件内容如下:


/**

  ******************************************************************************

  * @file    usbd_uvc_if.c

  * @author  MCD Application Team

  * @version V2.4.1

  * @date    19-June-2015

  * @brief   Generic media access Layer.

  ******************************************************************************

  * @attention

  *

  *

© COPYRIGHT 2015 STMicroelectronics

  *

  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");

  * You may not use this file except in compliance with the License.

  * You may obtain a copy of the License at:

  *

  *        http://www.st.com/software_license_agreement_liberty_v2

  *

  * Unless required by applicable law or agreed to in writing, software 

  * distributed under the License is distributed on an "AS IS" BASIS, 

  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

  * See the License for the specific language governing permissions and

  * limitations under the License.

  *

  ******************************************************************************

  */ 

 

/* Includes ------------------------------------------------------------------*/

#include "main.h"

 

/** @addtogroup STM32_USB_DEVICE_LIBRARY

  * @{

  */

 

 

/** @defgroup USBD_UVC 

  * @brief usbd core module

  * @{

  */ 

 

/** @defgroup USBD_UVC_Private_TypesDefinitions

  * @{

  */ 

/**

  * @}

  */ 

 

 

/** @defgroup USBD_UVC_Private_Defines

  * @{

  */ 

/**

  * @}

  */ 

 

/** @defgroup USBD_UVC_Private_Macros

  * @{

  */ 

/**

  * @}

  */ 

 

 

/** @defgroup USBD_UVC_Private_FunctionPrototypes

  * @{

  */

 

static int8_t UVC_Itf_Init     (void);

static int8_t UVC_Itf_DeInit   (void);

static int8_t UVC_Itf_Control  (uint8_t cmd, uint8_t* pbuf, uint16_t length);

 

 

USBD_UVC_ItfTypeDef USBD_UVC_fops = 

{

  UVC_Itf_Init,

  UVC_Itf_DeInit,

  UVC_Itf_Control,

};

 

/* TIM handler declaration */

/* USB handler declaration */

/* Private functions ---------------------------------------------------------*/

 

/**

  * @brief  TEMPLATE_Init

  *         Initializes the UVC media low layer

  * @param  None

  * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL

  */

static int8_t UVC_Itf_Init(void)

{

  /*

     Add your initialization code here 

  */  

  

  return (0);

}

 

/**

  * @brief  TEMPLATE_DeInit

  *         DeInitializes the UVC media low layer

  * @param  None

  * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL

  */

static int8_t UVC_Itf_DeInit(void)

{

  /*

     Add your deinitialization code here 

  */  

  return (0);

}

 

 

/**

  * @brief  TEMPLATE_Control

  *         Manage the UVC class requests

  * @param  Cmd: Command code            

  * @param  Buf: Buffer containing command data (request parameters)

  * @param  Len: Number of data to be sent (in bytes)

  * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL

  */

static int8_t UVC_Itf_Control  (uint8_t cmd, uint8_t* pbuf, uint16_t length)

 

  return (0);

}

 

/**

  * @}

  */ 

 

/**

  * @}

  */ 

 

/**

  * @}

  */ 

 

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

该文件也是空,但我们在UVC类文件中需要用到这个接口(为了日后扩展使用),当然如果闲麻烦的话这两个文件可以直接删除的。代码实现还是从最简单的开始即usbd_desc文件,头文件当然不需要改动了,我们改动的只有usbd_desc.c文件,在该文件中我们改动的也只是描述符而已,如下:


/**

  ******************************************************************************

  * @file    USB_Device/UVC_Standalone/Src/usbd_desc.c

  * @author  MCD Application Team

  * @version V1.2.0

  * @date    19-June-2015

  * @brief   This file provides the USBD descriptors and string formating method.

  ******************************************************************************

  * @attention

  *

  *

© COPYRIGHT(c) 2015 STMicroelectronics

  *

  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");

  * You may not use this file except in compliance with the License.

  * You may obtain a copy of the License at:

  *

  *        http://www.st.com/software_license_agreement_liberty_v2

  *

  * Unless required by applicable law or agreed to in writing, software 

  * distributed under the License is distributed on an "AS IS" BASIS, 

  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

  * See the License for the specific language governing permissions and

  * limitations under the License.

  *

  ******************************************************************************

  */

 

/* Includes ------------------------------------------------------------------*/

#include "usbd_core.h"

#include "usbd_desc.h"

#include "usbd_conf.h"

 

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

#define USBD_VID                      0x1985

#define USBD_PID                      0x1707

#define USBD_LANGID_STRING            0x409 //English(United States)

#define USBD_MANUFACTURER_STRING      "ANOBODYKEY"

#define USBD_PRODUCT_FS_STRING        "STM32 Video Streaming in FS Mode"

#define USBD_CONFIGURATION_FS_STRING  "UVC Config"

#define USBD_INTERFACE_FS_STRING      "UVC Interface"

 

/* Private macro -------------------------------------------------------------*/

/* Private function prototypes -----------------------------------------------*/

uint8_t *USBD_UVC_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);

uint8_t *USBD_UVC_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);

uint8_t *USBD_UVC_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);

uint8_t *USBD_UVC_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);

uint8_t *USBD_UVC_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);

uint8_t *USBD_UVC_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);

uint8_t *USBD_UVC_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);

#ifdef USB_SUPPORT_USER_STRING_DESC

uint8_t *USBD_UVC_USRStringDesc(USBD_SpeedTypeDef speed, uint8_t idx, uint16_t *length);  

#endif /* USB_SUPPORT_USER_STRING_DESC */  

 

/* Private variables ---------------------------------------------------------*/

USBD_DescriptorsTypeDef UVC_Desc = {

  USBD_UVC_DeviceDescriptor,

  USBD_UVC_LangIDStrDescriptor, 

  USBD_UVC_ManufacturerStrDescriptor,

  USBD_UVC_ProductStrDescriptor,

  USBD_UVC_SerialStrDescriptor,

  USBD_UVC_ConfigStrDescriptor,

  USBD_UVC_InterfaceStrDescriptor, 

};

 

const uint8_t hUSBDDeviceDesc[USB_LEN_DEV_DESC]= {

  0x12,                       /* bLength */

  USB_DESC_TYPE_DEVICE,       /* bDescriptorType */

  0x00,                       /* bcdUSB */

  0x02,

  0xEF,                       /* bDeviceClass */

  0x02,                       /* bDeviceSubClass */

  0x01,                       /* bDeviceProtocol */

  USB_MAX_EP0_SIZE,           /* bMaxPacketSize*/

  LOBYTE(USBD_VID),           /* idVendor */

  HIBYTE(USBD_VID),           /* idVendor */

  LOBYTE(USBD_PID),           /* idVendor */

  HIBYTE(USBD_PID),           /* idVendor */

  0x00,                       /* bcdDevice rel. 2.00 */

  0x02,

  USBD_IDX_MFC_STR,           /* Index of manufacturer string */

  USBD_IDX_PRODUCT_STR,       /* Index of product string */

  USBD_IDX_SERIAL_STR,        /* Index of serial number string */

  USBD_MAX_NUM_CONFIGURATION  /* bNumConfigurations */

}; /* USB_DeviceDescriptor */

 

/* USB Standard Device Descriptor */

const uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC]= {

  USB_LEN_LANGID_STR_DESC,         

  USB_DESC_TYPE_STRING,       

  LOBYTE(USBD_LANGID_STRING),

  HIBYTE(USBD_LANGID_STRING), 

};

 

uint8_t USBD_StringSerial[USB_SIZ_STRING_SERIAL] =

{

  USB_SIZ_STRING_SERIAL,      

  USB_DESC_TYPE_STRING,    

};

 

uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ];

 

/* Private functions ---------------------------------------------------------*/

static void IntToUnicode (uint32_t value , uint8_t *pbuf , uint8_t len);

static void Get_SerialNum(void);

/**

  * @brief  Returns the device descriptor. 

  * @param  speed: Current device speed

  * @param  length: Pointer to data length variable

  * @retval Pointer to descriptor buffer

  */

uint8_t *USBD_UVC_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)

{

  *length = sizeof(hUSBDDeviceDesc);

  return (uint8_t *)hUSBDDeviceDesc;

}

 

/**

  * @brief  Returns the LangID string descriptor.        

  * @param  speed: Current device speed

  * @param  length: Pointer to data length variable

  * @retval Pointer to descriptor buffer

  */

uint8_t *USBD_UVC_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)

{

  *length = sizeof(USBD_LangIDDesc);  

  return (uint8_t *)USBD_LangIDDesc;

}

 

/**

  * @brief  Returns the product string descriptor. 

  * @param  speed: Current device speed

  * @param  length: Pointer to data length variable

  * @retval Pointer to descriptor buffer

  */

uint8_t *USBD_UVC_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)

{

  USBD_GetString((uint8_t *)USBD_PRODUCT_FS_STRING, USBD_StrDesc, length);    

  return USBD_StrDesc;

}

 

/**

  * @brief  Returns the manufacturer string descriptor. 

  * @param  speed: Current device speed

  * @param  length: Pointer to data length variable

  * @retval Pointer to descriptor buffer

  */

uint8_t *USBD_UVC_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)

{

  USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);

  return USBD_StrDesc;

}

 

/**

  * @brief  Returns the serial number string descriptor.        

  * @param  speed: Current device speed

  * @param  length: Pointer to data length variable

  * @retval Pointer to descriptor buffer

  */

uint8_t *USBD_UVC_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)

{

  *length = USB_SIZ_STRING_SERIAL;

  

  /* Update the serial number string descriptor with the data from the unique ID*/

  Get_SerialNum();

  

  return USBD_StringSerial;

}

 

/**

  * @brief  Returns the configuration string descriptor.    

  * @param  speed: Current device speed

  * @param  length: Pointer to data length variable

  * @retval Pointer to descriptor buffer

  */

uint8_t *USBD_UVC_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)

{

  USBD_GetString((uint8_t *)USBD_CONFIGURATION_FS_STRING, USBD_StrDesc, length); 

  return USBD_StrDesc;  

}

 

/**

  * @brief  Returns the interface string descriptor.        

  * @param  speed: Current device speed

  * @param  length: Pointer to data length variable

  * @retval Pointer to descriptor buffer

  */

uint8_t *USBD_UVC_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)

{

  USBD_GetString((uint8_t *)USBD_INTERFACE_FS_STRING, USBD_StrDesc, length);

  return USBD_StrDesc;  

}

 

/**

  * @brief  Create the serial number string descriptor 

  * @param  None 

  * @retval None

  */

static void Get_SerialNum(void)

{

  uint32_t deviceserial0, deviceserial1, deviceserial2;

  

  deviceserial0 = *(uint32_t*)DEVICE_ID1;

  deviceserial1 = *(uint32_t*)DEVICE_ID2;

  deviceserial2 = *(uint32_t*)DEVICE_ID3;

  

  deviceserial0 += deviceserial2;

  

  if (deviceserial0 != 0)

  {

    IntToUnicode (deviceserial0, &USBD_StringSerial[2] ,8);

    IntToUnicode (deviceserial1, &USBD_StringSerial[18] ,4);

  }

}

 

/**

  * @brief  Convert Hex 32Bits value into char 

  * @param  value: value to convert

  * @param  pbuf: pointer to the buffer 

  * @param  len: buffer length

  * @retval None

  */

static void IntToUnicode (uint32_t value , uint8_t *pbuf , uint8_t len)

{

  uint8_t idx = 0;

  

  for( idx = 0 ; idx < len ; idx ++)

  {

    if( ((value >> 28)) < 0xA )

    {

      pbuf[ 2* idx] = (value >> 28) + '0';

    }

    else

    {

      pbuf[2* idx] = (value >> 28) + 'A' - 10; 

    }

    

    value = value << 4;

    

    pbuf[ 2* idx + 1] = 0;

  }

}

 

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

这是从之前的VCP例程中的文件修改过来的,其中VID和PID自己随便修改吧,其中的设备描述符就需要我们注意了,这里面的内容就是我从Example文件中拷贝的,Example文档中提供了2个示例,这里我参考的是第一个示例Destop Video Camera Example,当然参考哪个示例都是可以的,该示例的框架图如下所示:


图中的概念缩写大家可以去看UVC1.5的协议规范,都有介绍的,该图只是作为参考,我在实现中省略了很多中间环节的,为了简洁而已。设备描述符的简介如下:

可以看到代码中的实现跟示例是一致的,接下来就是配置描述符,也是重中之重,也是我们修改较多的地方,描述符如下



/* USB UVC device Configuration Descriptor */

static uint8_t USBD_UVC_CfgDesc[USB_UVC_CONFIG_DESC_SIZ] =

{

  /*Configuration Descriptor*/

  0x09, /* bLength: Configuation Descriptor size */

  USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */

  LOBYTE(USB_UVC_CONFIG_DESC_SIZ),     /* wTotalLength: Bytes returned */

  HIBYTE(USB_UVC_CONFIG_DESC_SIZ),

  0x02,         /*bNumInterfaces: 2 interface*/

  0x01,         /*bConfigurationValue: Configuration value*/

  USBD_IDX_CONFIG_STR,         /*iConfiguration: Index of string descriptor describing the configuration*/

  0x80,         /*bmAttributes: bus powered device */

  0xFA,         /*MaxPower 500 mA: this current is used for detecting Vbus*/

  /* 09 */

  /*---------------------------------------------------------------------------*/

 

  /*Interface Association Descriptor*/

  0x08, /* bLength: Interface Association Descriptor size */

  USB_DESC_TYPE_INTERFACE_ASSOCIATION, /* bDescritorType: Interface Association */

  0x00, /* bFirstInterface: VideoControl Interface ID */

  0x02, /* bInterfaceCount: 2 Video Interface */

  0x0E, /* bFunctionClass: CC_VIDEO */

  0x03, /* bFunctionSubClass: SC_VIDEO_INTERFACE_COLLECTION */

  0x00, /* bFunctionProtocol: PC_PROTOCOL_UNDEFINED */

  USBD_IDX_INTERFACE_STR, /* iFunction: Index of string descriptor descripting the function */

 

  /*Standard VC Interface Descriptor*/

  0x09, /* bLenght: Standard VC Interface Descriptor size */

  USB_DESC_TYPE_INTERFACE, /*bDescriptorType: interface */

  0x00, /* bInterfaceNumber: interface ID */

  0x00, /* bAlternateSetting: Alternate setting */

  0x00, /* bNumEndpoints: no endpoint */

  0x0E, /* bInterfaceClass: CC_VIDEO */

  0x01, /* bInterfaceSubClass: SC_VIDEOCONTROL */

  0x00, /* bInterfacePortocol: PC_PROTOCOL_15 */

  USBD_IDX_INTERFACE_STR, /*iInterface: Index of string descriptor descripting the interface */

 

  /*Class-specific VC Interface Header Descriptor*/

  0x0D, /* bLength: Class-specific VC Interface Header Descriptor size */

  0x24, /* bDescriptorType: CS_INTERFACE */

  0x01, /* bDescriptorSubType: VC_HEADER */

  0x10, /* bcdUVC: UVC1.5 revision */

  0x01,

  0x27, /* wTotalLength: total size of class-specific descriptors */

  0x00,

  0x80, /* dwClockFrequency: deprecated */

  0x8D,

  0x5B,

  0x00,

  0x01, /* bInCollection: number of streaming interfaces */

  0x01, /* baInterfaceNr(1): VideoStreaming interface 1 belongs to VC interface */

 

  /*Input Terminal Descriptor Composite*/

  0x11, /* bLength: Input Terminal Descriptor size */

  0x24, /* bDescriptorType: CS_INTERFACE */

  0x02, /* bDescriptorSubType: VC_INPUT_TERMINAL */

  0x01, /* bTerminalID: Terminal ID */

  0x01, /* wTerminalType: ITT_CAMERA */

  0x02,

  0x00, /* bAssocTerminal: no association */

  0x00, /*iTerminal: index of string descriptor descripting the terminal */

  0x00, /* wObjectiveFocalLengthMin: No optical zoom supported */

  0x00,

  0x00, /* wObjectiveFocalLengthMax: No optical zoom supported */

  0x00,

  0x00, /* wOcularFocalLength: No optical zoom supported */

  0x00,

  0x02, /* bControlSize: this terminal doesn't implement any controls */

  0x00, /* bmControls: No controls are supported */

  0x00,

 

  /*Output Terminal Descriptor*/

  0x09, /* bLength: Output Terminal Descriptor size */

  0x24, /* bDescriptorType: CS_INTERFACE */

  0x03, /* bDescriptorSubType: VC_OUTPUT_TERMINAL */

  0x02, /* bTerminalID: Terminal ID */

  0x01, /* wTerminalType: TT_STREAMING */

  0x01,

  0x00, /* bAssocTerminal: no association */

  0x01, /* bSourceID: connect to the input terminal output pin */

  0x00, /*iTerminal: index of string descriptor descripting the terminal */

 

  /*---------------------------------------------------------------------------*/

  /*Standard VS Interface Alternate 0 setting Descriptor*/

  0x09, /* bLength: Standard VS Interface Descriptor size */

  USB_DESC_TYPE_INTERFACE, /* bDescriptorType: INTERFACE */

  0x01, /* bInterfaceNumber: Interface ID */

  0x00, /* bAlternateSetting: index of this alternate setting */

  0x00, /* bNumEndpoints: 0 endpoint */

  0x0E, /* bInterfaceClass: CC_VIDEO */

  0x02, /* bInterfaceSubClass: SC_VIDEOSTREAMING */

  0x00, /* bInterfaceProtocol: PC_PROTOCOL_15 */

  USBD_IDX_INTERFACE_STR, /*iInterface: Index of string descriptor descripting the interface */

 

  /*Class-specific VS Header Descriptor*/

  0x0E, /* bLength: Class-specific VS Header Descriptor size */

  0x24, /* bDescriptorType: CS_INTERFACE */

  0x01, /* bDescriptorSubType: VS_INPUT_HEADER */

  0x01, /* bNumFormats: one format descriptor follows */

  0x3F,//0x45, /* wTotalLength: Total size of class-specific VS interface descriptors */

  0x00,

  UVC_ISO_DATA_EP, /* bEndpointAddress: address of isochronour video data endpoint */

  0x00, /* bmInfo: no dynamic format change supported */

  0x02, /* bTerminalLink: the terminal ID of output Terminal */

  0x00, /* bStillCaptureMethod: no supports still image capture method */

  0x00, /* bTriggerSupport: no supports hardware trigger */

  0x00, /* bTriggerUsage: initiate still image capture */

  0x01, /* bControlSize: the size of bmaControls field */

  0x00, /* bmaControls: no VS specific controls are supported */

 

  /*Payload Format Descriptor*/

  0x0B, /* blength: Payload Format Descriptor size */

  0x24, /* bDescriptorType: CS_INTERFACE */

  0x06, /* bDescriptorSubType: VS_FORMAT_MJPEG */

  0x01, /* bFormatIndex: index of the format descriptor */

  0x01, /* bNumFrameDescriptor: number of frame descriptors */

  0x01, /* bmFlags: FixedSizeSamples */

  0x01, /* bDefaultFrameIndex: */

  0x00, /* bAspectRatioX: not required */

  0x00, /* bAspectRatioY: not required */

  0x00, /* bInterlaceFlags: non-interlaced stream */

  0x00, /* bCopyProtect: no restrictions */

 

  /*Class-specific VS Frame Descriptor*/

  0x26, /* bLength: Class-specific VS Frame Descriptor size */

  0x24, /* bDescriptorType: CS_INTERFACE */

  0x07, /* bDescriptorSubType: VS_FRAME_MJPEG */

  0x01, /* bFrameIndex: index of frame descriptor */

  0x02, /* bmCapabilities:still image capture method 0 supported,fixed frame-rate */

  0x80, /* wWidth: frame width */

  0x00,

  0xA0, /* wHeight: frame height */

  0x00,

  0x00, /* dwMinBitRate: */

  0xB0,

  0x04,

  0x00,

  0x00, /* dwMaxBitRate: */

  0x00,

  0x4B,

  0x00,

  0x00, /* dwMaxVideoFrameBufSize: in bytes */

  0xA0,

  0x00,

  0x00,

  0x2A, /* dwDefaultFrameInterval: */

  0x2C,

  0x0A,

  0x00,

  0x00, /* bFrameIntervalType: Continuous frame interval */

  0x2A, /* dwMinFrameInterval: */

  0x2C,

  0x0A,

  0x00,

  0x2A, /* dwMaxFrameInterval: */

  0x2C,

  0x0A,

  0x00,

  0x00, /* dwFrameIntervalSetp: no frame interval step supported */

  0x00,

  0x00,

  0x00,

 

  /*---------------------------------------------------------------------------*/

  /*Standard VS Interface  Alternate setting 1 Descriptor*/

  0x09, /* bLength: Standard VS Interface Descriptor size */

  USB_DESC_TYPE_INTERFACE, /* bDescriptorType: INTERFACE */

  0x01, /* bInterfaceNumber: Interface ID */

  0x01, /* bAlternateSetting: index of this alternate setting */

  0x01, /* bNumEndpoints: 1 endpoint */

  0x0E, /* bInterfaceClass: CC_VIDEO */

  0x02, /* bInterfaceSubClass: SC_VIDEOSTREAMING */

  0x00, /* bInterfaceProtocol: PC_PROTOCOL_15 */

  USBD_IDX_INTERFACE_STR, /*iInterface: Index of string descriptor descripting the interface */

 

  /*Endpoint Descriptor*/

  0x07, /* bLength: Endpoint Descriptor size */

  USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: ENDPOINT */

  UVC_ISO_DATA_EP, /* bEndpointAddress: address of isochronour video data endpoint */

  0x05, /* bmAttributes: Isochronous transfer Asynchronous data type */

  LOBYTE(UVC_ISO_DATA_PACKET_SIZE), /* wMaxPacketSize: */

  HIBYTE(UVC_ISO_DATA_PACKET_SIZE),

  0x01, /* bInterval: */

  /**********  Descriptor of UVC interface 0 Alternate setting 0 **************/  

 

};

对比之前的拓扑图就可以知道这里使用到了CT(相机终端),去掉了SU(选择单元)和PU(处理单元),CT直接连至OT(输出终端),这里虽然是参考的UVC1.5的文档,但最后我给改成了UVC1.1,UVC1.5其实和UVC1.1相差不多,可以使用UVCView软件来检查描述符是否正确,配置的具体含义看代码中的注释即可明白。目前UVCView只能检查UVC1.1协议,如果使用的是UVC1.5协议,该软件会提示错误,但其实并没有错误。这里是使用端点0作为默认的控制端点,使用端点1来发送视频数据流,且端点配置成同步端点。端点大小的取值在后面会解释,这里需要注意的是使用同步端点的话就一定要使用两种接口配置,默认情况下使用接口配置0,默认接口配置中不能包含数据负载非0的同步端点,只能在交替配置中包含同步端点,关于USB不同的传输类型的详细说明可以查看USB2.0协议规范的第5章节,该章节我可是仔细阅读了一下,还试着翻译了一下便于理解。也希望大家可以看看该章节以便对各个传输类型有所了解。STM32的USB模块支持全速模式即通信速率为12MBit/s,也就是1.5MByte/s,由于我的单板啥外设也没得,因此图像数据只能存储在单片机中,从STM32F1Cube中找了一张128*160的图片,来实现以15fps帧传输该图片到USB主机,该图片经过压缩成jpeg格式大概为9K字节,每秒15帧的话也就是每秒传输9K*15=135K字节,USB2.0全速模式下把1S分成了1000个微帧,即1ms为一个微帧,视频数据流在微帧内传输,全速设备在每个微帧内可以进行一次同步传输,由此得知,一次微帧我们需要传输135个字节,这里我把同步端点的最大包大小设置成150字节,足以传输这张图片了,有关为什么这里是那一张JPEG图片来传输可以查看USB_Video_Payload_MJPEG文档,MJPEG就是把一幅幅JPEG格式的帧连续的播放,因此为了简介,这里就是把一张JPEG图片连续发送到USB主机。对了,在配置描述符中有用到一个接口连接描述符,在USB设备库中是没有定义,因此把该定义加到USB设备库中,即usbd_def.h文件中,如下:


#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_BOS                                 0x0F

#define  USB_DESC_TYPE_INTERFACE_ASSOCIATION    11

至此,我们知道了所用的端点数:2个,端点类型:一个控制端点和一个同步端点,我们就可以修改usbd_conf文件了,usbd_conf.h文件如下:


/**

  ******************************************************************************

  * @file    USB_Device/UVC_Standalone/Inc/usbd_conf.h

  * @author  MCD Application Team

  * @version V1.2.0

  * @date    19-June-2015

  * @brief   General low level driver configuration

  ******************************************************************************

  * @attention

  *

  *

© COPYRIGHT(c) 2015 STMicroelectronics

  *

  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");

  * You may not use this file except in compliance with the License.

  * You may obtain a copy of the License at:

  *

  *        http://www.st.com/software_license_agreement_liberty_v2

  *

  * Unless required by applicable law or agreed to in writing, software 

  * distributed under the License is distributed on an "AS IS" BASIS, 

  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

  * See the License for the specific language governing permissions and

  * limitations under the License.

  *

  ******************************************************************************

  */

 

/* Define to prevent recursive inclusion -------------------------------------*/

#ifndef __USBD_CONF_H

#define __USBD_CONF_H

 

/* Includes ------------------------------------------------------------------*/

#include "stm32f1xx_hal.h"

#include

#include

#include

 

/* Exported types ------------------------------------------------------------*/

/* Exported constants --------------------------------------------------------*/

/* Common Config */

#define USBD_MAX_NUM_INTERFACES               1

#define USBD_MAX_NUM_CONFIGURATION            1

#define USBD_MAX_STR_DESC_SIZ                 0x100

#define USBD_SUPPORT_USER_STRING              0 

#define USBD_SELF_POWERED                     0

#define USBD_DEBUG_LEVEL                      0

 

/* VIDEO Class Config */

#define USBD_VIDEO_FPS                        15

#define ENDP1_BUF0ADDR   (0xC0)

#define ENDP1_BUF1ADDR   (0xC0)

#define VIDEO_IN_TX_ADDRESS   (ENDP1_BUF0ADDR | (ENDP1_BUF1ADDR<<16))

 

/* Exported macro ------------------------------------------------------------*/

/* Memory management macros */   

 

/* For footprint reasons and since only one allocation is handled in the AUDIO class 

   driver, the malloc/free is changed into a static allocation method */

 

void *USBD_static_malloc(uint32_t size);

void USBD_static_free(void *p);

 

#define MAX_STATIC_ALLOC_SIZE     40 /*Video Class Driver Structure size*/

 

#define USBD_malloc              (uint32_t *)USBD_static_malloc

#define USBD_free                 USBD_static_free

#define USBD_memset               /* Not used */

#define USBD_memcpy               /* Not used */

 

/* DEBUG macros */  

#if (USBD_DEBUG_LEVEL > 0)

#define  USBD_UsrLog(...)   printf(__VA_ARGS__);\

                            printf("\n");

#else

#define USBD_UsrLog(...)

#endif

 

#if (USBD_DEBUG_LEVEL > 1)

 

#define  USBD_ErrLog(...)   printf("ERROR: ") ;\

                            printf(__VA_ARGS__);\

                            printf("\n");

#else

#define USBD_ErrLog(...)

#endif

 

#if (USBD_DEBUG_LEVEL > 2)

#define  USBD_DbgLog(...)   printf("DEBUG : ") ;\

                            printf(__VA_ARGS__);\

                            printf("\n");

#else

#define USBD_DbgLog(...)

#endif

 

/* Exported functions ------------------------------------------------------- */

 

#endif /* __USBD_CONF_H */

 

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

该文件修改不大,首先是修改端点的缓冲区地址,这里是参考UAC文件来修改的,使用双缓冲,因为STM32在把端点配置成同步端点时就自动启用了双缓冲,一开始我还想着,不使用双缓冲而使用单缓冲结构发送视频数据流,结果在测试时一直有包相同的数据跟在我发送的有效数据后面,后来在查看STM32F103C8T6参考文档时才发现,使用同步端点必须要使用双缓冲,因此,这里要配置BUF0和BUF1地址,这两个地址配成一样或不一样都不影响,因为Cube库中只对外提供了一个接口USBD_LL_Transmit,因此在USB模块使用其中一个缓冲时,应用程序也无法灵活使用另一段缓冲,再有一个修改就是MAX_STATIC_ALLOC_SIZE把值改小了,因为这里是把数据发往USB主机并不需要接口很多数据,因此,UVC的类结构并不需要使用太多的内存,usbd_conf.c文件如下:


/**

  ******************************************************************************

  * @file    USB_Device/UVC_Standalone/Src/usbd_conf.c

  * @author  MCD Application Team

  * @version V1.2.0

  * @date    31-July-2015

  * @brief   This file implements the USB Device library callbacks and MSP

  ******************************************************************************

  * @attention

  *

  *

© COPYRIGHT(c) 2015 STMicroelectronics

  *

  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");

  * You may not use this file except in compliance with the License.

  * You may obtain a copy of the License at:

  *

  *        http://www.st.com/software_license_agreement_liberty_v2

  *

  * Unless required by applicable law or agreed to in writing, software 

  * distributed under the License is distributed on an "AS IS" BASIS, 

  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

  * See the License for the specific language governing permissions and

  * limitations under the License.

  *

  ******************************************************************************

  */

 

/* Includes ------------------------------------------------------------------*/

#include "main.h"

 

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/

PCD_HandleTypeDef hpcd;

 

/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/

 

/*******************************************************************************

                       PCD BSP Routines

*******************************************************************************/

 

/**

  * @brief  Initializes the PCD MSP.

  * @param  hpcd: PCD handle

  * @retval None

  */

void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd)

{

  GPIO_InitTypeDef  GPIO_InitStruct;

   

  /* Enable the GPIOA clock */

  __HAL_RCC_GPIOA_CLK_ENABLE();

  

  /* Configure USB DM/DP pins */

  GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12);

  GPIO_InitStruct.Mode = GPIO_MODE_AF_INPUT;

  GPIO_InitStruct.Pull = GPIO_PULLUP;

  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;

  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  

  /* Enable USB Clock */

  __HAL_RCC_USB_CLK_ENABLE();

    

  /* Set USB Interrupt priority */

  HAL_NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn, 7, 0);

 

  /* Enable USB Interrupt */

  HAL_NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);

}

 

/**

  * @brief  De-Initializes the PCD MSP.

  * @param  hpcd: PCD handle

  * @retval None

  */

void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd)

{

  /* Disable USB FS Clock */

  __HAL_RCC_USB_CLK_DISABLE();

}

 

/*******************************************************************************

                       LL Driver Callbacks (PCD -> USB Device Library)

*******************************************************************************/

 

/**

  * @brief  SetupStage callback.

  * @param  hpcd: PCD handle

  * @retval None

  */

void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)

{

  USBD_LL_SetupStage((USBD_HandleTypeDef*)hpcd->pData, (uint8_t *)hpcd->Setup);

}

 

/**

  * @brief  DataOut Stage callback.

  * @param  hpcd: PCD handle

  * @param  epnum: Endpoint Number

  * @retval None

  */

void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)

{

  USBD_LL_DataOutStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff);

}

 

/**

  * @brief  DataIn Stage callback.

  * @param  hpcd: PCD handle

  * @param  epnum: Endpoint Number

  * @retval None

  */

void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)

{

  USBD_LL_DataInStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->IN_ep[epnum].xfer_buff);

}

 

/**

  * @brief  SOF callback.

  * @param  hpcd: PCD handle

  * @retval None

  */

void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd)

{

  USBD_LL_SOF((USBD_HandleTypeDef*)hpcd->pData);

}

 

/**

  * @brief  Reset callback.

  * @param  hpcd: PCD handle

  * @retval None

  */

void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd)

{

  USBD_LL_SetSpeed((USBD_HandleTypeDef*)hpcd->pData, USBD_SPEED_FULL);

  /* Reset Device */

  USBD_LL_Reset((USBD_HandleTypeDef*)hpcd->pData);

}

 

/**

  * @brief  Suspend callback.

  * @param  hpcd: PCD handle

  * @retval None

  */

void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd)

{

  /* Inform USB library that core enters in suspend Mode */

  USBD_LL_Suspend((USBD_HandleTypeDef*)hpcd->pData);

}

 

/**

  * @brief  Resume callback.

  * @param  hpcd: PCD handle

  * @retval None

  */

void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd)

{

  USBD_LL_Resume((USBD_HandleTypeDef*)hpcd->pData);

}

 

/**

  * @brief  ISOOUTIncomplete callback.

  * @param  hpcd: PCD handle

  * @param  epnum: Endpoint Number

  * @retval None

  */

void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)

{

  USBD_LL_IsoOUTIncomplete((USBD_HandleTypeDef*)hpcd->pData, epnum);

}

 

/**

  * @brief  ISOINIncomplete callback.

  * @param  hpcd: PCD handle

  * @param  epnum: Endpoint Number

  * @retval None

  */

void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)

{

  USBD_LL_IsoINIncomplete((USBD_HandleTypeDef*)hpcd->pData, epnum);

}

 

/**

  * @brief  ConnectCallback callback.

  * @param  hpcd: PCD handle

  * @retval None

  */

void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd)

{

  USBD_LL_DevConnected((USBD_HandleTypeDef*)hpcd->pData);

}

 

/**

  * @brief  Disconnect callback.

  * @param  hpcd: PCD handle

  * @retval None

  */

void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd)

{

  USBD_LL_DevDisconnected((USBD_HandleTypeDef*)hpcd->pData);

}

 

/*******************************************************************************

                       LL Driver Interface (USB Device Library --> PCD)

*******************************************************************************/

 

/**

  * @brief  Initializes the Low Level portion of the Device driver.

  * @param  pdev: Device handle

  * @retval USBD Status

  */

USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev)

{

  /* Set LL Driver parameters */

  hpcd.Instance = USB;

  hpcd.Init.dev_endpoints = 8; //STM32F103C8T6支持8个双向端点

  hpcd.Init.ep0_mps = PCD_EP0MPS_64; //端点0支持的最大分组字节为64

  hpcd.Init.phy_itface = PCD_PHY_EMBEDDED;

  hpcd.Init.speed = PCD_SPEED_FULL; //USB2.0全速设备

  hpcd.Init.low_power_enable = 0; //不使能低功耗模式

  

  /* Link The driver to the stack */

  hpcd.pData = pdev;

  pdev->pData = &hpcd;

  

  /* Initialize LL Driver */

  HAL_PCD_Init((PCD_HandleTypeDef*)pdev->pData);

 

  HAL_PCDEx_PMAConfig(pdev->pData , 0x00 , PCD_SNG_BUF, 0x40); //OUT端点

  HAL_PCDEx_PMAConfig(pdev->pData , 0x80 , PCD_SNG_BUF, 0x80); //IN端点

  HAL_PCDEx_PMAConfig(pdev->pData , UVC_ISO_DATA_EP, PCD_DBL_BUF, VIDEO_IN_TX_ADDRESS);

 

  return USBD_OK;

}

 

/**

  * @brief  De-Initializes the Low Level portion of the Device driver.

  * @param  pdev: Device handle

  * @retval USBD Status

  */

USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *pdev)

{

  HAL_PCD_DeInit((PCD_HandleTypeDef*)pdev->pData);

  return USBD_OK;

}

 

/**

  * @brief  Starts the Low Level portion of the Device driver.

  * @param  pdev: Device handle

  * @retval USBD Status

  */

USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev)

{

  HAL_PCD_Start((PCD_HandleTypeDef*)pdev->pData);

  return USBD_OK;

}

 

/**

  * @brief  Stops the Low Level portion of the Device driver.

  * @param  pdev: Device handle

  * @retval USBD Status

  */

USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *pdev)

{

  HAL_PCD_Stop((PCD_HandleTypeDef*)pdev->pData);

  return USBD_OK;

}

 

/**

  * @brief  Opens an endpoint of the Low Level Driver.

  * @param  pdev: Device handle

  * @param  ep_addr: Endpoint Number

  * @param  ep_type: Endpoint Type

  * @param  ep_mps: Endpoint Max Packet Size

  * @retval USBD Status

  */

USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev,

                                  uint8_t ep_addr,

                                  uint8_t ep_type,

                                  uint16_t ep_mps)

{

  HAL_PCD_EP_Open((PCD_HandleTypeDef*)pdev->pData,

                  ep_addr,

                  ep_mps,

                  ep_type);

 

  return USBD_OK;

}

 

/**

  * @brief  Closes an endpoint of the Low Level Driver.

  * @param  pdev: Device handle

  * @param  ep_addr: Endpoint Number

  * @retval USBD Status

  */

USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)

{

  HAL_PCD_EP_Close((PCD_HandleTypeDef*)pdev->pData, ep_addr);

  return USBD_OK;

}

 

/**

  * @brief  Flushes an endpoint of the Low Level Driver.

  * @param  pdev: Device handle

  * @param  ep_addr: Endpoint Number

  * @retval USBD Status

  */

USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)

{

  HAL_PCD_EP_Flush((PCD_HandleTypeDef*)pdev->pData, ep_addr);

  return USBD_OK;

}

 

/**

  * @brief  Sets a Stall condition on an endpoint of the Low Level Driver.

  * @param  pdev: Device handle

  * @param  ep_addr: Endpoint Number

  * @retval USBD Status

  */

USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)

{

  HAL_PCD_EP_SetStall((PCD_HandleTypeDef*)pdev->pData, ep_addr);

  return USBD_OK;

}

 

/**

  * @brief  Clears a Stall condition on an endpoint of the Low Level Driver.

  * @param  pdev: Device handle

  * @param  ep_addr: Endpoint Number

  * @retval USBD Status

  */

USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)

{

  HAL_PCD_EP_ClrStall((PCD_HandleTypeDef*)pdev->pData, ep_addr);

  return USBD_OK;

}

 

/**

  * @brief  Returns Stall condition.

  * @param  pdev: Device handle

  * @param  ep_addr: Endpoint Number

  * @retval Stall (1: Yes, 0: No)

  */

uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)

{

  PCD_HandleTypeDef *hpcd = (PCD_HandleTypeDef*)pdev->pData;

 

  if ((ep_addr & 0x80) == 0x80)

  {

    return hpcd->IN_ep[ep_addr & 0x7F].is_stall;

  }

  else

  {

    return hpcd->OUT_ep[ep_addr & 0x7F].is_stall;

  }

}

 

/**

  * @brief  Assigns a USB address to the device.

  * @param  pdev: Device handle

  * @param  ep_addr: Endpoint Number

  * @retval USBD Status

  */

USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *pdev, uint8_t dev_addr)

{

  HAL_PCD_SetAddress((PCD_HandleTypeDef*)pdev->pData, dev_addr);

  return USBD_OK;

}

 

/**

  * @brief  Transmits data over an endpoint.

  * @param  pdev: Device handle

  * @param  ep_addr: Endpoint Number

  * @param  pbuf: Pointer to data to be sent

  * @param  size: Data size

  * @retval USBD Status

  */

USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev,

                                    uint8_t ep_addr,

                                    uint8_t *pbuf,

                                    uint16_t size)

{

  HAL_PCD_EP_Transmit((PCD_HandleTypeDef*)pdev->pData, ep_addr, pbuf, size);

  return USBD_OK;

}

 

/**

  * @brief  Prepares an endpoint for reception.

  * @param  pdev: Device handle

  * @param  ep_addr: Endpoint Number

  * @param  pbuf: Pointer to data to be received

  * @param  size: Data size

  * @retval USBD Status

  */

USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev,

                                          uint8_t ep_addr,

                                          uint8_t *pbuf,

                                          uint16_t size)

{

  HAL_PCD_EP_Receive((PCD_HandleTypeDef*)pdev->pData, ep_addr, pbuf, size);

  return USBD_OK;

}

 

/**

  * @brief  Returns the last transferred packet size.

  * @param  pdev: Device handle

  * @param  ep_addr: Endpoint Number

  * @retval Recived Data Size

  */

uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr)

{

  return HAL_PCD_EP_GetRxCount((PCD_HandleTypeDef*)pdev->pData, ep_addr);

}

 

/**

  * @brief  Delays routine for the USB Device Library.

  * @param  Delay: Delay in ms

  * @retval None

  */

void USBD_LL_Delay(uint32_t Delay)

{

  HAL_Delay(Delay);

}

 

/**

  * @brief  static single allocation.

  * @param  size: size of allocated memory

  * @retval None

  */

void *USBD_static_malloc(uint32_t size)

{

  static uint32_t mem[MAX_STATIC_ALLOC_SIZE];

  return mem;

}

 

/**

  * @brief  Dummy memory free

  * @param  *p pointer to allocated  memory address

  * @retval None

  */

void USBD_static_free(void *p)

{

 

}

 

/**

  * @brief  Software Device Connection

  * @param  hpcd: PCD handle

  * @param  state: connection state (0 : disconnected / 1: connected)

  * @retval None

  */

void HAL_PCDEx_SetConnectionState(PCD_HandleTypeDef *hpcd, uint8_t state)

{


}

 

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

这里至改动了USBD_LL_Init()函数,配置端点1为双缓冲模式。同时在usbd_uvc.c文件中修改USBD_UVC_Init()函数打开所需的端点,如下:


/**

  * @brief  USBD_UVC_Init

  *         Initialize the UVC interface

  * @param  pdev: device instance

  * @param  cfgidx: Configuration index

  * @retval status

  */

static uint8_t  USBD_UVC_Init (USBD_HandleTypeDef *pdev, 

                               uint8_t cfgidx)

{

  uint8_t ret = 0;

  USBD_UVC_HandleTypeDef *huvc;

 

  USBD_LL_OpenEP(pdev, UVC_ISO_DATA_EP, USBD_EP_TYPE_ISOC, UVC_ISO_DATA_PACKET_SIZE);

 

  pdev->pClassData = USBD_malloc(sizeof (USBD_UVC_HandleTypeDef));

  

  if(pdev->pClassData == NULL)

  {

    ret = 1; 

  }

  else

  {

    huvc = (USBD_UVC_HandleTypeDef*) pdev->pClassData;

    

    /* Init  physical Interface components */

    ((USBD_UVC_ItfTypeDef *)pdev->pUserData)->Init();

  }

 

  return ret;

}

 

/**

  * @brief  USBD_UVC_Init

  *         DeInitialize the UVC layer

  * @param  pdev: device instance

  * @param  cfgidx: Configuration index

  * @retval status

  */

static uint8_t  USBD_UVC_DeInit (USBD_HandleTypeDef *pdev, 

                                 uint8_t cfgidx)

{

  /* Close EP 1 */

  USBD_LL_CloseEP(pdev,UVC_ISO_DATA_EP);

  

  /* DeInit  physical Interface components */

  if(pdev->pClassData != NULL)

  {

    ((USBD_UVC_ItfTypeDef *)pdev->pUserData)->DeInit();

    USBD_free(pdev->pClassData);

    pdev->pClassData = NULL;

  }

 

  return USBD_OK;

}

至此,我们就可以实现UVC设备的枚举过程了。先到这吧,未完待续。。。


推荐阅读

史海拾趣

德旭电子(DEXU)公司的发展小趣事

随着产品质量的不断提升和市场份额的逐步扩大,德旭电子开始注重品牌建设和市场拓展。公司积极参加各类行业展会和交流活动,展示自身实力和产品优势。同时,德旭电子还加大了广告宣传力度,通过线上线下相结合的方式提升品牌知名度和美誉度。

在市场拓展方面,德旭电子不仅深耕国内市场,还积极开拓国际市场。公司凭借优质的产品和专业的服务赢得了越来越多客户的信赖和支持。国际市场的拓展为德旭电子的持续发展注入了新的动力。

EKIT公司的发展小趣事

早在2022年,HUAWEI eKit就在中东地区进行了首次海外亮相。在GITEX展会期间,华为举办了HUAWEI eKit分销论坛,向与会者系统介绍了其“以分销商为主,以工程商为中心”的分销业务战略。通过与中东中亚区域的分销伙伴紧密合作,HUAWEI eKit成功推出了多款针对中小企业市场的新产品,覆盖了数通园区网络和数据存储等多个领域,为当地市场带来了前所未有的商机。

Conditioning Semiconductor Devices Corp公司的发展小趣事

随着半导体行业的竞争加剧,价格战和技术更新速度不断加快。CSDC面临着巨大的市场压力。为了应对这些挑战,公司决定调整战略,专注于高端市场的开发。通过加大研发投入,提升产品质量和性能,CSDC逐渐在高端市场站稳了脚跟,实现了业务的稳步增长。

Chipcon AS公司的发展小趣事

Chipcon AS公司深知人才是企业发展的核心力量。因此,公司一直注重人才的引进和培养。通过与高校和研究机构建立合作关系,公司吸引了大量优秀的研发人才加入。同时,公司还建立了完善的培训体系,为员工提供了广阔的职业发展空间。这些措施使得Chipcon AS公司的研发实力不断增强,为公司的持续发展提供了有力保障。

Automatic Connector公司的发展小趣事

为了保持技术创新的活力,Automatic Connector公司积极与高校和研究机构开展产学研合作。通过与这些机构的深度合作,公司能够及时了解最新的科研成果和技术趋势,为产品的研发和创新提供有力的支持。同时,公司还为合作机构提供实践平台和技术支持,实现了资源共享和互利共赢。这种产学研合作的模式为Automatic Connector公司的创新发展注入了强大的动力。

这五个故事虽然是以虚构的Automatic Connector公司为背景,但它们所反映的电子连接器制造企业的发展规律和市场环境是真实存在的。希望这些故事能够为您了解电子行业中的企业发展提供一些启示。

Digitron公司的发展小趣事

Digitron公司成立于XXXX年,由一群热衷于电子技术的工程师和科学家创立。在成立初期,公司专注于开发高精度、高可靠性的温度数据记录器。这些设备在医药、冷链物流等领域得到了广泛应用,为Digitron公司赢得了良好的声誉。随着技术的不断进步,Digitron公司逐渐扩大了产品线,推出了更多适用于不同行业的数据记录器和传感器。

问答坊 | AI 解惑

有关单片机应用PS/2键盘程序的修改

本人在网上找到了一个单片机应用PS-2键盘的实例的程序,这个程序是把读到的键值用1602液晶显示,现在我想去掉液晶,把单片机接8个LED灯,通过灯的亮灭来显示所读取键值的ASC码,不知道要怎么修改这个程序才能做到,望各位大虾指点…

查看全部问答>

请问管理员,我怎么回复不了帖子?

我今天怎么回复不了我自己的帖子,我的问题解决了本来想说明下情况,是如何解决的,然后结贴,结果我一回复就说我\"回复太快!如果你是恶意刷楼,将会受到严厉惩罚!\"我没有刷楼啊,到了下午再试试还是不行,这个怎么回事,网站有问题了?也不知道我这个 ...…

查看全部问答>

单片机串口控制TFT(1.3-15寸TFT通用解决方案)

公司提供4.3-10.4寸系列真彩液晶终端,单片机,PLC,ARM串口直接控制,采用M600通用液晶显示驱动。       TFT驱动模组M600,这款模块的优势非常大,驱动模组提供的是RS232串口方式,通过协议来控制屏的显示,内置128M flash ...…

查看全部问答>

求教液晶屏色彩问题!

Wince启动后,色彩不对,偏色严重。但是在用Windows Media Player播放视频文件的时候,画面清晰的很。不过WMP的界面仍然偏色。请教各位可遇到这种情况,是哪方面原因造成的。…

查看全部问答>

大家有没有自己DIY个文本显示器啊?

用市场上现有的文本显示器的外壳,可以实现人机界面,DI,DO,AI,AO及RS232 ,RS485的通用控制器啊!    …

查看全部问答>

请问:只设计了8M的晶振如何实现1秒钟的定时时间

我设计板子的时候只用了XT2 的晶振为8Mhz的,然后现在想要一个1秒钟的定时,请问下该如何实现啊,原来我我想的用中断嵌套,可是总是不对啊,进不了那个嵌套,大侠们指点下啊,谢谢啦…

查看全部问答>

阻容电源问题

做了一个阻容电源,发现在会有变压器的那种兹兹的声音,而且电源摸上去还有点热,高手分析下原因…

查看全部问答>

开关电源变压器选择需要计算出哪些参数

本帖最后由 dontium 于 2015-1-23 13:32 编辑 同事花了半个月,就做了一款开关电源,还说技术保密。说实话做开关电源有技术难度吗? …

查看全部问答>

Keil Cx51 V7.0单片机高级语言编程与μVision2应用实践

Keil Cx51 V7.0单片机高级语言编程与μVision2应用实践 据说是一本很不错的书,我刚找到,还木有看,大家分享一下!…

查看全部问答>