STM32 USB
来源:互联网 发布:unity3d itweenpath 编辑:程序博客网 时间:2024/06/05 10:55
转自:http://blog.csdn.net/anobodykey/article/details/50700304
主机环境: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 <stdio.h>#include <stdlib.h>#include <string.h>/* 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文件分析完毕。
- stm32 usb
- STM32 USB
- STM32 USB
- STM32 USB 键盘
- STM32 USB设计
- STM32 USB学习笔记
- STM32 USB IAP 步骤
- STM32 USB转串口
- STM32 USB 问题汇总
- STM32 USB设计
- STM32 USB 问题汇总
- STM32 USB设计
- STM32 USB 键盘
- STM32 USB IAP 步骤
- STM32 USB 问题汇总
- STM32 USB详细使用说明
- STM32 USB设计
- STM32 USB模块
- 4. Median of Two Sorted Arrays
- 10815
- 微信的redirect_uri参数错误解决办法
- java基础----内部类
- cookie中文乱码问题解决
- STM32 USB
- CSS定位之相对定位
- Puppet之master_agent模型
- Node.js中的module.exports和exports的区别
- 银行外围业务简介
- 关于排序的框架
- Java基础---异常
- LINUX 用户 及 组
- (3)冒泡排序