历史上的今天
返回首页

历史上的今天

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

正在发生

2019年03月11日 | STM32 USB学习笔记4

2019-03-11 来源:eefocus

主机环境:Windows 7 SP1


开发环境:MDK5.14


目标板:STM32F103C8T6


开发库:STM32F1Cube库和STM32_USB_Device_Library


前面分析了USB的描述符文件,现在分析一下usbd_conf文件,usbd_conf.h文件是配置文件,如下:



/* 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                     1

#define USBD_DEBUG_LEVEL                      0

 

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

/* Memory management macros */

 

/* For footprint reasons and since only one allocation is handled in the CDC 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     140 /* CDC 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 */

配置文件很简单,指明最大接口数为1,最大配置数为1,不支持用户字符串,支持自供电,调试级别为0,在USB通信中USB设备支持两种供电方式:自供电(设备有自己独立电源),总线供电(设备由USB主机提供电源)。同时,在这里采用静态空间分配方案,分配的静态空间大小为140字节。调试界别为0是没有调试信息输出的,根据自己需求来使能调试功能。usbd_conf.c文件要复杂一些,用于实现USB设备库的回调函数以及MCU的一些底层初始化。各个中断的服务例程在stm32f1xx_it.c文件中,如下:


void SysTick_Handler(void)

{

  Toggle_Leds();

  HAL_IncTick();

}

 

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

/*                 STM32F1xx Peripherals Interrupt Handlers                   */

/*  Add here the Interrupt Handler for the used peripheral(s) (PPP), for the  */

/*  available peripheral interrupt handler's name please refer to the startup */

/*  file (startup_stm32f1xx.s).                                               */

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

 

/**

  * @brief  This function handles USB Handler.

  * @param  None

  * @retval None

  */

void USB_LP_CAN1_RX0_IRQHandler(void)

{

  HAL_PCD_IRQHandler(&hpcd);

}

 

/**

  * @brief  This function handles DMA interrupt request.

  * @param  None

  * @retval None

  */

void USARTx_DMA_TX_IRQHandler(void)

{

  HAL_DMA_IRQHandler(UartHandle.hdmatx);

}

 

/**

  * @brief  This function handles UART interrupt request.  

  * @param  None

  * @retval None

  */

void USARTx_IRQHandler(void)

{

  HAL_UART_IRQHandler(&UartHandle);

}

 

/**

  * @brief  This function handles TIM interrupt request.

  * @param  None

  * @retval None

  */

void TIMx_IRQHandler(void)

{

  HAL_TIM_IRQHandler(&TimHandle);

}

中断服务例程很简单提供了一个IRQHandler接口,通过该接口会调用一些回调函数来实现具体的处理,其中各个接口可以在库函数说明中找到,如下:

USB底层API如下:

以上这些接口是需要在usbd_conf.c文件中实现的,此外还有一个USB接口的硬件IO初始化,如下:



/**

  * @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();

}

设置USB的硬件IO口为复用模式,并设置中断优先级且使能USB中断,USB中断号有三个:USB低优先级中断(20),USB高优先级中断(19),USB唤醒中断(42),这里是使能的USB低优先级中断,所有的USB事件均可触发该中断。USB底层回调函数接口实现如下:


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

                       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);

}

每一个回调函数都是调用的usbd_core.c中的底层函数,对于不同的USB类该回调函数的接口实现是类似的,分别对应了触发USB中断的各个情况,跟串口中断不同,串口中断我们一般关心接收和发送中断即可。而USB的中断源比较多,从回调函数的个数就可以看得出来,即使这样,但这些回调函数里面有几个是为空的,如同步传输完成的回调函数以及设备连接的回调函数,此外,HAL_PCD_IRQHandler()里是没有调用同步传输完成回调函数的,在OTG模块的中断服务例程里才有调用。既然在全速模式下回调函数为空就不必刻意关注该回调函数了。重点关注Setup、DataIn、DataOut等即可,与之相关的是USB通信中的Setup阶段、数据阶段,所有的USB通信请求都是由USB主机发起,一般分为三个阶段:设置阶段、数据阶段、状态阶段。其中数据阶段是可以省略的。具体内容在后面遇到再分析,至此,USB中断底层回调函数浏览完毕,还剩下底层的设备驱动API,在分析之前需要注意两个个重要的结构体PCD_HandleTypeDef和USBD_HandleTypeDef,前者是STM32Cube库提供的跟寄存器相关的数据结构,后者是USB器件库提供的跟USB协议相关的数据结构,在例程中两者相互引用,PCD_HandleTypeDef结构如下:


/** 

  * @brief  PCD Handle Structure definition

  */

typedef struct

{

  PCD_TypeDef             *Instance;   /*!< Register base address               */

  PCD_InitTypeDef         Init;        /*!< PCD required parameters             */

  __IO uint8_t            USB_Address; /*!< USB Address: not used by USB OTG FS */  

  PCD_EPTypeDef           IN_ep[15];   /*!< IN endpoint parameters              */

  PCD_EPTypeDef           OUT_ep[15];  /*!< OUT endpoint parameters             */

  HAL_LockTypeDef         Lock;        /*!< PCD peripheral status               */

  __IO PCD_StateTypeDef   State;       /*!< PCD communication state             */

  uint32_t                Setup[12];   /*!< Setup packet buffer                 */

  void                    *pData;      /*!< Pointer to upper stack Handler      */

} PCD_HandleTypeDef;

 

/**

  * @brief  PCD State structure definition

  */

typedef enum

{

  HAL_PCD_STATE_RESET   = 0x00,

  HAL_PCD_STATE_READY   = 0x01,

  HAL_PCD_STATE_ERROR   = 0x02,

  HAL_PCD_STATE_BUSY    = 0x03,

  HAL_PCD_STATE_TIMEOUT = 0x04

} PCD_StateTypeDef;

 

#if defined (USB)

typedef USB_TypeDef        PCD_TypeDef;

typedef USB_CfgTypeDef     PCD_InitTypeDef;

typedef USB_EPTypeDef      PCD_EPTypeDef;

#endif /* USB */

 

/** 

  * @brief Universal Serial Bus Full Speed Device

  */

  

typedef struct

{

  __IO uint16_t EP0R;                 /*!< USB Endpoint 0 register,                   Address offset: 0x00 */ 

  __IO uint16_t RESERVED0;            /*!< Reserved */     

  __IO uint16_t EP1R;                 /*!< USB Endpoint 1 register,                   Address offset: 0x04 */

  __IO uint16_t RESERVED1;            /*!< Reserved */       

  __IO uint16_t EP2R;                 /*!< USB Endpoint 2 register,                   Address offset: 0x08 */

  __IO uint16_t RESERVED2;            /*!< Reserved */       

  __IO uint16_t EP3R;                 /*!< USB Endpoint 3 register,                   Address offset: 0x0C */ 

  __IO uint16_t RESERVED3;            /*!< Reserved */       

  __IO uint16_t EP4R;                 /*!< USB Endpoint 4 register,                   Address offset: 0x10 */

  __IO uint16_t RESERVED4;            /*!< Reserved */       

  __IO uint16_t EP5R;                 /*!< USB Endpoint 5 register,                   Address offset: 0x14 */

  __IO uint16_t RESERVED5;            /*!< Reserved */       

  __IO uint16_t EP6R;                 /*!< USB Endpoint 6 register,                   Address offset: 0x18 */

  __IO uint16_t RESERVED6;            /*!< Reserved */       

  __IO uint16_t EP7R;                 /*!< USB Endpoint 7 register,                   Address offset: 0x1C */

  __IO uint16_t RESERVED7[17];        /*!< Reserved */     

  __IO uint16_t CNTR;                 /*!< Control register,                          Address offset: 0x40 */

  __IO uint16_t RESERVED8;            /*!< Reserved */       

  __IO uint16_t ISTR;                 /*!< Interrupt status register,                 Address offset: 0x44 */

  __IO uint16_t RESERVED9;            /*!< Reserved */       

  __IO uint16_t FNR;                  /*!< Frame number register,                     Address offset: 0x48 */

  __IO uint16_t RESERVEDA;            /*!< Reserved */       

  __IO uint16_t DADDR;                /*!< Device address register,                   Address offset: 0x4C */

  __IO uint16_t RESERVEDB;            /*!< Reserved */       

  __IO uint16_t BTABLE;               /*!< Buffer Table address register,             Address offset: 0x50 */

  __IO uint16_t RESERVEDC;            /*!< Reserved */       

} USB_TypeDef;

 

#if defined (USB)

/** 

  * @brief  USB Initialization Structure definition  

  */

typedef struct

{

  uint32_t dev_endpoints;        /*!< Device Endpoints number.

                                      This parameter depends on the used USB core.   

                                      This parameter must be a number between Min_Data = 1 and Max_Data = 15 */

  

  uint32_t speed;                /*!< USB Core speed.

                                      This parameter can be any value of @ref USB_Core_Speed                 */

  

  uint32_t ep0_mps;              /*!< Set the Endpoint 0 Max Packet size. 

                                      This parameter can be any value of @ref USB_EP0_MPS                    */

  

  uint32_t phy_itface;           /*!< Select the used PHY interface.

                                      This parameter can be any value of @ref USB_Core_PHY                   */

  

  uint32_t Sof_enable;           /*!< Enable or disable the output of the SOF signal.                        */

  

  uint32_t low_power_enable;       /*!< Enable or disable Low Power mode                                      */

  

  uint32_t lpm_enable;             /*!< Enable or disable Battery charging.                                  */

  

  uint32_t battery_charging_enable; /*!< Enable or disable Battery charging.                                  */

} USB_CfgTypeDef;

 

typedef struct

{

  uint8_t   num;            /*!< Endpoint number

                                This parameter must be a number between Min_Data = 1 and Max_Data = 15    */

  

  uint8_t   is_in;          /*!< Endpoint direction

                                This parameter must be a number between Min_Data = 0 and Max_Data = 1     */

  

  uint8_t   is_stall;       /*!< Endpoint stall condition

                                This parameter must be a number between Min_Data = 0 and Max_Data = 1     */

  

  uint8_t   type;           /*!< Endpoint type

                                 This parameter can be any value of @ref USB_EP_Type                      */

  

  uint16_t  pmaadress;      /*!< PMA Address

                                 This parameter can be any value between Min_addr = 0 and Max_addr = 1K   */

  

  uint16_t  pmaaddr0;       /*!< PMA Address0

                                 This parameter can be any value between Min_addr = 0 and Max_addr = 1K   */

  

  uint16_t  pmaaddr1;        /*!< PMA Address1

                                 This parameter can be any value between Min_addr = 0 and Max_addr = 1K   */

  

  uint8_t   doublebuffer;    /*!< Double buffer enable

                                 This parameter can be 0 or 1                                             */

  

  uint16_t  tx_fifo_num;    /*!< This parameter is not required by USB Device FS peripheral, it is used 

                                 only by USB OTG FS peripheral    

                                 This parameter is added to ensure compatibility across USB peripherals   */

  

  uint32_t  maxpacket;      /*!< Endpoint Max packet size

                                 This parameter must be a number between Min_Data = 0 and Max_Data = 64KB */

  

  uint8_t   *xfer_buff;     /*!< Pointer to transfer buffer                                               */

  

  uint32_t  xfer_len;       /*!< Current transfer length                                                  */

  

  uint32_t  xfer_count;     /*!< Partial transfer length in case of multi packet transfer                 */

 

} USB_EPTypeDef;

#endif /* USB */

其中USB_TypeDef结构跟STM32寄存器相关,可通过查看STM32F103C8T6参考手册来熟悉USB相关寄存器。剩余的两个结构USB_CfgTypeDef和USB_EPTypeDef跟STM32中USB模块的特性相关,因此需要多多熟悉相对应的参考手册,STM32F103C8T6可提供16个单向端点,至于PCD_HandleTypeDef中Setup数组大小为12,还不清楚为什么是12,USB协议中Setup包大小是8个字节,而这里是48个字节,后面有眉目了再说吧。对于USB器件库的使用来说PCD_HandleTypeDef结构体没有USBD_HandleTypeDef结构体重要,USBD_HandleTypeDef结构体是USB器件库中核心结构体,如下:


/* USB Device handle structure */

typedef struct _USBD_HandleTypeDef

{

  uint8_t                 id;

  uint32_t                dev_config;

  uint32_t                dev_default_config;

  uint32_t                dev_config_status; 

  USBD_SpeedTypeDef       dev_speed; 

  USBD_EndpointTypeDef    ep_in[15];

  USBD_EndpointTypeDef    ep_out[15];  

  uint32_t                ep0_state;  

  uint32_t                ep0_data_len;     

  uint8_t                 dev_state;

  uint8_t                 dev_old_state;

  uint8_t                 dev_address;

  uint8_t                 dev_connection_status;  

  uint8_t                 dev_test_mode;

  uint32_t                dev_remote_wakeup;

 

  USBD_SetupReqTypedef    request;

  USBD_DescriptorsTypeDef *pDesc;

  USBD_ClassTypeDef       *pClass;

  void                    *pClassData;  

  void                    *pUserData;    

  void                    *pData;    

} USBD_HandleTypeDef;

 

/* Following USB Device Speed */

typedef enum 

{

  USBD_SPEED_HIGH  = 0,

  USBD_SPEED_FULL  = 1,

  USBD_SPEED_LOW   = 2,  

}USBD_SpeedTypeDef;

 

/* USB Device handle structure */

typedef struct

  uint32_t                status;

  uint32_t                total_length;    

  uint32_t                rem_length; 

  uint32_t                maxpacket;   

} USBD_EndpointTypeDef;

 

/** @defgroup USBD_DEF_Exported_TypesDefinitions

  * @{

  */

 

typedef  struct  usb_setup_req 

{

    

    uint8_t   bmRequest;                      

    uint8_t   bRequest;                           

    uint16_t  wValue;                             

    uint16_t  wIndex;                             

    uint16_t  wLength;                            

}USBD_SetupReqTypedef;

 

typedef struct _Device_cb

{

  uint8_t  (*Init)             (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx);

  uint8_t  (*DeInit)           (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx);

 /* Control Endpoints*/

  uint8_t  (*Setup)            (struct _USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef  *req);  

  uint8_t  (*EP0_TxSent)       (struct _USBD_HandleTypeDef *pdev );    

  uint8_t  (*EP0_RxReady)      (struct _USBD_HandleTypeDef *pdev );  

  /* Class Specific Endpoints*/

  uint8_t  (*DataIn)           (struct _USBD_HandleTypeDef *pdev , uint8_t epnum);   

  uint8_t  (*DataOut)          (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); 

  uint8_t  (*SOF)              (struct _USBD_HandleTypeDef *pdev); 

  uint8_t  (*IsoINIncomplete)  (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); 

  uint8_t  (*IsoOUTIncomplete) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum);   

 

  uint8_t  *(*GetHSConfigDescriptor)(uint16_t *length); 

  uint8_t  *(*GetFSConfigDescriptor)(uint16_t *length);   

  uint8_t  *(*GetOtherSpeedConfigDescriptor)(uint16_t *length);

  uint8_t  *(*GetDeviceQualifierDescriptor)(uint16_t *length);

#if (USBD_SUPPORT_USER_STRING == 1)

  uint8_t  *(*GetUsrStrDescriptor)(struct _USBD_HandleTypeDef *pdev ,uint8_t index,  uint16_t *length);   

#endif  

  

} USBD_ClassTypeDef;

一个USB总线最多可支持1128个设备,地址范围为0~127,因此这里用一个字节的dev_address来存储唯一的设备地址。而USBD_SetupReqTypedef结构体跟USB协议相关,USB协议中定义的Setup请求格式如下:

可以看到二者相匹配,获取setup请求更多详情,请参考USB2.0协议规范中第九章节。同时可以看到在USBD_HandleTypeDef结构体中包含了之前提到的描述符结构体USBD_DescriptorTypeDef,此外还包含了一个新的结构体设备类结构体USBD_ClassTypeDef,它里面是各个回调函数,在USB中断的回调函数中会调用设备类中的回调函数来实现具体功能,USB器件库手册中说明了设备类回调函数的作用,如下:

这些接口的实现是在CDC接口文件中实现,后面再分析,PCD_HandleTypeDef和USBD_HandleTypeDef结构通过void指针相互引用。


USB模块中静态空间分配方案实现如下:



/**

  * @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)

{

 

}

实现很简单申请一块静态空间并返回给调用者。USB设备驱动的底层API实现如下:


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

                       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 , CDC_IN_EP , PCD_SNG_BUF, 0xC0);  

  HAL_PCDEx_PMAConfig(pdev->pData , CDC_OUT_EP , PCD_SNG_BUF, 0x110);

  HAL_PCDEx_PMAConfig(pdev->pData , CDC_CMD_EP , PCD_SNG_BUF, 0x100); 

 

  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);

}

这些底层驱动的实现大部分都是调用Cube库中USB接口,其具体实现不必刻意关注,如果有空闲可以静心研究其寄存器的操作,我们一般只关心底层接口即可,比较复杂的一个接口是USBD_LL_Init(),USB中端点分为IN端点和OUT端点,共16个端点,在USB器件库中使用一个字节来表示,最高位为0是OUT端点,最高位为1是IN端点,USBD_LL_Init()中设置端点数为8,端点0最大包大小为64字节,为全速设备,不支持低功耗模式,并通过void指针pData来实现USBD_HandleTypeDef和PCD_HandleTypeDef结构的相互引用,HAL_PCDEx_PMAConfig()函数来设置端点缓冲区大小,这里使用了5个单向端点,有关分组缓冲的的描述可以在对应的参考手册上查找到,示例如下:

STM32中有单独的512个字节是作为USB分组缓冲区,该区域的地址为0x4000_6000~0x4000_63FF,USB和CAN模块共用该区域,因此二者不能同时访问,可以互斥访问,有关分组缓冲区有两类寄存器:USB分组缓冲区描述表地址寄存器(USB_BTABLE


);缓冲区描述表寄存器。如上图所示缓冲区描述表寄存器是几组寄存器的集合(一共8个端点共8组集合,每组里包含了4个寄存器:ADDRn_TX、COUNTn_TX、ADDRn_RX、COUNTn_RX)。这些寄存器的地址是可变的,在0x4000_6000~0x4000_63FF中,具体地址由USB_BTABLE寄存器指定,在本例中USB_BTABLE指定为0,如下:



#define BTABLE_ADDRESS                         (0x000)

 

/*Set Btable Address*/

USBx->BTABLE = BTABLE_ADDRESS;

对于每个端点的缓冲区地址及大小则由缓冲区描述表中的对应的4个寄存器来指定。分组缓冲区的访问是32bit的,所以虽然0x4000_0000~0x4000_63FF(共1K字节),但实际上只用了512字节。此外,这也是为何USB有两种地址表示方式,一个是USB本地地址,另一个是应用程序访问USB分组缓冲地址。在示例中设置默认的控制端点的分组大小为64字节,这也和端点0的最大包大小为64相符,且都是使用的单缓冲端点,至此,usbd_conf文件分析完毕。

推荐阅读

史海拾趣

BusBoard Prototype Systems公司的发展小趣事

随着市场的不断变化,BusBoard Prototype Systems意识到,要想在激烈的竞争中保持领先地位,必须不断进行技术创新。于是,公司投入大量资源研发新的BusBoard技术,成功提高了原型制作的精度和效率。这一技术突破不仅赢得了客户的广泛赞誉,也为公司带来了更多的业务机会。

长江微电(cjiang)公司的发展小趣事

2022年8月,美国商务部出台了一项断供禁令,禁止向中国出售用于芯片设计的特定类型的EDA软件。这一制裁措施对中国的半导体行业造成了巨大冲击。然而,长江微电并未因此气馁,反而借此机会加大了对电感产品的研发力度。通过自主创新,公司成功开发出了一系列高性能、高品质的电感产品,满足了国内外客户的需求。这一成就不仅彰显了长江微电应对国际制裁的勇气和智慧,也为中国半导体行业的发展注入了新的活力。

Ericsson Power Modules公司的发展小趣事

Ericsson Power Modules一直将品质管理视为企业发展的核心。公司建立了完善的质量管理体系,从原材料采购到生产、检测、包装等各个环节都进行严格的质量控制。同时,Ericsson Power Modules还注重持续改进,通过引入先进的生产设备和工艺、优化生产流程等方式,不断提高产品质量和生产效率。这种对品质的执着追求使得Ericsson Power Modules的产品在市场上赢得了良好的口碑和信誉。

世纪金光(CENGOL)公司的发展小趣事

随着新能源汽车市场的快速发展,世纪金光敏锐地捕捉到了这一领域的巨大潜力。公司迅速组建专项研发团队,基于碳化硅技术开展新能源汽车电机驱动系统的研发工作。经过不懈努力,世纪金光成功开发出基于碳化硅技术的新能源汽车电机驱动系统,并在技术上取得了重要进展。这一成果不仅提升了新能源汽车的性能和效率,也为公司打开了新的市场空间。

FERYSTER公司的发展小趣事

在技术创新的同时,FERYSTER公司也非常注重市场拓展。公司管理层通过深入的市场调研,发现亚洲市场对于高性能电子产品有着巨大的需求。于是,他们制定了针对亚洲市场的营销策略,包括加强品牌宣传、与当地企业建立合作关系等。这些措施取得了显著成效,FERYSTER公司的产品在亚洲市场的销量迅速增长,为公司带来了丰厚的利润。

创世(CS)公司的发展小趣事

创世公司在SD NAND存储产品的研发过程中,不断突破技术壁垒,实现了产品的创新。例如,2018年,为满足轨道交通、航空航天、工业控制等行业类客户对存储产品的特殊需求,创世公司首家推出了第二代SD NAND产品。这一产品不仅具有更快的读写速度和更宽泛的使用环境,还能承受高低温冷热冲击、随机掉电等苛刻的操作环境。同时,创世公司还为客户提供个性化的固件定制服务,进一步满足了客户的个性化需求。

问答坊 | AI 解惑

我想问下为什么要在单片机的i/o0上加上啦电阻

为啥要在i/op.0上的管脚加上拉电阻??…

查看全部问答>

急问:MP3电路原理图!请教高手,帮我分析下这个MP3原理图中各个组成部分的原理、处理器的功能。

http://blog.ednchina.com/Upload/Blog/2007/3/30/826adf84-7829-4de7-8065-2149d80d0c85.jpg 请高手帮我分析下这个MP3原理图中各个组成部分的原理、处理器的功能。 谢谢!…

查看全部问答>

弱弱的问一个问题,Windows中的WinInet API在Window Mobile中能用吗?

例如HttpSendRequest、InternetReadFile之类的函数。 如果不可以,是否手机就不能通过http协议请求某个服务器的数据?…

查看全部问答>

u盘+数据读写

ClassGUID={36FC9E60-C465-11CF-8056-444553540000}这个是mass stor的guid么?我自己做了个u盘,平时可以从u盘读设备的纪录信息,但是我要设置设备的一些信息或开启某些功能就想用VC写个程序来控制。不知道大家有什么好方法。u盘我已经留出了几个没 ...…

查看全部问答>

LED散热陶瓷新发展 金属化技术取得突破

陶瓷材料因本身具有优良的绝缘、耐热及稳定等先天特性,所以被大量运用在电气设备的绝缘上,又因陶瓷金属化技术的成熟,近几年更被应用于led陶瓷散热基板与载板的线路铺设。陶瓷材料金属化技术主要分为「DBC(Direct Bonded Copper) 」及「DPC(Di ...…

查看全部问答>

2812的flash怎么写不进去了

我的2812芯片flash写入了一次之后,就没办法写了怎么回事的?CCS连接之后点on-chip flash programmer,对话框全是灰色的,只有一个onlock按钮可以点,但是点了之后弹出unlock failed,CCS提示解锁失败,设备锁定。 但是上次烧写的时候我并没有改动 ...…

查看全部问答>

ORI与SBR的区别

大家好,本人初学avr,在看到汇编指令中ORI与SBR都是寄存器与立即数与的操作,不明白这两条指令的区别在哪里?多谢指导…

查看全部问答>

TI LM3S811学习心得

记录学习LM3S的点点滴滴 (声明:该学习心得是本人通过学习周立功的相关资料后的个人理解后的笔记,由于本人水平有限,也许会有错误或是偏差,若想要保证准确无误,建议自己去下相关资料学习,本心得只供参考,若有错误之处,敬请指出,万分感谢 ...…

查看全部问答>

新手求助!关于uCOS移植到S3C44B0X问题 不甚感激

本人刚开始学uCOS系统,现在有一块S3C44B0X的板子,想把uCOS移植进去,于是在网上找了一些基于S3C44B0X的uCOS源码,但是不知道如何运用编译器把源码处理,自然也就不知道怎么把内核系统烧进板子,现在不知道如何下手,而且在网上找的资料都没有运用 ...…

查看全部问答>

串口调试出现乱码,那位大哥大姐能帮帮我,万分感谢!

我用Verilog HDL编写了一个rs232串口驱动程序。在用串口调试助手进行调试时,当我发送2,4,6,8,A,C,E时,接受没有出现一个乱码,但当我发送1,3,5,7,9,B,D,F时出现乱码,在每300中出现4——5个乱码,有时只出现一个。请问这是什么原因,还是 ...…

查看全部问答>