当前位置:   article > 正文

USB -- STM32-FS-USB-Device驱动代码简述(二)_stm32 usbfs

stm32 usbfs

目录

链接快速定位 

前沿

1 STM32-FS-USB驱动程序下载

2 STM32-USB-FS设备固件库

2.1 USB应用程序层次结构

2.2 USB-FS_Device peripheral interface

2.3 USB-FS-Device_Driver medium layer

2.3 Application interface

3 代码讲解

3.1 初始化代码讲解

3.2 描述符讲解

3.3 中断处理函数

3.3.1 复位函数

3.3.2 正确传输完成函数

3.3.2.1 枚举过程正确传输完成函数

3.3.2.2 非端点0正确传输完成函数


链接快速定位 

USB -- 初识USB协议(一)

STM32F10x, STM32L1xx and STM32F3xx USB full speed device library (UM0424)

STM32 USB-FS-Device development kit

前沿

        本小节主要讲述STM32F103USB设备模式下的标准库驱动程序结构,代码比较复杂,需要读者对USB协议有一个全面的了解,这里只讲述一下比较浅显的东西。

        更多资料请参考:STM32 USB-FS-Device development kit

1 STM32-FS-USB驱动程序下载

        每个芯片厂商都会提供一套属于自己的外设驱动及应用程序,这也是我们所说的生态的一部分,可以在官网下载。我们这里主要讲解STM32F103的USB驱动,所以我们需要去ST的官网下载我们需要的驱动程序,STM32F10x, STM32L1xx and STM32F3xx USB full speed device library (UM0424)

2 STM32-USB-FS设备固件库

2.1 USB应用程序层次结构

        下图显示了典型USB的不同组件之间的交互应用程序和USB FS设备库。

        从上图可知,USB设备固件库被分为两层:

  • STM32_USB-FS_Device_Driver:该层管理与USB-FS_ Device外围设备和USB标准协议的直接通信。STM32_USBFS_ Device_Driver符合USB 2.0规范,与标准STM32标准外设库分离。
  • Application Interface layer:该层为用户提供了库核心和最终应用程序之间的完整接口。

        下图显示了USB FS设备库的程序包组织以及所有演示和子文件夹。

2.2 USB-FS_Device peripheral interface

        USB全速设备外设接口层主要由以下部分组成:

  • 硬件抽象层
  • 正确传输中断服务例程
  • 数据传输管理

2.3 USB-FS-Device_Driver medium layer

        USB全速设备驱动中间层主要由以下部分组成:

  • USB设备全局变量初始化
  • USB协议管理
  • 简化了对端点的读写访问功能(USB-FS_Device外围设备的抽象层)
  • 库中使用的USB定义和类型
  • 根据使用的评估板定义硬件

2.3 Application interface

        应用接口主要由以下部分组成:

  • USB全速设备配置文件
  • USB设备描述符
  • USB设备应用程序特定属性
  • 不带控制端点的正确传输中断例程
  • USB设备中断处理函数
  • USB设备电源和连接管理函数

3 代码讲解

        代码讲解主要涉及以下几个方面:

  • 初始化
  • 描述符
  • 中断处理函数
    • 复位函数
    • 正确传输完成函数

        这里以“VirtualComport_Loopback”工程为例进行讲解。

3.1 初始化代码讲解

  • GPIO初始化

        GPIO初始化程序主要是初始化通信所使用的DM和DP引脚以及USB全速设备的DP上拉引脚。

  1. void Set_System(void)
  2. {
  3. GPIO_InitTypeDef GPIO_InitStructure;
  4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  5. /********************************************/
  6. /* Configure USB DM/DP pins */
  7. /********************************************/
  8. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
  9. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  10. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  11. GPIO_Init(GPIOA, &GPIO_InitStructure);
  12. /* USB_DISCONNECT used as USB pull-up */
  13. GPIO_InitStructure.GPIO_Pin = USB_DISCONNECT_PIN;
  14. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  15. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
  16. GPIO_Init(USB_DISCONNECT, &GPIO_InitStructure);
  17. /* Enable the USB disconnect GPIO clock */
  18. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_DISCONNECT, ENABLE);
  19. }
  • USB时钟配置

        USB时钟配置主要是配置USB的PHY时钟,运行在48MHz的时钟下(系统时钟72M),并使能USB时钟。

  1. void Set_USBClock(void)
  2. {
  3. /* Select USBCLK source */
  4. RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);
  5. /* Enable the USB clock */
  6. RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);
  7. }

  • USB中断初始化

        USB中断初始化,主要是使能USB的中断,并且使能中断屏蔽位。

  1. void USB_Interrupts_Config(void)
  2. {
  3. NVIC_InitTypeDef NVIC_InitStructure;
  4. /* 2 bit for pre-emption priority, 2 bits for subpriority */
  5. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  6. /* Enable the USB interrupt */
  7. NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
  8. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  9. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  10. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  11. NVIC_Init(&NVIC_InitStructure);
  12. /* Enable the USB Wake-up interrupt */
  13. NVIC_InitStructure.NVIC_IRQChannel = USBWakeUp_IRQn;
  14. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  15. NVIC_Init(&NVIC_InitStructure);
  16. }
  1. RESULT PowerOn(void)
  2. {
  3. uint16_t wRegVal;
  4. #if !defined (USE_NUCLEO)
  5. /*** cable plugged-in ? ***/
  6. USB_Cable_Config(ENABLE);
  7. #endif
  8. /*** CNTR_PWDN = 0 ***/
  9. wRegVal = CNTR_FRES;
  10. _SetCNTR(wRegVal);
  11. /* The following sequence is recommended:
  12. 1- FRES = 0
  13. 2- Wait until RESET flag = 1 (polling)
  14. 3- clear ISTR register */
  15. /*** CNTR_FRES = 0 ***/
  16. wInterrupt_Mask = 0;
  17. _SetCNTR(wInterrupt_Mask);
  18. /* Wait until RESET flag = 1 (polling) */
  19. while((_GetISTR()&ISTR_RESET) == 1);
  20. /*** Clear pending interrupts ***/
  21. SetISTR(0);
  22. /*** Set interrupt mask ***/
  23. wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM;
  24. _SetCNTR(wInterrupt_Mask);
  25. return USB_SUCCESS;
  26. }
  27. uint32_t USB_SIL_Init(void)
  28. {
  29. /* USB interrupts initialization */
  30. /* clear pending interrupts */
  31. _SetISTR(0);
  32. wInterrupt_Mask = IMR_MSK;
  33. /* set interrupts mask */
  34. _SetCNTR(wInterrupt_Mask);
  35. return 0;
  36. }
  37. void Virtual_Com_Port_init(void)
  38. {
  39. /* Update the serial number string descriptor with the data from the unique
  40. ID*/
  41. Get_SerialNum();
  42. pInformation->Current_Configuration = 0;
  43. /* Connect the device */
  44. PowerOn();
  45. /* Perform basic device initialization operations */
  46. USB_SIL_Init();
  47. bDeviceState = UNCONNECTED;
  48. }

        经过上面的配置,当USB设备端接入主机的时候,设备端的中断处理函数就能响应相应的中断请求,开始建立通信。

3.2 描述符讲解

        描述符放在“usb_desc.c”和“usb_desc.h”文件中,更多细节参见USB -- 初识USB协议(一)

  • 设备描述符

        包含了设备的基本信息,比如USB版本号,端点0的传输大小,VID,PID,设备的类型等。

  1. const uint8_t Virtual_Com_Port_DeviceDescriptor[] =
  2. {
  3. 0x12, /* bLength */
  4. USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */
  5. 0x00,
  6. 0x02, /* bcdUSB = 2.00 */
  7. 0x02, /* bDeviceClass: CDC */
  8. 0x02, /* bDeviceSubClass */
  9. 0x02, /* bDeviceProtocol */
  10. 0x40, /* bMaxPacketSize0 */
  11. 0x83,
  12. 0x04, /* idVendor = 0x0483 */
  13. 0x40,
  14. 0x57, /* idProduct = 0x7540 */
  15. 0x00,
  16. 0x02, /* bcdDevice = 2.00 */
  17. 1, /* Index of string descriptor describing manufacturer */
  18. 2, /* Index of string descriptor describing product */
  19. 3, /* Index of string descriptor describing the device's serial number */
  20. 0x01 /* bNumConfigurations */
  21. };
  • 配置描述符

        配置描述符数组包含了配置描述符、接口描述符、功能描述符,端点描述符等,具体的描述符含义根据每种USB的CLASS不同而含义有所不同,后期小节会陆续讲解。

  1. const uint8_t Virtual_Com_Port_ConfigDescriptor[] =
  2. {
  3. /*Configuration Descriptor*/
  4. 0x09, /* bLength: Configuration Descriptor size */
  5. USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
  6. VIRTUAL_COM_PORT_SIZ_CONFIG_DESC, /* wTotalLength:no of returned bytes */
  7. 0x00,
  8. 0x02, /* bNumInterfaces: 2 interface */
  9. 0x01, /* bConfigurationValue: Configuration value */
  10. 0x00, /* iConfiguration: Index of string descriptor describing the configuration */
  11. 0xC0, /* bmAttributes: self powered */
  12. 0x32, /* MaxPower 0 mA */
  13. /*Interface Descriptor*/
  14. 0x09, /* bLength: Interface Descriptor size */
  15. USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */
  16. /* Interface descriptor type */
  17. 0x00, /* bInterfaceNumber: Number of Interface */
  18. 0x00, /* bAlternateSetting: Alternate setting */
  19. 0x01, /* bNumEndpoints: One endpoints used */
  20. 0x02, /* bInterfaceClass: Communication Interface Class */
  21. 0x02, /* bInterfaceSubClass: Abstract Control Model */
  22. 0x01, /* bInterfaceProtocol: Common AT commands */
  23. 0x00, /* iInterface: */
  24. /*Header Functional Descriptor*/
  25. 0x05, /* bLength: Endpoint Descriptor size */
  26. 0x24, /* bDescriptorType: CS_INTERFACE */
  27. 0x00, /* bDescriptorSubtype: Header Func Desc */
  28. 0x10, /* bcdCDC: spec release number */
  29. 0x01,
  30. /*Call Management Functional Descriptor*/
  31. 0x05, /* bFunctionLength */
  32. 0x24, /* bDescriptorType: CS_INTERFACE */
  33. 0x01, /* bDescriptorSubtype: Call Management Func Desc */
  34. 0x00, /* bmCapabilities: D0+D1 */
  35. 0x01, /* bDataInterface: 1 */
  36. /*ACM Functional Descriptor*/
  37. 0x04, /* bFunctionLength */
  38. 0x24, /* bDescriptorType: CS_INTERFACE */
  39. 0x02, /* bDescriptorSubtype: Abstract Control Management desc */
  40. 0x02, /* bmCapabilities */
  41. /*Union Functional Descriptor*/
  42. 0x05, /* bFunctionLength */
  43. 0x24, /* bDescriptorType: CS_INTERFACE */
  44. 0x06, /* bDescriptorSubtype: Union func desc */
  45. 0x00, /* bMasterInterface: Communication class interface */
  46. 0x01, /* bSlaveInterface0: Data Class Interface */
  47. /*Endpoint 2 Descriptor*/
  48. 0x07, /* bLength: Endpoint Descriptor size */
  49. USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
  50. 0x82, /* bEndpointAddress: (IN2) */
  51. 0x03, /* bmAttributes: Interrupt */
  52. VIRTUAL_COM_PORT_INT_SIZE, /* wMaxPacketSize: */
  53. 0x00,
  54. 0xFF, /* bInterval: */
  55. /*Data class interface descriptor*/
  56. 0x09, /* bLength: Endpoint Descriptor size */
  57. USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */
  58. 0x01, /* bInterfaceNumber: Number of Interface */
  59. 0x00, /* bAlternateSetting: Alternate setting */
  60. 0x02, /* bNumEndpoints: Two endpoints used */
  61. 0x0A, /* bInterfaceClass: CDC */
  62. 0x00, /* bInterfaceSubClass: */
  63. 0x00, /* bInterfaceProtocol: */
  64. 0x00, /* iInterface: */
  65. /*Endpoint 3 Descriptor*/
  66. 0x07, /* bLength: Endpoint Descriptor size */
  67. USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
  68. 0x03, /* bEndpointAddress: (OUT3) */
  69. 0x02, /* bmAttributes: Bulk */
  70. VIRTUAL_COM_PORT_DATA_SIZE, /* wMaxPacketSize: */
  71. 0x00,
  72. 0x00, /* bInterval: ignore for Bulk transfer */
  73. /*Endpoint 1 Descriptor*/
  74. 0x07, /* bLength: Endpoint Descriptor size */
  75. USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
  76. 0x81, /* bEndpointAddress: (IN1) */
  77. 0x02, /* bmAttributes: Bulk */
  78. VIRTUAL_COM_PORT_DATA_SIZE, /* wMaxPacketSize: */
  79. 0x00,
  80. 0x00 /* bInterval */
  81. };
  • 其它描述符

        其它描述符包括语言描述符,PID描述符、VID描述符,报告描述符等,这些描述符根据不同的厂商,不同的产品以及不同的USB应用而有所不通,我们会在后续的类容对这些描述符做一个简单的讲解。

3.3 中断处理函数

        USB驱动最关键的部分在于中断处理函数部分,协议的大部分实现都是在中断中实现的,我们这里简单的讲解一下。首先进入USB中断处理函数,进入到USB_Istr()函数中去。

        可以看到USB_Istr()函数实现了USB的中断的所有功能,我们这里只针对几个比较重要的函数进行讲解:

  • 复位函数
  • 正确传输完成函数
  1. void USB_Istr(void)
  2. {
  3. uint32_t i = 0;
  4. __IO uint32_t EP[8];
  5. wIstr = _GetISTR();
  6. #if (IMR_MSK & ISTR_SOF)
  7. if (wIstr & ISTR_SOF & wInterrupt_Mask)
  8. {
  9. _SetISTR((uint16_t)CLR_SOF);
  10. bIntPackSOF++;
  11. #ifdef SOF_CALLBACK
  12. SOF_Callback();
  13. #endif
  14. }
  15. #endif
  16. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  17. #if (IMR_MSK & ISTR_CTR)
  18. if (wIstr & ISTR_CTR & wInterrupt_Mask)
  19. {
  20. /* servicing of the endpoint correct transfer interrupt */
  21. /* clear of the CTR flag into the sub */
  22. CTR_LP();
  23. #ifdef CTR_CALLBACK
  24. CTR_Callback();
  25. #endif
  26. }
  27. #endif
  28. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  29. #if (IMR_MSK & ISTR_RESET)
  30. if (wIstr & ISTR_RESET & wInterrupt_Mask)
  31. {
  32. _SetISTR((uint16_t)CLR_RESET);
  33. Device_Property.Reset();
  34. #ifdef RESET_CALLBACK
  35. RESET_Callback();
  36. #endif
  37. }
  38. #endif
  39. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  40. #if (IMR_MSK & ISTR_DOVR)
  41. if (wIstr & ISTR_DOVR & wInterrupt_Mask)
  42. {
  43. _SetISTR((uint16_t)CLR_DOVR);
  44. #ifdef DOVR_CALLBACK
  45. DOVR_Callback();
  46. #endif
  47. }
  48. #endif
  49. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  50. #if (IMR_MSK & ISTR_ERR)
  51. if (wIstr & ISTR_ERR & wInterrupt_Mask)
  52. {
  53. _SetISTR((uint16_t)CLR_ERR);
  54. #ifdef ERR_CALLBACK
  55. ERR_Callback();
  56. #endif
  57. }
  58. #endif
  59. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  60. #if (IMR_MSK & ISTR_WKUP)
  61. if (wIstr & ISTR_WKUP & wInterrupt_Mask)
  62. {
  63. _SetISTR((uint16_t)CLR_WKUP);
  64. Resume(RESUME_EXTERNAL);
  65. #ifdef WKUP_CALLBACK
  66. WKUP_Callback();
  67. #endif
  68. }
  69. #endif
  70. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  71. #if (IMR_MSK & ISTR_SUSP)
  72. if (wIstr & ISTR_SUSP & wInterrupt_Mask)
  73. {
  74. /* check if SUSPEND is possible */
  75. if (fSuspendEnabled)
  76. {
  77. Suspend();
  78. }
  79. else
  80. {
  81. /* if not possible then resume after xx ms */
  82. Resume(RESUME_LATER);
  83. }
  84. /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */
  85. _SetISTR((uint16_t)CLR_SUSP);
  86. #ifdef SUSP_CALLBACK
  87. SUSP_Callback();
  88. #endif
  89. }
  90. #endif
  91. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  92. #if (IMR_MSK & ISTR_ESOF)
  93. if (wIstr & ISTR_ESOF & wInterrupt_Mask)
  94. {
  95. /* clear ESOF flag in ISTR */
  96. _SetISTR((uint16_t)CLR_ESOF);
  97. if ((_GetFNR()&FNR_RXDP) != 0)
  98. {
  99. /* increment ESOF counter */
  100. esof_counter ++;
  101. /* test if we enter in ESOF more than 3 times with FSUSP =0 and RXDP =1=>> possible missing SUSP flag*/
  102. if ((esof_counter > 3) && ((_GetCNTR()&CNTR_FSUSP) == 0))
  103. {
  104. /* this a sequence to apply a force RESET*/
  105. /*Store CNTR value */
  106. wCNTR = _GetCNTR();
  107. /*Store endpoints registers status */
  108. for (i = 0; i < 8; i++) EP[i] = _GetENDPOINT(i);
  109. /*apply FRES */
  110. wCNTR |= CNTR_FRES;
  111. _SetCNTR(wCNTR);
  112. /*clear FRES*/
  113. wCNTR &= ~CNTR_FRES;
  114. _SetCNTR(wCNTR);
  115. /*poll for RESET flag in ISTR*/
  116. while ((_GetISTR()&ISTR_RESET) == 0);
  117. /* clear RESET flag in ISTR */
  118. _SetISTR((uint16_t)CLR_RESET);
  119. /*restore Enpoints*/
  120. for (i = 0; i < 8; i++)
  121. _SetENDPOINT(i, EP[i]);
  122. esof_counter = 0;
  123. }
  124. }
  125. else
  126. {
  127. esof_counter = 0;
  128. }
  129. /* resume handling timing is made with ESOFs */
  130. Resume(RESUME_ESOF); /* request without change of the machine state */
  131. #ifdef ESOF_CALLBACK
  132. ESOF_Callback();
  133. #endif
  134. }
  135. #endif
  136. } /* USB_Istr */

3.3.1 复位函数

        复位是在USB识别到设备的时候,主机主动发出的特定序列,当USB设备收到这个特定序列的时候,就会产生中断相应,并进入中断中去处理相应的函数,这里的复位中断处理函数主要是配置端点的属性及端点的大小。

        注意一下宏定义“BTABLE_ADDRESS”的对应的USB中断缓存区地址的偏移,也就是512Byte的RAM空间,宏“ENDP0_RXADDR”等是定义端点的发送和接收地址存放在RAM空间的具体位置,以“BTABLE_ADDRESS”为偏移。

  1. /* buffer table base address */
  2. /* buffer table base address */
  3. #define BTABLE_ADDRESS (0x00)
  4. /* EP0 */
  5. /* rx/tx buffer base address */
  6. #define ENDP0_RXADDR (0x40)
  7. #define ENDP0_TXADDR (0x80)
  8. /* EP1 */
  9. /* tx buffer base address */
  10. #define ENDP1_TXADDR (0xC0)
  11. #define ENDP2_TXADDR (0x100)
  12. #define ENDP3_RXADDR (0x110)
  13. void Virtual_Com_Port_Reset(void)
  14. {
  15. /* Set Virtual_Com_Port DEVICE as not configured */
  16. pInformation->Current_Configuration = 0;
  17. /* Current Feature initialization */
  18. pInformation->Current_Feature = Virtual_Com_Port_ConfigDescriptor[7];
  19. /* Set Virtual_Com_Port DEVICE with the default Interface*/
  20. pInformation->Current_Interface = 0;
  21. SetBTABLE(BTABLE_ADDRESS);
  22. /* Initialize Endpoint 0 */
  23. SetEPType(ENDP0, EP_CONTROL);
  24. SetEPTxStatus(ENDP0, EP_TX_STALL);
  25. SetEPRxAddr(ENDP0, ENDP0_RXADDR);
  26. SetEPTxAddr(ENDP0, ENDP0_TXADDR);
  27. Clear_Status_Out(ENDP0);
  28. SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);
  29. SetEPRxValid(ENDP0);
  30. /* Initialize Endpoint 1 */
  31. SetEPType(ENDP1, EP_BULK);
  32. SetEPTxAddr(ENDP1, ENDP1_TXADDR);
  33. SetEPTxStatus(ENDP1, EP_TX_NAK);
  34. SetEPRxStatus(ENDP1, EP_RX_DIS);
  35. /* Initialize Endpoint 2 */
  36. SetEPType(ENDP2, EP_INTERRUPT);
  37. SetEPTxAddr(ENDP2, ENDP2_TXADDR);
  38. SetEPRxStatus(ENDP2, EP_RX_DIS);
  39. SetEPTxStatus(ENDP2, EP_TX_NAK);
  40. /* Initialize Endpoint 3 */
  41. SetEPType(ENDP3, EP_BULK);
  42. SetEPRxAddr(ENDP3, ENDP3_RXADDR);
  43. SetEPRxCount(ENDP3, VIRTUAL_COM_PORT_DATA_SIZE);
  44. SetEPRxStatus(ENDP3, EP_RX_VALID);
  45. SetEPTxStatus(ENDP3, EP_TX_DIS);
  46. /* Set this device to response on default address */
  47. SetDeviceAddress(0);
  48. bDeviceState = ATTACHED;
  49. }

3.3.2 正确传输完成函数

        正确传输完成函数分为枚举过程(端点0)的正确传输完成函数和非端点0的正确传输完成函数。

  1. void CTR_LP(void)
  2. {
  3. __IO uint16_t wEPVal = 0;
  4. /* stay in loop while pending interrupts */
  5. while (((wIstr = _GetISTR()) & ISTR_CTR) != 0)
  6. {
  7. /* extract highest priority endpoint number */
  8. EPindex = (uint8_t)(wIstr & ISTR_EP_ID);
  9. if (EPindex == 0)
  10. {
  11. /* Decode and service control endpoint interrupt */
  12. /* calling related service routine */
  13. /* (Setup0_Process, In0_Process, Out0_Process) */
  14. /* save RX & TX status */
  15. /* and set both to NAK */
  16. SaveRState = _GetENDPOINT(ENDP0);
  17. SaveTState = SaveRState & EPTX_STAT;
  18. SaveRState &= EPRX_STAT;
  19. _SetEPRxTxStatus(ENDP0, EP_RX_NAK, EP_TX_NAK);
  20. /* DIR bit = origin of the interrupt */
  21. if ((wIstr & ISTR_DIR) == 0)
  22. {
  23. /* DIR = 0 */
  24. /* DIR = 0 => IN int */
  25. /* DIR = 0 implies that (EP_CTR_TX = 1) always */
  26. _ClearEP_CTR_TX(ENDP0);
  27. In0_Process();
  28. /* before terminate set Tx & Rx status */
  29. _SetEPRxTxStatus(ENDP0, SaveRState, SaveTState);
  30. return;
  31. }
  32. else
  33. {
  34. /* DIR = 1 */
  35. /* DIR = 1 & CTR_RX => SETUP or OUT int */
  36. /* DIR = 1 & (CTR_TX | CTR_RX) => 2 int pending */
  37. wEPVal = _GetENDPOINT(ENDP0);
  38. if ((wEPVal & EP_SETUP) != 0)
  39. {
  40. _ClearEP_CTR_RX(ENDP0); /* SETUP bit kept frozen while CTR_RX = 1 */
  41. Setup0_Process();
  42. /* before terminate set Tx & Rx status */
  43. _SetEPRxTxStatus(ENDP0, SaveRState, SaveTState);
  44. return;
  45. }
  46. else if ((wEPVal & EP_CTR_RX) != 0)
  47. {
  48. _ClearEP_CTR_RX(ENDP0);
  49. Out0_Process();
  50. /* before terminate set Tx & Rx status */
  51. _SetEPRxTxStatus(ENDP0, SaveRState, SaveTState);
  52. return;
  53. }
  54. }
  55. }/* if(EPindex == 0) */
  56. else
  57. {
  58. /* Decode and service non control endpoints interrupt */
  59. /* process related endpoint register */
  60. wEPVal = _GetENDPOINT(EPindex);
  61. if ((wEPVal & EP_CTR_RX) != 0)
  62. {
  63. /* clear int flag */
  64. _ClearEP_CTR_RX(EPindex);
  65. /* call OUT service function */
  66. (*pEpInt_OUT[EPindex - 1])();
  67. } /* if((wEPVal & EP_CTR_RX) */
  68. if ((wEPVal & EP_CTR_TX) != 0)
  69. {
  70. /* clear int flag */
  71. _ClearEP_CTR_TX(EPindex);
  72. /* call IN service function */
  73. (*pEpInt_IN[EPindex - 1])();
  74. } /* if((wEPVal & EP_CTR_TX) != 0) */
  75. }/* if(EPindex == 0) else */
  76. }/* while(...) */
  77. }
3.3.2.1 枚举过程正确传输完成函数

        枚举过程的正确传输完成函数主要是接收SETUP指令请求,并相应的告知USB主机设备的描述符信息。

        以下代码是处理USB主机的数据,把USB主机的SETUP请求数据存在pInformation结构体中,并在后续的函数进行指令的解析,并通过相对应的SETUP请求发送相对应的数据。

  1. uint8_t Setup0_Process(void)
  2. {
  3. union
  4. {
  5. uint8_t* b;
  6. uint16_t* w;
  7. } pBuf;
  8. #if defined STM32F303xE || defined STM32F302x8
  9. uint16_t offset = 0;
  10. pBuf.b = (uint8_t *)( PMAAddr + _GetEPRxAddr(ENDP0));
  11. #else
  12. uint16_t offset = 1;
  13. pBuf.b = PMAAddr + (uint8_t *)(_GetEPRxAddr(ENDP0) * 2); /* *2 for 32 bits addr */
  14. #endif
  15. if (pInformation->ControlState != PAUSE)
  16. {
  17. pInformation->USBbmRequestType = *pBuf.b++; /* bmRequestType */
  18. pInformation->USBbRequest = *pBuf.b++; /* bRequest */
  19. pBuf.w += offset; /* word not accessed because of 32 bits addressing */
  20. pInformation->USBwValue = ByteSwap(*pBuf.w++); /* wValue */
  21. pBuf.w += offset; /* word not accessed because of 32 bits addressing */
  22. pInformation->USBwIndex = ByteSwap(*pBuf.w++); /* wIndex */
  23. pBuf.w += offset; /* word not accessed because of 32 bits addressing */
  24. pInformation->USBwLength = *pBuf.w; /* wLength */
  25. }
  26. pInformation->ControlState = SETTING_UP;
  27. if (pInformation->USBwLength == 0)
  28. {
  29. /* Setup with no data stage */
  30. NoData_Setup0();
  31. }
  32. else
  33. {
  34. /* Setup with data stage */
  35. Data_Setup0();
  36. }
  37. return Post0_Process();
  38. }
  1. void Data_Setup0(void)
  2. {
  3. uint8_t *(*CopyRoutine)(uint16_t);
  4. RESULT Result;
  5. uint32_t Request_No = pInformation->USBbRequest;
  6. uint32_t Related_Endpoint, Reserved;
  7. uint32_t wOffset, Status;
  8. CopyRoutine = NULL;
  9. wOffset = 0;
  10. /*GET DESCRIPTOR*/
  11. if (Request_No == GET_DESCRIPTOR)
  12. {
  13. if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))
  14. {
  15. uint8_t wValue1 = pInformation->USBwValue1;
  16. if (wValue1 == DEVICE_DESCRIPTOR)
  17. {
  18. CopyRoutine = pProperty->GetDeviceDescriptor;
  19. }
  20. #ifdef LPM_ENABLED
  21. else if (wValue1 == DEVICE_BOS_DESCRIPTOR)
  22. {
  23. CopyRoutine = pProperty->GetBosDescriptor;
  24. }
  25. #endif
  26. else if (wValue1 == CONFIG_DESCRIPTOR)
  27. {
  28. CopyRoutine = pProperty->GetConfigDescriptor;
  29. }
  30. else if (wValue1 == STRING_DESCRIPTOR)
  31. {
  32. CopyRoutine = pProperty->GetStringDescriptor;
  33. } /* End of GET_DESCRIPTOR */
  34. }
  35. }
  36. /*GET STATUS*/
  37. else if ((Request_No == GET_STATUS) && (pInformation->USBwValue == 0)
  38. && (pInformation->USBwLength == 0x0002)
  39. && (pInformation->USBwIndex1 == 0))
  40. {
  41. /* GET STATUS for Device*/
  42. if ((Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))
  43. && (pInformation->USBwIndex == 0))
  44. {
  45. CopyRoutine = Standard_GetStatus;
  46. }
  47. /* GET STATUS for Interface*/
  48. else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))
  49. {
  50. if (((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0) == USB_SUCCESS)
  51. && (pInformation->Current_Configuration != 0))
  52. {
  53. CopyRoutine = Standard_GetStatus;
  54. }
  55. }
  56. /* GET STATUS for EndPoint*/
  57. else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT))
  58. {
  59. Related_Endpoint = (pInformation->USBwIndex0 & 0x0f);
  60. Reserved = pInformation->USBwIndex0 & 0x70;
  61. if (ValBit(pInformation->USBwIndex0, 7))
  62. {
  63. /*Get Status of endpoint & stall the request if the related_ENdpoint
  64. is Disabled*/
  65. Status = _GetEPTxStatus(Related_Endpoint);
  66. }
  67. else
  68. {
  69. Status = _GetEPRxStatus(Related_Endpoint);
  70. }
  71. if ((Related_Endpoint < Device_Table.Total_Endpoint) && (Reserved == 0)
  72. && (Status != 0))
  73. {
  74. CopyRoutine = Standard_GetStatus;
  75. }
  76. }
  77. }
  78. /*GET CONFIGURATION*/
  79. else if (Request_No == GET_CONFIGURATION)
  80. {
  81. if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))
  82. {
  83. CopyRoutine = Standard_GetConfiguration;
  84. }
  85. }
  86. /*GET INTERFACE*/
  87. else if (Request_No == GET_INTERFACE)
  88. {
  89. if ((Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))
  90. && (pInformation->Current_Configuration != 0) && (pInformation->USBwValue == 0)
  91. && (pInformation->USBwIndex1 == 0) && (pInformation->USBwLength == 0x0001)
  92. && ((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0) == USB_SUCCESS))
  93. {
  94. CopyRoutine = Standard_GetInterface;
  95. }
  96. }
  97. if (CopyRoutine)
  98. {
  99. pInformation->Ctrl_Info.Usb_wOffset = wOffset;
  100. pInformation->Ctrl_Info.CopyData = CopyRoutine;
  101. /* sb in the original the cast to word was directly */
  102. /* now the cast is made step by step */
  103. (*CopyRoutine)(0);
  104. Result = USB_SUCCESS;
  105. }
  106. else
  107. {
  108. Result = (*pProperty->Class_Data_Setup)(pInformation->USBbRequest);
  109. if (Result == USB_NOT_READY)
  110. {
  111. pInformation->ControlState = PAUSE;
  112. return;
  113. }
  114. }
  115. if (pInformation->Ctrl_Info.Usb_wLength == 0xFFFF)
  116. {
  117. /* Data is not ready, wait it */
  118. pInformation->ControlState = PAUSE;
  119. return;
  120. }
  121. if ((Result == USB_UNSUPPORT) || (pInformation->Ctrl_Info.Usb_wLength == 0))
  122. {
  123. /* Unsupported request */
  124. pInformation->ControlState = STALLED;
  125. return;
  126. }
  127. if (ValBit(pInformation->USBbmRequestType, 7))
  128. {
  129. /* Device ==> Host */
  130. __IO uint32_t wLength = pInformation->USBwLength;
  131. /* Restrict the data length to be the one host asks for */
  132. if (pInformation->Ctrl_Info.Usb_wLength > wLength)
  133. {
  134. pInformation->Ctrl_Info.Usb_wLength = wLength;
  135. }
  136. else if (pInformation->Ctrl_Info.Usb_wLength < pInformation->USBwLength)
  137. {
  138. if (pInformation->Ctrl_Info.Usb_wLength < pProperty->MaxPacketSize)
  139. {
  140. Data_Mul_MaxPacketSize = FALSE;
  141. }
  142. else if ((pInformation->Ctrl_Info.Usb_wLength % pProperty->MaxPacketSize) == 0)
  143. {
  144. Data_Mul_MaxPacketSize = TRUE;
  145. }
  146. }
  147. pInformation->Ctrl_Info.PacketSize = pProperty->MaxPacketSize;
  148. DataStageIn();
  149. }
  150. else
  151. {
  152. pInformation->ControlState = OUT_DATA;
  153. vSetEPRxStatus(EP_RX_VALID); /* enable for next data reception */
  154. }
  155. return;
  156. }
3.3.2.2 非端点0正确传输完成函数

        非控制端点0正确传输完成函数根据不同的USB应用存在不同的差距,但是主体框架已经完成,只需要用户在特定的框架中填写特定的程序即可。

        比如当前程序只用到端点1的TX和端点3的RX,就只需要在端点1的TX和端点3的RX中编写相应的应用程序,其它端点不必理会。

  1. /* associated to defined endpoints */
  2. /*#define EP1_IN_Callback NOP_Process*/
  3. #define EP2_IN_Callback NOP_Process
  4. #define EP3_IN_Callback NOP_Process
  5. #define EP4_IN_Callback NOP_Process
  6. #define EP5_IN_Callback NOP_Process
  7. #define EP6_IN_Callback NOP_Process
  8. #define EP7_IN_Callback NOP_Process
  9. #define EP1_OUT_Callback NOP_Process
  10. #define EP2_OUT_Callback NOP_Process
  11. /*#define EP3_OUT_Callback NOP_Process*/
  12. #define EP4_OUT_Callback NOP_Process
  13. #define EP5_OUT_Callback NOP_Process
  14. #define EP6_OUT_Callback NOP_Process
  15. #define EP7_OUT_Callback NOP_Process
  16. void (*pEpInt_IN[7])(void) =
  17. {
  18. EP1_IN_Callback,
  19. EP2_IN_Callback,
  20. EP3_IN_Callback,
  21. EP4_IN_Callback,
  22. EP5_IN_Callback,
  23. EP6_IN_Callback,
  24. EP7_IN_Callback,
  25. };
  26. void (*pEpInt_OUT[7])(void) =
  27. {
  28. EP1_OUT_Callback,
  29. EP2_OUT_Callback,
  30. EP3_OUT_Callback,
  31. EP4_OUT_Callback,
  32. EP5_OUT_Callback,
  33. EP6_OUT_Callback,
  34. EP7_OUT_Callback,
  35. };
  36. void EP1_IN_Callback (void)
  37. {
  38. packet_sent = 1;
  39. }
  40. void EP3_OUT_Callback(void)
  41. {
  42. packet_receive = 1;
  43. Receive_length = GetEPRxCount(ENDP3);
  44. PMAToUserBufferCopy((unsigned char*)Receive_Buffer, ENDP3_RXADDR, Receive_length);
  45. }

        到这里,本章就基本上讲完了,主要还是从应用的角度去简单的讲解了一下代码,如果读者需要更深入的了解代码的结构,还是需要大家仔细去学习USB的驱动源码的。

接下来讲解STM32 USB的虚拟串口环回功能实现,敬请期待。。。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/164306?site
推荐阅读
相关标签
  

闽ICP备14008679号