STM32官方USB例程JoyStick詳解_第1頁
STM32官方USB例程JoyStick詳解_第2頁
STM32官方USB例程JoyStick詳解_第3頁
STM32官方USB例程JoyStick詳解_第4頁
STM32官方USB例程JoyStick詳解_第5頁
已閱讀5頁,還剩33頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

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

2、;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中的頭文件,。2上層結(jié)構(gòu)上層結(jié)構(gòu)總共5個文件:用于USB硬件配置、用于USB連接、斷開操作、直接處理USB中斷、用于上層協(xié)議處理,比方HID協(xié)議,大容量存儲設(shè)備協(xié)議、具體設(shè)備的相關(guān)描述符定義和處理??梢姡琒T的USB操作庫結(jié)構(gòu)十分清晰明了,我先不準(zhǔn)備直接閱讀源代碼。而是先利用MDK的軟件模擬器

3、仿真執(zhí)行,先了解一下設(shè)備初始化的流程。2、設(shè)備初始化所做的工作1Set_System(void)這個是main函數(shù)中首先調(diào)用的函數(shù),它位于hw_config.c文件中。它的主要功能是初始化時鐘系統(tǒng)、使能相關(guān)的外圍設(shè)備電源。配置了JoyStickMouse所用到的5個按鍵,并且配置了兩個EXTI中斷,一個是用于把USB從掛起模式喚醒,還有一個用途未知。2USB_Interrupts_Config();這個是main函數(shù)中調(diào)用的第二個函數(shù),它也位于hw_config.c文件中。主要功能是配置USB所用到的中斷。跟蹤到代碼中,主要設(shè)配置了USB低優(yōu)先級中斷和喚醒中斷,又有一個EXTI中斷功能未知。3

4、Set_USBClock()這個是main函數(shù)中調(diào)用的第三個函數(shù),它也位于hw_config.c文件中。它的功能是配置和使能USB時鐘。4USB_Init(void)這個是main函數(shù)中調(diào)用的第四個函數(shù),它也位于usb_init.c文件中。它初始化了三個全局指針,指向DEVICE_INFO、USER_STANDARD_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

5、= 2;pProperty = &Device_Property;pUser_Standard_Requests = &User_Standard_Requests;/* Initialize devices one by one */pProperty->Init();這三個結(jié)構(gòu)體都是與具體設(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,Joys

6、tick_Data_Setup,Joystick_NoData_Setup,Joystick_Get_Interface_Setting,Joystick_GetDeviceDescriptor,Joystick_GetConfigDescriptor,Joystick_GetStringDescriptor,0,0x40 /*MAX PACKET SIZE*/;USER_STANDARD_REQUESTS User_Standard_Requests =Joystick_GetConfiguration,Joystick_SetConfiguration,Joystick_GetInterf

7、ace,Joystick_SetInterface,Joystick_GetStatus,Joystick_ClearFeature,Joystick_SetEndPointFeature,Joystick_SetDeviceFeature,Joystick_SetDeviceAddress;Usb_init()函數(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)函

8、數(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 data from the uniqueID*/Get_SerialNum();/獲取設(shè)備序列號,轉(zhuǎn)變?yōu)閡nicode字符串pInformation->Current_Configuration = 0;/* Connect the device */PowerOn();/連接USB設(shè)備,實

9、質(zhì)是能讓主機(jī)檢測到了。/* USB interrupts initialization */_SetISTR(0);/* clear pending interrupts */wInterrupt_Mask = IMR_MSK;_SetCNTR(wInterrupt_Mask); /* set interrupts mask */bDeviceState = UNCONNECTED;實質(zhì)上,代碼執(zhí)行到這里,開發(fā)板已經(jīng)可以響應(yīng)主機(jī)發(fā)來的數(shù)據(jù)了。但我還是先把main函數(shù)的代碼看完吧。5SysTick_Config();這個函數(shù)調(diào)用主要是為程序中用到的精確延時作配置。3、進(jìn)入主循環(huán)進(jìn)入主循環(huán)的工作就

10、兩個:Joystick_Send(JoyState()。JoyState()用來獲取按鍵的狀態(tài)。Joystick_Send(JoyState()用來把按鍵狀態(tài)發(fā)到主機(jī)。當(dāng)然這里真正的發(fā)送工作并不是由該代碼完成的。它的工作只是將數(shù)據(jù)寫入IN端點緩沖區(qū),主機(jī)的IN令牌包來的時候,SIE負(fù)責(zé)把它返回給主機(jī)。主要代碼如下:UserToPMABufferCopy(Mouse_Buffer, GetEPTxAddr(ENDP1), 4);/從用戶復(fù)制四個字節(jié)到端點1緩沖區(qū),控制端點的輸入緩沖區(qū)。SetEPTxValid(ENDP1); /* enable endpoint for transmission

11、 */4、中斷處理過程大致理解1usb_istr()函數(shù)中的中斷處理簡單分析有用的代碼大概以下幾段,首先是處理復(fù)位的代碼,調(diào)用設(shè)備結(jié)構(gòu)中的復(fù)位處理函數(shù)。wIstr = _GetISTR();if (wIstr & ISTR_RESET & wInterrupt_Mask)_SetISTR(u16)CLR_RESET); /清復(fù)位中斷Device_Property.Reset();處理喚醒的代碼:if (wIstr & ISTR_WKUP & wInterrupt_Mask)_SetISTR(u16)CLR_WKUP);Resume(RESUME_EXTERNAL

12、);處理總線掛起的代碼:if (wIstr & ISTR_SUSP & wInterrupt_Mask)if (fSuspendEnabled) /* check if SUSPEND is possible */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(u16)CLR_SUSP);處理端點傳輸完成的代碼,這段

13、是最重要的,它調(diào)用底層usb_int.c文件中的CTR_LP函數(shù)來處理端點數(shù)據(jù)傳輸完成中斷。if (wIstr & ISTR_CTR & wInterrupt_Mask)CTR_LP(); /* servicing of the endpoint correct transfer 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

14、相關(guān)的的有三大塊:CPU內(nèi)部控制、中斷和端點控制存放器,掛起定時器這個好似是USB協(xié)議的要求,總線在一定時間內(nèi)沒有活動,SIE模塊能夠進(jìn)入SUSPEND狀態(tài)以節(jié)約電能,還有包緩沖區(qū)接口模塊。說到包緩沖區(qū)接口模塊,這個對應(yīng)的含義是,USB設(shè)備應(yīng)該提供USB包緩沖區(qū)。這塊緩沖區(qū)同時受到SIE和CPU核心的控制,用于CPU與SIE共享到達(dá)數(shù)據(jù)傳輸?shù)哪康?。所以CPU通過APB1總線接口訪問,SIE通過包緩沖區(qū)接口模塊訪問,中間通過Arbiter來協(xié)調(diào)訪問。當(dāng)然我們關(guān)注的中心點是控制、中斷和端點控制存放器。我們通過這些存放器來獲取總線傳輸?shù)臓顟B(tài),控制各個端點的狀態(tài),并可以產(chǎn)生中斷來讓CPU處理當(dāng)前的US

15、B事件。CPU可以通過APB1總線接口來訪問這些存放器。它們使用的都是PCLK1時鐘。2、USB模塊的存放器認(rèn)識1控制存放器CNTR傳輸完成中斷允許位。CTRM,1有效,如果SIE置位傳輸完成標(biāo)志,那么相應(yīng)的數(shù)據(jù)傳輸完成中斷發(fā)生。第15位包緩沖區(qū)溢出中斷允許位錯誤中斷允許位喚醒中斷允許位。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

16、位向主機(jī)發(fā)送的喚醒請求,RESUME。1有效,主機(jī)收到該信號,將喚醒設(shè)備。這個由軟件置位。第4位強(qiáng)制掛起控制,F(xiàn)SUSP。1有效。與由于總線無活動引起掛起的效果相同。低功耗模式。前提是先進(jìn)入掛起狀態(tài)。由軟件設(shè)置,一般又硬件復(fù)位被喚醒后自動清零。斷電模式控制位。PDWN。此位為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.PMA

17、OVR標(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的地址。3 USB設(shè)備地址存放器第7位,EF,USB模塊允許位。如果EF=0,那么USB模塊將停止工作。第6-0位。USB當(dāng)前使用的地址。復(fù)位時為0.4端點狀態(tài)和配置存放器,8個存放器,支持8個雙向端點和16個單向端點。 CTR_RX,正確接收標(biāo)志位。第15位。DTOG_RX,用于檢測的數(shù)據(jù)翻轉(zhuǎn)位。一般由硬件自動設(shè)置,軟件寫1可使其手動翻轉(zhuǎn)。STAT_RX,占據(jù)兩位

18、。00表示該端點不可用,無回應(yīng)。01表示響應(yīng)STALL10響應(yīng)NAK11表示端點有效,可接收數(shù)據(jù)。SETUP標(biāo)志。收到SETUP令牌包時置位。用戶收到數(shù)據(jù)后需檢查次位。第11位。EP_TYPE,兩位,表示端點類型。00表示批量端點。01表示控制端點10表示等時端點。11表示中斷端點。EP_KIND,端點特殊類型。在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表示該端點不可用,無回應(yīng)。01表示響應(yīng)STALL10響應(yīng)NAK

19、11表示端點有效,可發(fā)送數(shù)據(jù)。端點地址:EA【3:0】,說明該存放器對應(yīng)的端點號碼。比方1、2號存放器都可以對應(yīng)端點1在雙緩沖情況下。第3-0位。5端點描述符表相關(guān)存放器首先有一個描述符表地址存放器,指明了包緩沖區(qū)內(nèi)端點描述符表的地址。每一個端點都對應(yīng)一個描述附表。描述符表也在包緩沖區(qū)內(nèi)。每個端點存放器對應(yīng)的描述符表的地址可根據(jù)公式計算。單緩沖、雙向的端點描述符表有四項,每項占據(jù)兩個字節(jié):分別是端點n的發(fā)送緩沖區(qū)地址、發(fā)送字節(jié)數(shù)、接收緩沖區(qū)地址、接收字節(jié)數(shù)。了解USB相關(guān)存放器的知識以后,接下來就可以分析“JoyStickMouse詳細(xì)的工作過程了。三、USB的“JoyStickMouse工作

20、過程詳細(xì)分析1、初始化過程表達(dá)從main函數(shù)開始1Set_System(void)的工作過程由于這些代碼都是采用庫代碼,所以我主要分析每個代碼具體做了什么工作。有些常用、類似的代碼這里就不列出來了。先將RCC局部復(fù)位,系統(tǒng)使用內(nèi)部振蕩HSI,8MHzRCC_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_PLLC

21、onfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);系統(tǒng)時鐘采用PLL輸出RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);使能PWR控制,目的是為了控制CPU的低功耗模式;將所有輸入口初始化為模擬輸入GPIO_AINConfig();使能USB上拉控制GPIO端口的時鐘,這個端口設(shè)置為低電平時,USB外設(shè)會被集線器檢測到,并報告給主機(jī),這也是設(shè)備枚舉的開始;將這個端口的模式設(shè)置為開漏輸出;初始化上下左右四個按鍵為上下拉輸入;配置GPIOG8為EXTI8中斷輸入引腳,這個是在外部按鍵輸入引起中斷。配置EXTI18中斷。這個是

22、發(fā)生USB喚醒事件時用。EXTI_InitStructure.EXTI_Line = EXTI_Line18; / USB resume from suspend modeEXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);2USB_Interrupts_Config(void)的工作過程設(shè)置向量表位置在FLASH起始位置NVIC_SetVectorTable(NVIC_VectTab_F

23、LASH, 0x00);設(shè)置優(yōu)先級分組,1位用于搶占組級別。其余用于子優(yōu)先級NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);接下來配置、使能了三個中斷,包括USB低優(yōu)先級中斷、USB喚醒中斷EXTI18、和EXTI8按鍵控制中斷。它的優(yōu)先級設(shè)置有些問題,明明只有一位用于搶占優(yōu)先級。它把EXTI8的搶占優(yōu)先級設(shè)為2。結(jié)果在調(diào)試時發(fā)現(xiàn),它的搶占優(yōu)先級仍然是0。3Set_USBClock()的工作過程這個代碼就兩句話:RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);RCC_APB1PeriphClockCm

24、d(RCC_APB1Periph_USB, ENABLE);作用是設(shè)置并使能USB時鐘,從RCC輸出可以看到,USB時鐘是48MHz。4USB_Init()的工作過程void USB_Init(void)pInformation = &Device_Info;pInformation->ControlState = 2;pProperty = &Device_Property;/這個是設(shè)備本身支持的屬性和方法pUser_Standard_Requests = &User_Standard_Requests; /這個是主機(jī)請求的實現(xiàn)方法。pProperty->

25、Init(); /回調(diào)設(shè)備的初始化例程。這個主要是初始化了三個全局結(jié)構(gòu)體指針,pInformation說明當(dāng)前連接的狀態(tài)和信息,pProperty說明設(shè)備支持的方法,pUser_Standard_Requests是主機(jī)請求實現(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;/* wV

26、alue */u16_u8 USBwIndexs;/* wIndex */u16_u8 USBwLengths;/* wLength */u8 ControlState;/* of type CONTROL_STATE */u8 Current_Feature;u8 Current_Configuration;/* Selected configuration */u8 Current_Interface;/* Selected interface of current configuration */u8 Current_AlternateSetting;/* Selected Altern

27、ate Setting of currentinterface*/ENDPOINT_INFO Ctrl_Info;/端點信息結(jié)構(gòu)體DEVICE_INFO;最后調(diào)用pProperty->Init(),實質(zhì)就是調(diào)用Joystick_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(),而它先

28、調(diào)用USB_Cable_Config(ENABLE),這個函數(shù)實質(zhì)上將USB連接控制線設(shè)置為低電平,然后設(shè)備就可以檢測到設(shè)備了。當(dāng)集線器報告設(shè)備連接狀態(tài),并收到主機(jī)指令后,會復(fù)位USB總線,這需要一定的時間這段時間內(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,

29、模塊開始工作。_SetCNTR是一個宏,將wRegVal賦值給CNTR存放器,此時所有的中斷被屏蔽。再接下來兩句指令又將去除復(fù)位信號。然后去除所有的狀態(tài)位。_SetISTR(0);接下來是很關(guān)鍵的兩句話:wInterrupt_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ù)位中斷允許、且總線被集線

30、器復(fù)位的時候,固件程序進(jìn)入USB_LP中斷。中斷程序直接調(diào)用USB_Istr(void)程序。接下來講對中斷位進(jìn)行判斷:if (wIstr & ISTR_RESET & wInterrupt_Mask)_SetISTR(u16)CLR_RESET);/先去除復(fù)位中斷位Device_Property.Reset();/進(jìn)入設(shè)備定義的復(fù)位過程。實際上是調(diào)用JoyStick_Reset函數(shù)進(jìn)行處理。3JoyStick_Reset函數(shù)的處理。這里將一句句來分析:void Joystick_Reset(void)pInformation->Current_Configuration

31、 = 0;/當(dāng)前配置為0pInformation->Current_Interface = 0;/當(dāng)前接口為0pInformation->Current_Feature = Joystick_ConfigDescriptor7;/需要總線供電SetBTABLE(BTABLE_ADDRESS); /設(shè)置包緩沖區(qū)地址。SetEPType(ENDP0, EP_CONTROL);/端點0為控制端點SetEPTxStatus(ENDP0, EP_TX_STALL);/端點狀態(tài)為發(fā)送無效,也就是主機(jī)IN令牌包來的時候,回送一個STALL。SetEPRxAddr(ENDP0, ENDP0_RXA

32、DDR); /設(shè)置端點0描述符表,包括接收緩沖區(qū)地址、最大允許接收的字節(jié)數(shù)、發(fā)送緩沖區(qū)地址三個量。SetEPTxAddr(ENDP0, ENDP0_TXADDR); /這是發(fā)送緩沖區(qū)地址Clear_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);/使能端點0的接收,因為很快就要接收SETUP

33、令牌包后面跟著的數(shù)據(jù)包了。SetEPType(ENDP1, EP_INTERRUPT);/端點1為中斷端點。SetEPTxAddr(ENDP1, ENDP1_TXADDR); /設(shè)置發(fā)送緩沖區(qū)地址。SetEPTxCount(ENDP1, 4);/每次發(fā)送四個字節(jié)SetEPRxStatus(ENDP1, EP_RX_DIS);/接收禁止,只發(fā)送Mouse信息,而不從主機(jī)接收。SetEPTxStatus(ENDP1, EP_TX_NAK); /現(xiàn)在發(fā)送端點還不允許發(fā)送數(shù)據(jù)。bDeviceState = ATTACHED;/連接狀態(tài)改為已經(jīng)連接,默認(rèn)地址狀態(tài)。SetDeviceAddress(0);

34、 /地址默認(rèn)為0.復(fù)位中斷執(zhí)行完成后,開發(fā)板的USB接口能夠以默認(rèn)地址對主機(jī)來的數(shù)據(jù)包進(jìn)行響應(yīng)了。這個階段的分析到此結(jié)束,下一個階段就是正式分析代碼實現(xiàn)的枚舉過程了。四、USB的“JoyStickMouse工作過程詳細(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

35、); /* set interrupts mask */以上這兩句話將允許所有的USB中斷bDeviceState = UNCONNECTED;/設(shè)備狀態(tài)置位為未連接狀態(tài)。這里我不太理解。這時候即使復(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、端點0發(fā)出SETUP令牌包,首先端點0存放器的第11位SETUP位置位,說明收到了setup令牌包。由于此時端點0數(shù)據(jù)接收有效,所以接下來主機(jī)的請求數(shù)據(jù)包被SIE保存到端點0描述附表的 RxADD

36、R里面,收到的字節(jié)數(shù)保存到 RxCount里面。端點0存放器的CTR_RX被置位為1,ISTR的CTR置位為1,DIR=1,EP_ID=0,表示端點0接收到主機(jī)來的請求數(shù)據(jù)。此時設(shè)備已經(jīng)ACK主機(jī),將觸發(fā)正確傳輸完成中斷,下面就進(jìn)入中斷看一看。_SetISTR(u16)CLR_CTR); /*首先去除傳輸完成標(biāo)志 */EPindex = (u8)(wIstr & ISTR_EP_ID); /獲取數(shù)據(jù)傳輸針對的端點號。if (EPindex = 0)/如果是端點0,這里確實是端點0SaveRState = _GetEPRxStatus(ENDP0); /保存端點0狀態(tài),原本是有效狀態(tài)。S

37、aveTState = _GetEPTxStatus(ENDP0); _SetEPRxStatus(ENDP0, EP_RX_NAK); /在本次數(shù)據(jù)處理好之前,對主機(jī)發(fā)來的數(shù)據(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);r

38、eturn;Else/DIR=1時,要么是SETUP包,要么是OUT包。/這里先分析SETUP包。wEPVal = _GetENDPOINT(ENDP0);/獲取整個端點0狀態(tài)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);_SetEP

39、TxStatus(ENDP0, SaveTState);return;else if (wEPVal & EP_CTR_RX) != 0) /暫時不執(zhí)行的代碼先刪除掉。/* if(EPindex = 0) */后面處理其他端點的代碼就先不看了。/* while(.) */3Setup0_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); /這是取

40、得端點0接收緩沖區(qū)的起始地址。PMAAddr是包緩沖區(qū)起始地址,_GetEPRxAddr(ENDP0)獲得端點0描述符表里的接收緩沖區(qū)地址,為什么要乘以2呢?大概因為描述符表里地址項為16位,使用的是相對偏移。if (pInformation->ControlState != PAUSE)pInformation->USBbmRequestType = *pBuf.b+; /請求類型,說明方向和接收對象設(shè)備、接口還是端點此時為80,說明設(shè)備到主機(jī)pInformation->USBbRequest = *pBuf.b+; /* 請求代碼,第一次時應(yīng)該是6,說明主機(jī)要獲取設(shè)備描述

41、符。 */pBuf.w+;pInformation->USBwValue = ByteSwap(*pBuf.w+); /* wValue */pBuf.w+;/我覺得這里可能有些問題。pInformation->USBwIndex= ByteSwap(*pBuf.w+); /* wIndex */pBuf.w+; pInformation->USBwLength = *pBuf.w; /* wLength */pInformation->ControlState = SETTING_UP;if (pInformation->USBwLength = 0)NoDat

42、a_Setup0();elseData_Setup0();/這次是有數(shù)據(jù)傳輸?shù)模杂羞M(jìn)入該該函數(shù)。return Post0_Process();4Data_Setup0()函數(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

43、_DESCRIPTOR)CopyRoutine = pProperty->GetDeviceDescriptor; /獲取設(shè)備描述符的操作由用戶提供。if (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-&

44、gt;USBbmRequestType, 7)/此時為80/上面這個語句主要是判斷傳輸方向。如果為1,那么是設(shè)備到主機(jī)vu32 wLength = pInformation->USBwLength; 這個一般是64if (pInformation->Ctrl_Info.Usb_wLength > wLength)/設(shè)備描述符長度18pInformation->Ctrl_Info.Usb_wLength = wLength; /有些細(xì)節(jié)暫時先放著pInformation->Ctrl_Info.PacketSize = pProperty->MaxPacketS

45、ize;DataStageIn();/最主要是調(diào)用這個函數(shù)完成描述符的輸出準(zhǔn)備5DataStageIn()函數(shù)的執(zhí)行分析以下是主要執(zhí)行代碼:DataBuffer = (*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;

46、 等于0pEPinfo->Usb_wOffset += Length; 偏移到18vSetEPTxStatus(EP_TX_VALID); /使能端點發(fā)送,只要主機(jī)的IN令牌包一來,SIE就會將描述符返回給主機(jī)。USB_StatusOut();/* 這個實際上是使接收也有效,主機(jī)可取消IN。 */Expect_Status_Out:pInformation->ControlState = ControlState;6執(zhí)行流程返回到CTR_LP(void)_SetEPRxStatus(ENDP0, SaveRState);_SetEPTxStatus(ENDP0, SaveTStat

47、e);/由于vSetEPTxStatus(EP_TX_VALID)實際改變了SaveTState,所以此時端點發(fā)送已經(jīng)使能。return;7主機(jī)的IN令牌包獲取描述符的控制傳輸進(jìn)入第二階段,主機(jī)首先發(fā)一個IN令牌包,由于端點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ù),但是目

48、的只是期待主機(jī)的0狀態(tài)字節(jié)輸出了。if (ControlState = IN_DATA) | (ControlState = LAST_IN_DATA)第一次取設(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ī)收到1

49、8個字節(jié)的描述符后,進(jìn)入狀態(tài)事務(wù)過程,此過程的令牌包為OUT,字節(jié)數(shù)為0.只需要用戶回一個ACK。所以中斷處理程序會進(jìn)入Out0_Process。由于此時狀態(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è)置

50、地址1重新從復(fù)位狀態(tài)開始在第一次獲取設(shè)備描述符后,程序使端點0的發(fā)送和接收都無效,狀態(tài)也設(shè)置為STALLED,所以主機(jī)先發(fā)一個復(fù)位,使得端點0接收有效。雖然說在NAK和STALL狀態(tài)下,端點仍然可以響應(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,所做

51、的工作仍然是先填充pInformation結(jié)構(gòu),獲取請求特征碼、請求代碼和數(shù)據(jù)長度。由于設(shè)置地址不會攜帶數(shù)據(jù),所以接下來調(diào)用NoData_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令牌包,

52、設(shè)備返回0字節(jié)數(shù)據(jù)包,主機(jī)再ACK。它對應(yīng)的宏是這樣的:#define USB_StatusIn() Send0LengthData() /準(zhǔn)備發(fā)送0字節(jié)數(shù)據(jù)#define Send0LengthData() _SetEPTxCount(ENDP0, 0); vSetEPTxStatus(EP_TX_VALID); /設(shè)置發(fā)送有效,發(fā)送字節(jié)數(shù)為03設(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í)行以下代碼:e

53、lse if (ControlState = WAIT_STATUS_IN)if (pInformation->USBbRequest = SET_ADDRESS) &&(Type_Recipient=(STANDARD_REQUEST|DEVICE_RECIPIENT)SetDeviceAddress(pInformation->USBwValue0);pUser_Standard_Requests->User_SetDeviceAddress(); /這個函數(shù)就一個賦值語句,bDeviceState = ADDRESSED。 (*pProperty->

54、;Process_Status_IN)(); /這是一個空函數(shù)。ControlState = STALLED;執(zhí)行設(shè)置地址操作、采用新地址后,把設(shè)備的狀態(tài)改為STALLED。而在處理的出口中調(diào)用Post0_Process()函數(shù),這個所做的工作是:SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);/將端點0的緩沖區(qū)大小設(shè)置為64字節(jié)if (pInformation->ControlState = STALLED)vSetEPRxStatus(EP_RX_STALL);vSetEPTxStatus(EP_TX_STALL);將端點0的發(fā)送和接收都設(shè)置為:STALL,這種狀態(tài)下只接受SETUP令牌包。2、枚舉第三步:從新地址獲取設(shè)備描述符1上一階段

溫馨提示

  • 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

提交評論