版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、轉(zhuǎn)載:作者:追風(fēng)、USB的“ JoyStickMouse ”例程結(jié)構(gòu)分析1、例程的結(jié)構(gòu)(1)底層結(jié)構(gòu)包括5個(gè)文件: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 ”。在這個(gè) 頭文件中,又有以下定義:#in clude "usb_type.h"#i nclude "usb_regs.h"#in clude "usb_def.h"
2、#i nclude "usb_core.h"#in clude "usb_i ni t.h"#include "usb_mem.h"#include "usb_int.h"usb_lib.h 中又包含了七個(gè)頭文件,其中 usb_type.h中主要是用typedef為 stm32支持的數(shù)據(jù)類型取一些新的名稱。usb_def.h中主要是定義一些相關(guān)的數(shù) 據(jù)類型。還有一個(gè)未包含在usb_lib.h 中的頭文件,usb_conf.h用于USB設(shè)備的配置。(2)上層結(jié)構(gòu)上層結(jié)構(gòu)總共5個(gè)文件:hw_config.c (用于US
3、B硬件配置)、usb_pwr.c (用 于USB連接、斷開操作)、usb_istr.c (直接處理USB中斷)、usb_prop.c (用 于上層協(xié)議處理,比如 HID協(xié)議,大容量存儲(chǔ)設(shè)備協(xié)議)、usb_desc.c (具體 設(shè)備的相關(guān)描述符定義和處理)??梢姡琒T的USB操作庫(kù)結(jié)構(gòu)十分清晰明了,我先不準(zhǔn)備直接閱讀源代碼。而是 先利用MDK的軟件模擬器仿真執(zhí)行,先了解一下設(shè)備初始化的流程。2、設(shè)備初始化所做的工作(1)Set_System(void)這個(gè)是 main 函數(shù)中首先調(diào)用的函數(shù),它位于 hw_config.c 文件中。它的主要功 能是初始化時(shí)鐘系統(tǒng)、使能相關(guān)的外圍設(shè)備電源 。配置了
4、JoyStickMouse所用到的5個(gè)按鍵,并且配置了兩個(gè)exti中斷, 個(gè)是用于把USB從掛起模式喚醒,還有一個(gè)用途未知。2) U S B_ i nterrupts_Config();這個(gè)是 main 函數(shù)中調(diào)用的第二個(gè)函數(shù),它也位于 hw_config.c 文件中。主要功 能是配置USB所用到的中斷。跟蹤到代碼中,主要設(shè)配置了 USB氐優(yōu)先級(jí)中斷和喚醒中斷,又有一個(gè) EXTI中 斷功能未知。(3) Set_USBClock()這個(gè)是 main 函數(shù)中調(diào)用的第三個(gè)函數(shù),它也位于 hw_config.c 文件中。它的功 能是配置和使能USB寸鐘。4)USB_Init(void)這個(gè)是 main
5、 函數(shù)中調(diào)用的第四個(gè)函數(shù),它也位于 usb_init.c 文件中。它 初始 結(jié)構(gòu)體 后面兩個(gè)是函數(shù)指針結(jié)構(gòu)體,里面都是 USB青求實(shí)現(xiàn)、功能實(shí)現(xiàn)的函數(shù)指針 void USB_Init(void)化了三個(gè)全局指針,指向 DEVICE_INFOUSER_STANDARD_REQU和SDTESVVICE_PROPpInformation = &Device_Info;pInformation->ControlState = 2;pProperty = &Device_Property;pUser_Standard_Requests = &User_Standard_Re
6、quests;/* Initialize devices one by one */pProperty->Init();這三個(gè)結(jié)構(gòu)體都是與具體設(shè)備枚舉和功能實(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_Ge
7、tDeviceDescriptor,Joystick_GetConfigDescriptor, Joystick_GetStringDescriptor,0,0x40 /*MAX PACKET SIZE*/;USER_STANDARD_REQUESTS User_Standard_Requ=estsJoystick_GetConfiguration,Joystick_SetConfiguration,Joystick_GetInterface,Joystick_SetInterface,Joystick_GetStatus,Joystick_ClearFeature,Joystick_SetE
8、ndPointFeature,Joystick_SetDeviceFeature,Joystick_SetDeviceAddress;Usb_init() 函數(shù)調(diào)用 pProperty->Init() ( 實(shí)質(zhì)上就是 Joystick_init )完成設(shè) 備的初始化。上層程序調(diào)用下次函數(shù)是常規(guī)性的操作。 而下層函數(shù)( usb_init 相對(duì)于 usb_prop 是輸入底層操作文件)調(diào)用上層文件函數(shù)我們稱之為回調(diào)。回調(diào)函數(shù)的意義在于同一種操作模式、提供不同的回調(diào)函數(shù)則可以實(shí)現(xiàn)不同的 功能。Windows中處理消息,好像也用到了這種模式?;卣{(diào)函數(shù)的實(shí)現(xiàn)方法是函數(shù)指針數(shù)組。這是指針的高級(jí)應(yīng)用。
9、這是函數(shù)的代碼:void Joystick_init(void)/* Update the serial number string descriptor with the data from the uniqueID*/Get_SerialNum();/ 獲取設(shè)備序列號(hào),轉(zhuǎn)變?yōu)?unicode 字符串 pInformation->Current_Configuration = 0;/* Connect the device */PowerOn();/連接USB設(shè)備,實(shí)質(zhì)是能讓主機(jī)檢測(cè)到了。/* USB interrupts initialization */_SetISTR(0);/*
10、 clear pending interrupts */wInterrupt_Mask = IMR_MSK;_SetCNTR(wInterrupt_Mask); /* set interrupts mask */bDeviceState = UNCONNECTED;實(shí)質(zhì)上,代碼執(zhí)行到這里,開發(fā)板已經(jīng)可以響應(yīng)主機(jī)發(fā)來(lái)的數(shù)據(jù)了。但我還是 先把main ()函數(shù)的代碼看完吧。(5)SysTick_Config();這個(gè)函數(shù)調(diào)用主要是為程序中用到的精確延時(shí)作配置。3、進(jìn)入主循環(huán)進(jìn)入主循環(huán)的工作就兩個(gè):Joystick_Send(JoyState() 。JoyState() 用來(lái)獲取按鍵的狀態(tài)。Joys
11、tick_Send(JoyState() 用來(lái)把按鍵狀態(tài)發(fā)到主機(jī)。當(dāng)然這里真正的發(fā)送工 作并不是由該代碼完成的。 它的工作只是 將數(shù)據(jù)寫入 IN 端點(diǎn)緩沖區(qū), 主機(jī)的 IN 令牌包來(lái)的時(shí)候, SIE 負(fù)責(zé)把它返回給主機(jī)。主要代碼如下:UserToPMABufferCopy(Mouse_Buffer, GetEPTxAddr(ENDP1), 4) ;/ 從用戶復(fù)制四個(gè)字節(jié)到端點(diǎn) 1 緩沖區(qū),控制端點(diǎn)的輸入緩沖區(qū)。SetEPTxValid(ENDP1); /* enable endpoint for transmission */4、中斷處理過(guò)程大致理解( 1) usb_istr() 函數(shù)中的中斷
12、處理簡(jiǎn)單分析有用的代碼大概以下幾段,首先是處理復(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);處理總線掛起的代碼:if (wIstr & IS
13、TR_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);)文件中處理端點(diǎn)傳輸完成的代碼,這段是最重要的,它調(diào)用底層 usb_int.c 的CTR
14、_LP()函數(shù)來(lái)處理端點(diǎn)數(shù)據(jù)傳輸完成中斷。if (wIstr & ISTR_CTR & wInterrupt_Mask)CTR_LP(); /* servic ing of the en dpo int correct tran sfer in terrupt */二、STM32處理器的 USB接口1、接口模塊的內(nèi)部結(jié)構(gòu)在書上有一個(gè)很好的USB內(nèi)部接口模塊內(nèi)部結(jié)構(gòu)圖,比較好的解釋了各個(gè)模塊 之間的關(guān)系,我這里試著用我自己的理解闡述一下吧。首先在總線端(與D+ D-相連的那一端),通過(guò)模擬收發(fā)器與 SIE連接。SIE 使用48MHZ的專用時(shí)鐘。與SIE相關(guān)的的有三大塊:CPU內(nèi)部
15、控制、中斷和端點(diǎn)控制寄存器,掛起定時(shí)器 (這個(gè)好像是USB協(xié)議的要求,總線在一定時(shí)間內(nèi)沒(méi)有活動(dòng),SIE模塊能夠進(jìn)入 SUSPEN狀態(tài)以節(jié)約電能),還有 包緩沖區(qū)接口模塊。說(shuō)到包緩沖區(qū)接口模塊,這個(gè)對(duì)應(yīng)的含義是, USB設(shè)備應(yīng)該提供USB包緩沖區(qū)。 這塊緩沖區(qū)同時(shí)受到SIE和CPU核心的控制,用于CPU與 SIE共享達(dá)到數(shù)據(jù)傳 輸?shù)哪康?。所以CPU通過(guò)APB1總線接口訪問(wèn),SIE通過(guò)包緩沖區(qū)接口模塊訪問(wèn),中間通過(guò)Arbiter 來(lái)協(xié)調(diào)訪問(wèn)。當(dāng)然我們關(guān)注的中心點(diǎn)是控制、中斷和端點(diǎn)控制寄存器。我們通過(guò)這些寄存器 來(lái)獲取總線傳輸?shù)臓顟B(tài),控制各個(gè)端點(diǎn)的狀態(tài),并可以產(chǎn)生中斷來(lái)讓CPU處理當(dāng)前的USB事件。
16、CPU可以通過(guò)APB1總線接口來(lái)訪問(wèn)這些寄存器。它們使用的都是PCLK1時(shí)鐘。2、USB模塊的寄存器認(rèn)識(shí)(1)控制寄存器CNTR傳輸完 成中斷包緩沖 區(qū)溢出錯(cuò)誤中 斷允許喚醒中斷 允許位。掛起中 斷允許復(fù)位中斷 允許位。幀首中 斷允許期望幀 首中斷允許位。中斷允位WKUPM1位。RESETM1位允許位。CTRM 1許位有效,如SUSPM1有效,軟ESOFM有效,如果喚醒請(qǐng)有效,當(dāng)件強(qiáng)制復(fù)它的含果SIE求標(biāo)志位總線掛位和總線義是沒(méi)置位傳置位,則起標(biāo)志復(fù)位信有收到輸完成產(chǎn)生喚醒置位時(shí),號(hào),都能幀首信標(biāo)志,則中斷。發(fā)生掛觸發(fā)復(fù)位號(hào),允許相應(yīng)的起中斷。中斷。發(fā)生中數(shù)據(jù)傳斷。輸完成中斷發(fā)第8位生。第15
17、位向主機(jī)發(fā) 送的喚醒 請(qǐng)求,RESUME 有效,主 機(jī)收到該 信號(hào),將 喚醒設(shè) 備。這個(gè) 由軟件置 位。強(qiáng)制掛 起控制,F(xiàn)SUSP 1 有效。與 由于總 線無(wú)活 動(dòng)引起 掛起的 效果相 同。低功耗模 式。前提 是先進(jìn)入 掛起狀 態(tài)。由軟 件設(shè)置, 一般又硬 件復(fù)位(被喚醒 后自動(dòng)清 零)。斷電模 式控制 位。PDWZN此位為1時(shí),USB 模塊關(guān) 閉。強(qiáng)制復(fù) 位控制。FRES 與總線上 的復(fù)位 信號(hào)產(chǎn) 生相同 的效果。 也能產(chǎn) 生復(fù)位 中斷第0位。(2)中斷狀態(tài)寄存器ISTR這個(gè)寄存器主要是 反映USB模塊當(dāng)前的狀態(tài)的。第15-8為與控制寄存器的中斷 允許是意義對(duì)應(yīng)的。相應(yīng)的標(biāo)志位置位,且中斷未
18、屏蔽,則向 CPU發(fā)出對(duì)應(yīng)的 中斷。CTR標(biāo) 志,數(shù)據(jù) 傳輸完 成后硬 件置1.PMAOV標(biāo)ERF標(biāo)WKU請(qǐng)求,總線 檢測(cè)到 主機(jī)喚 醒請(qǐng)求 時(shí)由硬SUSP請(qǐng)求標(biāo)志 位。RESET 青求標(biāo)志 位。SOF幀首標(biāo)志ESOF 期待幀首 標(biāo)志。件置位。DIR傳輸方向,此 位由硬件控制。IN 時(shí)為0, OUT為1.第4位。發(fā)生數(shù)據(jù)傳輸?shù)亩它c(diǎn)的地址。(3) USB設(shè)備地址寄存器第7位,EF, USB模塊允許位。如果EF=O,則USB模塊將停止工作。第6-0位。USB當(dāng)前使用的地址。復(fù)位時(shí)為0.(4)端點(diǎn)狀態(tài)和配置寄存器,8個(gè)寄存器,支持8個(gè)雙向端點(diǎn)和16個(gè)單向端點(diǎn)。CTR_RX正確接收 標(biāo)志位。第15位。
19、DTOG_R刈 于檢測(cè) 的數(shù)據(jù)翻轉(zhuǎn)位。一 般由硬件自動(dòng)設(shè) 置,軟件寫1可使 其手動(dòng)翻轉(zhuǎn)。STAT_R,占據(jù)兩位。00表示該端點(diǎn)不可用,無(wú)回應(yīng)。01表示響應(yīng)STALL10響應(yīng)NAK11表示端點(diǎn)有效,可接收數(shù)據(jù)。SETUPS志。收到 SETUP令牌包時(shí)置 位。用戶收到數(shù)據(jù) 后需檢查次位。第11位。EP_TYPE兩位,表示端點(diǎn)類型。00表示批量端點(diǎn)。01表示控制端點(diǎn)10表示等時(shí)端點(diǎn)。11表示中斷端點(diǎn)。EP_KIND端點(diǎn)特殊 類型。在EP_TYPE=0 時(shí),表 示設(shè)備期望主機(jī)的0字節(jié)狀態(tài)包。CTR_TX止確發(fā)送標(biāo)志。主DTOG_Tffl于檢測(cè) 的數(shù)據(jù)翻轉(zhuǎn)位。一 般由硬件自動(dòng)設(shè) 置,軟件寫1可使STAT
20、_TX占據(jù)兩位。00表示該端點(diǎn)不可用,無(wú)回應(yīng)。機(jī)的IN包之后。第7位。其手動(dòng)翻轉(zhuǎn)。01表示響應(yīng)STALL10響應(yīng)NAK11表示端點(diǎn)有效,可發(fā)送數(shù)據(jù)。端點(diǎn)地址:EA【3: 0】,表明該寄存器對(duì)應(yīng)的端點(diǎn)號(hào)碼。比如1、2號(hào)寄存器都可以對(duì)應(yīng)端點(diǎn)1 (在雙緩沖情況下)。第3-0位。(5)端點(diǎn)描述符表相關(guān)寄存器首先有一個(gè)描述符表地址寄存器,指明了包緩沖區(qū)內(nèi)端點(diǎn)描述符表的地址。每一個(gè)端點(diǎn)都對(duì)應(yīng)一個(gè)描述附表。描述符表也在包緩沖區(qū)內(nèi)。每個(gè)端點(diǎn)寄存器 對(duì)應(yīng)的描述符表的地址可根據(jù)公式計(jì)算。單緩沖、雙向的端點(diǎn)描述符表有四項(xiàng),每項(xiàng)占據(jù)兩個(gè)字節(jié):分別是端點(diǎn) n的發(fā) 送緩沖區(qū)地址、發(fā)送字節(jié)數(shù)、接收緩沖區(qū)地址、接收字節(jié)數(shù)。了
21、解usb相關(guān)寄存器的知識(shí)以后,接下來(lái)就可以分析“ JoyStickMouse ”詳細(xì)的工作過(guò)程了。三、USB的“ JoyStickMouse ”工作過(guò)程詳細(xì)分析1、初始化過(guò)程敘述從main ()函數(shù)開始(1) Set_System(void)的工作過(guò)程由于這些代碼都是采用庫(kù)代碼,所以我主要分析每個(gè)代碼具體做了什么工作。 有些常用、類似的代碼這里就不列出來(lái)了。先將RCC部分復(fù)位,系統(tǒng)使用內(nèi)部振蕩 HSI, 8MHRCC_Delnit(); 使能 HSE RCC_HSEConfig(RCC_HSE_ON);設(shè)置 HCLK = SYSCLK RCC_HCLKConfig(RCC_SYSCLK_Div
22、1); 設(shè)置 PCLK2,PCLK1 RCC_PCLK2Config(RCC_HCLK_Div1);設(shè)置PLL,使能PL PLL采用HSE輸出=HSE X 9;RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);系統(tǒng)時(shí)鐘采用PLL輸出一一 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);使能PWR控制,目的是為了控制CPU勺低功耗模式; 將所有輸入口初始化為模擬輸入 GPIO_AINConfig();使能USB上拉控制GPIO端口的時(shí)鐘,這個(gè)端口設(shè)置為低電平時(shí),USB外設(shè)會(huì)被 集線器檢測(cè)到,并報(bào)告給主機(jī),這
23、也是設(shè)備枚舉的開始;將這個(gè)端口的模式設(shè)置為開漏輸出; 初始化上下左右四個(gè)按鍵為上下拉輸入;配置GPIOG8為EXTI8中斷輸入引腳,這個(gè)是在外部按鍵輸入引起中斷。配置EXTI18中斷。這個(gè)是發(fā)生USB喚醒事件時(shí)用。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_Init
24、Structure);(2) USB_Interrupts_Config(void)的工作過(guò)程設(shè)置向量表位置在FLASH起始位置NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x00); 設(shè)置優(yōu)先級(jí)分組, 1 位用于搶占組級(jí)別。其余用于子優(yōu)先級(jí) NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);接下來(lái)配置、使能了三個(gè)中斷,包括USB氐優(yōu)先級(jí)中斷、USB喚醒中斷(EXTI18)、 和EXTI8 (按鍵控制)中斷。它的優(yōu)先級(jí)設(shè)置有些問(wèn)題,明明只有一位用于搶占優(yōu)先級(jí)。它把EXTI8的搶占優(yōu)先級(jí)設(shè)為 2 。結(jié)果在調(diào)試時(shí)發(fā)現(xiàn),
25、它的搶占優(yōu)先級(jí)仍然是 0。(3) Set_USBClock() 的工作過(guò)程這個(gè)代碼就兩句話:RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);作用是設(shè)置并使能USB寸鐘,從RCC俞出可以看到,USB寸鐘是48MHz(4) USB_Init() 的工作過(guò)程void USB_Init(void)pInformation = &Device_Info;pInformation->ControlState = 2;pProperty = &a
26、mp;Device_Property;/ 這個(gè)是設(shè)備本身支持的屬性和方法pUser_Standard_Requests = &User_Standard_Requests; / 這個(gè)是主機(jī)請(qǐng)求的 實(shí)現(xiàn)方法。pProperty->Init();/ / 回調(diào)設(shè)備的初始化例程。這個(gè)主要是初始化了三個(gè)全局結(jié)構(gòu)體指針, pInformation 表明當(dāng)前連接的狀態(tài) 和信息, pProperty 表明設(shè)備支持的方法, pUser_Standard_Requests 是主機(jī)請(qǐng) 求實(shí)現(xiàn)的函數(shù)指針數(shù)組。Device_Info 是一個(gè)結(jié)構(gòu)體,包括 11 個(gè)成員變量。這里是將它的 ControlSta
27、te 設(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 */ u8 Current_Feature; u8 Current_Configuration;/*
28、 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() ,實(shí)質(zhì)就是調(diào)用 Joystick_init(void) 。 在這個(gè)函數(shù)中,首先獲取設(shè)備版本,并轉(zhuǎn)換為 Uni
29、code 存入版本號(hào)字符串 Get_SerialNum();設(shè)備當(dāng)前配置置為0。然后調(diào)用PowerOn(),這個(gè)函數(shù)實(shí)質(zhì)上將D+上拉,此時(shí) USE設(shè)備就能被集線器檢測(cè)到了。 因此分析進(jìn)入下一個(gè)流程。2、進(jìn)入設(shè)備檢測(cè)狀態(tài)( 1)在 PowerOn() 中執(zhí)行的情況。在 USB_init ()中調(diào)用 PowerOn(),而它 先調(diào)用 USB_Cable_Config(ENABLE, 這個(gè)函數(shù)實(shí)質(zhì)上將USB4接控制線設(shè)置為低電平,然后設(shè)備就可以檢測(cè)到設(shè)備 了。當(dāng)集線器報(bào)告設(shè)備連接狀態(tài),并收到主機(jī)指令后,會(huì)復(fù)位 USB總線,這需要一 定的時(shí)間(這段時(shí)間內(nèi)設(shè)備應(yīng)該準(zhǔn)備好處理復(fù)位指令)。但是現(xiàn)在 設(shè)備初始
30、化 程序?qū)⒗^續(xù)往下進(jìn)行,因?yàn)樗€沒(méi)有使能復(fù)位中斷。wRegVal = CNTR_FRES;_SetCNTR(wRegVal);/這句話實(shí)際上使能了 USB模塊的電源,因?yàn)樯想姀?fù)位時(shí),CNTR寄存器的斷電 控制為PDW位是1模塊是斷電的。這句話雖然將強(qiáng)制復(fù)位USE模塊,但由于復(fù)位中斷允許位沒(méi)有使能,不會(huì)引起 復(fù)位中斷,而間接上由使 PDWN=0模塊開始工作。_SetCNTR是一個(gè)宏,將wRegVal賦值給CNTR寄存器,此時(shí)所有的中斷被屏蔽。再接下來(lái)兩句指令又將清除復(fù)位信號(hào)。然后清除所有的狀態(tài)位。 _SetISTR(0);接下來(lái)是很關(guān)鍵的兩句話:wInterrupt_Mask= CNTR_RES
31、ETM| CNTR_SUSPM | CNTR_WKUPM;_SetCNTR(wInterrupt_Mask);后面一個(gè)語(yǔ)句執(zhí)行后,復(fù)位中斷已經(jīng)被允許,而此時(shí)集線器多半已經(jīng)開始復(fù)位 端口了?;蛘哒f(shuō)稍微有限延遲,設(shè)備固件還能繼續(xù)初始化一些部件,但已經(jīng)不 會(huì)影響整個(gè)工作流程了。所以接下來(lái), 分析直接進(jìn)入復(fù)位中斷。(2) 復(fù)位中斷的處理。當(dāng)復(fù)位中斷允許、且總線被集線器復(fù)位的時(shí)候,固件程序進(jìn)入U(xiǎn)SB_L沖斷。中斷程序直接調(diào)用 USB_Istr(void) 程序。接下來(lái)講對(duì)中斷位進(jìn)行判斷:if (wIstr & ISTR_RESET & wInterrupt_Mask)_SetISTR(u
32、16)CLR_RESET);/ 先清除復(fù)位中斷位Device_Property.Reset();/ 進(jìn)入設(shè)備定義的復(fù)位過(guò)程。實(shí)際上是調(diào)用 JoyStick_Reset ()函數(shù)進(jìn)行處理 (3) JoyStick_Reset ()函數(shù)的處理。這里將一句句來(lái)分析:void Joystick_Reset(void)pInformation->Current_Configuration = 0;/ 當(dāng)前配置為 0pInformation->Current_Interface = 0;/ 當(dāng)前接口為 0 pInformation->Current_Feature = Joystick_
33、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ā)送無(wú)效,也就是主機(jī) IN 令牌包來(lái)的時(shí)候,回送一個(gè) STALL。SetEPRxAddr(ENDP0, ENDP0_RXADDR); /設(shè)/ 置端點(diǎn) 0 描述符表,包括接收緩沖 區(qū)地址、最大允許接收的字節(jié)數(shù)、發(fā)送緩沖區(qū)地址三個(gè)量。SetEPTxAddr(ENDP0, ENDP0_TXADDR); /這/ 是發(fā)送緩
34、沖區(qū)地址Clear_Status_Out(ENDP0);/清除EP_KIND勺STATUS_OUtt,如果改位被設(shè)置,在控制模式下只對(duì) 0字節(jié) 數(shù)據(jù)包相應(yīng)。其它的都返回 STALL主要用于控制傳輸?shù)臓顟B(tài)過(guò)程。SetEPRxCount(ENDP0, Device_Property.MaxPacketSize); / 接收緩沖區(qū)支持64 個(gè)字節(jié)。SetEPRxValid(ENDP0);/使能端點(diǎn)0的接收,因?yàn)楹芸炀鸵邮誗ETUP令牌包后面跟著的數(shù)據(jù)包了SetEPType(ENDP1, EP_INTERRUPT);/ / 端點(diǎn) 1 為中斷端點(diǎn) 。SetEPTxAddr(ENDP1, ENDP1_T
35、XADDR); /設(shè)/ 置發(fā)送緩沖區(qū)地址SetEPTxCount(ENDP1, 4);/ 每次發(fā)送四個(gè)字節(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)地址對(duì)主機(jī)來(lái)的數(shù)據(jù)包進(jìn)行響應(yīng)了 。這個(gè)階段的分析到此結(jié)束,下一個(gè)階段就是正式分析
36、 代碼實(shí)現(xiàn)的枚 舉過(guò)程了。四、USB的“ JoyStickMouse ”工作過(guò)程詳細(xì)分析1、枚舉第一步:獲取設(shè)備的描述符從 USB_init ()開始(1)先要允許數(shù)據(jù)傳輸完成中斷在poweron ()函數(shù)后面緊跟著幾句話:PowerOn();/ 這句執(zhí)行完,設(shè)備被主機(jī)檢測(cè)到,并且能夠響應(yīng)復(fù)位中斷了_SetISTR(0);/* clear pending interrupts */ wInterrupt_Mask = IMR_MSK;_SetCNTR(wInterrupt_Mask); /* set interrupts mask */以上這兩句話將允許所有的 USB中斷 bDeviceSta
37、te = UNCONNECTED;/ 設(shè)備狀態(tài)置位為未連接狀態(tài)。這里我不太理解。這時(shí)候 即使復(fù)位中斷未發(fā)生, 最起碼設(shè)備已經(jīng)算是連接入總線了,為什么這個(gè)狀態(tài)還要設(shè)置為“未連接”呢?2)主機(jī)獲取描述符 主機(jī)進(jìn)入控制傳輸?shù)牡谝浑A段: 建立事務(wù),發(fā) setup 令牌包、發(fā)請(qǐng)求數(shù)據(jù)包、 設(shè)備發(fā)ACK包。主機(jī)發(fā)出對(duì)地址0、端點(diǎn)0發(fā)出SETUPS牌包,首先端點(diǎn)0寄存器的第11位SETUP 位 置位,表明收到了 setup 令牌包。由于此時(shí)端點(diǎn) 0 數(shù)據(jù)接收有效,所以接下來(lái)主機(jī)的 請(qǐng)求數(shù)據(jù)包被 SIE 保存到端 點(diǎn)0描述附表的RxADDF里面,收到的字節(jié)數(shù)保存到 RxCount里面。端點(diǎn)0寄存器的CTR_R
38、被置位為1,ISTR的CTR置位為1,DIR=1,EP_ID=0, 表示端點(diǎn)0接收到主機(jī)來(lái)的請(qǐng)求數(shù)據(jù)。此時(shí)設(shè)備已經(jīng) ACK主機(jī),將觸發(fā)正確傳 輸完成中斷,下面就進(jìn)入中斷看一看。_SetISTR(u16)CLR_CTR); /* 首先清除傳輸完成標(biāo)志 * /EPindex = (u8)(wIstr & ISTR_EP_ID); / 獲取數(shù)據(jù)傳輸針對(duì)的端點(diǎn)號(hào) 。if (EPindex = 0)/ 如果是端點(diǎn) 0,這里的確是端點(diǎn) 0SaveRState = _GetEPRxStatus(ENDP0); / 保存端點(diǎn) 0狀態(tài),原本是有效狀態(tài)。SaveTState = _GetEPTxStatu
39、s(ENDP0);_SetEPRxStatus(ENDP0, EP_RX_NAK); / 在本次數(shù)據(jù)處理好之前,對(duì)主機(jī)發(fā)來(lái) 的數(shù)據(jù)包以NAK回應(yīng)_SetEPTxStatus(ENDP0, EP_TX_NAK);if (wlstr & 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時(shí),要么是SE
40、TUP包,要么是 OUT包/這里先分析SETUP包 wEPVal = _GetENDPOINT(ENDP0);/ 獲取整個(gè)端點(diǎn) 0 狀態(tài)if (wEPVal & EP_CTR_TX) != 0) / 這種情況一般不太可能,/ 如果出現(xiàn)表示同時(shí) TX 和 RX 同時(shí)置位else if (wEPVal &EP_SETUP) != 0) / 我們的程序會(huì)執(zhí)行到這里_ClearEP_CTR_RX(ENDP0);Setup0_Process();/ 主要是調(diào)用該程序來(lái)處理主機(jī)請(qǐng)求。_SetEPRxStatus(ENDP0, SaveRState);_SetEPTxStatus(ENDP0
41、, SaveTState);return;else if (wEPVal & EP_CTR_RX) != 0) /暫時(shí)不執(zhí)行的代碼先刪除掉/* if(EPindex = 0) */后面處理其他端點(diǎn)的代碼就先不看了。/* while(.) */(3) Setup0_Process() 函數(shù)的執(zhí)行分析這個(gè)函數(shù)執(zhí)行的時(shí)候,主機(jī)發(fā)來(lái)的請(qǐng)求數(shù)據(jù)包已經(jīng)存在于RxADD緩沖區(qū)了。大部分的標(biāo)志位已經(jīng)清除,除了 SETUP位,這個(gè)味將由下一個(gè)令牌包自動(dòng)清除。進(jìn)入處理函數(shù):pBuf.b = PMAAddr + (u8 *)(_GetEPRxAddr(ENDP0) * 2); /這是取得端點(diǎn) 0接收緩沖區(qū)的
42、起始地址。PMAAdd是包緩沖區(qū)起始地址,_GetEPRxAddr(ENDPC獲得端點(diǎn)0描述符表里的 接收緩沖區(qū)地址,為什么要乘以 2呢?大概因?yàn)槊枋龇砝锏刂讽?xiàng)為 16 位,使 用的是相對(duì)偏移。if (pInformation->ControlState != PAUSE) pInformation->USBbmRequestType = *pBuf.b+; / 請(qǐng)求類型,表明方向和接 收對(duì)象(設(shè)備、接口還是端點(diǎn))此時(shí)為 80,表明設(shè)備到主機(jī) pInformation->USBbRequest = *pBuf.b+; /* 請(qǐng)求代碼,第一次時(shí)應(yīng)該是 6, 表明主機(jī)要獲取設(shè)備
43、描述符。 */ pBuf.w+;pInformation->USBwValue = ByteSwap(*pBuf.w+); /* wValue */ pBuf.w+;/ 我覺(jué)得這里可能有些問(wèn)題pInformation->USBwIndex= ByteSwap(*pBuf.w+); /* wIndex */pBuf.w+;pInformation->USBwLength = *pBuf.w; /* wLength */pInformation->ControlState = SETTING_UP;if (pInformation->USBwLength = 0)No
44、Data_Setup0();elseData_Setup0();/ 這次是有數(shù)據(jù)傳輸?shù)?,所以有進(jìn)入該該函數(shù)。return Post0_Process();(4) Data_Setup0() 函數(shù)的執(zhí)行分析CopyRoutine = NULL; / 這是一個(gè)函數(shù)指針,由用戶提供。wOffset = 0;if (Request_No = GET_DESCRIPTOR) / / 如果是獲取設(shè)備描述符if(Type_Recipient=(STANDARD_REQUEST| EVICE_RECIPIENT)u8 wValue1 = pInformation->USBwValue1;if (wVal
45、ue1 = DEVICE_DESCRIPTOR)CopyRoutine = pProperty->GetDeviceDescriptor; / 獲取設(shè)備描述符的操作由用戶提供。if (CopyRoutine)pInformation->Ctrl_Info.Usb_wOffset = wOffset;pInformation->Ctrl_Info.CopyData = CopyRoutine;(*CopyRoutine)(0); /這個(gè)函數(shù)這里調(diào)用的目的只是設(shè)置了 pInformation 中需要寫入的描述符的長(zhǎng)度。Result = USB_SUCCESS;USBbmReque
46、stTyp,e7)if (ValBit(pInformation-> / 此時(shí)為 80/ 上面這個(gè)語(yǔ)句主要是判斷傳輸方向。如果為 1,則是設(shè)備到主機(jī)vu32 wLength = pInformation->USBwLength; 這個(gè)一般是 64 if (pInformation-> Ctrl_Info.Usb_wLength > wLength)/ 設(shè)備描述符長(zhǎng)度 18 pInformation->Ctrl_Info.Usb_wLength = wLength;/ 有些細(xì)節(jié)暫時(shí)先放著pInformation->Ctrl_Info.PacketSize =
47、pProperty->MaxPacketSize;DataStageIn();/ 最主要是調(diào)用這個(gè)函數(shù)完成描述符的輸出準(zhǔn)備(5) DataStageIn() 函數(shù)的執(zhí)行分析以下是主要執(zhí)行代碼:DataBuffer = (*pEPinfo->CopyData)(Length); / 這個(gè)是取得用戶描述符緩沖 區(qū)的地址。這里共 18 個(gè)字節(jié)UserToPMABufferCopy(DataBuffer, GetEPTxAddr(ENDP0), Length);/ 這個(gè)函 數(shù)將設(shè)備描述符復(fù)制到用戶的發(fā)送緩沖區(qū)。SetEPTxCount(ENDP0, Length);/ / 設(shè)置發(fā)送字節(jié)的數(shù)
48、目、 18pEPinfo->Usb_wLength -= Length;等于 0pEPinfo->Usb_wOffset += Length;偏移到 18vSetEPTxStatus(EP_TX_VALID); / 使能端點(diǎn)發(fā)送,只要主機(jī)的 IN 令牌包一來(lái), SIE 就會(huì)將描述符返回給主機(jī)。USB_StatusOut();/ * 這個(gè)實(shí)際上是使接收也有效,主機(jī)可取消IN。 */Expect_Status_Out: pInformation->ControlState = ControlState;( 6)執(zhí)行流程返回到CTR_LP(void)_SetEPRxStatus(E
49、NDP0, SaveRState);_SetEPTxStatus(ENDP0, SaveTState);/ 由于 vSetEPTxStatus(EP_TX_VALID)實(shí)際改變了 SaveTState,所以此時(shí)端點(diǎn) 發(fā)送已經(jīng)使能。return;7)主機(jī)的 IN 令牌包 獲取描述符的控制傳輸進(jìn)入第二階段, 主機(jī)首先發(fā)一個(gè) IN 令牌包,由于端點(diǎn) 0 發(fā)送有效, SIE 將數(shù)據(jù)返回主機(jī)。主機(jī)方返回一個(gè)ACK后,主機(jī)發(fā)送數(shù)據(jù)的CTR標(biāo)志置位,DIR=O, EP_ID=O,表 明主機(jī)正確收到了用戶發(fā)過(guò)去的描述符。固件程序由此進(jìn)入中斷。此時(shí)是由 IN 引起的。主要是調(diào)用 InO_Process() 完成
50、剩下的工作。( 7)追蹤進(jìn)入函數(shù) InO_Process()此時(shí)實(shí)際上設(shè)備返回描述符已經(jīng)成功了。這一次還是調(diào)用 DataStageIn() 函數(shù),但是目的只是期待主機(jī)的O 狀態(tài)字節(jié)輸出了。if (ControlState = IN_DATA) | (ControlState = LAST_IN_DATA ) 第一次取設(shè)備描述符只取一次 。DataStageIn();/此次調(diào)用后,當(dāng)前狀態(tài)變成 WAIT_STATUS_O,U表明設(shè)備等待狀態(tài)過(guò)程,主機(jī) 輸出 O 字節(jié)。/* Con trolState may be cha nged outside the fun ctio n */Control
51、State = pInformation->ControlState; 返回時(shí)調(diào)用 PostO_Process(void) 函數(shù),這個(gè)函數(shù)沒(méi)做什么事。8)進(jìn)入狀態(tài)過(guò)程 主機(jī)收到 18 個(gè)字節(jié)的描述符后,進(jìn)入狀態(tài)事務(wù)過(guò)程, 此過(guò)程的令牌包為 OUT, 字節(jié)數(shù)為 0. 只需要用戶回一個(gè) ACK。所以中斷處理程序會(huì)進(jìn)入 Out0_Process ()。由于此時(shí)狀態(tài)為 WAIT_STATUS_O,所以執(zhí)行以下這段。else if (ControlState = WAIT_STATUS_OUT)(*pProperty->Process_Status_OUT)();/ 這是個(gè)空函數(shù),什么也不做
52、。ControlState = STALLED;/ 狀態(tài)轉(zhuǎn)為 STALLED。獲取設(shè)備描述符后,主機(jī)再一次復(fù)位設(shè)備。設(shè)備又進(jìn)入初始狀態(tài) 。五、USB的“ JoyStickMouse ”工作過(guò)程詳細(xì)分析1、枚舉第二步:設(shè)置地址(1) 重新從復(fù)位狀態(tài)開始在第一次獲取設(shè)備描述符后,程序使端點(diǎn) 0的發(fā)送和接收都無(wú)效,狀態(tài)也設(shè)置為STALLED所以主機(jī)先發(fā)一個(gè)復(fù)位,使得端點(diǎn) 0接收有效。雖然說(shuō)在NAK和 STALL狀態(tài)下,端點(diǎn)仍然可以響應(yīng)和接收 SETUP包o(2) 設(shè)置地址的建立階段:主機(jī)先發(fā)一個(gè)SETU令牌包,設(shè)備端EP0的SETUP標(biāo)志置位。然后主機(jī)發(fā)了一 個(gè)OUT包,共8個(gè)字節(jié),里面包含設(shè)置地址
53、的要求。設(shè)備在檢驗(yàn)數(shù)據(jù)后,發(fā)一個(gè) ACK握手包。同時(shí)CTR_R;置位,CTF置位。數(shù)據(jù)已 經(jīng)保存到RxADD所指向的緩沖區(qū)。此時(shí) USBT生數(shù)據(jù)接收中斷。由于CTR_R刑SETUP同時(shí)置位,終端處理程序調(diào)用 SetupO_Process(),所做 的工作仍然是先 填充 pInformation 結(jié)構(gòu),獲取請(qǐng)求特征碼、請(qǐng)求代碼和數(shù)據(jù)長(zhǎng) 度。由于設(shè)置地址不會(huì)攜帶數(shù)據(jù),所以接下來(lái)調(diào)用NoData_SetupO()。執(zhí)行以下代碼:else if (RequestNo = SET_ADDRESS)Result = USB_SUCCESS;說(shuō)明設(shè)置地址沒(méi)有做任何工作。ControlState = WAIT
54、_STATUS_IN ;/* After no data stage SETUP */USB_Statusln(); /這句話是一個(gè)關(guān)鍵,它是一個(gè)宏,實(shí)際是準(zhǔn)備好發(fā)送0字節(jié)的狀態(tài)數(shù)據(jù)包。因?yàn)榈刂吩O(shè)置沒(méi)有數(shù)據(jù)過(guò)程, 建立階段后直接進(jìn)入狀態(tài)階段, 主機(jī)發(fā) lN 令牌包,設(shè)備返回 0字節(jié)數(shù)據(jù)包,主機(jī)再 ACK。它對(duì)應(yīng)的宏是這樣的:#define USB_Statusln() Send0LengthData() / 準(zhǔn)備發(fā)送 0字節(jié)數(shù)據(jù) vSetEPTxStatus(EP_TX_VALlD); / 設(shè)置發(fā)送有效,發(fā)送字節(jié)數(shù)為 03)設(shè)置地址的狀態(tài)階段: 而前面把狀態(tài)設(shè)置為WAIT_STATUS_I是給
55、IN令牌包的處理提供指示。因?yàn)榻?立階段結(jié)束以后, 主機(jī)接著發(fā)一個(gè) IN 令牌包,設(shè)備返回 0 字節(jié)數(shù)據(jù)包后,進(jìn)入 中斷。本次中斷由 IN0_Process ()函數(shù)來(lái)處理,追蹤進(jìn)入,它執(zhí)行以下代碼:else if ( ControlState = WAIT_STATUS_IN )if (pInformation->USBbRequest = SET_ADDRESS) && (Type_Recipient=(STANDARD_REQUEST|DEVICE_RECIPIENT)SetDeviceAddress(pInformation->USBwValue0);pUs
56、er_Standard_Requests->User_SetDeviceAddress(); / 這個(gè)函數(shù)就一個(gè)賦 值語(yǔ)句, bDeviceState = ADDRESSED。(*pProperty->Process_Status_IN)(); / 這是一個(gè)空函數(shù)。ControlState = STALLED;執(zhí)行設(shè)置地址操作、采用新地址后,把設(shè)備的狀態(tài)改為STALLED而在處理的出口中調(diào)用 Post0_Process() 函數(shù),這個(gè)所做的工作是:SetEPRxCount(ENDP0, Device_Property.MaxPacketSize); / 將端點(diǎn) 0的緩沖區(qū)大小設(shè)置為 6
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 九年級(jí)政治尊重他人是我的需要課件
- 液壓與氣動(dòng)技術(shù) 課件 模塊四 課題14
- 單位管理制度集合大合集職工管理篇
- 單位管理制度集粹匯編員工管理
- 議論文結(jié)構(gòu)的六種模式
- 單位管理制度匯編大合集人員管理
- 單位管理制度分享大全【人力資源管理】十篇
- 單位管理制度范例合集員工管理篇十篇
- 單位管理制度呈現(xiàn)合集【人力資源管理篇】十篇
- 萬(wàn)有引力定律復(fù)習(xí)課件
- 2024版房屋市政工程生產(chǎn)安全重大事故隱患判定標(biāo)準(zhǔn)內(nèi)容解讀
- 江蘇省鎮(zhèn)江市實(shí)驗(yàn)學(xué)校2023-2024學(xué)年九年級(jí)上學(xué)期期末考試化學(xué)試卷
- 期末 (試題) -2024-2025學(xué)年人教PEP版(2024)英語(yǔ)三年級(jí)上冊(cè)
- GB/T 32066-2024煤基費(fèi)托合成液體石蠟
- 2019年北京外國(guó)語(yǔ)大學(xué)博士生英語(yǔ)入學(xué)考試試題
- 肝膽外科出科考試試卷
- 塔吊運(yùn)行作業(yè)方案
- 重慶中考數(shù)學(xué)最新26題練習(xí)及答案
- 江蘇衛(wèi)視跨年演唱會(huì)電視轉(zhuǎn)播技術(shù)方案-209年精選文檔
- 水電工程施工機(jī)械臺(tái)時(shí)費(fèi)定額(2004年版)
- 鋼鐵企業(yè)安全生產(chǎn)事故案例匯編
評(píng)論
0/150
提交評(píng)論