|
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è)頭文件中,又有以下定義: #include "usb_type.h" #include "usb_regs.h" #include "usb_def.h" #include "usb_core.h" #include "usb_init.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(用于USB硬件配置)、usb_pwr.c(用于USB連接、斷開操作)、usb_istr.c(直接處理USB中斷)、usb_prop.c(用于上層協(xié)議處理,比如HID協(xié)議,大容量存儲(chǔ)設(shè)備協(xié)議)、usb_desc.c(具體設(shè)備的相關(guān)描述符定義和處理)。
可見,ST的USB操作庫結(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è)備電源。 配置了JoyStickMouse所用到的5個(gè)按鍵,并且配置了兩個(gè)EXTI中斷,一個(gè)是用于把USB從掛起模式喚醒,還有一個(gè)用途未知。
(2)USB_Interrupts_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時(shí)鐘。
(4)USB_Init(void) 這個(gè)是main函數(shù)中調(diào)用的第四個(gè)函數(shù),它也位于usb_init.c文件中。它初始化了三個(gè)全局指針,指向DEVICE_INFO、USER_STANDARD_REQUESTS和DEVICE_PROP結(jié)構(gòu)體。 后面兩個(gè)是函數(shù)指針結(jié)構(gòu)體,里面都是USB請求實(shí)現(xiàn)、功能實(shí)現(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(); } 這三個(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_GetDeviceDescriptor, Joystick_GetConfigDescriptor, Joystick_GetStringDescriptor, 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()函數(shù)調(diào)用pProperty->Init()(實(shí)質(zhì)上就是Joystick_init)完成設(shè)備的初始化。
上層程序調(diào)用下次函數(shù)是常規(guī)性的操作。而下層函數(shù)(usb_init相對于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)用。
這是函數(shù)的代碼: void Joystick_init(void) { /* Update the serial number string descriptor with the data from the unique ID*/ Get_SerialNum();
pInformation->Current_Configuration = 0; /* USB interrupts initialization */ _SetISTR(0); wInterrupt_Mask = IMR_MSK; _SetCNTR(wInterrupt_Mask); /* set interrupts mask */
bDeviceState = UNCONNECTED; } 實(shí)質(zhì)上,代碼執(zhí)行到這里,開發(fā)板已經(jīng)可以響應(yīng)主機(jī)發(fā)來的數(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()用來獲取按鍵的狀態(tài)。 Joystick_Send(JoyState())用來把按鍵狀態(tài)發(fā)到主機(jī)。當(dāng)然這里真正的發(fā)送工作并不是由該代碼完成的。它的工作只是將數(shù)據(jù)寫入IN端點(diǎn)緩沖區(qū),主機(jī)的IN令牌包來的時(shí)候,SIE負(fù)責(zé)把它返回給主機(jī)。
主要代碼如下: 4、中斷處理過程大致理解 (1)usb_istr()函數(shù)中的中斷處理簡單分析 有用的代碼大概以下幾段,首先是處理復(fù)位的代碼,調(diào)用設(shè)備結(jié)構(gòu)中的復(fù)位處理函數(shù)。
處理喚醒的代碼:
處理總線掛起的代碼: 處理端點(diǎn)傳輸完成的代碼,這段是最重要的,它調(diào)用底層usb_int.c()文件中的CTR_LP()函數(shù)來處理端點(diǎn)數(shù)據(jù)傳輸完成中斷。 |
|
|