官方USB程序和例程_第1頁
官方USB程序和例程_第2頁
官方USB程序和例程_第3頁
官方USB程序和例程_第4頁
官方USB程序和例程_第5頁
已閱讀5頁,還剩33頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、一、USB的“JoyStickMouse”例程結(jié)構(gòu)分析1、例程的結(jié)構(gòu)(1)底層結(jié)構(gòu)包括5個文件:usb_core.c(USB總線數(shù)據(jù)處理的核心文件),usb_init.c,usb_int.c(用于端點(diǎn)數(shù)據(jù)輸入輸入中斷處理),usb_mem.c(用于緩沖區(qū)操作),usb_regs.c(用于寄存器操作)。它們都包含了頭文件“usb_lib.h”。在這個頭文件中,又有以下定義:#include "usb_type.h"#include "usb_regs.h"#include "usb_def.h"#include "usb_co

2、re.h"#include "usb_init.h"#include "usb_mem.h"#include "usb_int.h"usb_lib.h中又包含了七個頭文件,其中usb_type.h中主要是用typedef為stm32支持的數(shù)據(jù)類型取一些新的名稱。usb_def.h中主要是定義一些相關(guān)的數(shù)據(jù)類型。還有一個未包含在usb_lib.h中的頭文件,usb_conf.h用于USB設(shè)備的配置。(2)上層結(jié)構(gòu)上層結(jié)構(gòu)總共5個文件:hw_config.c(用于USB硬件配置)、usb_pwr.c(用于USB連接、斷開操作)、

3、usb_istr.c(直接處理USB中斷)、usb_prop.c(用于上層協(xié)議處理,比如HID協(xié)議,大容量存儲設(shè)備協(xié)議)、usb_desc.c(具體設(shè)備的相關(guān)描述符定義和處理)??梢?,ST的USB操作庫結(jié)構(gòu)十分清晰明了,我先不準(zhǔn)備直接閱讀源代碼。而是先利用MDK的軟件模擬器仿真執(zhí)行,先了解一下設(shè)備初始化的流程。2、設(shè)備初始化所做的工作(1)Set_System(void)這個是main函數(shù)中首先調(diào)用的函數(shù),它位于hw_config.c文件中。它的主要功能是初始化時鐘系統(tǒng)、使能相關(guān)的外圍設(shè)備電源。配置了JoyStickMouse所用到的5個按鍵,并且配置了兩個EXTI中斷,一個是用于把USB從掛

4、起模式喚醒,還有一個用途未知。(2)USB_Interrupts_Config();這個是main函數(shù)中調(diào)用的第二個函數(shù),它也位于hw_config.c文件中。主要功能是配置USB所用到的中斷。跟蹤到代碼中,主要設(shè)配置了USB低優(yōu)先級中斷和喚醒中斷,又有一個EXTI中斷功能未知。(3)Set_USBClock()這個是main函數(shù)中調(diào)用的第三個函數(shù),它也位于hw_config.c文件中。它的功能是配置和使能USB時鐘。(4)USB_Init(void)這個是main函數(shù)中調(diào)用的第四個函數(shù),它也位于usb_init.c文件中。它初始化了三個全局指針,指向DEVICE_INFO、USER_STAN

5、DARD_REQUESTS和DEVICE_PROP結(jié)構(gòu)體。后面兩個是函數(shù)指針結(jié)構(gòu)體,里面都是USB請求實現(xiàn)、功能實現(xiàn)的函數(shù)指針。void USB_Init(void)pInformation = &Device_Info;pInformation->ControlState = 2;pProperty = &Device_Property;pUser_Standard_Requests = &User_Standard_Requests;/* Initialize devices one by one */pProperty->Init();這三個結(jié)構(gòu)體都是

6、與具體設(shè)備枚舉和功能實現(xiàn)相關(guān)的,定義在usb_prop.c和usb_desc.c文件中。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

7、,0,0x40 /*MAX PACKET SIZE*/;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_init

8、()函數(shù)調(diào)用pProperty->Init()(實質(zhì)上就是Joystick_init)完成設(shè)備的初始化。上層程序調(diào)用下次函數(shù)是常規(guī)性的操作。而下層函數(shù)(usb_init相對于usb_prop是輸入底層操作文件)調(diào)用上層文件函數(shù)我們稱之為回調(diào)?;卣{(diào)函數(shù)的意義在于同一種操作模式、提供不同的回調(diào)函數(shù)則可以實現(xiàn)不同的功能。Windows中處理消息,好像也用到了這種模式?;卣{(diào)函數(shù)的實現(xiàn)方法是函數(shù)指針數(shù)組。這是指針的高級應(yīng)用。這是函數(shù)的代碼:void Joystick_init(void)/* Update the serial number string descriptor with the d

9、ata from the uniqueID*/Get_SerialNum();/獲取設(shè)備序列號,轉(zhuǎn)變?yōu)閡nicode字符串pInformation->Current_Configuration = 0;/* Connect the device */PowerOn();/連接USB設(shè)備,實質(zhì)是能讓主機(jī)檢測到了。/* USB interrupts initialization */_SetISTR(0);/* clear pending interrupts */wInterrupt_Mask = IMR_MSK;_SetCNTR(wInterrupt_Mask); /* set inte

10、rrupts mask */bDeviceState = UNCONNECTED;實質(zhì)上,代碼執(zhí)行到這里,開發(fā)板已經(jīng)可以響應(yīng)主機(jī)發(fā)來的數(shù)據(jù)了。但我還是先把main()函數(shù)的代碼看完吧。(5)SysTick_Config();這個函數(shù)調(diào)用主要是為程序中用到的精確延時作配置。3、進(jìn)入主循環(huán)進(jìn)入主循環(huán)的工作就兩個:Joystick_Send(JoyState()。JoyState()用來獲取按鍵的狀態(tài)。Joystick_Send(JoyState()用來把按鍵狀態(tài)發(fā)到主機(jī)。當(dāng)然這里真正的發(fā)送工作并不是由該代碼完成的。它的工作只是將數(shù)據(jù)寫入IN端點(diǎn)緩沖區(qū),主機(jī)的IN令牌包來的時候,SIE負(fù)責(zé)把它返回給

11、主機(jī)。主要代碼如下:UserToPMABufferCopy(Mouse_Buffer, GetEPTxAddr(ENDP1), 4);/從用戶復(fù)制四個字節(jié)到端點(diǎn)1緩沖區(qū),控制端點(diǎn)的輸入緩沖區(qū)。SetEPTxValid(ENDP1); /* enable endpoint for transmission */4、中斷處理過程大致理解(1)usb_istr()函數(shù)中的中斷處理簡單分析有用的代碼大概以下幾段,首先是處理復(fù)位的代碼,調(diào)用設(shè)備結(jié)構(gòu)中的復(fù)位處理函數(shù)。wIstr = _GetISTR();if (wIstr & ISTR_RESET & wInterrupt_Mask)_S

12、etISTR(u16)CLR_RESET); /清復(fù)位中斷Device_Property.Reset();處理喚醒的代碼:if (wIstr & ISTR_WKUP & wInterrupt_Mask)_SetISTR(u16)CLR_WKUP);Resume(RESUME_EXTERNAL);處理總線掛起的代碼:if (wIstr & ISTR_SUSP & wInterrupt_Mask)if (fSuspendEnabled) /* check if SUSPEND is possible */Suspend();else/* if not possibl

13、e then resume after xx ms */Resume(RESUME_LATER);/* clear of the ISTR bit must be done after setting of CNTR_FSUSP */_SetISTR(u16)CLR_SUSP);處理端點(diǎn)傳輸完成的代碼,這段是最重要的,它調(diào)用底層usb_int.c()文件中的CTR_LP()函數(shù)來處理端點(diǎn)數(shù)據(jù)傳輸完成中斷。if (wIstr & ISTR_CTR & wInterrupt_Mask)CTR_LP(); /* servicing of the endpoint correct tr

14、ansfer interrupt */二、STM32處理器的USB接口1、接口模塊的內(nèi)部結(jié)構(gòu)在書上有一個很好的USB內(nèi)部接口模塊內(nèi)部結(jié)構(gòu)圖,比較好的解釋了各個模塊之間的關(guān)系,我這里試著用我自己的理解闡述一下吧。首先在總線端(與D+、D-相連的那一端),通過模擬收發(fā)器與SIE連接。SIE使用48MHz的專用時鐘。與SIE相關(guān)的的有三大塊:CPU內(nèi)部控制、中斷和端點(diǎn)控制寄存器,掛起定時器(這個好像是USB協(xié)議的要求,總線在一定時間內(nèi)沒有活動,SIE模塊能夠進(jìn)入SUSPEND狀態(tài)以節(jié)約電能),還有包緩沖區(qū)接口模塊。說到包緩沖區(qū)接口模塊,這個對應(yīng)的含義是,USB設(shè)備應(yīng)該提供USB包緩沖區(qū)。這塊緩沖區(qū)同

15、時受到SIE和CPU核心的控制,用于CPU與SIE共享達(dá)到數(shù)據(jù)傳輸?shù)哪康?。所以CPU通過APB1總線接口訪問,SIE通過包緩沖區(qū)接口模塊訪問,中間通過Arbiter來協(xié)調(diào)訪問。當(dāng)然我們關(guān)注的中心點(diǎn)是控制、中斷和端點(diǎn)控制寄存器。我們通過這些寄存器來獲取總線傳輸?shù)臓顟B(tài),控制各個端點(diǎn)的狀態(tài),并可以產(chǎn)生中斷來讓CPU處理當(dāng)前的USB事件。CPU可以通過APB1總線接口來訪問這些寄存器。它們使用的都是PCLK1時鐘。2、USB模塊的寄存器認(rèn)識(1)控制寄存器CNTR傳輸完成中斷允許位。CTRM,1有效,如果SIE置位傳輸完成標(biāo)志,則相應(yīng)的數(shù)據(jù)傳輸完成中斷發(fā)生。第15位包緩沖區(qū)溢出中斷允許位錯誤中斷允許位

16、喚醒中斷允許位。WKUPM。1有效,如果喚醒請求標(biāo)志位置位,則產(chǎn)生喚醒中斷。掛起中斷允許位。SUSPM,1有效,當(dāng)總線掛起標(biāo)志置位時,發(fā)生掛起中斷。復(fù)位中斷允許位。RESETM。1有效,軟件強(qiáng)制復(fù)位和總線復(fù)位信號,都能觸發(fā)復(fù)位中斷。幀首中斷允許位期望幀首中斷允許位。ESOFM。它的含義是沒有收到幀首信號,允許發(fā)生中斷。第8位向主機(jī)發(fā)送的喚醒請求,RESUME。1有效,主機(jī)收到該信號,將喚醒設(shè)備。這個由軟件置位。第4位強(qiáng)制掛起控制,F(xiàn)SUSP。1有效。與由于總線無活動引起掛起的效果相同。低功耗模式。前提是先進(jìn)入掛起狀態(tài)。由軟件設(shè)置,一般又硬件復(fù)位(被喚醒后自動清零)。斷電模式控制位。PDWN。此

17、位為1時,USB模塊關(guān)閉。強(qiáng)制復(fù)位控制。FRES。與總線上的復(fù)位信號產(chǎn)生相同的效果。也能產(chǎn)生復(fù)位中斷.第0位。(2)中斷狀態(tài)寄存器ISTR這個寄存器主要是反映USB模塊當(dāng)前的狀態(tài)的。第15-8為與控制寄存器的中斷允許是意義對應(yīng)的。相應(yīng)的標(biāo)志位置位,且中斷未屏蔽,則向CPU發(fā)出對應(yīng)的中斷。CTR標(biāo)志,數(shù)據(jù)傳輸完成后硬件置1.PMAOVR標(biāo)志ERR標(biāo)志W(wǎng)KUP請求,總線檢測到主機(jī)喚醒請求時由硬件置位。SUSP請求標(biāo)志位。RESET請求標(biāo)志位。SOF幀首標(biāo)志ESOF,期待幀首標(biāo)志。DIR傳輸方向,此位由硬件控制。IN時為0,OUT為1.第4位。發(fā)生數(shù)據(jù)傳輸?shù)亩它c(diǎn)的地址。(3) USB設(shè)備地址寄存器第

18、7位,EF,USB模塊允許位。如果EF=0,則USB模塊將停止工作。第6-0位。USB當(dāng)前使用的地址。復(fù)位時為0.(4)端點(diǎn)狀態(tài)和配置寄存器,8個寄存器,支持8個雙向端點(diǎn)和16個單向端點(diǎn)。 CTR_RX,正確接收標(biāo)志位。第15位。DTOG_RX,用于檢測的數(shù)據(jù)翻轉(zhuǎn)位。一般由硬件自動設(shè)置,軟件寫1可使其手動翻轉(zhuǎn)。STAT_RX,占據(jù)兩位。00表示該端點(diǎn)不可用,無回應(yīng)。01表示響應(yīng)STALL10響應(yīng)NAK11表示端點(diǎn)有效,可接收數(shù)據(jù)。SETUP標(biāo)志。收到SETUP令牌包時置位。用戶收到數(shù)據(jù)后需檢查次位。第11位。EP_TYPE,兩位,表示端點(diǎn)類型。00表示批量端點(diǎn)。01表示控制端點(diǎn)10表示等時端點(diǎn)

19、。11表示中斷端點(diǎn)。EP_KIND,端點(diǎn)特殊類型。在EP_TYPE=01時,表示設(shè)備期望主機(jī)的0字節(jié)狀態(tài)包。CTR_TX。正確發(fā)送標(biāo)志。主機(jī)的IN包之后。第7位。DTOG_TX,用于檢測的數(shù)據(jù)翻轉(zhuǎn)位。一般由硬件自動設(shè)置,軟件寫1可使其手動翻轉(zhuǎn)。STAT_TX,占據(jù)兩位。00表示該端點(diǎn)不可用,無回應(yīng)。01表示響應(yīng)STALL10響應(yīng)NAK11表示端點(diǎn)有效,可發(fā)送數(shù)據(jù)。端點(diǎn)地址:EA【3:0】,表明該寄存器對應(yīng)的端點(diǎn)號碼。比如1、2號寄存器都可以對應(yīng)端點(diǎn)1(在雙緩沖情況下)。第3-0位。(5)端點(diǎn)描述符表相關(guān)寄存器首先有一個描述符表地址寄存器,指明了包緩沖區(qū)內(nèi)端點(diǎn)描述符表的地址。每一個端點(diǎn)都對應(yīng)一個

20、描述附表。描述符表也在包緩沖區(qū)內(nèi)。每個端點(diǎn)寄存器對應(yīng)的描述符表的地址可根據(jù)公式計算。單緩沖、雙向的端點(diǎn)描述符表有四項,每項占據(jù)兩個字節(jié):分別是端點(diǎn)n的發(fā)送緩沖區(qū)地址、發(fā)送字節(jié)數(shù)、接收緩沖區(qū)地址、接收字節(jié)數(shù)。了解USB相關(guān)寄存器的知識以后,接下來就可以分析“JoyStickMouse”詳細(xì)的工作過程了。三、USB的“JoyStickMouse”工作過程詳細(xì)分析1、初始化過程敘述從main()函數(shù)開始(1)Set_System(void)的工作過程由于這些代碼都是采用庫代碼,所以我主要分析每個代碼具體做了什么工作。有些常用、類似的代碼這里就不列出來了。先將RCC部分復(fù)位,系統(tǒng)使用內(nèi)部振蕩HSI,8

21、MHzRCC_DeInit();。使能HSERCC_HSEConfig(RCC_HSE_ON);設(shè)置HCLK = SYSCLKRCC_HCLKConfig(RCC_SYSCLK_Div1);設(shè)置PCLK2,PCLK1RCC_PCLK2Config(RCC_HCLK_Div1);設(shè)置PLL,使能PLLPLL采用HSE,輸出=HSE X 9;RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);系統(tǒng)時鐘采用PLL輸出RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);使能PWR控制,目的是為了控制CPU的低功耗模式;

22、將所有輸入口初始化為模擬輸入GPIO_AINConfig();使能USB上拉控制GPIO端口的時鐘,這個端口設(shè)置為低電平時,USB外設(shè)會被集線器檢測到,并報告給主機(jī),這也是設(shè)備枚舉的開始;將這個端口的模式設(shè)置為開漏輸出;初始化上下左右四個按鍵為上下拉輸入;配置GPIOG8為EXTI8中斷輸入引腳,這個是在外部按鍵輸入引起中斷。配置EXTI18中斷。這個是發(fā)生USB喚醒事件時用。EXTI_InitStructure.EXTI_Line = EXTI_Line18; / USB resume from suspend modeEXTI_InitStructure.EXTI_Trigger = EX

23、TI_Trigger_Rising;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);(2)USB_Interrupts_Config(void)的工作過程設(shè)置向量表位置在FLASH起始位置NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x00);設(shè)置優(yōu)先級分組,1位用于搶占組級別。其余用于子優(yōu)先級NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);接下來配置、使能了三個中斷,包括USB低優(yōu)先級中斷、USB喚醒中斷(E

24、XTI18)、和EXTI8(按鍵控制)中斷。它的優(yōu)先級設(shè)置有些問題,明明只有一位用于搶占優(yōu)先級。它把EXTI8的搶占優(yōu)先級設(shè)為2。結(jié)果在調(diào)試時發(fā)現(xiàn),它的搶占優(yōu)先級仍然是0。(3)Set_USBClock()的工作過程這個代碼就兩句話:RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);作用是設(shè)置并使能USB時鐘,從RCC輸出可以看到,USB時鐘是48MHz。(4)USB_Init()的工作過程void USB_Init(void)pInformati

25、on = &Device_Info;pInformation->ControlState = 2;pProperty = &Device_Property;/這個是設(shè)備本身支持的屬性和方法pUser_Standard_Requests = &User_Standard_Requests; /這個是主機(jī)請求的實現(xiàn)方法。pProperty->Init(); /回調(diào)設(shè)備的初始化例程。這個主要是初始化了三個全局結(jié)構(gòu)體指針,pInformation表明當(dāng)前連接的狀態(tài)和信息,pProperty表明設(shè)備支持的方法,pUser_Standard_Requests是主機(jī)請求實

26、現(xiàn)的函數(shù)指針數(shù)組。Device_Info是一個結(jié)構(gòu)體,包括11個成員變量。這里是將它的ControlState設(shè)為2,意義現(xiàn)在還不十分明了。typedef struct _DEVICE_INFOu8 USBbmRequestType;/* bmRequestType */u8 USBbRequest;/* bRequest */u16_u8 USBwValues;/* wValue */u16_u8 USBwIndexs;/* wIndex */u16_u8 USBwLengths;/* wLength */u8 ControlState;/* of type CONTROL_STATE */

27、u8 Current_Feature;u8 Current_Configuration;/* Selected configuration */u8 Current_Interface;/* Selected interface of current configuration */u8 Current_AlternateSetting;/* Selected Alternate Setting of currentinterface*/ENDPOINT_INFO Ctrl_Info;/端點(diǎn)信息結(jié)構(gòu)體DEVICE_INFO;最后調(diào)用pProperty->Init(),實質(zhì)就是調(diào)用Joys

28、tick_init(void)。在這個函數(shù)中,首先獲取設(shè)備版本,并轉(zhuǎn)換為Unicode存入版本號字符串。Get_SerialNum();設(shè)備當(dāng)前配置置為0。然后調(diào)用PowerOn(),這個函數(shù)實質(zhì)上將D+上拉,此時USB設(shè)備就能被集線器檢測到了。因此分析進(jìn)入下一個流程。2、進(jìn)入設(shè)備檢測狀態(tài)(1)在PowerOn()中執(zhí)行的情況。在USB_init()中調(diào)用PowerOn(),而它先調(diào)用USB_Cable_Config(ENABLE),這個函數(shù)實質(zhì)上將USB連接控制線設(shè)置為低電平,然后設(shè)備就可以檢測到設(shè)備了。當(dāng)集線器報告設(shè)備連接狀態(tài),并收到主機(jī)指令后,會復(fù)位USB總線,這需要一定的時間(這段時間

29、內(nèi)設(shè)備應(yīng)該準(zhǔn)備好處理復(fù)位指令)。但是現(xiàn)在設(shè)備初始化程序?qū)⒗^續(xù)往下進(jìn)行,因為它還沒有使能復(fù)位中斷。wRegVal = CNTR_FRES;_SetCNTR(wRegVal);/這句話實際上使能了USB模塊的電源,因為上電復(fù)位時,CNTR寄存器的斷電控制為PDWN位是1,模塊是斷電的。這句話雖然將強(qiáng)制復(fù)位USB模塊,但由于復(fù)位中斷允許位沒有使能,不會引起復(fù)位中斷,而間接上由使PDWN=0,模塊開始工作。_SetCNTR是一個宏,將wRegVal賦值給CNTR寄存器,此時所有的中斷被屏蔽。再接下來兩句指令又將清除復(fù)位信號。然后清除所有的狀態(tài)位。_SetISTR(0);接下來是很關(guān)鍵的兩句話:wInt

30、errupt_Mask=CNTR_RESETM| CNTR_SUSPM | CNTR_WKUPM;_SetCNTR(wInterrupt_Mask);后面一個語句執(zhí)行后,復(fù)位中斷已經(jīng)被允許,而此時集線器多半已經(jīng)開始復(fù)位端口了?;蛘哒f稍微有限延遲,設(shè)備固件還能繼續(xù)初始化一些部件,但已經(jīng)不會影響整個工作流程了。所以接下來,分析直接進(jìn)入復(fù)位中斷。(2)復(fù)位中斷的處理。當(dāng)復(fù)位中斷允許、且總線被集線器復(fù)位的時候,固件程序進(jìn)入USB_LP中斷。中斷程序直接調(diào)用USB_Istr(void)程序。接下來講對中斷位進(jìn)行判斷:if (wIstr & ISTR_RESET & wInterrupt_

31、Mask)_SetISTR(u16)CLR_RESET);/先清除復(fù)位中斷位Device_Property.Reset();/進(jìn)入設(shè)備定義的復(fù)位過程。實際上是調(diào)用JoyStick_Reset()函數(shù)進(jìn)行處理。(3)JoyStick_Reset()函數(shù)的處理。這里將一句句來分析:void Joystick_Reset(void)pInformation->Current_Configuration = 0;/當(dāng)前配置為0pInformation->Current_Interface = 0;/當(dāng)前接口為0pInformation->Current_Feature = Joyst

32、ick_ConfigDescriptor7;/需要總線供電SetBTABLE(BTABLE_ADDRESS); /設(shè)置包緩沖區(qū)地址。SetEPType(ENDP0, EP_CONTROL);/端點(diǎn)0為控制端點(diǎn)SetEPTxStatus(ENDP0, EP_TX_STALL);/端點(diǎn)狀態(tài)為發(fā)送無效,也就是主機(jī)IN令牌包來的時候,回送一個STALL。SetEPRxAddr(ENDP0, ENDP0_RXADDR); /設(shè)置端點(diǎn)0描述符表,包括接收緩沖區(qū)地址、最大允許接收的字節(jié)數(shù)、發(fā)送緩沖區(qū)地址三個量。SetEPTxAddr(ENDP0, ENDP0_TXADDR); /這是發(fā)送緩沖區(qū)地址Clear

33、_Status_Out(ENDP0);/清除EP_KIND的STATUS_OUT位,如果改位被設(shè)置,在控制模式下只對0字節(jié)數(shù)據(jù)包相應(yīng)。其它的都返回STALL。主要用于控制傳輸?shù)臓顟B(tài)過程。SetEPRxCount(ENDP0, Device_Property.MaxPacketSize); /接收緩沖區(qū)支持64個字節(jié)。SetEPRxValid(ENDP0);/使能端點(diǎn)0的接收,因為很快就要接收SETUP令牌包后面跟著的數(shù)據(jù)包了。SetEPType(ENDP1, EP_INTERRUPT);/端點(diǎn)1為中斷端點(diǎn)。SetEPTxAddr(ENDP1, ENDP1_TXADDR); /設(shè)置發(fā)送緩沖區(qū)地址

34、。SetEPTxCount(ENDP1, 4);/每次發(fā)送四個字節(jié)SetEPRxStatus(ENDP1, EP_RX_DIS);/接收禁止,只發(fā)送Mouse信息,而不從主機(jī)接收。SetEPTxStatus(ENDP1, EP_TX_NAK); /現(xiàn)在發(fā)送端點(diǎn)還不允許發(fā)送數(shù)據(jù)。bDeviceState = ATTACHED;/連接狀態(tài)改為已經(jīng)連接,默認(rèn)地址狀態(tài)。SetDeviceAddress(0); /地址默認(rèn)為0.復(fù)位中斷執(zhí)行完成后,開發(fā)板的USB接口能夠以默認(rèn)地址對主機(jī)來的數(shù)據(jù)包進(jìn)行響應(yīng)了。這個階段的分析到此結(jié)束,下一個階段就是正式分析代碼實現(xiàn)的枚舉過程了。四、USB的“JoyStick

35、Mouse”工作過程詳細(xì)分析1、枚舉第一步:獲取設(shè)備的描述符從USB_init()開始(1)先要允許數(shù)據(jù)傳輸完成中斷在poweron()函數(shù)后面緊跟著幾句話:PowerOn();/這句執(zhí)行完,設(shè)備被主機(jī)檢測到,并且能夠響應(yīng)復(fù)位中斷了。_SetISTR(0);/* clear pending interrupts */wInterrupt_Mask = IMR_MSK;_SetCNTR(wInterrupt_Mask); /* set interrupts mask */以上這兩句話將允許所有的USB中斷bDeviceState = UNCONNECTED;/設(shè)備狀態(tài)置位為未連接狀態(tài)。這里我不太

36、理解。這時候即使復(fù)位中斷未發(fā)生,最起碼設(shè)備已經(jīng)算是連接入總線了,為什么這個狀態(tài)還要設(shè)置為“未連接”呢?(2)主機(jī)獲取描述符主機(jī)進(jìn)入控制傳輸?shù)牡谝浑A段:建立事務(wù),發(fā)setup令牌包、發(fā)請求數(shù)據(jù)包、設(shè)備發(fā)ACK包。主機(jī)發(fā)出對地址0、端點(diǎn)0發(fā)出SETUP令牌包,首先端點(diǎn)0寄存器的第11位SETUP位置位,表明收到了setup令牌包。由于此時端點(diǎn)0數(shù)據(jù)接收有效,所以接下來主機(jī)的請求數(shù)據(jù)包被SIE保存到端點(diǎn)0描述附表的 RxADDR里面,收到的字節(jié)數(shù)保存到 RxCount里面。端點(diǎn)0寄存器的CTR_RX被置位為1,ISTR的CTR置位為1,DIR=1,EP_ID=0,表示端點(diǎn)0接收到主機(jī)來的請求數(shù)據(jù)。此

37、時設(shè)備已經(jīng)ACK主機(jī),將觸發(fā)正確傳輸完成中斷,下面就進(jìn)入中斷看一看。_SetISTR(u16)CLR_CTR); /*首先清除傳輸完成標(biāo)志 */EPindex = (u8)(wIstr & ISTR_EP_ID); /獲取數(shù)據(jù)傳輸針對的端點(diǎn)號。if (EPindex = 0)/如果是端點(diǎn)0,這里的確是端點(diǎn)0SaveRState = _GetEPRxStatus(ENDP0); /保存端點(diǎn)0狀態(tài),原本是有效狀態(tài)。SaveTState = _GetEPTxStatus(ENDP0); _SetEPRxStatus(ENDP0, EP_RX_NAK); /在本次數(shù)據(jù)處理好之前,對主機(jī)發(fā)來的數(shù)

38、據(jù)包以NAK回應(yīng)_SetEPTxStatus(ENDP0, EP_TX_NAK); if (wIstr & ISTR_DIR) = 0) /如果是IN令牌,數(shù)據(jù)被取走_(dá)ClearEP_CTR_TX(ENDP0);In0_Process();/調(diào)用該程序處理固件數(shù)據(jù)輸出后的工作。_SetEPRxStatus(ENDP0, SaveRState);_SetEPTxStatus(ENDP0, SaveTState);return;Else/DIR=1時,要么是SETUP包,要么是OUT包。/這里先分析SETUP包。wEPVal = _GetENDPOINT(ENDP0);/獲取整個端點(diǎn)0狀態(tài)

39、if (wEPVal & EP_CTR_TX) != 0)/這種情況一般不太可能,/如果出現(xiàn)表示同時 TX和RX 同時置位。else if (wEPVal &EP_SETUP) != 0)/我們的程序會執(zhí)行到這里_ClearEP_CTR_RX(ENDP0);Setup0_Process(); /主要是調(diào)用該程序來處理主機(jī)請求。_SetEPRxStatus(ENDP0, SaveRState);_SetEPTxStatus(ENDP0, SaveTState);return;else if (wEPVal & EP_CTR_RX) != 0) /暫時不執(zhí)行的代碼先刪除掉。

40、/* if(EPindex = 0) */后面處理其他端點(diǎn)的代碼就先不看了。/* while(.) */(3)Setup0_Process()函數(shù)的執(zhí)行分析這個函數(shù)執(zhí)行的時候,主機(jī)發(fā)來的請求數(shù)據(jù)包已經(jīng)存在于RxADDR緩沖區(qū)了。大部分的標(biāo)志位已經(jīng)清除,除了SETUP位,這個味將由下一個令牌包自動清除。進(jìn)入處理函數(shù):pBuf.b = PMAAddr + (u8 *)(_GetEPRxAddr(ENDP0) * 2); /這是取得端點(diǎn)0接收緩沖區(qū)的起始地址。PMAAddr是包緩沖區(qū)起始地址,_GetEPRxAddr(ENDP0)獲得端點(diǎn)0描述符表里的接收緩沖區(qū)地址,為什么要乘以2呢?大概因為描述符

41、表里地址項為16位,使用的是相對偏移。if (pInformation->ControlState != PAUSE)pInformation->USBbmRequestType = *pBuf.b+; /請求類型,表明方向和接收對象(設(shè)備、接口還是端點(diǎn))此時為80,表明設(shè)備到主機(jī)pInformation->USBbRequest = *pBuf.b+; /* 請求代碼,第一次時應(yīng)該是6,表明主機(jī)要獲取設(shè)備描述符。 */pBuf.w+;pInformation->USBwValue = ByteSwap(*pBuf.w+); /* wValue */pBuf.w+;/我

42、覺得這里可能有些問題。pInformation->USBwIndex= ByteSwap(*pBuf.w+); /* wIndex */pBuf.w+; pInformation->USBwLength = *pBuf.w; /* wLength */pInformation->ControlState = SETTING_UP;if (pInformation->USBwLength = 0)NoData_Setup0();elseData_Setup0();/這次是有數(shù)據(jù)傳輸?shù)?,所以有進(jìn)入該該函數(shù)。return Post0_Process();(4)Data_Set

43、up0()函數(shù)的執(zhí)行分析CopyRoutine = NULL; /這是一個函數(shù)指針,由用戶提供。wOffset = 0;if (Request_No = GET_DESCRIPTOR) /如果是獲取設(shè)備描述符if(Type_Recipient=(STANDARD_REQUEST| EVICE_RECIPIENT)u8 wValue1 = pInformation->USBwValue1;if (wValue1 = DEVICE_DESCRIPTOR)CopyRoutine = pProperty->GetDeviceDescriptor; /獲取設(shè)備描述符的操作由用戶提供。if (

44、CopyRoutine)pInformation->Ctrl_Info.Usb_wOffset = wOffset;pInformation->Ctrl_Info.CopyData = CopyRoutine;(*CopyRoutine)(0); /這個函數(shù)這里調(diào)用的目的只是設(shè)置了pInformation中需要寫入的描述符的長度。Result = USB_SUCCESS;if (ValBit(pInformation->USBbmRequestType, 7)/此時為80/上面這個語句主要是判斷傳輸方向。如果為1,則是設(shè)備到主機(jī)vu32 wLength = pInformat

45、ion->USBwLength; 這個一般是64if (pInformation->Ctrl_Info.Usb_wLength > wLength)/設(shè)備描述符長度18pInformation->Ctrl_Info.Usb_wLength = wLength; /有些細(xì)節(jié)暫時先放著pInformation->Ctrl_Info.PacketSize = pProperty->MaxPacketSize;DataStageIn();/最主要是調(diào)用這個函數(shù)完成描述符的輸出準(zhǔn)備(5)DataStageIn()函數(shù)的執(zhí)行分析以下是主要執(zhí)行代碼:DataBuffer

46、= (*pEPinfo->CopyData)(Length); /這個是取得用戶描述符緩沖區(qū)的地址。這里共18個字節(jié)UserToPMABufferCopy(DataBuffer, GetEPTxAddr(ENDP0), Length);/這個函數(shù)將設(shè)備描述符復(fù)制到用戶的發(fā)送緩沖區(qū)。SetEPTxCount(ENDP0, Length);/設(shè)置發(fā)送字節(jié)的數(shù)目、18pEPinfo->Usb_wLength -= Length; 等于0pEPinfo->Usb_wOffset += Length; 偏移到18vSetEPTxStatus(EP_TX_VALID); /使能端點(diǎn)發(fā)送,

47、只要主機(jī)的IN令牌包一來,SIE就會將描述符返回給主機(jī)。USB_StatusOut();/* 這個實際上是使接收也有效,主機(jī)可取消IN。 */Expect_Status_Out:pInformation->ControlState = ControlState;(6)執(zhí)行流程返回到CTR_LP(void)_SetEPRxStatus(ENDP0, SaveRState);_SetEPTxStatus(ENDP0, SaveTState);/由于vSetEPTxStatus(EP_TX_VALID)實際改變了SaveTState,所以此時端點(diǎn)發(fā)送已經(jīng)使能。return;(7)主機(jī)的IN令牌

48、包獲取描述符的控制傳輸進(jìn)入第二階段,主機(jī)首先發(fā)一個IN令牌包,由于端點(diǎn)0發(fā)送有效,SIE將數(shù)據(jù)返回主機(jī)。主機(jī)方返回一個ACK后,主機(jī)發(fā)送數(shù)據(jù)的CTR標(biāo)志置位,DIR=0,EP_ID=0,表明主機(jī)正確收到了用戶發(fā)過去的描述符。固件程序由此進(jìn)入中斷。此時是由IN引起的。主要是調(diào)用In0_Process()完成剩下的工作。(7)追蹤進(jìn)入函數(shù)In0_Process()此時實際上設(shè)備返回描述符已經(jīng)成功了。這一次還是調(diào)用DataStageIn()函數(shù),但是目的只是期待主機(jī)的0狀態(tài)字節(jié)輸出了。if (ControlState = IN_DATA) | (ControlState = LAST_IN_DATA

49、)第一次取設(shè)備描述符只取一次。DataStageIn();/此次調(diào)用后,當(dāng)前狀態(tài)變成WAIT_STATUS_OUT,表明設(shè)備等待狀態(tài)過程,主機(jī)輸出0字節(jié)。/* ControlState may be changed outside the function */ControlState = pInformation->ControlState;返回時調(diào)用Post0_Process(void)函數(shù),這個函數(shù)沒做什么事。(8)進(jìn)入狀態(tài)過程主機(jī)收到18個字節(jié)的描述符后,進(jìn)入狀態(tài)事務(wù)過程,此過程的令牌包為OUT,字節(jié)數(shù)為0.只需要用戶回一個ACK。所以中斷處理程序會進(jìn)入Out0_Process(

50、)。由于此時狀態(tài)為WAIT_STATUS_OUT,所以執(zhí)行以下這段。else if (ControlState = WAIT_STATUS_OUT)(*pProperty->Process_Status_OUT)();/這是個空函數(shù),什么也不做。ControlState = STALLED;/狀態(tài)轉(zhuǎn)為STALLED。獲取設(shè)備描述符后,主機(jī)再一次復(fù)位設(shè)備。設(shè)備又進(jìn)入初始狀態(tài)。五、USB的“JoyStickMouse”工作過程詳細(xì)分析1、枚舉第二步:設(shè)置地址(1)重新從復(fù)位狀態(tài)開始在第一次獲取設(shè)備描述符后,程序使端點(diǎn)0的發(fā)送和接收都無效,狀態(tài)也設(shè)置為STALLED,所以主機(jī)先發(fā)一個復(fù)位,使得

51、端點(diǎn)0接收有效。雖然說在NAK和STALL狀態(tài)下,端點(diǎn)仍然可以響應(yīng)和接收SETUP包。(2)設(shè)置地址的建立階段:主機(jī)先發(fā)一個SETUP令牌包,設(shè)備端EP0的SETUP標(biāo)志置位。然后主機(jī)發(fā)了一個OUT包,共8個字節(jié),里面包含設(shè)置地址的要求。設(shè)備在檢驗數(shù)據(jù)后,發(fā)一個ACK握手包。同時CTR_RX置位,CTR置位。數(shù)據(jù)已經(jīng)保存到RxADDR所指向的緩沖區(qū)。此時USB產(chǎn)生數(shù)據(jù)接收中斷。由于CTR_RX和SETUP同時置位,終端處理程序調(diào)用Setup0_Process(),所做的工作仍然是先填充pInformation結(jié)構(gòu),獲取請求特征碼、請求代碼和數(shù)據(jù)長度。由于設(shè)置地址不會攜帶數(shù)據(jù),所以接下來調(diào)用No

52、Data_Setup0()。執(zhí)行以下代碼:else if (RequestNo = SET_ADDRESS)Result = USB_SUCCESS;說明設(shè)置地址沒有做任何工作。ControlState = WAIT_STATUS_IN;/* After no data stage SETUP */USB_StatusIn(); /這句話是一個關(guān)鍵,它是一個宏,實際是準(zhǔn)備好發(fā)送0字節(jié)的狀態(tài)數(shù)據(jù)包。因為地址設(shè)置沒有數(shù)據(jù)過程,建立階段后直接進(jìn)入狀態(tài)階段,主機(jī)發(fā)IN令牌包,設(shè)備返回0字節(jié)數(shù)據(jù)包,主機(jī)再ACK。它對應(yīng)的宏是這樣的:#define USB_StatusIn() Send0LengthDa

53、ta() /準(zhǔn)備發(fā)送0字節(jié)數(shù)據(jù)#define Send0LengthData() _SetEPTxCount(ENDP0, 0); vSetEPTxStatus(EP_TX_VALID); /設(shè)置發(fā)送有效,發(fā)送字節(jié)數(shù)為0(3)設(shè)置地址的狀態(tài)階段:而前面把狀態(tài)設(shè)置為WAIT_STATUS_IN是給IN令牌包的處理提供指示。因為建立階段結(jié)束以后,主機(jī)接著發(fā)一個IN令牌包,設(shè)備返回0字節(jié)數(shù)據(jù)包后,進(jìn)入中斷。本次中斷由IN0_Process()函數(shù)來處理,追蹤進(jìn)入,它執(zhí)行以下代碼:else if (ControlState = WAIT_STATUS_IN)if (pInformation->U

54、SBbRequest = SET_ADDRESS) &&(Type_Recipient=(STANDARD_REQUEST|DEVICE_RECIPIENT)SetDeviceAddress(pInformation->USBwValue0);pUser_Standard_Requests->User_SetDeviceAddress(); /這個函數(shù)就一個賦值語句,bDeviceState = ADDRESSED。 (*pProperty->Process_Status_IN)(); /這是一個空函數(shù)。ControlState = STALLED;執(zhí)行設(shè)置地址操作、采用新地址后,把設(shè)備的狀態(tài)改為STALLED。而在處理的出口中調(diào)用Post0_Process()函數(shù),這個所做的工作是:SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);/將端點(diǎn)0的緩沖區(qū)大小設(shè)置為64字節(jié)if (pInformation->ControlState = STALLED)vSetEPRxStatus(EP_RX_STALL);vSetEPTxS

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論