【正文】
atus(ENDP0, SaveRState)。}else if ((wEPVal amp。{//這里先分析SETUP包。_SetEPRxStatus(ENDP0, SaveRState)。 if ((wIstr amp。 //保存端點0狀態(tài),原本是有效狀態(tài)。 /*首先清除傳輸完成標志 */EPindex = (u8)(wIstr amp。由于此時端點0數(shù)據(jù)接收有效,所以接下來主機的請求數(shù)據(jù)包被SIE保存到端點0描述附表的 RxADDR里面,收到的字節(jié)數(shù)保存到 RxCount里面。//設備狀態(tài)置位為未連接狀態(tài)。_SetISTR(0)。 //地址默認為0.}復位中斷執(zhí)行完成后,開發(fā)板的USB接口能夠以默認地址對主機來的數(shù)據(jù)包進行響應了。 //現(xiàn)在發(fā)送端點還不允許發(fā)送數(shù)據(jù)。SetEPTxCount(ENDP1, 4)。SetEPType(ENDP1, EP_INTERRUPT)。SetEPRxCount(ENDP0, )。 //這是發(fā)送緩沖區(qū)地址Clear_Status_Out(ENDP0)。//端點狀態(tài)為發(fā)送無效,也就是主機IN令牌包來的時候,回送一個STALL。//需要總線供電SetBTABLE(BTABLE_ADDRESS)。}(3)JoyStick_Reset()函數(shù)的處理。 wInterrupt_Mask){_SetISTR((u16)CLR_RESET)。當復位中斷允許、且總線被集線器復位的時候,固件程序進入USB_LP中斷。后面一個語句執(zhí)行后,復位中斷已經(jīng)被允許,而此時集線器多半已經(jīng)開始復位端口了。然后清除所有的狀態(tài)位。//這句話實際上使能了USB模塊的電源,因為上電復位時,CNTR寄存器的斷電控制為PDWN位是1,模塊是斷電的。當集線器報告設備連接狀態(tài),并收到主機指令后,會復位USB總線,這需要一定的時間(這段時間內(nèi)設備應該準備好處理復位指令)。然后調(diào)用PowerOn(),這個函數(shù)實質(zhì)上將D+上拉,此時USB設備就能被集線器檢測到了。最后調(diào)用pPropertyInit(),實質(zhì)就是調(diào)用Joystick_init(void)。/* Selected configuration */u8 Current_Interface。/* wIndex */u16_u8 USBwLengths。typedef struct _DEVICE_INFO{u8 USBbmRequestType。 //回調(diào)設備的初始化例程。//這個是設備本身支持的屬性和方法pUser_Standard_Requests = amp。Device_Info。(3)Set_USBClock()的工作過程這個代碼就兩句話:RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5)。接下來配置、使能了三個中斷,包括USB低優(yōu)先級中斷、USB喚醒中斷(EXTI18)、和EXTI8(按鍵控制)中斷。EXTI_InitStructure)。 = EXTI_Line18。使能PWR控制,目的是為了控制CPU的低功耗模式;將所有輸入口初始化為模擬輸入——GPIO_AINConfig()。設置HCLK = SYSCLK——RCC_HCLKConfig(RCC_SYSCLK_Div1)。三、USB的“JoyStickMouse”工作過程詳細分析初始化過程敘述從main()函數(shù)開始(1)Set_System(void)的工作過程由于這些代碼都是采用庫代碼,所以我主要分析每個代碼具體做了什么工作。描述符表也在包緩沖區(qū)內(nèi)。比如2號寄存器都可以對應端點1(在雙緩沖情況下)。STAT_TX,占據(jù)兩位。主機的IN包之后。EP_KIND,端點特殊類型。EP_TYPE,兩位,表示端點類型。SETUP標志。一般由硬件自動設置,軟件寫1可使其手動翻轉(zhuǎn)。復位時為0.(4)端點狀態(tài)和配置寄存器,8個寄存器,支持8個雙向端點和16個單向端點。(3) USB設備地址寄存器第7位,EF,USB模塊允許位。SOF幀首標志ESOF,期待幀首標志。相應的標志位置位,且中斷未屏蔽,則向CPU發(fā)出對應的中斷。與總線上的復位信號產(chǎn)生相同的效果。PDWN。低功耗模式。這個由軟件置位。ESOFM。復位中斷允許位。WKUPM。它們使用的都是PCLK1時鐘。所以CPU通過APB1總線接口訪問,SIE通過包緩沖區(qū)接口模塊訪問,中間通過Arbiter來協(xié)調(diào)訪問。SIE使用48MHz的專用時鐘。 ISTR_CTR amp。}else{/* if not possible then resume after xx ms */Resume(RESUME_LATER)。Resume(RESUME_EXTERNAL)。 //清復位中斷()。wIstr = _GetISTR()。主要代碼如下:UserToPMABufferCopy(Mouse_Buffer, GetEPTxAddr(ENDP1), 4)。JoyState()用來獲取按鍵的狀態(tài)。但我還是先把main()函數(shù)的代碼看完吧。/* clear pending interrupts */wInterrupt_Mask = IMR_MSK。//獲取設備序列號,轉(zhuǎn)變?yōu)閡nicode字符串pInformationCurrent_Configuration = 0。Windows中處理消息,好像也用到了這種模式。Usb_init()函數(shù)調(diào)用pPropertyInit()(實質(zhì)上就是Joystick_init)完成設備的初始化。/* Initialize devices one by one */pPropertyInit()。pProperty = amp。后面兩個是函數(shù)指針結構體,里面都是USB請求實現(xiàn)、功能實現(xiàn)的函數(shù)指針。(3)Set_USBClock()這個是main函數(shù)中調(diào)用的第三個函數(shù)。(2)USB_Interrupts_Config()。而是先利用MDK的軟件模擬器仿真執(zhí)行,先了解一下設備初始化的流程。在這個頭文件中,又有以下定義:include include include include include include include 。它們都包含了頭文件“”。可見,ST的USB操作庫結構十分清晰明了,我先不準備直接閱讀源代碼。配置了JoyStickMouse所用到的5個按鍵,并且配置了兩個EXTI中斷,一個是用于把USB從掛起模式喚醒,還有一個用途未知。跟蹤到代碼中,主要設配置了USB低優(yōu)先級中斷和喚醒中斷,又有一個EXTI中斷功能未知。它初始化了三個全局指針,指向DEVICE_INFO、USER_STANDARD_REQUESTS和DEVICE_PROP結構體。pInformationControlState = 2。User_Standard_Requests。USER_STANDARD_REQUESTS User_Standard_Requests ={Joystick_GetConfiguration,Joystick_SetConfiguration,Joystick_GetInterface,Joystick_SetInterface,Joystick_GetStatus,Joystick_ClearFeature,Joystick_SetEndPointFeature,Joystick_SetDeviceFeature,Joystick_SetDeviceAddress}。回調(diào)函數(shù)的意義在于同一種操作模式、提供不同的回調(diào)函數(shù)則可以實現(xiàn)不同的功能。這是函數(shù)的代碼:void Joystick_init(void){/* Update the serial number string descriptor with the data from the uniqueID*/Get_SerialNum()。/* USB interrupts initialization */_SetISTR(0)。}實質(zhì)上,代碼執(zhí)行到這里,開發(fā)板已經(jīng)可以響應主機發(fā)來的數(shù)據(jù)了。進入主循環(huán)進入主循環(huán)的工作就兩個:Joystick_Send(JoyState())。它的工作只是將數(shù)據(jù)寫入IN端點緩沖區(qū),主機的IN令牌包來的時候,SIE負責把它返回給主機。 /* enable endpoint for transmission */中斷處理過程大致理解(1)usb_istr()函數(shù)中的中斷處理簡單分析有用的代碼大概以下幾段,首先是處理復位的代碼,調(diào)用設備結構中的復位處理函數(shù)。 wInterrupt_Mask){_SetISTR((u16)CLR_RESET)。 wInterrupt_Mask){_SetISTR((u16)CLR_WKUP)。 wInterrupt_Mask){if (fSuspendEnabled) /* check if SUSPEND is possible */{Suspend()。if (wIstr amp。首先在總線端(與D+、D相連的那一端),通過模擬收發(fā)器與SIE連接