×
单片机 > 单片机程序设计 > 详情

STM32 USB学习笔记9

发布时间:2020-06-16 发布时间:
|

主机环境:Windows 7 SP1


开发环境:MDK5.14


目标板:STM32F103C8T6


开发库:STM32F1Cube库和STM32_USB_Device_Library


现在我们来分析VCP例程的最后一个文件USB设备类的usbd_cdc文件,该文件跟CDC类紧密相关,看下其头文件的一些定义:



/** @defgroup usbd_cdc_Exported_Defines

  * @{

  */ 

#define CDC_IN_EP                                   0x81  /* EP1 for data IN */

#define CDC_OUT_EP                                  0x01  /* EP1 for data OUT */

#define CDC_CMD_EP                                  0x82  /* EP2 for CDC commands */

 

/* CDC Endpoints parameters: you can fine tune these values depending on the needed baudrates and performance. */

#define CDC_DATA_HS_MAX_PACKET_SIZE                 512  /* Endpoint IN & OUT Packet size */

#define CDC_DATA_FS_MAX_PACKET_SIZE                 64  /* Endpoint IN & OUT Packet size */

#define CDC_CMD_PACKET_SIZE                         8  /* Control Endpoint Packet size */ 

 

#define USB_CDC_CONFIG_DESC_SIZ                     67

#define CDC_DATA_HS_IN_PACKET_SIZE                  CDC_DATA_HS_MAX_PACKET_SIZE

#define CDC_DATA_HS_OUT_PACKET_SIZE                 CDC_DATA_HS_MAX_PACKET_SIZE

 

#define CDC_DATA_FS_IN_PACKET_SIZE                  CDC_DATA_FS_MAX_PACKET_SIZE

#define CDC_DATA_FS_OUT_PACKET_SIZE                 CDC_DATA_FS_MAX_PACKET_SIZE

这些宏定义指明了CDC类使用的端点,以及最大包大小,对于STM32F103C8T6来说最大包大小是是64字节,其中命令控制端点最大包大小为8字节。在头文件中还有一个CDC类的结构声明,如下:


typedef struct

{

  uint32_t data[CDC_DATA_HS_MAX_PACKET_SIZE/4];      /* Force 32bits alignment */

  uint8_t  CmdOpCode;

  uint8_t  CmdLength;    

  uint8_t  *RxBuffer;  

  uint8_t  *TxBuffer;   

  uint32_t RxLength;

  uint32_t TxLength;    

  

  __IO uint32_t TxState;     

  __IO uint32_t RxState;    

}

USBD_CDC_HandleTypeDef; 

该句柄管理着CDC类的数据信息,接着我们来查看usbd_cdc.c文件,该文件需要配合CDC1.20以及PSTN1.20协议文档来查看,在usbd_cdc,c中有我们CDC类的具体实现,如下:


/* CDC interface class callbacks structure */

USBD_ClassTypeDef  USBD_CDC = 

{

  USBD_CDC_Init,

  USBD_CDC_DeInit,

  USBD_CDC_Setup,

  NULL,                 /* EP0_TxSent, */

  USBD_CDC_EP0_RxReady,

  USBD_CDC_DataIn,

  USBD_CDC_DataOut,

  NULL,

  NULL,

  NULL,     

  USBD_CDC_GetHSCfgDesc,  

  USBD_CDC_GetFSCfgDesc,    

  USBD_CDC_GetOtherSpeedCfgDesc, 

  USBD_CDC_GetDeviceQualifierDescriptor,

};

其中EP0_TxSent、SOF、IsoINIncomplete、ISOOUTIncomplete为空。该文件中函数比较多,先从简单的分析,首先看下注册接口的函数,如下:


/**

* @brief  USBD_CDC_RegisterInterface

  * @param  pdev: device instance

  * @param  fops: CD  Interface callback

  * @retval status

  */

uint8_t  USBD_CDC_RegisterInterface  (USBD_HandleTypeDef   *pdev, 

                                      USBD_CDC_ItfTypeDef *fops)

{

  uint8_t  ret = USBD_FAIL;

  

  if(fops != NULL)

  {

    pdev->pUserData= fops;

    ret = USBD_OK;    

  }

  

  return ret;

}

注册接口很简单,即把CDC接口指针链接到USB句柄中的UserData即可。接着是在CDC接口文件中提到的两个设置缓存区的函数,如下:


/**

  * @brief  USBD_CDC_SetTxBuffer

  * @param  pdev: device instance

  * @param  pbuff: Tx Buffer

  * @retval status

  */

uint8_t  USBD_CDC_SetTxBuffer  (USBD_HandleTypeDef   *pdev,

                                uint8_t  *pbuff,

                                uint16_t length)

{

  USBD_CDC_HandleTypeDef   *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;

  

  hcdc->TxBuffer = pbuff;

  hcdc->TxLength = length;  

  

  return USBD_OK;  

}

 

 

/**

  * @brief  USBD_CDC_SetRxBuffer

  * @param  pdev: device instance

  * @param  pbuff: Rx Buffer

  * @retval status

  */

uint8_t  USBD_CDC_SetRxBuffer  (USBD_HandleTypeDef   *pdev,

                                   uint8_t  *pbuff)

{

  USBD_CDC_HandleTypeDef   *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;

  

  hcdc->RxBuffer = pbuff;

  

  return USBD_OK;

}

给CDC句柄的相应字段赋值即可。再有两个是CDC接口文件中提到的数据发送和接收函数,如下:


/**

  * @brief  USBD_CDC_DataOut

  *         Data received on non-control Out endpoint

  * @param  pdev: device instance

  * @param  epnum: endpoint number

  * @retval status

  */

uint8_t  USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev)

{      

  USBD_CDC_HandleTypeDef   *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;

  

  if(pdev->pClassData != NULL)

  {

    if(hcdc->TxState == 0)

    {

      /* Tx Transfer in progress */

      hcdc->TxState = 1;

      

      /* Transmit next packet */

      USBD_LL_Transmit(pdev,

                       CDC_IN_EP,

                       hcdc->TxBuffer,

                       hcdc->TxLength);

      

      return USBD_OK;

    }

    else

    {

      return USBD_BUSY;

    }

  }

  else

  {

    return USBD_FAIL;

  }

}

 

 

/**

  * @brief  USBD_CDC_ReceivePacket

  *         prepare OUT Endpoint for reception

  * @param  pdev: device instance

  * @retval status

  */

uint8_t  USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev)

{      

  USBD_CDC_HandleTypeDef   *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;

  

  /* Suspend or Resume USB Out process */

  if(pdev->pClassData != NULL)

  {

    if(pdev->dev_speed == USBD_SPEED_HIGH  ) 

    {      

      /* Prepare Out endpoint to receive next packet */

      USBD_LL_PrepareReceive(pdev,

                             CDC_OUT_EP,

                             hcdc->RxBuffer,

                             CDC_DATA_HS_OUT_PACKET_SIZE);

    }

    else

    {

      /* Prepare Out endpoint to receive next packet */

      USBD_LL_PrepareReceive(pdev,

                             CDC_OUT_EP,

                             hcdc->RxBuffer,

                             CDC_DATA_FS_OUT_PACKET_SIZE);

    }

    return USBD_OK;

  }

  else

  {

    return USBD_FAIL;

  }

}

发送函数很简单,检测到发送状态处于空闲时则执行发送操作,并设置发送状态有BUSY,这里这里使用的发送端点是0x81,不是端点0。而且数据的发送和发送数据的缓存区设置二者是成对使用的。接收函数也比较简单只是区分了高速和全速模式下的最大包大小不同,这里使用的端点同样不是端点0而是端点0x001。CDC类接口使用的函数补充完毕,现在来看CDC类各个函数,依然从简单的开始几个描述符的获取,这个有四个描述符的获取,如下:


/**

  * @brief  USBD_CDC_GetFSCfgDesc 

  *         Return configuration descriptor

  * @param  speed : current device speed

  * @param  length : pointer data length

  * @retval pointer to descriptor buffer

  */

static uint8_t  *USBD_CDC_GetFSCfgDesc (uint16_t *length)

{

  *length = sizeof (USBD_CDC_CfgFSDesc);

  return USBD_CDC_CfgFSDesc;

}

 

/**

* @brief USBD_C


关键字:STM32  USB  学习笔记 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
如何为单片机选择合适的负载电容