赞
踩
目录
2.2 USB-FS_Device peripheral interface
2.3 USB-FS-Device_Driver medium layer
STM32F10x, STM32L1xx and STM32F3xx USB full speed device library (UM0424)
STM32 USB-FS-Device development kit
本小节主要讲述STM32F103USB设备模式下的标准库驱动程序结构,代码比较复杂,需要读者对USB协议有一个全面的了解,这里只讲述一下比较浅显的东西。
更多资料请参考:STM32 USB-FS-Device development kit
每个芯片厂商都会提供一套属于自己的外设驱动及应用程序,这也是我们所说的生态的一部分,可以在官网下载。我们这里主要讲解STM32F103的USB驱动,所以我们需要去ST的官网下载我们需要的驱动程序,STM32F10x, STM32L1xx and STM32F3xx USB full speed device library (UM0424)。
下图显示了典型USB的不同组件之间的交互应用程序和USB FS设备库。
从上图可知,USB设备固件库被分为两层:
下图显示了USB FS设备库的程序包组织以及所有演示和子文件夹。
USB全速设备外设接口层主要由以下部分组成:
USB全速设备驱动中间层主要由以下部分组成:
应用接口主要由以下部分组成:
代码讲解主要涉及以下几个方面:
这里以“VirtualComport_Loopback”工程为例进行讲解。
GPIO初始化程序主要是初始化通信所使用的DM和DP引脚以及USB全速设备的DP上拉引脚。
- void Set_System(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
-
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
-
- /********************************************/
- /* Configure USB DM/DP pins */
- /********************************************/
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
-
- /* USB_DISCONNECT used as USB pull-up */
- GPIO_InitStructure.GPIO_Pin = USB_DISCONNECT_PIN;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
- GPIO_Init(USB_DISCONNECT, &GPIO_InitStructure);
-
- /* Enable the USB disconnect GPIO clock */
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_DISCONNECT, ENABLE);
- }
USB时钟配置主要是配置USB的PHY时钟,运行在48MHz的时钟下(系统时钟72M),并使能USB时钟。
- void Set_USBClock(void)
- {
- /* Select USBCLK source */
- RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);
-
- /* Enable the USB clock */
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);
- }
USB中断初始化,主要是使能USB的中断,并且使能中断屏蔽位。
- void USB_Interrupts_Config(void)
- {
- NVIC_InitTypeDef NVIC_InitStructure;
-
- /* 2 bit for pre-emption priority, 2 bits for subpriority */
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
-
-
- /* Enable the USB interrupt */
- NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
-
- /* Enable the USB Wake-up interrupt */
- NVIC_InitStructure.NVIC_IRQChannel = USBWakeUp_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
- NVIC_Init(&NVIC_InitStructure);
-
- }
- RESULT PowerOn(void)
- {
- uint16_t wRegVal;
-
- #if !defined (USE_NUCLEO)
- /*** cable plugged-in ? ***/
- USB_Cable_Config(ENABLE);
- #endif
-
- /*** CNTR_PWDN = 0 ***/
- wRegVal = CNTR_FRES;
- _SetCNTR(wRegVal);
-
- /* The following sequence is recommended:
- 1- FRES = 0
- 2- Wait until RESET flag = 1 (polling)
- 3- clear ISTR register */
-
- /*** CNTR_FRES = 0 ***/
- wInterrupt_Mask = 0;
-
- _SetCNTR(wInterrupt_Mask);
-
- /* Wait until RESET flag = 1 (polling) */
- while((_GetISTR()&ISTR_RESET) == 1);
-
- /*** Clear pending interrupts ***/
- SetISTR(0);
-
- /*** Set interrupt mask ***/
- wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM;
- _SetCNTR(wInterrupt_Mask);
-
- return USB_SUCCESS;
- }
-
- uint32_t USB_SIL_Init(void)
- {
- /* USB interrupts initialization */
- /* clear pending interrupts */
- _SetISTR(0);
- wInterrupt_Mask = IMR_MSK;
- /* set interrupts mask */
- _SetCNTR(wInterrupt_Mask);
- return 0;
- }
-
- void Virtual_Com_Port_init(void)
- {
-
- /* Update the serial number string descriptor with the data from the unique
- ID*/
- Get_SerialNum();
-
- pInformation->Current_Configuration = 0;
-
- /* Connect the device */
- PowerOn();
-
- /* Perform basic device initialization operations */
- USB_SIL_Init();
-
- bDeviceState = UNCONNECTED;
- }
经过上面的配置,当USB设备端接入主机的时候,设备端的中断处理函数就能响应相应的中断请求,开始建立通信。
描述符放在“usb_desc.c”和“usb_desc.h”文件中,更多细节参见USB -- 初识USB协议(一)。
包含了设备的基本信息,比如USB版本号,端点0的传输大小,VID,PID,设备的类型等。
- const uint8_t Virtual_Com_Port_DeviceDescriptor[] =
- {
- 0x12, /* bLength */
- USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */
- 0x00,
- 0x02, /* bcdUSB = 2.00 */
- 0x02, /* bDeviceClass: CDC */
- 0x02, /* bDeviceSubClass */
- 0x02, /* bDeviceProtocol */
- 0x40, /* bMaxPacketSize0 */
- 0x83,
- 0x04, /* idVendor = 0x0483 */
- 0x40,
- 0x57, /* idProduct = 0x7540 */
- 0x00,
- 0x02, /* bcdDevice = 2.00 */
- 1, /* Index of string descriptor describing manufacturer */
- 2, /* Index of string descriptor describing product */
- 3, /* Index of string descriptor describing the device's serial number */
- 0x01 /* bNumConfigurations */
- };
配置描述符数组包含了配置描述符、接口描述符、功能描述符,端点描述符等,具体的描述符含义根据每种USB的CLASS不同而含义有所不同,后期小节会陆续讲解。
- const uint8_t Virtual_Com_Port_ConfigDescriptor[] =
- {
- /*Configuration Descriptor*/
- 0x09, /* bLength: Configuration Descriptor size */
- USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
- VIRTUAL_COM_PORT_SIZ_CONFIG_DESC, /* wTotalLength:no of returned bytes */
- 0x00,
- 0x02, /* bNumInterfaces: 2 interface */
- 0x01, /* bConfigurationValue: Configuration value */
- 0x00, /* iConfiguration: Index of string descriptor describing the configuration */
- 0xC0, /* bmAttributes: self powered */
- 0x32, /* MaxPower 0 mA */
- /*Interface Descriptor*/
- 0x09, /* bLength: Interface Descriptor size */
- USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */
- /* Interface descriptor type */
- 0x00, /* bInterfaceNumber: Number of Interface */
- 0x00, /* bAlternateSetting: Alternate setting */
- 0x01, /* bNumEndpoints: One endpoints used */
- 0x02, /* bInterfaceClass: Communication Interface Class */
- 0x02, /* bInterfaceSubClass: Abstract Control Model */
- 0x01, /* bInterfaceProtocol: Common AT commands */
- 0x00, /* iInterface: */
- /*Header Functional Descriptor*/
- 0x05, /* bLength: Endpoint Descriptor size */
- 0x24, /* bDescriptorType: CS_INTERFACE */
- 0x00, /* bDescriptorSubtype: Header Func Desc */
- 0x10, /* bcdCDC: spec release number */
- 0x01,
- /*Call Management Functional Descriptor*/
- 0x05, /* bFunctionLength */
- 0x24, /* bDescriptorType: CS_INTERFACE */
- 0x01, /* bDescriptorSubtype: Call Management Func Desc */
- 0x00, /* bmCapabilities: D0+D1 */
- 0x01, /* bDataInterface: 1 */
- /*ACM Functional Descriptor*/
- 0x04, /* bFunctionLength */
- 0x24, /* bDescriptorType: CS_INTERFACE */
- 0x02, /* bDescriptorSubtype: Abstract Control Management desc */
- 0x02, /* bmCapabilities */
- /*Union Functional Descriptor*/
- 0x05, /* bFunctionLength */
- 0x24, /* bDescriptorType: CS_INTERFACE */
- 0x06, /* bDescriptorSubtype: Union func desc */
- 0x00, /* bMasterInterface: Communication class interface */
- 0x01, /* bSlaveInterface0: Data Class Interface */
- /*Endpoint 2 Descriptor*/
- 0x07, /* bLength: Endpoint Descriptor size */
- USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
- 0x82, /* bEndpointAddress: (IN2) */
- 0x03, /* bmAttributes: Interrupt */
- VIRTUAL_COM_PORT_INT_SIZE, /* wMaxPacketSize: */
- 0x00,
- 0xFF, /* bInterval: */
- /*Data class interface descriptor*/
- 0x09, /* bLength: Endpoint Descriptor size */
- USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */
- 0x01, /* bInterfaceNumber: Number of Interface */
- 0x00, /* bAlternateSetting: Alternate setting */
- 0x02, /* bNumEndpoints: Two endpoints used */
- 0x0A, /* bInterfaceClass: CDC */
- 0x00, /* bInterfaceSubClass: */
- 0x00, /* bInterfaceProtocol: */
- 0x00, /* iInterface: */
- /*Endpoint 3 Descriptor*/
- 0x07, /* bLength: Endpoint Descriptor size */
- USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
- 0x03, /* bEndpointAddress: (OUT3) */
- 0x02, /* bmAttributes: Bulk */
- VIRTUAL_COM_PORT_DATA_SIZE, /* wMaxPacketSize: */
- 0x00,
- 0x00, /* bInterval: ignore for Bulk transfer */
- /*Endpoint 1 Descriptor*/
- 0x07, /* bLength: Endpoint Descriptor size */
- USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
- 0x81, /* bEndpointAddress: (IN1) */
- 0x02, /* bmAttributes: Bulk */
- VIRTUAL_COM_PORT_DATA_SIZE, /* wMaxPacketSize: */
- 0x00,
- 0x00 /* bInterval */
- };
其它描述符包括语言描述符,PID描述符、VID描述符,报告描述符等,这些描述符根据不同的厂商,不同的产品以及不同的USB应用而有所不通,我们会在后续的类容对这些描述符做一个简单的讲解。
USB驱动最关键的部分在于中断处理函数部分,协议的大部分实现都是在中断中实现的,我们这里简单的讲解一下。首先进入USB中断处理函数,进入到USB_Istr()函数中去。
可以看到USB_Istr()函数实现了USB的中断的所有功能,我们这里只针对几个比较重要的函数进行讲解:
- void USB_Istr(void)
- {
- uint32_t i = 0;
- __IO uint32_t EP[8];
-
- wIstr = _GetISTR();
-
- #if (IMR_MSK & ISTR_SOF)
-
- if (wIstr & ISTR_SOF & wInterrupt_Mask)
- {
- _SetISTR((uint16_t)CLR_SOF);
- bIntPackSOF++;
-
- #ifdef SOF_CALLBACK
- SOF_Callback();
- #endif
- }
-
- #endif
- /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
-
- #if (IMR_MSK & ISTR_CTR)
-
- if (wIstr & ISTR_CTR & wInterrupt_Mask)
- {
- /* servicing of the endpoint correct transfer interrupt */
- /* clear of the CTR flag into the sub */
- CTR_LP();
- #ifdef CTR_CALLBACK
- CTR_Callback();
- #endif
- }
-
- #endif
- /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
- #if (IMR_MSK & ISTR_RESET)
-
- if (wIstr & ISTR_RESET & wInterrupt_Mask)
- {
- _SetISTR((uint16_t)CLR_RESET);
- Device_Property.Reset();
- #ifdef RESET_CALLBACK
- RESET_Callback();
- #endif
- }
-
- #endif
- /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
- #if (IMR_MSK & ISTR_DOVR)
-
- if (wIstr & ISTR_DOVR & wInterrupt_Mask)
- {
- _SetISTR((uint16_t)CLR_DOVR);
- #ifdef DOVR_CALLBACK
- DOVR_Callback();
- #endif
- }
-
- #endif
- /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
- #if (IMR_MSK & ISTR_ERR)
-
- if (wIstr & ISTR_ERR & wInterrupt_Mask)
- {
- _SetISTR((uint16_t)CLR_ERR);
- #ifdef ERR_CALLBACK
- ERR_Callback();
- #endif
- }
-
- #endif
- /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
- #if (IMR_MSK & ISTR_WKUP)
-
- if (wIstr & ISTR_WKUP & wInterrupt_Mask)
- {
- _SetISTR((uint16_t)CLR_WKUP);
- Resume(RESUME_EXTERNAL);
- #ifdef WKUP_CALLBACK
- WKUP_Callback();
- #endif
- }
-
- #endif
- /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
- #if (IMR_MSK & ISTR_SUSP)
-
- if (wIstr & ISTR_SUSP & wInterrupt_Mask)
- {
-
- /* check if SUSPEND is possible */
- if (fSuspendEnabled)
- {
- Suspend();
- }
- else
- {
- /* if not possible then resume after xx ms */
- Resume(RESUME_LATER);
- }
-
- /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */
- _SetISTR((uint16_t)CLR_SUSP);
- #ifdef SUSP_CALLBACK
- SUSP_Callback();
- #endif
- }
-
- #endif
- /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
-
- #if (IMR_MSK & ISTR_ESOF)
-
- if (wIstr & ISTR_ESOF & wInterrupt_Mask)
- {
- /* clear ESOF flag in ISTR */
- _SetISTR((uint16_t)CLR_ESOF);
-
- if ((_GetFNR()&FNR_RXDP) != 0)
- {
- /* increment ESOF counter */
- esof_counter ++;
-
- /* test if we enter in ESOF more than 3 times with FSUSP =0 and RXDP =1=>> possible missing SUSP flag*/
- if ((esof_counter > 3) && ((_GetCNTR()&CNTR_FSUSP) == 0))
- {
- /* this a sequence to apply a force RESET*/
-
- /*Store CNTR value */
- wCNTR = _GetCNTR();
-
- /*Store endpoints registers status */
- for (i = 0; i < 8; i++) EP[i] = _GetENDPOINT(i);
-
- /*apply FRES */
- wCNTR |= CNTR_FRES;
- _SetCNTR(wCNTR);
-
- /*clear FRES*/
- wCNTR &= ~CNTR_FRES;
- _SetCNTR(wCNTR);
-
- /*poll for RESET flag in ISTR*/
- while ((_GetISTR()&ISTR_RESET) == 0);
-
- /* clear RESET flag in ISTR */
- _SetISTR((uint16_t)CLR_RESET);
-
- /*restore Enpoints*/
- for (i = 0; i < 8; i++)
- _SetENDPOINT(i, EP[i]);
-
- esof_counter = 0;
- }
- }
- else
- {
- esof_counter = 0;
- }
-
- /* resume handling timing is made with ESOFs */
- Resume(RESUME_ESOF); /* request without change of the machine state */
-
- #ifdef ESOF_CALLBACK
- ESOF_Callback();
- #endif
- }
-
- #endif
- } /* USB_Istr */
复位是在USB识别到设备的时候,主机主动发出的特定序列,当USB设备收到这个特定序列的时候,就会产生中断相应,并进入中断中去处理相应的函数,这里的复位中断处理函数主要是配置端点的属性及端点的大小。
注意一下宏定义“BTABLE_ADDRESS”的对应的USB中断缓存区地址的偏移,也就是512Byte的RAM空间,宏“ENDP0_RXADDR”等是定义端点的发送和接收地址存放在RAM空间的具体位置,以“BTABLE_ADDRESS”为偏移。
- /* buffer table base address */
- /* buffer table base address */
- #define BTABLE_ADDRESS (0x00)
-
- /* EP0 */
- /* rx/tx buffer base address */
- #define ENDP0_RXADDR (0x40)
- #define ENDP0_TXADDR (0x80)
-
- /* EP1 */
- /* tx buffer base address */
- #define ENDP1_TXADDR (0xC0)
- #define ENDP2_TXADDR (0x100)
- #define ENDP3_RXADDR (0x110)
-
- void Virtual_Com_Port_Reset(void)
- {
- /* Set Virtual_Com_Port DEVICE as not configured */
- pInformation->Current_Configuration = 0;
-
- /* Current Feature initialization */
- pInformation->Current_Feature = Virtual_Com_Port_ConfigDescriptor[7];
-
- /* Set Virtual_Com_Port DEVICE with the default Interface*/
- pInformation->Current_Interface = 0;
-
- SetBTABLE(BTABLE_ADDRESS);
-
- /* Initialize Endpoint 0 */
- SetEPType(ENDP0, EP_CONTROL);
- SetEPTxStatus(ENDP0, EP_TX_STALL);
- SetEPRxAddr(ENDP0, ENDP0_RXADDR);
- SetEPTxAddr(ENDP0, ENDP0_TXADDR);
- Clear_Status_Out(ENDP0);
- SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);
- SetEPRxValid(ENDP0);
-
- /* Initialize Endpoint 1 */
- SetEPType(ENDP1, EP_BULK);
- SetEPTxAddr(ENDP1, ENDP1_TXADDR);
- SetEPTxStatus(ENDP1, EP_TX_NAK);
- SetEPRxStatus(ENDP1, EP_RX_DIS);
-
- /* Initialize Endpoint 2 */
- SetEPType(ENDP2, EP_INTERRUPT);
- SetEPTxAddr(ENDP2, ENDP2_TXADDR);
- SetEPRxStatus(ENDP2, EP_RX_DIS);
- SetEPTxStatus(ENDP2, EP_TX_NAK);
-
- /* Initialize Endpoint 3 */
- SetEPType(ENDP3, EP_BULK);
- SetEPRxAddr(ENDP3, ENDP3_RXADDR);
- SetEPRxCount(ENDP3, VIRTUAL_COM_PORT_DATA_SIZE);
- SetEPRxStatus(ENDP3, EP_RX_VALID);
- SetEPTxStatus(ENDP3, EP_TX_DIS);
-
- /* Set this device to response on default address */
- SetDeviceAddress(0);
-
- bDeviceState = ATTACHED;
- }
正确传输完成函数分为枚举过程(端点0)的正确传输完成函数和非端点0的正确传输完成函数。
- void CTR_LP(void)
- {
- __IO uint16_t wEPVal = 0;
-
- /* stay in loop while pending interrupts */
- while (((wIstr = _GetISTR()) & ISTR_CTR) != 0)
- {
- /* extract highest priority endpoint number */
- EPindex = (uint8_t)(wIstr & ISTR_EP_ID);
-
- if (EPindex == 0)
- {
- /* Decode and service control endpoint interrupt */
- /* calling related service routine */
- /* (Setup0_Process, In0_Process, Out0_Process) */
-
- /* save RX & TX status */
- /* and set both to NAK */
-
- SaveRState = _GetENDPOINT(ENDP0);
- SaveTState = SaveRState & EPTX_STAT;
- SaveRState &= EPRX_STAT;
-
- _SetEPRxTxStatus(ENDP0, EP_RX_NAK, EP_TX_NAK);
-
- /* DIR bit = origin of the interrupt */
-
- if ((wIstr & ISTR_DIR) == 0)
- {
- /* DIR = 0 */
-
- /* DIR = 0 => IN int */
- /* DIR = 0 implies that (EP_CTR_TX = 1) always */
-
- _ClearEP_CTR_TX(ENDP0);
- In0_Process();
-
- /* before terminate set Tx & Rx status */
-
- _SetEPRxTxStatus(ENDP0, SaveRState, SaveTState);
- return;
- }
- else
- {
- /* DIR = 1 */
-
- /* DIR = 1 & CTR_RX => SETUP or OUT int */
- /* DIR = 1 & (CTR_TX | CTR_RX) => 2 int pending */
-
- wEPVal = _GetENDPOINT(ENDP0);
-
- if ((wEPVal & EP_SETUP) != 0)
- {
- _ClearEP_CTR_RX(ENDP0); /* SETUP bit kept frozen while CTR_RX = 1 */
- Setup0_Process();
- /* before terminate set Tx & Rx status */
-
- _SetEPRxTxStatus(ENDP0, SaveRState, SaveTState);
- return;
- }
-
- else if ((wEPVal & EP_CTR_RX) != 0)
- {
- _ClearEP_CTR_RX(ENDP0);
- Out0_Process();
- /* before terminate set Tx & Rx status */
-
- _SetEPRxTxStatus(ENDP0, SaveRState, SaveTState);
- return;
- }
- }
- }/* if(EPindex == 0) */
- else
- {
- /* Decode and service non control endpoints interrupt */
-
- /* process related endpoint register */
- wEPVal = _GetENDPOINT(EPindex);
-
- if ((wEPVal & EP_CTR_RX) != 0)
- {
- /* clear int flag */
- _ClearEP_CTR_RX(EPindex);
-
- /* call OUT service function */
- (*pEpInt_OUT[EPindex - 1])();
-
- } /* if((wEPVal & EP_CTR_RX) */
-
- if ((wEPVal & EP_CTR_TX) != 0)
- {
- /* clear int flag */
- _ClearEP_CTR_TX(EPindex);
-
- /* call IN service function */
- (*pEpInt_IN[EPindex - 1])();
- } /* if((wEPVal & EP_CTR_TX) != 0) */
-
- }/* if(EPindex == 0) else */
-
- }/* while(...) */
- }
枚举过程的正确传输完成函数主要是接收SETUP指令请求,并相应的告知USB主机设备的描述符信息。
以下代码是处理USB主机的数据,把USB主机的SETUP请求数据存在pInformation结构体中,并在后续的函数进行指令的解析,并通过相对应的SETUP请求发送相对应的数据。
- uint8_t Setup0_Process(void)
- {
-
- union
- {
- uint8_t* b;
- uint16_t* w;
- } pBuf;
- #if defined STM32F303xE || defined STM32F302x8
- uint16_t offset = 0;
- pBuf.b = (uint8_t *)( PMAAddr + _GetEPRxAddr(ENDP0));
- #else
- uint16_t offset = 1;
-
- pBuf.b = PMAAddr + (uint8_t *)(_GetEPRxAddr(ENDP0) * 2); /* *2 for 32 bits addr */
- #endif
-
- if (pInformation->ControlState != PAUSE)
- {
- pInformation->USBbmRequestType = *pBuf.b++; /* bmRequestType */
- pInformation->USBbRequest = *pBuf.b++; /* bRequest */
- pBuf.w += offset; /* word not accessed because of 32 bits addressing */
- pInformation->USBwValue = ByteSwap(*pBuf.w++); /* wValue */
- pBuf.w += offset; /* word not accessed because of 32 bits addressing */
- pInformation->USBwIndex = ByteSwap(*pBuf.w++); /* wIndex */
- pBuf.w += offset; /* word not accessed because of 32 bits addressing */
- pInformation->USBwLength = *pBuf.w; /* wLength */
- }
-
- pInformation->ControlState = SETTING_UP;
-
- if (pInformation->USBwLength == 0)
- {
- /* Setup with no data stage */
- NoData_Setup0();
- }
- else
- {
- /* Setup with data stage */
- Data_Setup0();
- }
-
- return Post0_Process();
- }
- void Data_Setup0(void)
- {
- uint8_t *(*CopyRoutine)(uint16_t);
- RESULT Result;
- uint32_t Request_No = pInformation->USBbRequest;
-
- uint32_t Related_Endpoint, Reserved;
- uint32_t wOffset, Status;
-
-
-
- CopyRoutine = NULL;
- wOffset = 0;
-
- /*GET DESCRIPTOR*/
- if (Request_No == GET_DESCRIPTOR)
- {
- if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))
- {
- uint8_t wValue1 = pInformation->USBwValue1;
-
- if (wValue1 == DEVICE_DESCRIPTOR)
- {
- CopyRoutine = pProperty->GetDeviceDescriptor;
- }
-
- #ifdef LPM_ENABLED
- else if (wValue1 == DEVICE_BOS_DESCRIPTOR)
- {
- CopyRoutine = pProperty->GetBosDescriptor;
- }
-
- #endif
- else if (wValue1 == CONFIG_DESCRIPTOR)
- {
- CopyRoutine = pProperty->GetConfigDescriptor;
- }
- else if (wValue1 == STRING_DESCRIPTOR)
- {
- CopyRoutine = pProperty->GetStringDescriptor;
- } /* End of GET_DESCRIPTOR */
- }
- }
-
- /*GET STATUS*/
- else if ((Request_No == GET_STATUS) && (pInformation->USBwValue == 0)
- && (pInformation->USBwLength == 0x0002)
- && (pInformation->USBwIndex1 == 0))
- {
- /* GET STATUS for Device*/
- if ((Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))
- && (pInformation->USBwIndex == 0))
- {
- CopyRoutine = Standard_GetStatus;
- }
-
- /* GET STATUS for Interface*/
- else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))
- {
- if (((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0) == USB_SUCCESS)
- && (pInformation->Current_Configuration != 0))
- {
- CopyRoutine = Standard_GetStatus;
- }
- }
-
- /* GET STATUS for EndPoint*/
- else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT))
- {
- Related_Endpoint = (pInformation->USBwIndex0 & 0x0f);
- Reserved = pInformation->USBwIndex0 & 0x70;
-
- if (ValBit(pInformation->USBwIndex0, 7))
- {
- /*Get Status of endpoint & stall the request if the related_ENdpoint
- is Disabled*/
- Status = _GetEPTxStatus(Related_Endpoint);
- }
- else
- {
- Status = _GetEPRxStatus(Related_Endpoint);
- }
-
- if ((Related_Endpoint < Device_Table.Total_Endpoint) && (Reserved == 0)
- && (Status != 0))
- {
- CopyRoutine = Standard_GetStatus;
- }
- }
-
- }
-
- /*GET CONFIGURATION*/
- else if (Request_No == GET_CONFIGURATION)
- {
- if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))
- {
- CopyRoutine = Standard_GetConfiguration;
- }
- }
- /*GET INTERFACE*/
- else if (Request_No == GET_INTERFACE)
- {
- if ((Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))
- && (pInformation->Current_Configuration != 0) && (pInformation->USBwValue == 0)
- && (pInformation->USBwIndex1 == 0) && (pInformation->USBwLength == 0x0001)
- && ((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0) == USB_SUCCESS))
- {
- CopyRoutine = Standard_GetInterface;
- }
-
- }
-
- if (CopyRoutine)
- {
- pInformation->Ctrl_Info.Usb_wOffset = wOffset;
- pInformation->Ctrl_Info.CopyData = CopyRoutine;
- /* sb in the original the cast to word was directly */
- /* now the cast is made step by step */
- (*CopyRoutine)(0);
- Result = USB_SUCCESS;
- }
- else
- {
- Result = (*pProperty->Class_Data_Setup)(pInformation->USBbRequest);
-
- if (Result == USB_NOT_READY)
- {
- pInformation->ControlState = PAUSE;
- return;
- }
- }
-
- if (pInformation->Ctrl_Info.Usb_wLength == 0xFFFF)
- {
- /* Data is not ready, wait it */
- pInformation->ControlState = PAUSE;
- return;
- }
-
- if ((Result == USB_UNSUPPORT) || (pInformation->Ctrl_Info.Usb_wLength == 0))
- {
- /* Unsupported request */
- pInformation->ControlState = STALLED;
- return;
- }
-
-
- if (ValBit(pInformation->USBbmRequestType, 7))
- {
- /* Device ==> Host */
- __IO uint32_t wLength = pInformation->USBwLength;
-
- /* Restrict the data length to be the one host asks for */
- if (pInformation->Ctrl_Info.Usb_wLength > wLength)
- {
- pInformation->Ctrl_Info.Usb_wLength = wLength;
- }
-
- else if (pInformation->Ctrl_Info.Usb_wLength < pInformation->USBwLength)
- {
- if (pInformation->Ctrl_Info.Usb_wLength < pProperty->MaxPacketSize)
- {
- Data_Mul_MaxPacketSize = FALSE;
- }
- else if ((pInformation->Ctrl_Info.Usb_wLength % pProperty->MaxPacketSize) == 0)
- {
- Data_Mul_MaxPacketSize = TRUE;
- }
- }
-
- pInformation->Ctrl_Info.PacketSize = pProperty->MaxPacketSize;
- DataStageIn();
- }
- else
- {
- pInformation->ControlState = OUT_DATA;
- vSetEPRxStatus(EP_RX_VALID); /* enable for next data reception */
- }
-
- return;
- }
非控制端点0正确传输完成函数根据不同的USB应用存在不同的差距,但是主体框架已经完成,只需要用户在特定的框架中填写特定的程序即可。
比如当前程序只用到端点1的TX和端点3的RX,就只需要在端点1的TX和端点3的RX中编写相应的应用程序,其它端点不必理会。
- /* associated to defined endpoints */
- /*#define EP1_IN_Callback NOP_Process*/
- #define EP2_IN_Callback NOP_Process
- #define EP3_IN_Callback NOP_Process
- #define EP4_IN_Callback NOP_Process
- #define EP5_IN_Callback NOP_Process
- #define EP6_IN_Callback NOP_Process
- #define EP7_IN_Callback NOP_Process
-
- #define EP1_OUT_Callback NOP_Process
- #define EP2_OUT_Callback NOP_Process
- /*#define EP3_OUT_Callback NOP_Process*/
- #define EP4_OUT_Callback NOP_Process
- #define EP5_OUT_Callback NOP_Process
- #define EP6_OUT_Callback NOP_Process
- #define EP7_OUT_Callback NOP_Process
-
- void (*pEpInt_IN[7])(void) =
- {
- EP1_IN_Callback,
- EP2_IN_Callback,
- EP3_IN_Callback,
- EP4_IN_Callback,
- EP5_IN_Callback,
- EP6_IN_Callback,
- EP7_IN_Callback,
- };
-
- void (*pEpInt_OUT[7])(void) =
- {
- EP1_OUT_Callback,
- EP2_OUT_Callback,
- EP3_OUT_Callback,
- EP4_OUT_Callback,
- EP5_OUT_Callback,
- EP6_OUT_Callback,
- EP7_OUT_Callback,
- };
-
- void EP1_IN_Callback (void)
- {
- packet_sent = 1;
- }
-
- void EP3_OUT_Callback(void)
- {
- packet_receive = 1;
- Receive_length = GetEPRxCount(ENDP3);
- PMAToUserBufferCopy((unsigned char*)Receive_Buffer, ENDP3_RXADDR, Receive_length);
- }
到这里,本章就基本上讲完了,主要还是从应用的角度去简单的讲解了一下代码,如果读者需要更深入的了解代码的结构,还是需要大家仔细去学习USB的驱动源码的。
接下来讲解STM32 USB的虚拟串口环回功能实现,敬请期待。。。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。