天天看點

STM32 USB詳細使用說明

說明:使用的是STM32F103ZET6

硬體原理圖

STM32 USB詳細使用說明

在開始枚舉裝置的一些初始化

void bsp_USBInit(void)

{

   GPIO_InitTypeDef  GPIO_InitStructure;

   RCC_APB2PeriphClockCmd(RCC_USB_PULL_UP, ENABLE);

   USB_CABLE_DISABLE();

   GPIO_InitStructure.GPIO_Pin = PIN_USB_PULL_UP;

   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;

   GPIO_Init(GPIOB, &GPIO_InitStructure);

   {

     NVIC_InitTypeDef NVIC_InitStructure;

     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 

     NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;

     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

     NVIC_Init(&NVIC_InitStructure);

    }

   RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);

   RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);

   USB_Init();

}

現在開始分析真正的初始化

第一步:初始化,總線複位及向預設位址 0發送 GET_DESCRIPTOR指令包,請求裝置描述

STM32 USB詳細使用說明

1)Index[4 - 5]:表示 USB插入總線複位;

2)Index[7 -8]:表示主機向預設位址發送GET_DESCRIPTOR指令包,詳細信

息也抓出來了,如(圖二)所示

STM32 USB詳細使用說明

3)Index[15 - 17]:表示裝置向主機發送裝置描述資料 Index[16]

4)Index[18 - 19]:表示主機完成 GET_DESCRIPTOR指令後,給裝置發送一個

空應答

STM32 USB詳細使用說明

現在具體的分析103的usb的執行過程按順序向下執行

***************(1)**************

DEVICE_INFO*pInformation;

DEVICE_PROP*pProperty;

DEVICE_PROP Device_Property=

  {

   Joystick_init,

   Joystick_Reset,

   Joystick_Status_In,

   Joystick_Status_Out,

   Joystick_Data_Setup,

   Joystick_NoData_Setup,

   Joystick_Get_Interface_Setting,

   Joystick_GetDeviceDescriptor,

   Joystick_GetConfigDescriptor,

   Joystick_GetStringDescriptor,

    0,

    0x40

  };

USER_STANDARD_REQUESTS User_Standard_Requests=

  {

   Joystick_GetConfiguration,

   Joystick_SetConfiguration,

   Joystick_GetInterface,

   Joystick_SetInterface,

   Joystick_GetStatus,

   Joystick_ClearFeature,

   Joystick_SetEndPointFeature,

   Joystick_SetDeviceFeature,

   Joystick_SetDeviceAddress

  };

//USB核心将主機發送過來的用于實作USB裝置的設定包儲存在裝置資訊結構表中

typedef struct _DEVICE_INFO

{

  uint8_tUSBbmRequestType;           

  uint8_tUSBbRequest;                

  uint16_t_uint8_tUSBwValues;        

  uint16_t_uint8_tUSBwIndexs;        

  uint16_t_uint8_tUSBwLengths;       

  uint8_tControlState;               

  uint8_t Current_Feature;

  uint8_tCurrent_Configuration;    

  uint8_tCurrent_Interface;        

  uint8_tCurrent_AlternateSetting; 

  ENDPOINT_INFO Ctrl_Info;

}DEVICE_INFO;

usb_init.c檔案裡面的

void USB_Init(void)

{

  pInformation =&Device_Info;

  pInformation->ControlState =2;

  pProperty =&Device_Property;

  pUser_Standard_Requests =&User_Standard_Requests;

 pProperty->Init();

}

***************(2)**************通過函數指針指向這個初始化函數pProperty 在usb_prop.c檔案裡面

void Joystick_init(void)

{

 Get_SerialNum();                                      //得到串行号

  pInformation->Current_Configuration=0;         //

 PowerOn();                                            //将USB上電 連接配接裝置

 USB_SIL_Init();                                       //主要是CNTR寄存器的初始化

  bDeviceState =UNCONNECTED;                       //裝置狀态标志 目前狀态未連接配接

}

hw_config.c檔案裡面這個和标準的不一樣有改動,擷取裝置版本号,将其存入到版本号字元串。

voidGet_SerialNum(void)  //得到串行号

{

    uint32_tDevice_Serial0, Device_Serial1, Device_Serial2;

   Device_Serial0 = *(__IO uint32_t*)(0x1FFFF7E8);

   Device_Serial1 = *(__IO uint32_t*)(0x1FFFF7EC);

   Device_Serial2 = *(__IO uint32_t*)(0x1FFFF7F0);

   Device_Serial0 += Device_Serial2;

    if(Device_Serial0 != 0)

    {

       IntToUnicode (Device_Serial0,&Joystick_StringSerial[2] , 8);

       IntToUnicode (Device_Serial1,&Joystick_StringSerial[18], 4);

    }

}

usb_pwr.c檔案裡面在這個檔案裡面隻是使能了複位,挂起,喚醒中斷,在PowerOn函數使能了複位中斷以後,将進入到USB的複位中斷裡面去。

然後再執行函數USB_SIL_Init将所有的USB中斷都打開。在D+被接通上拉以後,裝置就能被主機檢測到。

RESULT PowerOn(void)

{

#ifndef STM32F10X_CL

  uint16_t wRegVal;

USB_Cable_Config(ENABLE);                   //将USB上電連接配接

//對USB子產品強制複位,類似于USB總線上的複位信号。USB子產品将一直保持在複位狀态下

//直到軟體清除此位。如果USB複位中斷被使能,将産生一個複位中斷。

 wRegVal =CNTR_FRES;                     //強制複位                               

  _SetCNTR(wRegVal);

 wInterrupt_Mask = 0;

 _SetCNTR(wInterrupt_Mask);                //清除複位信号

  _SetISTR(0);

//複位中斷屏蔽位 挂起中斷屏蔽位喚醒中斷屏蔽位使能  

  wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM |CNTR_WKUPM;

 _SetCNTR(wInterrupt_Mask);

#endif

  return USB_SUCCESS;

}

usb_istr.c檔案裡面,下面隻寫了進入到複位中斷函數,進入到USB連接配接狀态

void USB_Istr(void)

{

   wIstr =_GetISTR();

  #if (IMR_MSK &ISTR_RESET)                      //USB複位請求中斷

  if (wIstr & ISTR_RESET&wInterrupt_Mask)     

  {

   _SetISTR((uint16_t)CLR_RESET);               //清楚複位中斷标志

   Device_Property.Reset();                     //進入到複位中斷

 #ifdef RESET_CALLBACK

   RESET_Callback();

  #endif

  }

#end

}

usb_prop.c檔案裡面,實作對端點的設定。

void Joystick_Reset(void)

{

 pInformation->Current_Configuration =0;

  pInformation->Current_Interface =0;                                 

 pInformation->Current_Feature =Joystick_ConfigDescriptor[7];       //供電模式選擇

#ifdefSTM32F10X_CL  

 OTG_DEV_EP_Init(EP1_IN, OTG_DEV_EP_TYPE_INT, 4);

#else

 SetBTABLE(BTABLE_ADDRESS);                 //分組緩沖區描述表位址設定

  SetEPType(ENDP0,EP_CONTROL);              //初始化為控制端點類型

 SetEPTxStatus(ENDP0,EP_TX_STALL);        //端點以STALL分組響應所有的發送請求。

 //也就是端點狀态設定成發送無效,也就是主機的IN令牌包來的時候,回送一個STALL。    

  SetEPRxAddr(ENDP0,ENDP0_RXADDR);         //設定端點0描述符的接受位址,

  SetEPTxAddr(ENDP0,ENDP0_TXADDR);          //設定端點0描述符的發送位址

 Clear_Status_Out(ENDP0);                      

  //僅用于控制端點 如果STATUS_OUT位被清除,OUT分組可以包含任意長度的資料

  SetEPRxCount(ENDP0,Device_Property.MaxPacketSize); 

  //設定端點0的接受位元組寄存器的最大值是64

 SetEPRxValid(ENDP0);                                //設定接受端點有效

  SetEPType(ENDP1,EP_INTERRUPT);                     //初始化為中斷端點類型

 SetEPTxAddr(ENDP1,ENDP1_TXADDR);                   //設定發送資料的位址

  SetEPTxCount(ENDP1,4);                             //設定發送的長度

  SetEPRxStatus(ENDP1,EP_RX_DIS);                    //設定接受端點關閉

  SetEPTxStatus(ENDP1,EP_TX_NAK);                    //設定發送端點端點非應答

 SetDeviceAddress(0);                                //設定裝置用預設位址相應

#endif

  bDeviceState =ATTACHED;                         //目前狀态連接配接

}

usb_sil.c的檔案裡面,主要是使能了如下這些中斷

CNTR_CTRM  正确傳輸(CTR)中斷使能   CNTR_WKUPM喚醒中斷使能

CNTR_SUSPM 挂起(SUSP)中斷使能     CNTR_ERRM  出錯中斷使能

CNTR_SOFM  幀首中斷使能           CNTR_ESOFM 期望幀首中斷使能CNTR_RESETM設定此位将向PC主機發送喚醒請求。根據USB協定,如果此位在1ms到15ms内保持有效,主機将對USB子產品實行喚醒操作。

uint32_t USB_SIL_Init(void)

{

#ifndef STM32F10X_CL

 _SetISTR(0);                             //清除中斷标志

  wInterrupt_Mask = IMR_MSK;

//這組寄存器用于定義USB子產品的工作模式,中斷的處理,裝置的位址和讀取目前幀的編号

 _SetCNTR(wInterrupt_Mask);             //設定相應的控制寄存器 

#else 

  OTG_DEV_Init();

#endif

  return 0;

}

***************(3)**************

1.擷取裝置描述符

STM32 USB詳細使用說明

usb_int.c的檔案裡面

低優先級中斷  在控制中斷  批量傳輸下使用(在單緩沖模式下使用)

當一次正确的OUT,SETUP,IN資料傳輸完成後,硬體會自動設定此位為NAK狀态,使應用程式有足夠的時間處理完目前傳輸的資料後,響應下一個資料分組

void CTR_LP(void)

{

  __IO uint16_t wEPVal = 0;

  while (((wIstr =_GetISTR()) & ISTR_CTR) != 0)

  {

   EPindex = (uint8_t)(wIstr &ISTR_EP_ID);                //讀出端點ID

    if (EPindex==0)                                        //如果是端點0

    {

       SaveRState =_GetENDPOINT(ENDP0);                   //讀取端點0寄存器USB_EP0R

       SaveTState = SaveRState &EPTX_STAT;                //儲存發送狀态位

       SaveRState &= EPRX_STAT;                           //儲存接受狀态位

       _SetEPRxTxStatus(ENDP0,EP_RX_NAK,EP_TX_NAK);        //端點以NAK分組響應所有的發送和接受請求(解釋在上面)

     if ((wIstr & ISTR_DIR) ==0)   //IN令牌,資料被取走                       

    {

       _ClearEP_CTR_TX(ENDP0);                                //清除正确發送标志位

       In0_Process();                                         //處理INT事件

       _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);

       return;

     }

     else

     {

       wEPVal =_GetENDPOINT(ENDP0);                  //得到端點0寄存器的資料

       if ((wEPVal &EP_SETUP) !=0)                   //SETUP分組傳輸完成标志   

       {

         _ClearEP_CTR_RX(ENDP0);

         Setup0_Process();                          //處理SETUP事件

                                                      //程式會進入到這個函數裡面

        _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);

         return;

       }

       else if ((wEPVal & EP_CTR_RX) != 0)

       {

         _ClearEP_CTR_RX(ENDP0);

         Out0_Process();                             //處理OUT事件

         _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);

         return;

       }

     }

    }

   else                                            //如果是除端點0以外的端點

    {

     wEPVal =_GetENDPOINT(EPindex);              //得到相應端點寄存器值

     if ((wEPVal & EP_CTR_RX) !=0)               //檢測正确接收标志 PC-USB OUTint

     {

       _ClearEP_CTR_RX(EPindex);                //清除相應的标志

       (*pEpInt_OUT[EPindex-1])();              //調用OUT int服務功能

     }

     if ((wEPVal & EP_CTR_TX) !=0)              //檢測正确發送标志 USB-PC IN int

     {

       _ClearEP_CTR_TX(EPindex);                //清除相應的标志

       (*pEpInt_IN[EPindex-1])();                //調用IN int服務功能

     }

   }

  }

}

usb_coer.c的檔案裡面,主要是得到主機發來的标準請求指令

uint8_t Setup0_Process(void)

{

  union

  {

    uint8_t*b;

    uint16_t*w;

  } pBuf;

#ifdef STM32F10X_CL

  USB_OTG_EP *ep;

  uint16_t offset = 0;

  ep = PCD_GetOutEP(ENDP0);

  pBuf.b = ep->xfer_buff;

#else 

  uint16_t offset = 1;

                            //得到接受緩沖區位址寄存器位址

  pBuf.b = PMAAddr + (uint8_t*)(_GetEPRxAddr(ENDP0) * 2);

#endif

  if(pInformation->ControlState != PAUSE)

  {

   pInformation->USBbmRequestType = *pBuf.b++;          

   pInformation->USBbRequest = *pBuf.b++;                     

    pBuf.w+= offset; 

   pInformation->USBwValue = ByteSwap(*pBuf.w++);                 

    pBuf.w+= offset; 

   pInformation->USBwIndex  =ByteSwap(*pBuf.w++);             

    pBuf.w+= offset; 

   pInformation->USBwLength = *pBuf.w;                         

  }

  pInformation->ControlState =SETTING_UP;

  if(pInformation->USBwLength == 0)

  {

   NoData_Setup0();

  }

  else

  {

   Data_Setup0();  //由于是有資料的傳輸,所有要進入到這個函數

  }

  return Post0_Process();

}

usb_core.c的檔案裡面,這裡隻是選取了GETDESCRIPTOR

的程式部分,其他的部分删除了

void Data_Setup0(void)

{

  uint8_t *(*CopyRoutine)(uint16_t);

  RESULT Result;

  uint32_t Request_No =pInformation->USBbRequest;

  uint32_tRelated_Endpoint, Reserved;

  uint32_t wOffset, Status;

  CopyRoutine =NULL;

  wOffset = 0;

                         //看标準請求碼格式就知道了

  if (Request_No ==GET_DESCRIPTOR)

  {

    //pInformation->USBbmRequestType是下面的兩種标準請求或裝置請求

    if(Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))

    {

     uint8_t wValue1 =pInformation->USBwValue1;  //高一位元組得到描述表種類一共有5種

     if (wValue1 ==DEVICE_DESCRIPTOR)            //裝置描述

     {

       CopyRoutine = pProperty->GetDeviceDescriptor;

     }

     else if (wValue1 == CONFIG_DESCRIPTOR)

     {

       CopyRoutine = pProperty->GetConfigDescriptor;//配置描述

     }

     else if (wValue1 == STRING_DESCRIPTOR)

     {

       CopyRoutine = pProperty->GetStringDescriptor;//字元串描述 

     }

   }

  }

  if(CopyRoutine)

  {

   pInformation->Ctrl_Info.Usb_wOffset =wOffset;  //本子程式的wOffset是0

   pInformation->Ctrl_Info.CopyData = CopyRoutine;//使指針pInformation->Ctrl_Info.CopyData指向CopyRoutine

   (*CopyRoutine)(0);                     //第一次執行時Length=0 傳回的是有效資料的長度存儲到pInformation->Ctrl_Info.Usb_wLength

    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)  //如果字元的長度是0xffff

  {

   pInformation->ControlState =PAUSE;

   return;

  }

  if ((Result == USB_UNSUPPORT) ||(pInformation->Ctrl_Info.Usb_wLength == 0))

  {

   pInformation->ControlState =STALLED;

   return;

  }

  if(ValBit(pInformation->USBbmRequestType,7))                                      //D7表示資料傳輸方向1:裝置向主機

  {

    __IOuint32_t wLength = pInformation->USBwLength;

   //設定使其為USB主機設定的長度  本程式HID 滑鼠 pProperty->MaxPacketSize是0x40

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

  }

  return;

}

usb_coer.c的檔案裡面

voidDataStageIn(void)

{

  ENDPOINT_INFO *pEPinfo =&pInformation->Ctrl_Info;      //端點資訊儲存在指針變量中

  uint32_t save_wLength =pEPinfo->Usb_wLength;           //得到字元的長度

  uint32_t ControlState =pInformation->ControlState;     //得到目前的狀态

  uint8_t*DataBuffer;

  uint32_t Length;

  if((save_wLength == 0) &&(ControlState == LAST_IN_DATA))//如果字元長度為0 且控制狀态是最後輸入的資料

 {

   if(Data_Mul_MaxPacketSize ==TRUE)        //如果字元的長度是資料包的整數倍

    {

     Send0LengthData();

     ControlState = LAST_IN_DATA;

     Data_Mul_MaxPacketSize =FALSE;         //這一次發送0位元組狀态轉為最後輸入階段

    }

   else                                     //字元的長度比資料包要小

   {                                         //資料已經發送完

     ControlState = WAIT_STATUS_OUT;

    #ifdefSTM32F10X_CL     

     PCD_EP_Read (ENDP0, 0, 0);

   #endif 

    #ifndefSTM32F10X_CL

     vSetEPTxStatus(EP_TX_STALL);          //設定端點的發送狀态停止

   #endif 

    }

    gotoExpect_Status_Out;

  }

  Length =pEPinfo->PacketSize;             //得到資料包大小 64位元組

  ControlState = (save_wLength<= Length) ? LAST_IN_DATA :IN_DATA;//比較大小得到是LAST_IN_DATA還是IN_DATA   18位元組<64位元組  ControlState =LAST_IN_DATA

  if (Length> save_wLength)

  {

    Length =save_wLength;

  }

  DataBuffer =(*pEPinfo->CopyData)(Length);//DataBuffer指向要複制資料的位址這個位址是随Usb_wOffset變化的

#ifdef STM32F10X_CL

  PCD_EP_Write (ENDP0, DataBuffer, Length);

#else

                                //GetEPTxAddr(ENDP0) 得到發送緩沖區相應端點的位址

                                //将DataBuffer中的資料複制到相應的發送緩沖區中  

  UserToPMABufferCopy(DataBuffer,GetEPTxAddr(ENDP0), Length);

#endif

 SetEPTxCount(ENDP0, Length);  //設定相應的端點要發送的位元組數

 pEPinfo->Usb_wLength -= Length;//等于0

 pEPinfo->Usb_wOffset += Length;//偏移到18

 vSetEPTxStatus(EP_TX_VALID);  //使能發送端點 隻要主機的IN令牌包一來SIE就會将描述符傳回給主機

 USB_StatusOut();             

                               //設定接收端點有效這個實際上使接受也有效,

Expect_Status_Out:

  pInformation->ControlState =ControlState; //儲存控制狀态

}

***************(4)**************

STM32 USB詳細使用說明

uint8_tIn0_Process(void)       

{

  uint32_t ControlState =pInformation->ControlState;

  if ((ControlState == IN_DATA)|| (ControlState ==LAST_IN_DATA))//進入到這裡

  {

   DataStageIn();//第一次取裝置描述符隻取一次目前的狀态變為WAIT_STATUS_IN 表明裝置等待狀态過程主機輸出0位元組

   ControlState = pInformation->ControlState;

  }

  else if (ControlState ==WAIT_STATUS_IN)           //設定位址狀态階段進入這個程式

  {

    if((pInformation->USBbRequest == SET_ADDRESS)&&

       (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)))

    {

     SetDeviceAddress(pInformation->USBwValue0);   //設定使用新的位址

     pUser_Standard_Requests->User_SetDeviceAddress();

    }

   (*pProperty->Process_Status_IN)();

    ControlState=STALLED;                        //變為這個狀态

 }

  else

  {

    ControlState= STALLED;

  }

 pInformation->ControlState =ControlState;

  return Post0_Process();

}

STM32 USB詳細使用說明

uint8_tOut0_Process(void)           

{

  uint32_t ControlState =pInformation->ControlState;

  if ((ControlState == IN_DATA)|| (ControlState == LAST_IN_DATA))

  {

   //主機在完成傳輸前終止傳輸  

    ControlState= STALLED;

  }

  else if ((ControlState == OUT_DATA) ||(ControlState == LAST_OUT_DATA))

  {

   DataStageOut();

    ControlState= pInformation->ControlState;

  }

  else if (ControlState ==WAIT_STATUS_OUT)   //進入到這個裡面

  {

   (*pProperty->Process_Status_OUT)();//這個函數其實什麼也沒做

  #ifndef STM32F10X_CL

   ControlState =STALLED;                //狀态變成了終止發送和接受       

  #endif               

  }

  else

  {

    ControlState= STALLED;

  }

 pInformation->ControlState =ControlState;

  return Post0_Process();

}

***************(5)**************

擷取裝置描述符以後,主機再一次的複位裝置,裝置又進入初始狀态。開始枚舉的第二步設定位址。

STM32 USB詳細使用說明
STM32 USB詳細使用說明
STM32 USB詳細使用說明
STM32 USB詳細使用說明
STM32 USB詳細使用說明

void NoData_Setup0(void)

{

  RESULT Result = USB_UNSUPPORT;

  uint32_t RequestNo =pInformation->USBbRequest;

  uint32_t ControlState;

  if(Type_Recipient == (STANDARD_REQUEST |DEVICE_RECIPIENT))             //裝置請求

  {

   else if (RequestNo ==SET_ADDRESS)                                      /設定位址

   {

    if ((pInformation->USBwValue0 > 127)|| (pInformation->USBwValue1 != 0)

        || (pInformation->USBwIndex != 0)

        || (pInformation->Current_Configuration != 0))

    {

      ControlState = STALLED;

      goto exit_NoData_Setup0;

    }

    else

    {

      Result = USB_SUCCESS;

    #ifdef STM32F10X_CL

       SetDeviceAddress(pInformation->USBwValue0);

    #endif 

    }

   }

ControlState =WAIT_STATUS_IN;

 USB_StatusIn();//準備好發送0位元組的狀态資料包SetEPTxCount(ENDP0, 0);

//vSetEPTxStatus(EP_TX_VALID);建立階段後直接的進入狀态階段

exit_NoData_Setup0:

  pInformation->ControlState =ControlState;

  return;

}

STM32 USB詳細使用說明

uint8_tIn0_Process(void)       

{

  uint32_t ControlState =pInformation->ControlState;

  if ((ControlState == IN_DATA)|| (ControlState == LAST_IN_DATA))  //控制狀态

  {

   DataStageIn();//第一次取裝置描述符隻取一次 目前的狀态變為WAIT_STATUS_IN 表明裝置等待狀态過程主機輸出0位元組

    ControlState= pInformation->ControlState;

  }

  else if (ControlState ==WAIT_STATUS_IN)       //設定位址狀态階段進入這個程式

  {

    if((pInformation->USBbRequest == SET_ADDRESS)&&

       (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)))

    {

     SetDeviceAddress(pInformation->USBwValue0); //設定使用新的位址

     pUser_Standard_Requests->User_SetDeviceAddress();

    }

   (*pProperty->Process_Status_IN)();

    ControlState=STALLED;                  //終止發送和接受

  }

  else

  {

    ControlState= STALLED;

  }

 pInformation->ControlState =ControlState;

  return Post0_Process();

}

uint8_t Post0_Process(void)

{

#ifdef STM32F10X_CL 

  USB_OTG_EP *ep;

#endif

  SetEPRxCount(ENDP0,Device_Property.MaxPacketSize);  //設定端點0 要接受的位元組數

  if(pInformation->ControlState ==STALLED)           //這種狀态下隻接受SETUP指令包

 {

   vSetEPRxStatus(EP_RX_STALL);                 //終止端點0接受

   vSetEPTxStatus(EP_TX_STALL);                      //終止端點0發送

 }

  return(pInformation->ControlState ==PAUSE);

}

***************(6)*************

從新位址擷取裝置描述符

STM32 USB詳細使用說明
STM32 USB詳細使用說明
STM32 USB詳細使用說明
STM32 USB詳細使用說明
STM32 USB詳細使用說明
STM32 USB詳細使用說明

繼續閱讀