USB的“Virtual_COM_Port”例程代碼詳細分析--初始化分析


一.初始化

USB進行枚舉前的初始化流程圖

 

  1. main()開始

 

int main(void)
{
  Set_System();//初始化時鍾系統、使能相關的外圍設備電源;
  Set_USBClock();//配置和使能USB時鍾
  USB_Interrupts_Config();//主要功能是配置USB所用到的中斷;USB低優先級中斷和喚醒中斷
  USB_Init();//USB系統初始化
  
  while (1)
  {
  }
}

 

 

 

 

  1. 開始USB系統初始化USB_Init()

 

void USB_Init(void)
{
    /*
    初始化三個全局指針,指向DEVICE_INFO、USER_STANDARD_REQUESTS 和 DEVICE_PROP結構體。
后面兩個是函數指針結構體,里面都是USB請求實現、功能實現的函數指針。
    */
  pInformation = &Device_Info;            //USB設備信息
  pInformation->ControlState = 2;         //設置控制狀態為IN_DATA
  pProperty = &Device_Property;            //設備本身支持的屬性和方法
  pUser_Standard_Requests = &User_Standard_Requests; //初始化主機標准請求
  /* Initialize devices one by one */
  pProperty->Init();                       //初始化
    /*
調用pProperty->Init()(實質上是執行Virtual_Com_Port_init()函數)完成設備的初始化。
上層函數調用下層函數是常規操作。而下層函數調用上層文件函數稱之為回調。
回調函數的意義在於給同一種操作模式,提供不同的回調函數即可實現不同的功能。
 回調函數的實現方法是函數指針數組,這是指針的高級應用。
    */
}

 

2.1 USB設備信息DEVICE_INFO

 

//USB內核將主機發送過來的用於實現USB設備的設置包保存在設備信息結構表中
typedef struct _DEVICE_INFO
{
  uint8_t USBbmRequestType;       /* bmRequestType */
  uint8_t USBbRequest;            /* bRequest */
  uint16_t_uint8_t USBwValues;         /* wValue */
  uint16_t_uint8_t USBwIndexs;         /* wIndex */
  uint16_t_uint8_t USBwLengths;        /* wLength */

  uint8_t ControlState;            /* 控制狀態 */
  uint8_t Current_Feature;         /* 當前功能 */
  uint8_t Current_Configuration;   /* 當前篇日志 */
  uint8_t Current_Interface;       /* 選擇當前配置接口 */
  uint8_t Current_AlternateSetting;/* 選擇當前接口備選設置 */

  ENDPOINT_INFO Ctrl_Info;
}DEVICE_INFO;

 

2.2 USB控制狀態

 

typedef enum _CONTROL_STATE
{
  WAIT_SETUP,       /* 0 */
  SETTING_UP,       /* 1 */
  IN_DATA,          /* 2 */
  OUT_DATA,         /* 3 */
  LAST_IN_DATA,     /* 4 */
  LAST_OUT_DATA,    /* 5 */
  WAIT_STATUS_IN,   /* 7 */
  WAIT_STATUS_OUT,  /* 8 */
  STALLED,          /* 9 */
  PAUSE             /* 10 */
} CONTROL_STATE;    /* The state machine states of a control pipe*/

 

2.3 USB功能實現Device_Property

 

DEVICE_PROP Device_Property =
  {
    Virtual_Com_Port_init,
    Virtual_Com_Port_Reset,
    Virtual_Com_Port_Status_In,
    Virtual_Com_Port_Status_Out,
    Virtual_Com_Port_Data_Setup,
    Virtual_Com_Port_NoData_Setup,
    Virtual_Com_Port_Get_Interface_Setting,
    Virtual_Com_Port_GetDeviceDescriptor,
    Virtual_Com_Port_GetConfigDescriptor,
    Virtual_Com_Port_GetStringDescriptor,
    0,
    0x40 /*MAX PACKET SIZE*/
  };

 

2.4 USB標准請求USER_STANDARD_REQUESTS

 

//標准請求的處理函數,非USB寄存器的操作,而是用戶自己設定的寄存器操作  好像都是設置當前的設備狀態
USER_STANDARD_REQUESTS User_Standard_Requests =
  {
    Virtual_Com_Port_GetConfiguration,//獲得配置
    Virtual_Com_Port_SetConfiguration,//設置配置
    Virtual_Com_Port_GetInterface,//獲得接口
    Virtual_Com_Port_SetInterface,//設置接口
    Virtual_Com_Port_GetStatus,//得到狀態
    Virtual_Com_Port_ClearFeature,//清除特性
    Virtual_Com_Port_SetEndPointFeature,//設置端點特性
    Virtual_Com_Port_SetDeviceFeature,//設置設備特性  
    Virtual_Com_Port_SetDeviceAddress//設置設備地址
  };
  1. 設備的初始化Virtual_Com_Port_init()

 

void Virtual_Com_Port_init(void)
{

  Get_SerialNum();//獲取設備序列號

  pInformation->Current_Configuration = 0;//使當前配置為0,說明還沒進行枚舉。

  PowerOn();//將USB上電 連接設備

    //主要是CNTR寄存器的初始化 開啟所有必須處理的中斷(除DMA溢出中斷)
  USB_SIL_Init();

  USART_Config_Default();//將USART配置為默認設置
    
  bDeviceState = UNCONNECTED;  //設備狀態標志 當前狀態未連接
}

 

3.1獲取設備序列號Get_SerialNum()

 

void Get_SerialNum(void)
{//獲取設備版本號,將其存入到版本號字符串。
  uint32_t Device_Serial0, Device_Serial1, Device_Serial2;

  Device_Serial0 = *(uint32_t*)ID1;
  Device_Serial1 = *(uint32_t*)ID2;
  Device_Serial2 = *(uint32_t*)ID3;  

  Device_Serial0 += Device_Serial2;

  if (Device_Serial0 != 0)
  {
    IntToUnicode (Device_Serial0, &Virtual_Com_Port_StringSerial[2] , 8);
    IntToUnicode (Device_Serial1, &Virtual_Com_Port_StringSerial[18], 4);
  }
}

 

3.2 USB上電PowerOn()

 

RESULT PowerOn(void)
{
  uint16_t wRegVal;
 /**
在PowerOn函數使能了復位中斷以后,將進入到USB的復位中斷里面去。
然后再執行函數USB_SIL_Init 將所有的USB中斷都打開。
這個函數首先把D+的上拉電阻上電;這樣電腦就可以檢測到設備了。
  */ 
#if !defined (USE_NUCLEO)
  /*** cable plugged-in ? ***/
  USB_Cable_Config(ENABLE);    //上電連接,實質上就是將USB控制線置為低電平,便於主機檢測
#endif

  /*** CNTR_PWDN = 0 ***/   //USB 收發器內部參照電壓
//這句話雖然將強制復位USB模塊,但由於復位中斷允許位沒有使能,不會引起復位中斷
  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;
}

 

PowerOn函數使能了復位中斷以后,將進入到USB的復位中斷里面去。然后再執行函數USB_SIL_Init 將所有的USB中斷都打開。

3.4 ISTR事件中斷服務程序USB_Istr()

 

#if (IMR_MSK & ISTR_RESET)//初始化時第一次進入
    //USB復位請求中斷
  if (wIstr & ISTR_RESET & wInterrupt_Mask)
  {
    _SetISTR((uint16_t)CLR_RESET); //清除復位中斷標志
    Device_Property.Reset();       //進入到復位中斷 
        //實際上是調用Virtual_Com_Port_Reset()函數進行處理

 

3.5 實現對端點的復位Virtual_Com_Port_Reset()

void Virtual_Com_Port_Reset(void)
{
  /* Set Virtual_Com_Port DEVICE as not configured 還沒被配置*/
  pInformation->Current_Configuration = 0;   //當前配置為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;  //當前接口為0

  SetBTABLE(BTABLE_ADDRESS);   //設置包緩沖區地址

 

 

  /* Set this device to response on default address */
  SetDeviceAddress(0);       //設置設備地址默認為0
  bDeviceState = ATTACHED;   //設置當前狀態為連接狀態

 

復位中斷執行完后,開發板的USB接口能夠以默認的地址對主機來的數據包進行響應了。這個階段的分析結束,下面正式分析代碼實現的枚舉過程。

 

3.6 CNTR寄存器的初始化USB_SIL_Init()

 

uint32_t USB_SIL_Init(void)
{  //USB中斷初始化
  /* USB interrupts initialization */
  /* clear pending interrupts */
  _SetISTR(0);     //清除掛起標志
  wInterrupt_Mask = IMR_MSK;
  /* set interrupts mask */
    //開啟所有必須處理的中斷(除DMA溢出中斷)
  _SetCNTR(wInterrupt_Mask);
  return 0;
}

 

3.7 串口初始化USART_Config_Default()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM